diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index bd9e8d6a..27d56673 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -32,7 +32,7 @@ jobs: uses: gradle/wrapper-validation-action@v1 - name: Build with Gradle - run: ./gradlew qa --parallel + run: ./gradlew qa - name: Archive reports for failed build if: ${{ failure() }} diff --git a/.github/workflows/diffuse.yml b/.github/workflows/diffuse.yml index b55a9bd0..99954ce8 100644 --- a/.github/workflows/diffuse.yml +++ b/.github/workflows/diffuse.yml @@ -38,7 +38,7 @@ jobs: - name: Build with Gradle if: steps.cache-base.outputs.cache-hit != 'true' - run: ./gradlew assemblePlayProdRelease --parallel + run: ./gradlew assemblePlayProdRelease - name: Copy base apk if: steps.cache-base.outputs.cache-hit != 'true' @@ -50,7 +50,7 @@ jobs: clean: 'false' - name: Build with Gradle - run: ./gradlew assemblePlayProdRelease --parallel + run: ./gradlew assemblePlayProdRelease - name: Copy PR apk run: mv app/build/outputs/apk/playProd/release/*arm64*.apk diffuse-new.apk diff --git a/README.md b/README.md index de13d6eb..9a405536 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Signal Android +# Signal Android Signal is a simple, powerful, and secure messenger. @@ -54,7 +54,7 @@ The form and manner of this distribution makes it eligible for export under the ## License -Copyright 2013-2023 Signal +Copyright 2013-2024 Signal Messenger, LLC Licensed under the GNU AGPLv3: https://www.gnu.org/licenses/agpl-3.0.html @@ -70,7 +70,7 @@ Signal – New Base-line a. thoughtcrime  tm b. securesms  archive 3. Replace all old package mentions vie “replace all” function (Ctrl +Shift + R) - a. org.thoughtcrime.securesms -> org.tm.archive + a. org.tm.archive -> org.tm.archive 4. Add our archiver SDK and Common library to new folder “libs” and compile them via dependencies. 5. Add archiver,intune,selfauthentication folders with all archiving class with util etc. (Take them from src->main->java->org) 6. Search “ArchiveLogger.Companion.sendArchiveLog” in the current project and add all those mentions to the updated project. diff --git a/apntool/.gitignore b/apntool/.gitignore deleted file mode 100644 index b174b758..00000000 --- a/apntool/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.db -*.db.gz diff --git a/apntool/apnlists/cyanogenmod.xml b/apntool/apnlists/cyanogenmod.xml deleted file mode 100644 index 2b7719b7..00000000 --- a/apntool/apnlists/cyanogenmod.xml +++ /dev/null @@ -1,1884 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apntool/apnlists/hangouts.xml b/apntool/apnlists/hangouts.xml deleted file mode 100644 index 2d3ce5b6..00000000 --- a/apntool/apnlists/hangouts.xml +++ /dev/null @@ -1,2217 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/apntool/apntool.py b/apntool/apntool.py deleted file mode 100644 index a687d4bf..00000000 --- a/apntool/apntool.py +++ /dev/null @@ -1,106 +0,0 @@ -import sys -import re -import argparse -import sqlite3 -import gzip -from progressbar import ProgressBar, Counter, Timer -from lxml import etree - -parser = argparse.ArgumentParser(prog='apntool', description="""Process Android's apn xml files and drop them into an - easily queryable SQLite db. Tested up to version 9 of - their APN file.""") -parser.add_argument('-v', '--version', action='version', version='%(prog)s v1.1') -parser.add_argument('-i', '--input', help='the xml file to parse', default='apns.xml', required=False) -parser.add_argument('-o', '--output', help='the sqlite db output file', default='apns.db', required=False) -parser.add_argument('--quiet', help='do not show progress or verbose instructions', action='store_true', required=False) -parser.add_argument('--no-gzip', help="do not gzip after creation", action='store_true', required=False) -args = parser.parse_args() - - -def normalized(target): - o2_typo = re.compile(r"02\.co\.uk") - port_typo = re.compile(r"(\d+\.\d+\.\d+\.\d+)\.(\d+)") - leading_zeros = re.compile(r"(/|\.|^)0+(\d+)") - subbed = o2_typo.sub(r'o2.co.uk', target) - subbed = port_typo.sub(r'\1:\2', subbed) - subbed = leading_zeros.sub(r'\1\2', subbed) - return subbed - -try: - connection = sqlite3.connect(args.output) - cursor = connection.cursor() - cursor.execute('SELECT SQLITE_VERSION()') - version = cursor.fetchone() - if not args.quiet: - print("SQLite version: %s" % version) - print("Opening %s" % args.input) - - cursor.execute("PRAGMA legacy_file_format=ON") - cursor.execute("PRAGMA journal_mode=DELETE") - cursor.execute("PRAGMA page_size=32768") - cursor.execute("VACUUM") - cursor.execute("DROP TABLE IF EXISTS apns") - cursor.execute("""CREATE TABLE apns(_id INTEGER PRIMARY KEY, mccmnc TEXT, mcc TEXT, mnc TEXT, carrier TEXT, - apn TEXT, mmsc TEXT, port INTEGER, type TEXT, protocol TEXT, bearer TEXT, roaming_protocol TEXT, - carrier_enabled INTEGER, mmsproxy TEXT, mmsport INTEGER, proxy TEXT, mvno_match_data TEXT, - mvno_type TEXT, authtype INTEGER, user TEXT, password TEXT, server TEXT)""") - - apns = etree.parse(args.input) - root = apns.getroot() - pbar = None - if not args.quiet: - pbar = ProgressBar(widgets=['Processed: ', Counter(), ' apns (', Timer(), ')'], maxval=len(list(root))).start() - - count = 0 - for apn in root.iter("apn"): - if apn.get("mmsc") is None: - continue - sqlvars = ["?" for x in apn.attrib.keys()] + ["?"] - mccmnc = "%s%s" % (apn.get("mcc"), apn.get("mnc")) - normalized_mmsc = normalized(apn.get("mmsc")) - if normalized_mmsc != apn.get("mmsc"): - print("normalize MMSC: %s => %s" % (apn.get("mmsc"), normalized_mmsc)) - apn.set("mmsc", normalized_mmsc) - - if not apn.get("mmsproxy") is None: - normalized_mmsproxy = normalized(apn.get("mmsproxy")) - if normalized_mmsproxy != apn.get("mmsproxy"): - print("normalize proxy: %s => %s" % (apn.get("mmsproxy"), normalized_mmsproxy)) - apn.set("mmsproxy", normalized_mmsproxy) - - values = [apn.get(attrib) for attrib in apn.attrib.keys()] + [mccmnc] - keys = apn.attrib.keys() + ["mccmnc"] - - cursor.execute("SELECT 1 FROM apns WHERE mccmnc = ? AND apn = ?", [mccmnc, apn.get("apn")]) - if cursor.fetchone() is None: - statement = "INSERT INTO apns (%s) VALUES (%s)" % (", ".join(keys), ", ".join(sqlvars)) - cursor.execute(statement, values) - - count += 1 - if not args.quiet: - pbar.update(count) - - if not args.quiet: - pbar.finish() - connection.commit() - print("Successfully written to %s" % args.output) - - if not args.no_gzip: - gzipped_file = "%s.gz" % (args.output,) - with open(args.output, 'rb') as orig: - with gzip.open(gzipped_file, 'wb') as gzipped: - gzipped.writelines(orig) - print("Successfully gzipped to %s" % gzipped_file) - - if not args.quiet: - print("\nTo include this in the distribution, copy it to the project's assets/databases/ directory.") - print("If you support API 10 or lower, you must use the gzipped version to avoid corruption.") - -except sqlite3.Error as e: - if connection: - connection.rollback() - print("Error: %s" % e.args[0]) - sys.exit(1) -finally: - if connection: - connection.close() diff --git a/apntool/requirements.txt b/apntool/requirements.txt deleted file mode 100644 index 4f7aa283..00000000 --- a/apntool/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -argparse>=1.2.1 -lxml>=3.3.3 -progressbar-latest>=2.4 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ce3c2870..639db23f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,13 +24,13 @@ plugins { apply(from = "static-ips.gradle.kts") //**TM_SA**//Start - Change the version code and version name upon the current version -val canonicalVersionCode = 1338 -val canonicalVersionName = "6.44.3.0" -val signal_teleMessage_version = "6.44.3.0"//Change this param in Jenkins builder and delete it. +val canonicalVersionCode = 1412 +val canonicalVersionName = "7.2.4.2" +val signal_teleMessage_version = "7.2.4.2"//Change this param in Jenkins builder and delete it. //**TM_SA**//end -/*val canonicalVersionCode = 1376 -val canonicalVersionName = "6.44.2"*/ +/*val canonicalVersionCode = 1405 +val canonicalVersionName = "7.2.4"*/ val postFixSize = 100 val abiPostFix: Map = mapOf( @@ -44,29 +44,25 @@ val abiPostFix: Map = mapOf( val keystores: Map = mapOf("debug" to loadKeystoreProperties("keystore.debug.properties")) val selectableVariants = listOf( - "nightlyProdSpinner", - "nightlyProdPerf", - "nightlyProdRelease", - "nightlyStagingRelease", - "nightlyPnpPerf", - "nightlyPnpRelease", - "playProdDebug", - "playProdSpinner", - "playProdCanary", - "playProdPerf", - "playProdBenchmark", - "playProdInstrumentation", - "playProdRelease", - "playStagingDebug", - "playStagingCanary", - "playStagingSpinner", - "playStagingPerf", - "playStagingInstrumentation", - "playPnpDebug", - "playPnpSpinner", - "playStagingRelease", - "websiteProdSpinner", - "websiteProdRelease" + "nightlyProdTmSpinner", + "nightlyProdTmPerf", + "nightlyProdTmRelease", + "nightlyStagingTmRelease", + "playProdTmDebug", + "playProdTmSpinner", + "playProdTmCanary", + "playProdTmPerf", + "playProdTmBenchmark", + "playProdTmInstrumentation", + "playProdTmRelease", + "playStagingTmDebug", + "playStagingTmCanary", + "playStagingTmSpinner", + "playStagingTmPerf", + "playStagingTmInstrumentation", + "playStagingTmRelease", + "websiteProdTmSpinner", + "websiteProdTmRelease" ) val signalBuildToolsVersion: String by rootProject.extra @@ -99,14 +95,13 @@ android { buildToolsVersion = signalBuildToolsVersion compileSdkVersion = signalCompileSdkVersion - +//**TM_SA**//add "ext".. flavorDimensions += listOf("distribution", "environment", "ext") useLibrary("org.apache.http.legacy") testBuildType = "instrumentation" kotlinOptions { jvmTarget = signalKotlinJvmTarget - freeCompilerArgs = listOf("-Xallow-result-return-type") } keystores["debug"]?.let { properties -> @@ -183,8 +178,8 @@ android { versionCode = canonicalVersionCode * postFixSize versionName = canonicalVersionName - minSdkVersion(signalMinSdkVersion) - targetSdkVersion(signalTargetSdkVersion) + minSdk = signalMinSdkVersion + targetSdk = signalTargetSdkVersion multiDexEnabled = true @@ -222,10 +217,9 @@ android { buildConfigField("String[]", "SIGNAL_SVR2_IPS", rootProject.extra["svr2_ips"] as String) buildConfigField("String", "SIGNAL_AGENT", "\"OWA\"") buildConfigField("String", "CDSI_MRENCLAVE", "\"0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57\"") - buildConfigField("String", "SVR2_MRENCLAVE_DEPRECATED", "\"6ee1042f9e20f880326686dd4ba50c25359f01e9f733eeba4382bca001d45094\"") buildConfigField("String", "SVR2_MRENCLAVE", "\"a6622ad4656e1abcd0bc0ff17c229477747d2ded0495c4ebee7ed35c1789fa97\"") buildConfigField("String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\"") - buildConfigField("String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P+NameAZYOD12qRkxosQQP5uux6B2nRyZ7sAV54DgFyLiRcq1FvwKw2EPQdk4HDoePrO/RNUbyNddnM/mMgj4FW65xCoT1LmjrIjsv/Ggdlx46ueczhMgtBunx1/w8k8V+l8LVZ8gAT6wkU5J+DPQalQguMg12Jzug3q4TbdHiGCmD9EunCwOmsLuLJkz6EcSYXtrlDEnAM+hicw7iergYLLlMXpfTdGxJCWJmP4zqUFeTTmsmhsjGBt7NiEB/9pFFEB3pSbf4iiUukw63Eo8Aqnf4iwob6X1QviCWuc8t0I=\"") + buildConfigField("String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P+NameAZYOD12qRkxosQQP5uux6B2nRyZ7sAV54DgFyLiRcq1FvwKw2EPQdk4HDoePrO/RNUbyNddnM/mMgj4FW65xCoT1LmjrIjsv/Ggdlx46ueczhMgtBunx1/w8k8V+l8LVZ8gAT6wkU5J+DPQalQguMg12Jzug3q4TbdHiGCmD9EunCwOmsLuLJkz6EcSYXtrlDEnAM+hicw7iergYLLlMXpfTdGxJCWJmP4zqUFeTTmsmhsjGBt7NiEB/9pFFEB3pSbf4iiUukw63Eo8Aqnf4iwob6X1QviCWuc8t0LUlT9vALgh/f2DPVOOmR0RW6bgRvc7DSF20V/omg+YBw==\"") buildConfigField("String", "GENERIC_SERVER_PUBLIC_PARAMS", "\"AByD873dTilmOSG0TjKrvpeaKEsUmIO8Vx9BeMmftwUs9v7ikPwM8P3OHyT0+X3EUMZrSe9VUp26Wai51Q9I8mdk0hX/yo7CeFGJyzoOqn8e/i4Ygbn5HoAyXJx5eXfIbqpc0bIxzju4H/HOQeOpt6h742qii5u/cbwOhFZCsMIbElZTaeU+BWMBQiZHIGHT5IE0qCordQKZ5iPZom0HeFa8Yq0ShuEyAl0WINBiY6xE3H/9WnvzXBbMuuk//eRxXgzO8ieCeK8FwQNxbfXqZm6Ro1cMhCOF3u7xoX83QhpN\"") buildConfigField("String", "BACKUP_SERVER_PUBLIC_PARAMS", "\"AJwNSU55fsFCbgaxGRD11wO1juAs8Yr5GF8FPlGzzvdJJIKH5/4CC7ZJSOe3yL2vturVaRU2Cx0n751Vt8wkj1bozK3CBV1UokxV09GWf+hdVImLGjXGYLLhnI1J2TWEe7iWHyb553EEnRb5oxr9n3lUbNAJuRmFM7hrr0Al0F0wrDD4S8lo2mGaXe0MJCOM166F8oYRQqpFeEHfiLnxA1O8ZLh7vMdv4g9jI5phpRBTsJ5IjiJrWeP0zdIGHEssUeprDZ9OUJ14m0v61eYJMKsf59Bn+mAT2a7YfB+Don9O\"") buildConfigField("String[]", "LANGUAGES", "new String[]{ ${languageList().map { "\"$it\"" }.joinToString(separator = ", ")} }") @@ -237,6 +231,7 @@ android { buildConfigField("String", "GIPHY_API_KEY", "\"3o6ZsYH6U6Eri53TXy\"") buildConfigField("String", "SIGNAL_CAPTCHA_URL", "\"https://signalcaptchas.org/registration/generate.html\"") buildConfigField("String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/challenge/generate.html\"") + buildConfigField("org.signal.libsignal.net.Network.Environment", "LIBSIGNAL_NET_ENV", "org.signal.libsignal.net.Network.Environment.PRODUCTION") buildConfigField("String", "BUILD_DISTRIBUTION_TYPE", "\"unset\"") buildConfigField("String", "BUILD_ENVIRONMENT_TYPE", "\"unset\"") @@ -244,6 +239,7 @@ android { buildConfigField("String", "BADGE_STATIC_ROOT", "\"https://updates2.signal.org/static/badges/\"") buildConfigField("String", "STRIPE_PUBLISHABLE_KEY", "\"pk_live_6cmGZopuTsV8novGgJJW9JpC00vLIgtQ1D\"") buildConfigField("boolean", "TRACING_ENABLED", "false") + buildConfigField("boolean", "MESSAGE_BACKUP_RESTORE_ENABLED", "false") ndk { abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") @@ -307,7 +303,7 @@ android { proguardFiles(*buildTypes["debug"].proguardFiles.toTypedArray()) //**TM_SA**//Start signingConfig = signingConfigs["release"] - //**TM_SA**//End + //**TM_SA**//End buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Release\"") } @@ -410,29 +406,21 @@ android { buildConfigField("String", "SIGNAL_CDSI_URL", "\"https://cdsi.staging.signal.org\"") buildConfigField("String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\"") buildConfigField("String", "SIGNAL_SVR2_URL", "\"https://svr2.staging.signal.org\"") - buildConfigField("String", "SVR2_MRENCLAVE_DEPRECATED", "\"a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95\"") buildConfigField("String", "SVR2_MRENCLAVE", "\"acb1973aa0bbbd14b3b4e06f145497d948fd4a98efc500fcce363b3b743ec482\"") buildConfigField("String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\"") - buildConfigField("String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXZSSsOZ6s7M1+rTJN0bI5CKY2PX29y5Ok3jSWufIKcgKOnWoP67d5b2du2ZVJjpjfibNIHbT/cegy/sBLoFwtHogVYUewANUAXIaMPyCLRArsKhfJ5wBtTminG/PAvuBdJ70Z/bXVPf8TVsR292zQ65xwvWTejROW6AZX6aqucUjlENAErBme1YHmOSpU6tr6doJ66dPzVAWIanmO/5mgjNEDeK7DDqQdB1xd03HT2Qs2TxY3kCK8aAb/0iM0HQiXjxZ9HIgYhbtvGEnDKW5ILSUydqH/KBhW4Pb0jZWnqN/YgbWDKeJxnDbYcUob5ZY5Lt5ZCMKuaGUvCJRrCtuugSMaqjowCGRempsDdJEt+cMaalhZ6gczklJB/IbdwENW9KeVFPoFNFzhxWUIS5ML9riVYhAtE6JE5jX0xiHNVIIPthb458cfA8daR0nYfYAUKogQArm0iBezOO+mPk5vCM=\"") + buildConfigField("String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXZSSsOZ6s7M1+rTJN0bI5CKY2PX29y5Ok3jSWufIKcgKOnWoP67d5b2du2ZVJjpjfibNIHbT/cegy/sBLoFwtHogVYUewANUAXIaMPyCLRArsKhfJ5wBtTminG/PAvuBdJ70Z/bXVPf8TVsR292zQ65xwvWTejROW6AZX6aqucUjlENAErBme1YHmOSpU6tr6doJ66dPzVAWIanmO/5mgjNEDeK7DDqQdB1xd03HT2Qs2TxY3kCK8aAb/0iM0HQiXjxZ9HIgYhbtvGEnDKW5ILSUydqH/KBhW4Pb0jZWnqN/YgbWDKeJxnDbYcUob5ZY5Lt5ZCMKuaGUvCJRrCtuugSMaqjowCGRempsDdJEt+cMaalhZ6gczklJB/IbdwENW9KeVFPoFNFzhxWUIS5ML9riVYhAtE6JE5jX0xiHNVIIPthb458cfA8daR0nYfYAUKogQArm0iBezOO+mPk5vCNWI+wwkyFCqNDXz/qxl1gAntuCJtSfq9OC3NkdhQlgYQ==\"") buildConfigField("String", "GENERIC_SERVER_PUBLIC_PARAMS", "\"AHILOIrFPXX9laLbalbA9+L1CXpSbM/bTJXZGZiuyK1JaI6dK5FHHWL6tWxmHKYAZTSYmElmJ5z2A5YcirjO/yfoemE03FItyaf8W1fE4p14hzb5qnrmfXUSiAIVrhaXVwIwSzH6RL/+EO8jFIjJ/YfExfJ8aBl48CKHgu1+A6kWynhttonvWWx6h7924mIzW0Czj2ROuh4LwQyZypex4GuOPW8sgIT21KNZaafgg+KbV7XM1x1tF3XA17B4uGUaDbDw2O+nR1+U5p6qHPzmJ7ggFjSN6Utu+35dS1sS0P9N\"") buildConfigField("String", "BACKUP_SERVER_PUBLIC_PARAMS", "\"AHYrGb9IfugAAJiPKp+mdXUx+OL9zBolPYHYQz6GI1gWjpEu5me3zVNSvmYY4zWboZHif+HG1sDHSuvwFd0QszSwuSF4X4kRP3fJREdTZ5MCR0n55zUppTwfHRW2S4sdQ0JGz7YDQIJCufYSKh0pGNEHL6hv79Agrdnr4momr3oXdnkpVBIp3HWAQ6IbXQVSG18X36GaicI1vdT0UFmTwU2KTneluC2eyL9c5ff8PcmiS+YcLzh0OKYQXB5ZfQ06d6DiINvDQLy75zcfUOniLAj0lGJiHxGczin/RXisKSR8\"") buildConfigField("String", "MOBILE_COIN_ENVIRONMENT", "\"testnet\"") buildConfigField("String", "SIGNAL_CAPTCHA_URL", "\"https://signalcaptchas.org/staging/registration/generate.html\"") buildConfigField("String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/staging/challenge/generate.html\"") + buildConfigField("org.signal.libsignal.net.Network.Environment", "LIBSIGNAL_NET_ENV", "org.signal.libsignal.net.Network.Environment.STAGING") buildConfigField("String", "BUILD_ENVIRONMENT_TYPE", "\"Staging\"") buildConfigField("String", "STRIPE_PUBLISHABLE_KEY", "\"pk_test_sngOd8FnXNkpce9nPXawKrJD00kIDngZkD\"") + buildConfigField("boolean", "MESSAGE_BACKUP_RESTORE_ENABLED", "true") } - - create("pnp") { - dimension = "environment" - - initWith(getByName("staging")) - applicationIdSuffix = ".pnp" - - buildConfigField("String", "BUILD_ENVIRONMENT_TYPE", "\"Pnp\"") - } - + //**TM_SA**//add create.. create("tm") { dimension = "ext" } @@ -446,9 +434,7 @@ android { } applicationVariants.all { - val variant = this - - variant.outputs + outputs .map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl } .forEach { output -> if (output.baseName.contains("nightly")) { @@ -461,10 +447,10 @@ android { output.versionNameOverride = tag output.outputFileName = output.outputFileName.replace(".apk", "-${output.versionNameOverride}.apk") } else { - output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk") + output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk") } } else { - output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk") + output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk") val abiName: String = output.getFilter("ABI") ?: "universal" val postFix: Int = abiPostFix[abiName]!! @@ -478,25 +464,20 @@ android { } } - android.variantFilter { - val distribution: String = flavors[0].name - val environment: String = flavors[1].name - val buildType: String = buildType.name - val fullName: String = distribution + environment.capitalize() + buildType.capitalize() - - if (!selectableVariants.contains(fullName)) { - ignore = true + androidComponents { + beforeVariants { variant -> + variant.enable = variant.name in selectableVariants } } - android.buildTypes.forEach { - val path: String = if (it.name == "release") { - "$projectDir/src/release/java" - } else { - "$projectDir/src/debug/java" - } + val releaseDir = "$projectDir/src/release/java" + val debugDir = "$projectDir/src/debug/java" - sourceSets.findByName(it.name)!!.java.srcDir(path) + android.buildTypes.configureEach { + val path = if (name == "release") releaseDir else debugDir + sourceSets.named(name) { + java.srcDir(path) + } } } @@ -515,10 +496,8 @@ dependencies { implementation(project(":donations")) implementation(project(":contacts")) implementation(project(":qr")) - implementation(project(":sms-exporter")) implementation(project(":sticky-header-grid")) implementation(project(":photoview")) - implementation(project(":glide-webp")) implementation(project(":core-ui")) implementation(libs.androidx.fragment.ktx) @@ -538,18 +517,22 @@ dependencies { implementation(libs.androidx.exifinterface) implementation(libs.androidx.compose.rxjava3) implementation(libs.androidx.compose.runtime.livedata) + implementation(libs.androidx.activity.compose) implementation(libs.androidx.constraintlayout) implementation(libs.androidx.multidex) implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) + implementation(libs.androidx.navigation.compose) implementation(libs.androidx.lifecycle.viewmodel.ktx) implementation(libs.androidx.lifecycle.livedata.ktx) implementation(libs.androidx.lifecycle.process) implementation(libs.androidx.lifecycle.viewmodel.savedstate) implementation(libs.androidx.lifecycle.common.java8) implementation(libs.androidx.lifecycle.reactivestreams.ktx) + implementation(libs.androidx.activity.compose) implementation(libs.androidx.camera.core) implementation(libs.androidx.camera.camera2) + implementation(libs.androidx.camera.extensions) implementation(libs.androidx.camera.lifecycle) implementation(libs.androidx.camera.view) implementation(libs.androidx.concurrent.futures) @@ -588,10 +571,6 @@ dependencies { implementation(libs.android.tooltips) { exclude(group = "com.android.support", module = "appcompat-v7") } - implementation(libs.android.smsmms) { - exclude(group = "com.squareup.okhttp", module = "okhttp") - exclude(group = "com.squareup.okhttp", module = "okhttp-urlconnection") - } implementation(libs.stream) implementation(libs.lottie) implementation(libs.signal.android.database.sqlcipher) @@ -656,7 +635,8 @@ dependencies { androidTestUtil(testLibs.androidx.test.orchestrator) //**TM_SA**//Start - implementation (libs.okhttp3) +// implementation (libs.okhttp3) + implementation(libs.square.okhttp3) implementation (libs.okhttpUrlconnection) implementation (libs.loggingInterceptor) implementation (libs.retrofit2) @@ -667,13 +647,15 @@ dependencies { implementation (libs.commonsLang3) implementation (libs.commonsIo) implementation (libs.commonsText) + implementation (libs.adapterRxjava) implementation (group = "commons-io", name = "commons-io", version = "2.6") //For test copy file debugImplementation(files("libs/androidcopysdk-signal-debug.aar")) releaseImplementation(files("libs/androidcopysdk-signal-release.aar")) debugImplementation(files("libs/authenticatorsdk-signal-debug.aar")) releaseImplementation(files("libs/authenticatorsdk-signal-release.aar")) - implementation(files("libs/common-debug.aar")) + debugImplementation(files("libs/common-debug.aar")) + releaseImplementation(files("libs/common-release.aar")) // Include the MAM SDK implementation("com.arthenica:mobile-ffmpeg-full:4.4.LTS") implementation (files("MAMSDK/Microsoft.Intune.MAM.SDK.aar")) @@ -691,7 +673,6 @@ fun assertIsGitRepo() { fun getLastCommitTimestamp(): String { assertIsGitRepo() - ByteArrayOutputStream().use { os -> exec { executable = "git" @@ -717,7 +698,6 @@ fun getGitHash(): String { fun getCurrentGitTag(): String? { assertIsGitRepo() - val stdout = ByteArrayOutputStream() exec { commandLine = listOf("git", "tag", "--points-at", "HEAD") diff --git a/app/jni/utils/org_thoughtcrime_securesms_util_FileUtils.cpp b/app/jni/utils/org_thoughtcrime_securesms_util_FileUtils.cpp index ba2500d9..37faba3b 100644 --- a/app/jni/utils/org_thoughtcrime_securesms_util_FileUtils.cpp +++ b/app/jni/utils/org_thoughtcrime_securesms_util_FileUtils.cpp @@ -6,7 +6,7 @@ #include #include //**TM_SA**//Change the package name to be our name. -jint JNICALL Java_org_tm_archive_util_FileUtils_getFileDescriptorOwner +jint JNICALL Java_tm_archive_securesms_util_FileUtils_getFileDescriptorOwner (JNIEnv *env, jclass clazz, jobject fileDescriptor) { jclass fdClass = env->GetObjectClass(fileDescriptor); @@ -31,9 +31,8 @@ jint JNICALL Java_org_tm_archive_util_FileUtils_getFileDescriptorOwner return stat_struct.st_uid; } - //**TM_SA**//Change the package name to be our name. -JNIEXPORT jint JNICALL Java_org_tm_archive_util_FileUtils_createMemoryFileDescriptor +JNIEXPORT jint JNICALL Java_tm_archive_securesms_util_FileUtils_createMemoryFileDescriptor (JNIEnv *env, jclass clazz, jstring jname) { const char *name = env->GetStringUTFChars(jname, NULL); diff --git a/app/libs/androidcopysdk-signal-debug.aar b/app/libs/androidcopysdk-signal-debug.aar index 01c03754..da1b700e 100644 Binary files a/app/libs/androidcopysdk-signal-debug.aar and b/app/libs/androidcopysdk-signal-debug.aar differ diff --git a/app/libs/androidcopysdk-signal-release.aar b/app/libs/androidcopysdk-signal-release.aar index 69d68108..75049de1 100644 Binary files a/app/libs/androidcopysdk-signal-release.aar and b/app/libs/androidcopysdk-signal-release.aar differ diff --git a/app/libs/authenticatorsdk-signal-debug.aar b/app/libs/authenticatorsdk-signal-debug.aar index da1eaab4..52d33c0c 100644 Binary files a/app/libs/authenticatorsdk-signal-debug.aar and b/app/libs/authenticatorsdk-signal-debug.aar differ diff --git a/app/libs/authenticatorsdk-signal-release.aar b/app/libs/authenticatorsdk-signal-release.aar index d498eccb..2257139f 100644 Binary files a/app/libs/authenticatorsdk-signal-release.aar and b/app/libs/authenticatorsdk-signal-release.aar differ diff --git a/app/libs/common-debug.aar b/app/libs/common-debug.aar index 1c283ad1..6406ef25 100644 Binary files a/app/libs/common-debug.aar and b/app/libs/common-debug.aar differ diff --git a/app/libs/common-release.aar b/app/libs/common-release.aar new file mode 100644 index 00000000..adc4afb7 Binary files /dev/null and b/app/libs/common-release.aar differ diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml index be335599..d1700d50 100644 --- a/app/lint-baseline.xml +++ b/app/lint-baseline.xml @@ -6,12 +6,11 @@ message="Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with `checkPermission`) or explicitly handle a potential `SecurityException`" errorLine1=" List<SubscriptionInfo> list = subscriptionManager.getActiveSubscriptionInfoList();" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - + - (); +} +-keepclassmembers class com.tm.androidcopysdk.** { + public (); +} + +-dontwarn com.github.underscore.lodash.$ +-dontwarn com.google.crypto.tink.subtle.Ed25519Sign$KeyPair +-dontwarn com.google.crypto.tink.subtle.Ed25519Sign +-dontwarn com.google.crypto.tink.subtle.Ed25519Verify +-dontwarn com.google.crypto.tink.subtle.X25519 +-dontwarn dalvik.system.VMStack +-dontwarn java.lang.ProcessHandle +-dontwarn java.lang.management.ManagementFactory +-dontwarn java.lang.management.RuntimeMXBean +-dontwarn javax.naming.InitialContext +-dontwarn javax.naming.NameNotFoundException +-dontwarn javax.naming.NamingException +-dontwarn org.bouncycastle.asn1.ASN1Encodable +-dontwarn org.bouncycastle.asn1.pkcs.PrivateKeyInfo +-dontwarn org.bouncycastle.asn1.x509.AlgorithmIdentifier +-dontwarn org.bouncycastle.asn1.x509.SubjectPublicKeyInfo +-dontwarn org.bouncycastle.cert.X509CertificateHolder +-dontwarn org.bouncycastle.cert.jcajce.JcaX509CertificateHolder +-dontwarn org.bouncycastle.crypto.BlockCipher +-dontwarn org.bouncycastle.crypto.CipherParameters +-dontwarn org.bouncycastle.crypto.InvalidCipherTextException +-dontwarn org.bouncycastle.crypto.engines.AESEngine +-dontwarn org.bouncycastle.crypto.modes.GCMBlockCipher +-dontwarn org.bouncycastle.crypto.params.AEADParameters +-dontwarn org.bouncycastle.crypto.params.KeyParameter +-dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider +-dontwarn org.bouncycastle.openssl.PEMException +-dontwarn org.bouncycastle.openssl.PEMKeyPair +-dontwarn org.bouncycastle.openssl.PEMParser +-dontwarn org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter +-dontwarn rx.android.schedulers.AndroidSchedulers +-dontwarn sun.reflect.Reflection +#TM_SA end diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/SignalInstrumentationApplicationContext.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/SignalInstrumentationApplicationContext.kt index 493e5be8..2c196020 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/SignalInstrumentationApplicationContext.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/SignalInstrumentationApplicationContext.kt @@ -35,4 +35,18 @@ class SignalInstrumentationApplicationContext : ApplicationContext() { LogDatabase.getInstance(this).logs.trimToSize() } } + + override fun beginJobLoop() = Unit + + /** + * Some of the jobs can interfere with some of the instrumentation tests. + * + * For example, we may try to create a release channel recipient while doing + * an import/backup test. + * + * This can be used to start the job loop if needed for tests that rely on it. + */ + fun beginJobLoopForTests() { + super.beginJobLoop() + } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/BackupTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/BackupTest.kt index 6696183c..6656ef3e 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/BackupTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/BackupTest.kt @@ -255,7 +255,7 @@ class BackupTest { SignalStore.donationsValues().setSubscriber(Subscriber(SubscriberId.generate(), "USD")) SignalStore.donationsValues().setDisplayBadgesOnProfile(false) - SignalStore.phoneNumberPrivacy().phoneNumberListingMode = PhoneNumberPrivacyValues.PhoneNumberListingMode.UNLISTED + SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode = PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE SignalStore.phoneNumberPrivacy().phoneNumberSharingMode = PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY SignalStore.settings().isLinkPreviewsEnabled = false diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt new file mode 100644 index 00000000..719e0e86 --- /dev/null +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt @@ -0,0 +1,1540 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2 + +import android.Manifest +import android.app.UiAutomation +import android.os.Environment +import androidx.test.platform.app.InstrumentationRegistry +import okio.ByteString.Companion.toByteString +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.signal.core.util.Base64 +import org.signal.libsignal.messagebackup.MessageBackup +import org.signal.libsignal.messagebackup.MessageBackupKey +import org.signal.libsignal.zkgroup.profiles.ProfileKey +import org.tm.archive.backup.v2.proto.AccountData +import org.tm.archive.backup.v2.proto.BackupInfo +import org.tm.archive.backup.v2.proto.BodyRange +import org.tm.archive.backup.v2.proto.Call +import org.tm.archive.backup.v2.proto.Chat +import org.tm.archive.backup.v2.proto.ChatItem +import org.tm.archive.backup.v2.proto.ChatUpdateMessage +import org.tm.archive.backup.v2.proto.Contact +import org.tm.archive.backup.v2.proto.DistributionList +import org.tm.archive.backup.v2.proto.ExpirationTimerChatUpdate +import org.tm.archive.backup.v2.proto.FilePointer +import org.tm.archive.backup.v2.proto.Frame +import org.tm.archive.backup.v2.proto.Group +import org.tm.archive.backup.v2.proto.MessageAttachment +import org.tm.archive.backup.v2.proto.ProfileChangeChatUpdate +import org.tm.archive.backup.v2.proto.Quote +import org.tm.archive.backup.v2.proto.Reaction +import org.tm.archive.backup.v2.proto.Recipient +import org.tm.archive.backup.v2.proto.ReleaseNotes +import org.tm.archive.backup.v2.proto.Self +import org.tm.archive.backup.v2.proto.SendStatus +import org.tm.archive.backup.v2.proto.SessionSwitchoverChatUpdate +import org.tm.archive.backup.v2.proto.SimpleChatUpdate +import org.tm.archive.backup.v2.proto.StandardMessage +import org.tm.archive.backup.v2.proto.StickerPack +import org.tm.archive.backup.v2.proto.Text +import org.tm.archive.backup.v2.proto.ThreadMergeChatUpdate +import org.tm.archive.backup.v2.stream.EncryptedBackupReader +import org.tm.archive.backup.v2.stream.EncryptedBackupWriter +import org.tm.archive.keyvalue.SignalStore +import org.whispersystems.signalservice.api.kbs.MasterKey +import org.whispersystems.signalservice.api.push.DistributionId +import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.subscriptions.SubscriberId +import org.whispersystems.signalservice.api.util.toByteArray +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.FileOutputStream +import java.util.UUID +import java.util.concurrent.TimeUnit +import kotlin.random.Random +import kotlin.time.Duration.Companion.days + +/** + * Test the import and export of message backup frames to make sure what + * goes in, comes out. + */ +class ImportExportTest { + companion object { + val SELF_ACI = ServiceId.ACI.from(UUID.fromString("77770000-b477-4f35-a824-d92987a63641")) + val SELF_PNI = ServiceId.PNI.from(UUID.fromString("77771111-b014-41fb-bf73-05cb2ec52910")) + const val SELF_E164 = "+10000000000" + val SELF_PROFILE_KEY = ProfileKey(Random.nextBytes(32)) + val MASTER_KEY = Base64.decode("sHuBMP4ToZk4tcNU+S8eBUeCt8Am5EZnvuqTBJIR4Do") + + val defaultBackupInfo = BackupInfo(version = 1L, backupTimeMs = 123456L) + val selfRecipient = Recipient(id = 1, self = Self()) + val releaseNotes = Recipient(id = 2, releaseNotes = ReleaseNotes()) + val standardAccountData = AccountData( + profileKey = SELF_PROFILE_KEY.serialize().toByteString(), + username = "self.01", + usernameLink = null, + givenName = "Peter", + familyName = "Parker", + avatarUrlPath = "https://example.com/", + subscriberId = SubscriberId.generate().bytes.toByteString(), + subscriberCurrencyCode = "USD", + subscriptionManuallyCancelled = true, + accountSettings = AccountData.AccountSettings( + readReceipts = true, + sealedSenderIndicators = true, + typingIndicators = true, + linkPreviews = true, + notDiscoverableByPhoneNumber = true, + preferContactAvatars = true, + universalExpireTimer = 42, + displayBadgesOnProfile = true, + keepMutedChatsArchived = true, + hasSetMyStoriesPrivacy = true, + hasViewedOnboardingStory = true, + storiesDisabled = true, + storyViewReceiptsEnabled = true, + hasSeenGroupStoryEducationSheet = true, + hasCompletedUsernameOnboarding = true, + phoneNumberSharingMode = AccountData.PhoneNumberSharingMode.EVERYBODY, + preferredReactionEmoji = listOf("a", "b", "c") + ) + ) + val alice = Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = false, + hidden = false, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ) + + /** + * When using standardFrames you must start recipient ids at 3. + */ + private val standardFrames = arrayOf(defaultBackupInfo, standardAccountData, selfRecipient, releaseNotes) + } + + @JvmField + @Rule + var testName = TestName() + + @Before + fun setup() { + SignalStore.svr().setMasterKey(MasterKey(MASTER_KEY), "1234") + SignalStore.account().setE164(SELF_E164) + SignalStore.account().setAci(SELF_ACI) + SignalStore.account().setPni(SELF_PNI) + SignalStore.account().generateAciIdentityKeyIfNecessary() + SignalStore.account().generatePniIdentityKeyIfNecessary() + } + + @Test + fun accountAndSelf() { + importExport(*standardFrames) + } + + @Test + fun largeNumberOfRecipientsAndChats() { + val recipients = ArrayList(5000) + val chats = ArrayList(5000) + var id = 3L + for (i in 0..5000) { + val recipientId = id++ + recipients.add( + Recipient( + id = recipientId, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "rec$i.01", + e164 = 14125550000 + i, + blocked = false, + hidden = false, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Test", + profileFamilyName = "Recipient$i", + hideStory = false + ) + ) + ) + chats.add( + Chat( + id = recipientId - 2L, + recipientId = recipientId + ) + ) + if (i % 10 == 0) { + val groupId = id++ + recipients.add( + Recipient( + id = groupId, + group = Group( + masterKey = TestRecipientUtils.generateGroupMasterKey().toByteString(), + whitelisted = true, + hideStory = false, + storySendMode = Group.StorySendMode.ENABLED, + name = "Cool Group $i" + ) + ) + ) + chats.add( + Chat( + id = groupId - 2L, + recipientId = groupId + ) + ) + } + } + importExport( + *standardFrames, + *recipients.toArray() + ) + } + + @Test + fun largeNumberOfMessagesAndChats() { + val NUM_INDIVIDUAL_RECIPIENTS = 1000 + val numIndividualMessages = 500 + val numGroupMessagesPerPerson = 200 + + val random = Random(1516) + + val recipients = ArrayList(1010) + val chats = ArrayList(1010) + var id = 3L + for (i in 0 until NUM_INDIVIDUAL_RECIPIENTS) { + val recipientId = id++ + recipients.add( + Recipient( + id = recipientId, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = if (random.trueWithProbability(0.2f)) "rec$i.01" else null, + e164 = 14125550000 + i, + blocked = random.trueWithProbability(0.1f), + hidden = random.trueWithProbability(0.1f), + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = random.trueWithProbability(0.9f), + profileGivenName = "Test", + profileFamilyName = "Recipient$i", + hideStory = false + ) + ) + ) + chats.add( + Chat( + id = recipientId - 2L, + recipientId = recipientId + ) + ) + if (i % 100 == 0) { + val groupId = id++ + recipients.add( + Recipient( + id = groupId, + group = Group( + masterKey = TestRecipientUtils.generateGroupMasterKey().toByteString(), + whitelisted = random.trueWithProbability(0.9f), + hideStory = random.trueWithProbability(0.1f), + storySendMode = if (random.trueWithProbability(0.9f)) Group.StorySendMode.ENABLED else Group.StorySendMode.DISABLED, + name = "Cool Group $i" + ) + ) + ) + chats.add( + Chat( + id = groupId - 2L, + recipientId = groupId + ) + ) + } + } + val chatItems = ArrayList() + var sentTime = 1L + val groupMembers = ArrayList() + var group: Recipient? = null + for (recipient in recipients) { + // Make another group and populate it with messages from these members + if (recipient.group != null) { + if (group == null) { + group = recipient + groupMembers.clear() + } else { + for (member in groupMembers) { + for (i in 0 until numGroupMessagesPerPerson) { + chatItems.add( + ChatItem( + chatId = group.id - 2L, + authorId = member.id, + dateSent = sentTime++, + sms = false, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = sentTime + 1, + dateServerSent = sentTime, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Medium length message from ${member.contact?.profileGivenName} ${member.contact?.profileFamilyName} sent at $sentTime" + ) + ) + ) + ) + } + } + for (i in 0 until numGroupMessagesPerPerson) { + ChatItem( + chatId = group.id - 2L, + authorId = selfRecipient.id, + dateSent = sentTime++, + sms = false, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = groupMembers.map { groupMember -> + SendStatus(recipientId = groupMember.id, deliveryStatus = if (random.trueWithProbability(0.8f)) SendStatus.Status.READ else SendStatus.Status.DELIVERED, sealedSender = true) + } + ), + standardMessage = StandardMessage( + text = Text( + body = "Outgoing message without much text in it just because" + ) + ) + ) + } + } + } else { + groupMembers.add(recipient) + for (i in 0 until numIndividualMessages) { + if (i % 2 == 0) { + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = sentTime++, + sms = false, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = listOf( + SendStatus(recipient.id, deliveryStatus = if (random.trueWithProbability(0.8f)) SendStatus.Status.READ else SendStatus.Status.DELIVERED, sealedSender = true) + ) + ), + standardMessage = StandardMessage( + text = Text( + body = "Outgoing message without much text in it just because" + ) + ) + ) + } else { + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = sentTime++, + sms = false, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = sentTime + 1, + dateServerSent = sentTime, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Outgoing message without much text in it just because" + ) + ) + ) + } + } + } + } + val import = exportFrames( + *standardFrames, + *recipients.toArray(), + *chatItems.toArray() + ) + outputFile(import) + } + + @Test + fun individualRecipients() { + importExport( + *standardFrames, + Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = true, + hidden = true, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ), + Recipient( + id = 4, + contact = Contact( + aci = null, + pni = null, + username = null, + e164 = 141255501235, + blocked = true, + hidden = true, + registered = Contact.Registered.NOT_REGISTERED, + unregisteredTimestamp = 1234568927398L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = false, + profileGivenName = "Peter", + profileFamilyName = "Kim", + hideStory = true + ) + ) + ) + } + + @Test + fun groupRecipients() { + importExport( + *standardFrames, + Recipient( + id = 3, + group = Group( + masterKey = TestRecipientUtils.generateGroupMasterKey().toByteString(), + whitelisted = true, + hideStory = true, + storySendMode = Group.StorySendMode.ENABLED, + name = "Cool test group" + ) + ), + Recipient( + id = 4, + group = Group( + masterKey = TestRecipientUtils.generateGroupMasterKey().toByteString(), + whitelisted = false, + hideStory = false, + storySendMode = Group.StorySendMode.DEFAULT, + name = "Cool test group" + ) + ) + ) + } + + @Test + fun distributionListRecipients() { + importExport( + *standardFrames, + Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = true, + hidden = true, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ), + Recipient( + id = 4, + contact = Contact( + aci = null, + pni = null, + username = null, + e164 = 141255501235, + blocked = true, + hidden = true, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Peter", + profileFamilyName = "Kim", + hideStory = true + ) + ), + Recipient( + id = 5, + contact = Contact( + aci = null, + pni = null, + username = null, + e164 = 141255501236, + blocked = true, + hidden = true, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Father", + profileFamilyName = "Kim", + hideStory = true + ) + ), + Recipient( + id = 6, + distributionList = DistributionList( + name = "Kim Family", + distributionId = DistributionId.create().asUuid().toByteArray().toByteString(), + allowReplies = true, + deletionTimestamp = 0L, + privacyMode = DistributionList.PrivacyMode.ONLY_WITH, + memberRecipientIds = listOf(3, 4, 5) + ) + ) + ) + } + + @Test + fun deletedDistributionList() { + val alexa = Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = true, + hidden = true, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ) + val importData = exportFrames( + *standardFrames, + alexa, + Recipient( + id = 6, + distributionList = DistributionList( + name = "Deleted list", + distributionId = DistributionId.create().asUuid().toByteArray().toByteString(), + allowReplies = true, + deletionTimestamp = 12345L, + privacyMode = DistributionList.PrivacyMode.ONLY_WITH, + memberRecipientIds = listOf(3) + ) + ) + ) + import(importData) + val exported = export() + val expected = exportFrames( + *standardFrames, + alexa + ) + outputFile(importData, expected) + compare(expected, exported) + } + + @Test + fun chatThreads() { + importExport( + *standardFrames, + Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = false, + hidden = false, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ), + Recipient( + id = 4, + group = Group( + masterKey = TestRecipientUtils.generateGroupMasterKey().toByteString(), + whitelisted = true, + hideStory = true, + storySendMode = Group.StorySendMode.DEFAULT, + name = "Cool test group" + ) + ), + Chat( + id = 1, + recipientId = 3, + archived = true, + pinnedOrder = 1, + expirationTimerMs = 1.days.inWholeMilliseconds, + muteUntilMs = System.currentTimeMillis(), + markedUnread = true, + dontNotifyForMentionsIfMuted = true, + wallpaper = null + ) + ) + } + + @Test + fun calls() { + val individualCalls = ArrayList() + val groupCalls = ArrayList() + val states = arrayOf(Call.State.MISSED, Call.State.COMPLETED, Call.State.DECLINED_BY_USER, Call.State.DECLINED_BY_NOTIFICATION_PROFILE) + val types = arrayOf(Call.Type.VIDEO_CALL, Call.Type.AD_HOC_CALL, Call.Type.AUDIO_CALL) + var id = 1L + var timestamp = 12345L + + for (state in states) { + for (type in types) { + individualCalls.add( + Call( + callId = id++, + conversationRecipientId = 3, + type = type, + state = state, + timestamp = timestamp++, + ringerRecipientId = 3, + outgoing = true + ) + ) + individualCalls.add( + Call( + callId = id++, + conversationRecipientId = 3, + type = type, + state = state, + timestamp = timestamp++, + ringerRecipientId = selfRecipient.id, + outgoing = false + ) + ) + } + groupCalls.add( + Call( + callId = id++, + conversationRecipientId = 4, + type = Call.Type.GROUP_CALL, + state = state, + timestamp = timestamp++, + ringerRecipientId = 3, + outgoing = true + ) + ) + groupCalls.add( + Call( + callId = id++, + conversationRecipientId = 4, + type = Call.Type.GROUP_CALL, + state = state, + timestamp = timestamp++, + ringerRecipientId = selfRecipient.id, + outgoing = false + ) + ) + } + + importExport( + *standardFrames, + Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = false, + hidden = false, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ), + Recipient( + id = 4, + group = Group( + masterKey = TestRecipientUtils.generateGroupMasterKey().toByteString(), + whitelisted = true, + hideStory = true, + storySendMode = Group.StorySendMode.DEFAULT, + name = "Cool test group" + ) + ), + *individualCalls.toArray(), + *groupCalls.toArray() + ) + } + + @Test + fun messageWithOnlyText() { + var dateSent = System.currentTimeMillis() + val sendStatuses = enumerateSendStatuses(alice.id) + val incomingMessageDetails = enumerateIncomingMessageDetails(dateSent + 200) + val outgoingMessages = ArrayList() + val incomingMessages = ArrayList() + for (sendStatus in sendStatuses) { + outgoingMessages.add( + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = dateSent++, + expireStartDate = dateSent + 1000, + expiresInMs = TimeUnit.DAYS.toMillis(2), + sms = false, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = listOf(sendStatus) + ), + standardMessage = StandardMessage( + text = Text( + body = "Text only body" + ) + ) + ) + ) + } + dateSent++ + for (incomingDetail in incomingMessageDetails) { + incomingMessages.add( + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSent++, + expireStartDate = dateSent + 1000, + expiresInMs = TimeUnit.DAYS.toMillis(2), + sms = false, + incoming = incomingDetail, + standardMessage = StandardMessage( + text = Text( + body = "Text only body" + ) + ) + ) + ) + } + + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + *outgoingMessages.toArray(), + *incomingMessages.toArray() + ) + } + + @Test + fun messageWithTextMentionsBodyRangesAndReactions() { + val time = System.currentTimeMillis() + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 100, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Hey check this out I love spans!", + bodyRanges = listOf( + BodyRange( + start = 6, + length = 3, + style = BodyRange.Style.BOLD + ), + BodyRange( + start = 10, + length = 3, + style = BodyRange.Style.ITALIC + ), + BodyRange( + start = 14, + length = 3, + style = BodyRange.Style.SPOILER + ), + BodyRange( + start = 18, + length = 3, + style = BodyRange.Style.STRIKETHROUGH + ), + BodyRange( + start = 22, + length = 3, + style = BodyRange.Style.MONOSPACE + ), + BodyRange( + start = 4, + length = 0, + mentionAci = alice.contact!!.aci + ) + ) + ), + reactions = listOf( + Reaction(emoji = "F", authorId = selfRecipient.id, sentTimestamp = 302, receivedTimestamp = 303), + Reaction(emoji = "F", authorId = alice.id, sentTimestamp = 301, receivedTimestamp = 302) + ) + ) + ) + ) + } + + @Test + fun messageWithTextAndQuotes() { + val spans = listOf( + BodyRange( + start = 6, + length = 3, + style = BodyRange.Style.BOLD + ), + BodyRange( + start = 10, + length = 3, + style = BodyRange.Style.ITALIC + ), + BodyRange( + start = 14, + length = 3, + style = BodyRange.Style.SPOILER + ), + BodyRange( + start = 18, + length = 3, + style = BodyRange.Style.STRIKETHROUGH + ), + BodyRange( + start = 22, + length = 3, + style = BodyRange.Style.MONOSPACE + ) + ) + val time = System.currentTimeMillis() + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 100, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Hey check this out I love spans!", + bodyRanges = spans + ) + ) + ), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 101, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "I quoted an existing message" + ), + quote = Quote( + targetSentTimestamp = 100, + authorId = alice.id, + type = Quote.Type.NORMAL, + text = "Hey check this out I love spans!", + bodyRanges = spans + ) + ) + ), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 102, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "I quoted an non-existing message" + ), + quote = Quote( + targetSentTimestamp = 60, + authorId = alice.id, + type = Quote.Type.NORMAL, + text = "Hey check this out I love spans!", + bodyRanges = spans + ) + ) + ) + ) + } + + @Test + fun messagesNearExpirationNotExported() { + val chat = buildChat(alice, 1) + val expirationNotStarted = ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = 101, + expireStartDate = null, + expiresInMs = TimeUnit.DAYS.toMillis(1), + sms = false, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 100, + dateServerSent = 100, + read = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Expiration not started but less than or equal to 1 day" + ) + ) + ) + val importData = exportFrames( + *standardFrames, + alice, + chat, + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = 100, + expireStartDate = System.currentTimeMillis(), + expiresInMs = TimeUnit.DAYS.toMillis(1), + sms = false, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 100, + dateServerSent = 100, + read = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Near expiration" + ) + ) + ), + expirationNotStarted + ) + import(importData) + val exported = export() + val expected = exportFrames( + *standardFrames, + alice, + chat, + expirationNotStarted + ) + outputFile(importData, expected) + compare(expected, exported) + } + + @Test + fun messageWithAttachmentsAndQuoteAttachments() { + var dateSent = System.currentTimeMillis() + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = dateSent++, + sms = false, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = listOf(SendStatus(alice.id, deliveryStatus = SendStatus.Status.READ, lastStatusUpdateTimestamp = -1)) + ), + standardMessage = StandardMessage( + attachments = listOf( + MessageAttachment( + pointer = FilePointer( + attachmentLocator = FilePointer.AttachmentLocator( + cdnKey = "coolCdnKey", + cdnNumber = 2, + uploadTimestamp = System.currentTimeMillis() + ), + key = (1..32).map { it.toByte() }.toByteArray().toByteString(), + contentType = "image/png", + size = 12345, + fileName = "very_cool_picture.png", + width = 100, + height = 200, + caption = "Love this cool picture!", + incrementalMacChunkSize = 0 + ) + ) + ) + ) + ) + ) + } + + @Test + fun simpleChatUpdateMessage() { + var dateSentStart = 100L + val updateMessages = ArrayList() + for (i in 1..11) { + updateMessages.add( + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSentStart++, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = dateSentStart, + dateServerSent = dateSentStart, + read = true, + sealedSender = true + ), + updateMessage = ChatUpdateMessage( + simpleUpdate = SimpleChatUpdate( + type = SimpleChatUpdate.Type.fromValue(i)!! + ) + ) + ) + ) + } + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + *updateMessages.toArray() + ) + } + + @Test + fun expirationTimerUpdateMessage() { + var dateSentStart = 100L + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSentStart++, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = dateSentStart, + dateServerSent = dateSentStart, + read = true, + sealedSender = true + ), + updateMessage = ChatUpdateMessage( + expirationTimerChange = ExpirationTimerChatUpdate( + 1000 + ) + ) + ), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = dateSentStart++, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = listOf( + SendStatus(alice.id, deliveryStatus = SendStatus.Status.READ, sealedSender = true, lastStatusUpdateTimestamp = -1) + ) + ), + updateMessage = ChatUpdateMessage( + expirationTimerChange = ExpirationTimerChatUpdate( + 0 + ) + ) + ), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = dateSentStart++, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = listOf(SendStatus(alice.id, deliveryStatus = SendStatus.Status.READ, sealedSender = true, lastStatusUpdateTimestamp = -1)) + ), + updateMessage = ChatUpdateMessage( + expirationTimerChange = ExpirationTimerChatUpdate( + 10000 + ) + ) + ), + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSentStart++, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = dateSentStart, + dateServerSent = dateSentStart, + read = true, + sealedSender = true + ), + updateMessage = ChatUpdateMessage( + expirationTimerChange = ExpirationTimerChatUpdate( + 0 + ) + ) + ) + ) + } + + @Test + fun profileChangeChatUpdateMessage() { + var dateSentStart = 100L + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSentStart++, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = dateSentStart, + dateServerSent = dateSentStart, + read = true, + sealedSender = true + ), + updateMessage = ChatUpdateMessage( + profileChange = ProfileChangeChatUpdate( + previousName = "Aliceee Kim", + newName = "Alice Kim" + ) + ) + ) + ) + } + + @Test + fun threadMergeChatUpdate() { + var dateSentStart = 100L + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSentStart++, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = dateSentStart, + dateServerSent = dateSentStart, + read = true, + sealedSender = true + ), + updateMessage = ChatUpdateMessage( + threadMerge = ThreadMergeChatUpdate( + previousE164 = 141255501237 + ) + ) + ) + ) + } + + @Test + fun sessionSwitchoverChatUpdate() { + var dateSentStart = 100L + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSentStart++, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = dateSentStart, + dateServerSent = dateSentStart, + read = true, + sealedSender = true + ), + updateMessage = ChatUpdateMessage( + sessionSwitchover = SessionSwitchoverChatUpdate( + e164 = 141255501237 + ) + ) + ) + ) + } + + fun enumerateIncomingMessageDetails(dateSent: Long): List { + val details = mutableListOf() + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = true, + sealedSender = true + ) + ) + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = true, + sealedSender = false + ) + ) + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = false, + sealedSender = true + ) + ) + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = false, + sealedSender = false + ) + ) + return details + } + + fun enumerateSendStatuses(recipientId: Long): List { + val statuses = ArrayList() + val sealedSenderStates = listOf(true, false) + for (sealedSender in sealedSenderStates) { + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.DELIVERED, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.PENDING, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1, + networkFailure = true + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.SENT, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.READ, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.PENDING, + sealedSender = sealedSender, + networkFailure = true, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.FAILED, + sealedSender = sealedSender, + identityKeyMismatch = true, + lastStatusUpdateTimestamp = -1 + ) + ) + } + return statuses + } + + private fun buildChat(recipient: Recipient, id: Long): Chat { + return Chat( + id = id, + recipientId = recipient.id, + archived = false, + pinnedOrder = 0, + expirationTimerMs = 0, + muteUntilMs = 0, + markedUnread = false, + dontNotifyForMentionsIfMuted = false, + wallpaper = null + ) + } + + /** + * Export passed in frames as a backup. Does not automatically include + * any standard frames (e.g. backup header). + */ + private fun exportFrames(vararg objects: Any): ByteArray { + val outputStream = ByteArrayOutputStream() + val writer = EncryptedBackupWriter( + key = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey(), + aci = SignalStore.account().aci!!, + outputStream = outputStream, + append = { mac -> outputStream.write(mac) } + ) + + writer.use { + for (obj in objects) { + when (obj) { + is BackupInfo -> writer.write(obj) + is AccountData -> writer.write(Frame(account = obj)) + is Recipient -> writer.write(Frame(recipient = obj)) + is Chat -> writer.write(Frame(chat = obj)) + is ChatItem -> writer.write(Frame(chatItem = obj)) + is Call -> writer.write(Frame(call = obj)) + is StickerPack -> writer.write(Frame(stickerPack = obj)) + else -> Assert.fail("invalid object $obj") + } + } + } + return outputStream.toByteArray() + } + + /** + * Exports the passed in frames as a backup and then attempts to + * import them. + */ + private fun import(vararg objects: Any) { + val importData = exportFrames(*objects) + import(importData) + } + + private fun import(importData: ByteArray) { + BackupRepository.import(length = importData.size.toLong(), inputStreamFactory = { ByteArrayInputStream(importData) }, selfData = BackupRepository.SelfData(SELF_ACI, SELF_PNI, SELF_E164, SELF_PROFILE_KEY)) + } + + /** + * Export our current database as a backup. + */ + private fun export(): ByteArray { + val exportData = BackupRepository.export() + return exportData + } + + private fun validate(importData: ByteArray): MessageBackup.ValidationResult { + val factory = { ByteArrayInputStream(importData) } + val masterKey = SignalStore.svr().getOrCreateMasterKey() + val key = MessageBackupKey(masterKey.serialize(), org.signal.libsignal.protocol.ServiceId.Aci.parseFromBinary(SELF_ACI.toByteArray())) + + return MessageBackup.validate(key, MessageBackup.Purpose.REMOTE_BACKUP, factory, importData.size.toLong()) + } + + /** + * Imports the passed in frames and then exports them. + * + * It will do a comparison to assert that the import and export + * are equal. + */ + private fun importExport(vararg objects: Any) { + val outputStream = ByteArrayOutputStream() + val writer = EncryptedBackupWriter( + key = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey(), + aci = SignalStore.account().aci!!, + outputStream = outputStream, + append = { mac -> outputStream.write(mac) } + ) + + writer.use { + for (obj in objects) { + when (obj) { + is BackupInfo -> writer.write(obj) + is AccountData -> writer.write(Frame(account = obj)) + is Recipient -> writer.write(Frame(recipient = obj)) + is Chat -> writer.write(Frame(chat = obj)) + is ChatItem -> writer.write(Frame(chatItem = obj)) + is Call -> writer.write(Frame(call = obj)) + is StickerPack -> writer.write(Frame(stickerPack = obj)) + else -> Assert.fail("invalid object $obj") + } + } + } + val importData = outputStream.toByteArray() + outputFile(importData) + BackupRepository.import(length = importData.size.toLong(), inputStreamFactory = { ByteArrayInputStream(importData) }, selfData = BackupRepository.SelfData(SELF_ACI, SELF_PNI, SELF_E164, SELF_PROFILE_KEY)) + + val export = export() + compare(importData, export) + } + + private fun compare(import: ByteArray, export: ByteArray) { + val selfData = BackupRepository.SelfData(SELF_ACI, SELF_PNI, SELF_E164, SELF_PROFILE_KEY) + val framesImported = readAllFrames(import, selfData) + val framesExported = readAllFrames(export, selfData) + + compareFrameList(framesImported, framesExported) + } + + private fun compareFrameList(framesImported: List, framesExported: List) { + val accountExported = ArrayList() + val accountImported = ArrayList() + val recipientsImported = ArrayList() + val recipientsExported = ArrayList() + val chatsImported = ArrayList() + val chatsExported = ArrayList() + val chatItemsImported = ArrayList() + val chatItemsExported = ArrayList() + val callsImported = ArrayList() + val callsExported = ArrayList() + val stickersImported = ArrayList() + val stickersExported = ArrayList() + + for (f in framesImported) { + when { + f.account != null -> accountExported.add(f.account!!) + f.recipient != null -> recipientsImported.add(f.recipient!!) + f.chat != null -> chatsImported.add(f.chat!!) + f.chatItem != null -> chatItemsImported.add(f.chatItem!!) + f.call != null -> callsImported.add(f.call!!) + f.stickerPack != null -> stickersImported.add(f.stickerPack!!) + } + } + + for (f in framesExported) { + when { + f.account != null -> accountImported.add(f.account!!) + f.recipient != null -> recipientsExported.add(f.recipient!!) + f.chat != null -> chatsExported.add(f.chat!!) + f.chatItem != null -> chatItemsExported.add(f.chatItem!!) + f.call != null -> callsExported.add(f.call!!) + f.stickerPack != null -> stickersExported.add(f.stickerPack!!) + } + } + prettyAssertEquals(accountImported, accountExported) + prettyAssertEquals(recipientsImported, recipientsExported) { it.id } + prettyAssertEquals(chatsImported, chatsExported) { it.id } + prettyAssertEquals(chatItemsImported, chatItemsExported) { it.dateSent } + prettyAssertEquals(callsImported, callsExported) { it.callId } + prettyAssertEquals(stickersImported, stickersExported) { it.packId } + } + + private fun prettyAssertEquals(import: List, export: List) { + Assert.assertEquals(import.size, export.size) + import.zip(export).forEach { (a1, a2) -> + if (a1 != a2) { + Assert.fail("Items do not match: \n $a1 \n $a2") + } + } + } + + private fun Random.trueWithProbability(prob: Float): Boolean { + return nextFloat() < prob + } + + private fun > prettyAssertEquals(import: List, export: List, selector: (T) -> R?) { + if (import.size != export.size) { + var msg = StringBuilder() + for (i in import) { + msg.append(i) + msg.append("\n") + } + for (i in export) { + msg.append(i) + msg.append("\n") + } + Assert.fail(msg.toString()) + } + Assert.assertEquals(import.size, export.size) + val sortedImport = import.sortedBy(selector) + val sortedExport = export.sortedBy(selector) + + prettyAssertEquals(sortedImport, sortedExport) + } + + private fun readAllFrames(import: ByteArray, selfData: BackupRepository.SelfData): List { + val inputFactory = { ByteArrayInputStream(import) } + val frameReader = EncryptedBackupReader( + key = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey(), + aci = selfData.aci, + streamLength = import.size.toLong(), + dataStream = inputFactory + ) + val frames = ArrayList() + while (frameReader.hasNext()) { + frames.add(frameReader.next()) + } + + return frames + } + + private fun outputFile(importBytes: ByteArray, resultBytes: ByteArray? = null) { + grantPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) + val dir = File(Environment.getExternalStorageDirectory(), "backup-tests") + if (dir.mkdirs() || dir.exists()) { + FileOutputStream(File(dir, testName.methodName + ".import")).use { + it.write(importBytes) + it.flush() + } + + if (resultBytes != null) { + FileOutputStream(File(dir, testName.methodName + ".result")).use { + it.write(resultBytes) + it.flush() + } + } + } + } + + private fun grantPermissions(vararg permissions: String?) { + val auto: UiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation + for (perm in permissions) { + auto.grantRuntimePermissionAsUser(InstrumentationRegistry.getInstrumentation().targetContext.packageName, perm, android.os.Process.myUserHandle()) + } + } +} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/TestRecipientUtils.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/TestRecipientUtils.kt new file mode 100644 index 00000000..f57de6ce --- /dev/null +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/TestRecipientUtils.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2 + +import org.tm.archive.crypto.ProfileKeyUtil +import org.whispersystems.signalservice.api.util.toByteArray +import java.util.UUID +import kotlin.random.Random + +object TestRecipientUtils { + + private var upperGenAci = 13131313L + private var lowerGenAci = 0L + + private var upperGenPni = 12121212L + private var lowerGenPni = 0L + + private var groupMasterKeyRandom = Random(12345) + + fun generateProfileKey(): ByteArray { + return ProfileKeyUtil.createNew().serialize() + } + + fun nextPni(): ByteArray { + synchronized(this) { + lowerGenPni++ + var uuid = UUID(upperGenPni, lowerGenPni) + return uuid.toByteArray() + } + } + + fun nextAci(): ByteArray { + synchronized(this) { + lowerGenAci++ + var uuid = UUID(upperGenAci, lowerGenAci) + return uuid.toByteArray() + } + } + + fun generateGroupMasterKey(): ByteArray { + val masterKey = ByteArray(32) + groupMasterKeyRandom.nextBytes(masterKey) + return masterKey + } +} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShapeTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShapeTest.kt index b129f9bb..6afca218 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShapeTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShapeTest.kt @@ -8,6 +8,7 @@ package org.tm.archive.conversation.v2.items import android.net.Uri import android.view.View import androidx.lifecycle.Observer +import com.bumptech.glide.RequestManager import io.mockk.mockk import org.junit.Assert.assertEquals import org.junit.Rule @@ -29,7 +30,6 @@ import org.tm.archive.groups.GroupId import org.tm.archive.groups.GroupMigrationMembershipChange import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.mediapreview.MediaIntentFactory -import org.tm.archive.mms.GlideRequests import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.stickers.StickerLocator @@ -209,8 +209,9 @@ class V2ConversationItemShapeTest { override val selectedItems: Set = emptySet() override val isMessageRequestAccepted: Boolean = true override val searchQuery: String? = null - override val glideRequests: GlideRequests = mockk() + override val requestManager: RequestManager = mockk() override val isParentInScroll: Boolean = false + override fun getChatColorsData(): ChatColorsDrawable.ChatColorsData = ChatColorsDrawable.ChatColorsData(null, null) override fun onStartExpirationTimeout(messageRecord: MessageRecord) = Unit @@ -321,5 +322,11 @@ class V2ConversationItemShapeTest { override fun onItemClick(item: MultiselectPart?) = Unit override fun onItemLongClick(itemView: View?, item: MultiselectPart?) = Unit + + override fun onShowSafetyTips(forGroup: Boolean) = Unit + + override fun onReportSpamLearnMoreClicked() = Unit + + override fun onMessageRequestAcceptOptionsClicked() = Unit } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt index bdcefe3b..35d95dc6 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt @@ -51,18 +51,16 @@ class AttachmentTableTest { SignalDatabase.attachments.updateAttachmentData( attachment, - createMediaStream(byteArrayOf(1, 2, 3, 4, 5)), - false + createMediaStream(byteArrayOf(1, 2, 3, 4, 5)) ) SignalDatabase.attachments.updateAttachmentData( attachment2, - createMediaStream(byteArrayOf(1, 2, 3)), - false + createMediaStream(byteArrayOf(1, 2, 3)) ) - val attachment1Info = SignalDatabase.attachments.getAttachmentDataFileInfo(attachment.attachmentId, AttachmentTable.DATA_FILE) - val attachment2Info = SignalDatabase.attachments.getAttachmentDataFileInfo(attachment2.attachmentId, AttachmentTable.DATA_FILE) + val attachment1Info = SignalDatabase.attachments.getDataFileInfo(attachment.attachmentId) + val attachment2Info = SignalDatabase.attachments.getDataFileInfo(attachment2.attachmentId) assertNotEquals(attachment1Info, attachment2Info) } @@ -79,18 +77,16 @@ class AttachmentTableTest { SignalDatabase.attachments.updateAttachmentData( attachment, - createMediaStream(byteArrayOf(1, 2, 3, 4, 5)), - true + createMediaStream(byteArrayOf(1, 2, 3, 4, 5)) ) SignalDatabase.attachments.updateAttachmentData( attachment2, - createMediaStream(byteArrayOf(1, 2, 3, 4)), - true + createMediaStream(byteArrayOf(1, 2, 3, 4)) ) - val attachment1Info = SignalDatabase.attachments.getAttachmentDataFileInfo(attachment.attachmentId, AttachmentTable.DATA_FILE) - val attachment2Info = SignalDatabase.attachments.getAttachmentDataFileInfo(attachment2.attachmentId, AttachmentTable.DATA_FILE) + val attachment1Info = SignalDatabase.attachments.getDataFileInfo(attachment.attachmentId) + val attachment2Info = SignalDatabase.attachments.getDataFileInfo(attachment2.attachmentId) assertNotEquals(attachment1Info, attachment2Info) } @@ -121,15 +117,14 @@ class AttachmentTableTest { val highDatabaseAttachment = SignalDatabase.attachments.insertAttachmentForPreUpload(highQualityPreUpload) // WHEN - SignalDatabase.attachments.updateAttachmentData(standardDatabaseAttachment, createMediaStream(compressedData), false) + SignalDatabase.attachments.updateAttachmentData(standardDatabaseAttachment, createMediaStream(compressedData)) // THEN - val previousInfo = SignalDatabase.attachments.getAttachmentDataFileInfo(previousDatabaseAttachmentId, AttachmentTable.DATA_FILE)!! - val standardInfo = SignalDatabase.attachments.getAttachmentDataFileInfo(standardDatabaseAttachment.attachmentId, AttachmentTable.DATA_FILE)!! - val highInfo = SignalDatabase.attachments.getAttachmentDataFileInfo(highDatabaseAttachment.attachmentId, AttachmentTable.DATA_FILE)!! + val previousInfo = SignalDatabase.attachments.getDataFileInfo(previousDatabaseAttachmentId)!! + val standardInfo = SignalDatabase.attachments.getDataFileInfo(standardDatabaseAttachment.attachmentId)!! + val highInfo = SignalDatabase.attachments.getDataFileInfo(highDatabaseAttachment.attachmentId)!! assertNotEquals(standardInfo, highInfo) - standardInfo.file assertIs previousInfo.file highInfo.file assertIsNot standardInfo.file highInfo.file.exists() assertIs true } @@ -158,9 +153,9 @@ class AttachmentTableTest { val secondHighDatabaseAttachment = SignalDatabase.attachments.insertAttachmentForPreUpload(secondHighQualityPreUpload) // THEN - val standardInfo = SignalDatabase.attachments.getAttachmentDataFileInfo(standardDatabaseAttachment.attachmentId, AttachmentTable.DATA_FILE)!! - val highInfo = SignalDatabase.attachments.getAttachmentDataFileInfo(highDatabaseAttachment.attachmentId, AttachmentTable.DATA_FILE)!! - val secondHighInfo = SignalDatabase.attachments.getAttachmentDataFileInfo(secondHighDatabaseAttachment.attachmentId, AttachmentTable.DATA_FILE)!! + val standardInfo = SignalDatabase.attachments.getDataFileInfo(standardDatabaseAttachment.attachmentId)!! + val highInfo = SignalDatabase.attachments.getDataFileInfo(highDatabaseAttachment.attachmentId)!! + val secondHighInfo = SignalDatabase.attachments.getDataFileInfo(secondHighDatabaseAttachment.attachmentId)!! highInfo.file assertIsNot standardInfo.file secondHighInfo.file assertIs highInfo.file diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt new file mode 100644 index 00000000..ef9bd16c --- /dev/null +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt @@ -0,0 +1,804 @@ +package org.tm.archive.database + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.signal.core.util.Base64 +import org.signal.core.util.update +import org.tm.archive.attachments.AttachmentId +import org.tm.archive.attachments.PointerAttachment +import org.tm.archive.database.AttachmentTable.TransformProperties +import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.mms.MediaStream +import org.tm.archive.mms.OutgoingMessage +import org.tm.archive.mms.QuoteModel +import org.tm.archive.mms.SentMediaQuality +import org.tm.archive.providers.BlobProvider +import org.tm.archive.recipients.Recipient +import org.tm.archive.util.MediaUtil +import org.whispersystems.signalservice.api.push.ServiceId +import java.io.File +import java.util.UUID +import kotlin.random.Random +import kotlin.time.Duration.Companion.days + +/** + * Collection of [AttachmentTable] tests focused around deduping logic. + */ +@RunWith(AndroidJUnit4::class) +class AttachmentTableTest_deduping { + + companion object { + val DATA_A = byteArrayOf(1, 2, 3) + val DATA_A_COMPRESSED = byteArrayOf(4, 5, 6) + val DATA_A_HASH = byteArrayOf(1, 1, 1) + + val DATA_B = byteArrayOf(7, 8, 9) + } + + @Before + fun setUp() { + SignalStore.account().setAci(ServiceId.ACI.from(UUID.randomUUID())) + SignalStore.account().setPni(ServiceId.PNI.from(UUID.randomUUID())) + SignalStore.account().setE164("+15558675309") + + SignalDatabase.attachments.deleteAllAttachments() + } + + /** + * Creates two different files with different data. Should not dedupe. + */ + @Test + fun differentFiles() { + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_B) + + assertDataFilesAreDifferent(id1, id2) + } + } + + /** + * Inserts files with identical data but with transform properties that make them incompatible. Should not dedupe. + */ + @Test + fun identicalFiles_incompatibleTransforms() { + // Non-matching qualities + test { + val id1 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.STANDARD.code)) + val id2 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.HIGH.code)) + + assertDataFilesAreDifferent(id1, id2) + assertDataHashStartMatches(id1, id2) + } + + // Non-matching video trim flag + test { + val id1 = insertWithData(DATA_A, TransformProperties()) + val id2 = insertWithData(DATA_A, TransformProperties(videoTrim = true)) + + assertDataFilesAreDifferent(id1, id2) + assertDataHashStartMatches(id1, id2) + } + + // Non-matching video trim start time + test { + val id1 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 1, videoTrimEndTimeUs = 2)) + val id2 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 0, videoTrimEndTimeUs = 2)) + + assertDataFilesAreDifferent(id1, id2) + assertDataHashStartMatches(id1, id2) + } + + // Non-matching video trim end time + test { + val id1 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 0, videoTrimEndTimeUs = 1)) + val id2 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 0, videoTrimEndTimeUs = 2)) + + assertDataFilesAreDifferent(id1, id2) + assertDataHashStartMatches(id1, id2) + } + + // Non-matching mp4 fast start + test { + val id1 = insertWithData(DATA_A, TransformProperties(mp4FastStart = true)) + val id2 = insertWithData(DATA_A, TransformProperties(mp4FastStart = false)) + + assertDataFilesAreDifferent(id1, id2) + assertDataHashStartMatches(id1, id2) + } + } + + /** + * Inserts files with identical data and compatible transform properties. Should dedupe. + */ + @Test + fun identicalFiles_compatibleTransforms() { + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_A) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, false) + assertSkipTransform(id2, false) + } + + test { + val id1 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.STANDARD.code)) + val id2 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.STANDARD.code)) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, false) + assertSkipTransform(id2, false) + } + + test { + val id1 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.HIGH.code)) + val id2 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.HIGH.code)) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, false) + assertSkipTransform(id2, false) + } + + test { + val id1 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 1, videoTrimEndTimeUs = 2)) + val id2 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 1, videoTrimEndTimeUs = 2)) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, false) + assertSkipTransform(id2, false) + } + } + + /** + * Walks through various scenarios where files are compressed and uploaded. + */ + @Test + fun compressionAndUploads() { + // Matches after the first is compressed, skip transform properly set + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + + val id2 = insertWithData(DATA_A) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id2, true) + } + + // Matches after the first is uploaded, skip transform and ending hash properly set + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + upload(id1) + + val id2 = insertWithData(DATA_A) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertDataHashEndMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id2, true) + } + + // Mimics sending two files at once. Ensures all fields are kept in sync as we compress and upload. + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_A) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, false) + assertSkipTransform(id2, false) + + compress(id1, DATA_A_COMPRESSED) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id2, true) + + upload(id1) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertDataHashEndMatches(id1, id2) + assertRemoteFieldsMatch(id1, id2) + } + + // Re-use the upload when uploaded recently + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis()) + + val id2 = insertWithData(DATA_A) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertDataHashEndMatches(id1, id2) + assertRemoteFieldsMatch(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id2, true) + } + + // Do not re-use old uploads + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis() - 100.days.inWholeMilliseconds) + + val id2 = insertWithData(DATA_A) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertDataHashEndMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id2, true) + + assertDoesNotHaveRemoteFields(id2) + } + + // This isn't so much "desirable behavior" as it is documenting how things work. + // If an attachment is compressed but not uploaded yet, it will have a DATA_HASH_START that doesn't match the actual file content. + // This means that if we insert a new attachment with data that matches the compressed data, we won't find a match. + // This is ok because we don't allow forwarding unsent messages, so the chances of the user somehow sending a file that matches data we compressed are very low. + // What *is* more common is that the user may send DATA_A again, and in this case we will still catch the dedupe (which is already tested above). + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + + val id2 = insertWithData(DATA_A_COMPRESSED) + + assertDataFilesAreDifferent(id1, id2) + } + + // This represents what would happen if you forward an already-send compressed attachment. We should match, skip transform, and skip upload. + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis()) + + val id2 = insertWithData(DATA_A_COMPRESSED) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id1, true) + assertRemoteFieldsMatch(id1, id2) + } + + // This represents what would happen if you edited a video, sent it, then forwarded it. We should match, skip transform, and skip upload. + test { + val id1 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 1, videoTrimEndTimeUs = 2)) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis()) + + val id2 = insertWithData(DATA_A_COMPRESSED) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id1, true) + assertRemoteFieldsMatch(id1, id2) + } + + // This represents what would happen if you edited a video, sent it, then forwarded it, but *edited the forwarded video*. We should not dedupe. + test { + val id1 = insertWithData(DATA_A, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 1, videoTrimEndTimeUs = 2)) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis()) + + val id2 = insertWithData(DATA_A_COMPRESSED, TransformProperties(videoTrim = true, videoTrimStartTimeUs = 1, videoTrimEndTimeUs = 2)) + + assertDataFilesAreDifferent(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id2, false) + assertDoesNotHaveRemoteFields(id2) + } + + // This represents what would happen if you sent an image using standard quality, then forwarded it using high quality. + // Since you're forwarding, it doesn't matter if the new thing has a higher quality, we should still match and skip transform. + test { + val id1 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.STANDARD.code)) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis()) + + val id2 = insertWithData(DATA_A_COMPRESSED, TransformProperties(sentMediaQuality = SentMediaQuality.HIGH.code)) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id1, true) + assertRemoteFieldsMatch(id1, id2) + } + + // This represents what would happen if you sent an image using high quality, then forwarded it using standard quality. + // Since you're forwarding, it doesn't matter if the new thing has a lower quality, we should still match and skip transform. + test { + val id1 = insertWithData(DATA_A, TransformProperties(sentMediaQuality = SentMediaQuality.HIGH.code)) + compress(id1, DATA_A_COMPRESSED) + upload(id1, uploadTimestamp = System.currentTimeMillis()) + + val id2 = insertWithData(DATA_A_COMPRESSED, TransformProperties(sentMediaQuality = SentMediaQuality.STANDARD.code)) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertSkipTransform(id1, true) + assertSkipTransform(id1, true) + assertRemoteFieldsMatch(id1, id2) + } + + // Make sure that files marked as unhashable are all updated together + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_A) + upload(id1) + upload(id2) + clearHashes(id1) + clearHashes(id2) + + val file = dataFile(id1) + SignalDatabase.attachments.markDataFileAsUnhashable(file) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + + val dataFileInfo = SignalDatabase.attachments.getDataFileInfo(id1)!! + assertTrue(dataFileInfo.hashEnd!!.startsWith("UNHASHABLE-")) + } + } + + /** + * Various deletion scenarios to ensure that duped files don't deleted while there's still references. + */ + @Test + fun deletions() { + // Delete original then dupe + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_A) + val dataFile = dataFile(id1) + + assertDataFilesAreTheSame(id1, id2) + + delete(id1) + + assertDeleted(id1) + assertRowAndFileExists(id2) + assertTrue(dataFile.exists()) + + delete(id2) + + assertDeleted(id2) + assertFalse(dataFile.exists()) + } + + // Delete dupe then original + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_A) + val dataFile = dataFile(id1) + + assertDataFilesAreTheSame(id1, id2) + + delete(id2) + assertDeleted(id2) + assertRowAndFileExists(id1) + assertTrue(dataFile.exists()) + + delete(id1) + assertDeleted(id1) + assertFalse(dataFile.exists()) + } + + // Delete original after it was compressed + test { + val id1 = insertWithData(DATA_A) + compress(id1, DATA_A_COMPRESSED) + + val id2 = insertWithData(DATA_A) + + delete(id1) + + assertDeleted(id1) + assertRowAndFileExists(id2) + assertSkipTransform(id2, true) + } + + // Quotes are weak references and should not prevent us from deleting the file + test { + val id1 = insertWithData(DATA_A) + val id2 = insertQuote(id1) + + val dataFile = dataFile(id1) + + delete(id1) + assertDeleted(id1) + assertRowExists(id2) + assertFalse(dataFile.exists()) + } + } + + @Test + fun quotes() { + // Basic quote deduping + test { + val id1 = insertWithData(DATA_A) + val id2 = insertQuote(id1) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + } + + // Making sure remote fields carry + test { + val id1 = insertWithData(DATA_A) + val id2 = insertQuote(id1) + upload(id1) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashStartMatches(id1, id2) + assertDataHashEndMatches(id1, id2) + assertRemoteFieldsMatch(id1, id2) + } + + // Making sure things work for quotes of videos, which have trickier transform properties + test { + val id1 = insertWithData(DATA_A, transformProperties = TransformProperties.forVideoTrim(1, 2)) + compress(id1, DATA_A_COMPRESSED) + upload(id1) + + val id2 = insertQuote(id1) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertRemoteFieldsMatch(id1, id2) + } + } + + /** + * Suite of tests around the migration where we hash all of the attachments and potentially dedupe them. + */ + @Test + fun migration() { + // Verifying that getUnhashedDataFile only returns if there's actually missing hashes + test { + val id = insertWithData(DATA_A) + upload(id) + assertNull(SignalDatabase.attachments.getUnhashedDataFile()) + } + + // Verifying that getUnhashedDataFile finds the missing hash + test { + val id = insertWithData(DATA_A) + upload(id) + clearHashes(id) + assertNotNull(SignalDatabase.attachments.getUnhashedDataFile()) + } + + // Verifying that getUnhashedDataFile doesn't return if the file isn't done downloading + test { + val id = insertWithData(DATA_A) + upload(id) + setTransferState(id, AttachmentTable.TRANSFER_PROGRESS_PENDING) + clearHashes(id) + assertNull(SignalDatabase.attachments.getUnhashedDataFile()) + } + + // If two attachments share the same file, when we backfill the hash, make sure both get their hashes set + test { + val id1 = insertWithData(DATA_A) + val id2 = insertWithData(DATA_A) + upload(id1) + upload(id2) + + clearHashes(id1) + clearHashes(id2) + + val file = dataFile(id1) + SignalDatabase.attachments.setHashForDataFile(file, DATA_A_HASH) + + assertDataHashEnd(id1, DATA_A_HASH) + assertDataHashEndMatches(id1, id2) + } + + // Creates a situation where two different attachments have the same data but wrote to different files, and verifies the migration dedupes it + test { + val id1 = insertWithData(DATA_A) + upload(id1) + clearHashes(id1) + + val id2 = insertWithData(DATA_A) + upload(id2) + clearHashes(id2) + + assertDataFilesAreDifferent(id1, id2) + + val file1 = dataFile(id1) + SignalDatabase.attachments.setHashForDataFile(file1, DATA_A_HASH) + + assertDataHashEnd(id1, DATA_A_HASH) + assertDataFilesAreDifferent(id1, id2) + + val file2 = dataFile(id2) + SignalDatabase.attachments.setHashForDataFile(file2, DATA_A_HASH) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertFalse(file2.exists()) + } + + // We've got three files now with the same data, with two of them sharing a file. We want to make sure *both* entries that share the same file get deduped. + test { + val id1 = insertWithData(DATA_A) + upload(id1) + clearHashes(id1) + + val id2 = insertWithData(DATA_A) + val id3 = insertWithData(DATA_A) + upload(id2) + upload(id3) + clearHashes(id2) + clearHashes(id3) + + assertDataFilesAreDifferent(id1, id2) + assertDataFilesAreTheSame(id2, id3) + + val file1 = dataFile(id1) + SignalDatabase.attachments.setHashForDataFile(file1, DATA_A_HASH) + assertDataHashEnd(id1, DATA_A_HASH) + + val file2 = dataFile(id2) + SignalDatabase.attachments.setHashForDataFile(file2, DATA_A_HASH) + + assertDataFilesAreTheSame(id1, id2) + assertDataHashEndMatches(id1, id2) + assertDataHashEndMatches(id2, id3) + assertFalse(file2.exists()) + } + + // We don't want to mess with files that are still downloading, so this makes sure that even if data matches, we don't dedupe and don't delete the file + test { + val id1 = insertWithData(DATA_A) + upload(id1) + clearHashes(id1) + + val id2 = insertWithData(DATA_A) + // *not* uploaded + clearHashes(id2) + + assertDataFilesAreDifferent(id1, id2) + + val file1 = dataFile(id1) + SignalDatabase.attachments.setHashForDataFile(file1, DATA_A_HASH) + assertDataHashEnd(id1, DATA_A_HASH) + + val file2 = dataFile(id2) + SignalDatabase.attachments.setHashForDataFile(file2, DATA_A_HASH) + + assertDataFilesAreDifferent(id1, id2) + assertTrue(file2.exists()) + } + } + + private class TestContext { + fun insertWithData(data: ByteArray, transformProperties: TransformProperties = TransformProperties.empty()): AttachmentId { + val uri = BlobProvider.getInstance().forData(data).createForSingleSessionInMemory() + + val attachment = UriAttachmentBuilder.build( + id = Random.nextLong(), + uri = uri, + contentType = MediaUtil.IMAGE_JPEG, + transformProperties = transformProperties + ) + + return SignalDatabase.attachments.insertAttachmentForPreUpload(attachment).attachmentId + } + + fun insertQuote(attachmentId: AttachmentId): AttachmentId { + val originalAttachment = SignalDatabase.attachments.getAttachment(attachmentId)!! + val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(Recipient.self()) + val messageId = SignalDatabase.messages.insertMessageOutbox( + message = OutgoingMessage( + threadRecipient = Recipient.self(), + sentTimeMillis = System.currentTimeMillis(), + body = "some text", + outgoingQuote = QuoteModel( + id = 123, + author = Recipient.self().id, + text = "Some quote text", + isOriginalMissing = false, + attachments = listOf(originalAttachment), + mentions = emptyList(), + type = QuoteModel.Type.NORMAL, + bodyRanges = null + ) + ), + threadId = threadId, + forceSms = false, + insertListener = null + ) + + val attachments = SignalDatabase.attachments.getAttachmentsForMessage(messageId) + return attachments[0].attachmentId + } + + fun compress(attachmentId: AttachmentId, newData: ByteArray, mp4FastStart: Boolean = false) { + val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId)!! + SignalDatabase.attachments.updateAttachmentData(databaseAttachment, newData.asMediaStream()) + SignalDatabase.attachments.markAttachmentAsTransformed(attachmentId, withFastStart = mp4FastStart) + } + + fun upload(attachmentId: AttachmentId, uploadTimestamp: Long = System.currentTimeMillis()) { + SignalDatabase.attachments.finalizeAttachmentAfterUpload(attachmentId, createPointerAttachment(attachmentId, uploadTimestamp), uploadTimestamp) + } + + fun delete(attachmentId: AttachmentId) { + SignalDatabase.attachments.deleteAttachment(attachmentId) + } + + fun dataFile(attachmentId: AttachmentId): File { + return SignalDatabase.attachments.getDataFileInfo(attachmentId)!!.file + } + + fun setTransferState(attachmentId: AttachmentId, transferState: Int) { + // messageId doesn't actually matter -- that's for notifying listeners + SignalDatabase.attachments.setTransferState(messageId = -1, attachmentId = attachmentId, transferState = transferState) + } + + fun clearHashes(id: AttachmentId) { + SignalDatabase.attachments.writableDatabase + .update(AttachmentTable.TABLE_NAME) + .values( + AttachmentTable.DATA_HASH_START to null, + AttachmentTable.DATA_HASH_END to null + ) + .where("${AttachmentTable.ID} = ?", id) + .run() + } + + fun assertDeleted(attachmentId: AttachmentId) { + assertNull("$attachmentId exists, but it shouldn't!", SignalDatabase.attachments.getAttachment(attachmentId)) + } + + fun assertRowAndFileExists(attachmentId: AttachmentId) { + val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId) + assertNotNull("$attachmentId does not exist!", databaseAttachment) + + val dataFileInfo = SignalDatabase.attachments.getDataFileInfo(attachmentId) + assertTrue("The file for $attachmentId does not exist!", dataFileInfo!!.file.exists()) + } + + fun assertRowExists(attachmentId: AttachmentId) { + val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId) + assertNotNull("$attachmentId does not exist!", databaseAttachment) + } + + fun assertDataFilesAreTheSame(lhs: AttachmentId, rhs: AttachmentId) { + val lhsInfo = SignalDatabase.attachments.getDataFileInfo(lhs)!! + val rhsInfo = SignalDatabase.attachments.getDataFileInfo(rhs)!! + + assert(lhsInfo.file.exists()) + assert(rhsInfo.file.exists()) + + assertEquals(lhsInfo.file, rhsInfo.file) + assertEquals(lhsInfo.length, rhsInfo.length) + assertArrayEquals(lhsInfo.random, rhsInfo.random) + } + + fun assertDataFilesAreDifferent(lhs: AttachmentId, rhs: AttachmentId) { + val lhsInfo = SignalDatabase.attachments.getDataFileInfo(lhs)!! + val rhsInfo = SignalDatabase.attachments.getDataFileInfo(rhs)!! + + assert(lhsInfo.file.exists()) + assert(rhsInfo.file.exists()) + + assertNotEquals(lhsInfo.file, rhsInfo.file) + } + + fun assertDataHashStartMatches(lhs: AttachmentId, rhs: AttachmentId) { + val lhsInfo = SignalDatabase.attachments.getDataFileInfo(lhs)!! + val rhsInfo = SignalDatabase.attachments.getDataFileInfo(rhs)!! + + assertNotNull(lhsInfo.hashStart) + assertEquals("DATA_HASH_START's did not match!", lhsInfo.hashStart, rhsInfo.hashStart) + } + + fun assertDataHashEndMatches(lhs: AttachmentId, rhs: AttachmentId) { + val lhsInfo = SignalDatabase.attachments.getDataFileInfo(lhs)!! + val rhsInfo = SignalDatabase.attachments.getDataFileInfo(rhs)!! + + assertNotNull(lhsInfo.hashEnd) + assertEquals("DATA_HASH_END's did not match!", lhsInfo.hashEnd, rhsInfo.hashEnd) + } + + fun assertDataHashEnd(id: AttachmentId, byteArray: ByteArray) { + val dataFileInfo = SignalDatabase.attachments.getDataFileInfo(id)!! + assertArrayEquals(byteArray, Base64.decode(dataFileInfo.hashEnd!!)) + } + + fun assertRemoteFieldsMatch(lhs: AttachmentId, rhs: AttachmentId) { + val lhsAttachment = SignalDatabase.attachments.getAttachment(lhs)!! + val rhsAttachment = SignalDatabase.attachments.getAttachment(rhs)!! + + assertEquals(lhsAttachment.remoteLocation, rhsAttachment.remoteLocation) + assertEquals(lhsAttachment.remoteKey, rhsAttachment.remoteKey) + assertArrayEquals(lhsAttachment.remoteDigest, rhsAttachment.remoteDigest) + assertArrayEquals(lhsAttachment.incrementalDigest, rhsAttachment.incrementalDigest) + assertEquals(lhsAttachment.incrementalMacChunkSize, rhsAttachment.incrementalMacChunkSize) + assertEquals(lhsAttachment.cdnNumber, rhsAttachment.cdnNumber) + } + + fun assertDoesNotHaveRemoteFields(attachmentId: AttachmentId) { + val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId)!! + assertEquals(0, databaseAttachment.uploadTimestamp) + assertNull(databaseAttachment.remoteLocation) + assertNull(databaseAttachment.remoteDigest) + assertNull(databaseAttachment.remoteKey) + assertEquals(0, databaseAttachment.cdnNumber) + } + + fun assertSkipTransform(attachmentId: AttachmentId, state: Boolean) { + val transformProperties = SignalDatabase.attachments.getTransformProperties(attachmentId)!! + assertEquals("Incorrect skipTransform!", transformProperties.skipTransform, state) + } + + private fun ByteArray.asMediaStream(): MediaStream { + return MediaStream(this.inputStream(), MediaUtil.IMAGE_JPEG, 2, 2) + } + + private fun createPointerAttachment(attachmentId: AttachmentId, uploadTimestamp: Long = System.currentTimeMillis()): PointerAttachment { + val location = "somewhere-${Random.nextLong()}" + val key = "somekey-${Random.nextLong()}" + val digest = Random.nextBytes(32) + val incrementalDigest = Random.nextBytes(16) + + val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId)!! + + return PointerAttachment( + "image/jpeg", + AttachmentTable.TRANSFER_PROGRESS_DONE, + databaseAttachment.size, // size + null, + 3, // cdnNumber + location, + key, + digest, + incrementalDigest, + 5, // incrementalMacChunkSize + null, + databaseAttachment.voiceNote, + databaseAttachment.borderless, + databaseAttachment.videoGif, + databaseAttachment.width, + databaseAttachment.height, + uploadTimestamp, + databaseAttachment.caption, + databaseAttachment.stickerLocator, + databaseAttachment.blurHash + ) + } + } + + private fun test(content: TestContext.() -> Unit) { + SignalDatabase.attachments.deleteAllAttachments() + val context = TestContext() + context.content() + } +} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt index 73970cde..163b92f1 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt @@ -7,7 +7,7 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test -import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.readToList import org.signal.core.util.requireLong import org.signal.core.util.withinTransaction @@ -33,8 +33,8 @@ class GroupTableTest { fun setUp() { groupTable = SignalDatabase.groups - groupTable.writableDatabase.delete(GroupTable.TABLE_NAME).run() - groupTable.writableDatabase.delete(GroupTable.MembershipTable.TABLE_NAME).run() + groupTable.writableDatabase.deleteAll(GroupTable.TABLE_NAME) + groupTable.writableDatabase.deleteAll(GroupTable.MembershipTable.TABLE_NAME) } @Test diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/LogDatabaseTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/LogDatabaseTest.kt index 3563ffdb..348c9f73 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/LogDatabaseTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/LogDatabaseTest.kt @@ -10,7 +10,7 @@ import org.signal.core.util.forEach import org.signal.core.util.requireLong import org.signal.core.util.requireNonNullString import org.signal.core.util.select -import org.signal.core.util.update +import org.signal.core.util.updateAll import org.tm.archive.crash.CrashConfig import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.testing.assertIs @@ -220,7 +220,7 @@ class LogDatabaseTest { ) db.writableDatabase - .update(LogDatabase.CrashTable.TABLE_NAME) + .updateAll(LogDatabase.CrashTable.TABLE_NAME) .values(LogDatabase.CrashTable.LAST_PROMPTED_AT to currentTime) .run() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt index 3cd2fa84..915ec274 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt @@ -11,8 +11,6 @@ import org.signal.core.util.CursorUtil import org.tm.archive.profiles.ProfileName import org.tm.archive.recipients.RecipientId import org.tm.archive.testing.SignalActivityRule -import org.tm.archive.util.FeatureFlags -import org.tm.archive.util.FeatureFlagsAccessor import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.UUID @@ -59,7 +57,7 @@ class RecipientTableTest { SignalDatabase.recipients.setProfileName(hiddenRecipient, ProfileName.fromParts("Hidden", "Person")) SignalDatabase.recipients.markHidden(hiddenRecipient) - val results = SignalDatabase.recipients.querySignalContacts("Hidden", false)!! + val results = SignalDatabase.recipients.querySignalContacts(RecipientTable.ContactSearchQuery("Hidden", false))!! assertEquals(0, results.count) } @@ -130,7 +128,7 @@ class RecipientTableTest { SignalDatabase.recipients.setProfileName(blockedRecipient, ProfileName.fromParts("Blocked", "Person")) SignalDatabase.recipients.setBlocked(blockedRecipient, true) - val results = SignalDatabase.recipients.querySignalContacts("Blocked", false)!! + val results = SignalDatabase.recipients.querySignalContacts(RecipientTable.ContactSearchQuery("Blocked", false))!! assertEquals(0, results.count) } @@ -167,8 +165,6 @@ class RecipientTableTest { @Test fun givenARecipientWithPniAndAci_whenIMarkItUnregistered_thenIExpectItToBeSplit() { - FeatureFlagsAccessor.forceValue(FeatureFlags.PHONE_NUMBER_PRIVACY, true) - val mainId = SignalDatabase.recipients.getAndPossiblyMerge(ACI_A, PNI_A, E164_A) SignalDatabase.recipients.markUnregistered(mainId) @@ -185,12 +181,10 @@ class RecipientTableTest { @Test fun givenARecipientWithPniAndAci_whenISplitItForStorageSync_thenIExpectItToBeSplit() { - FeatureFlagsAccessor.forceValue(FeatureFlags.PHONE_NUMBER_PRIVACY, true) - val mainId = SignalDatabase.recipients.getAndPossiblyMerge(ACI_A, PNI_A, E164_A) val mainRecord = SignalDatabase.recipients.getRecord(mainId) - SignalDatabase.recipients.splitForStorageSync(mainRecord.storageId!!) + SignalDatabase.recipients.splitForStorageSyncIfNecessary(mainRecord.aci!!) val byAci: RecipientId = SignalDatabase.recipients.getByAci(ACI_A).get() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt index c5b5d19e..bfca5657 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt @@ -18,6 +18,7 @@ import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.exists import org.signal.core.util.orNull +import org.signal.core.util.readToSingleBoolean import org.signal.core.util.requireLong import org.signal.core.util.requireNonNullString import org.signal.core.util.select @@ -40,8 +41,6 @@ import org.tm.archive.mms.IncomingMessage import org.tm.archive.notifications.profiles.NotificationProfile import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId -import org.tm.archive.util.FeatureFlags -import org.tm.archive.util.FeatureFlagsAccessor import org.tm.archive.util.Util import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI @@ -57,7 +56,6 @@ class RecipientTableTest_getAndPossiblyMerge { SignalStore.account().setE164(E164_SELF) SignalStore.account().setAci(ACI_SELF) SignalStore.account().setPni(PNI_SELF) - FeatureFlagsAccessor.forceValue(FeatureFlags.PHONE_NUMBER_PRIVACY, true) } @Test @@ -109,6 +107,18 @@ class RecipientTableTest_getAndPossiblyMerge { val record = SignalDatabase.recipients.getRecord(id) assertEquals(RecipientTable.RegisteredState.REGISTERED, record.registered) } + + test("e164+pni+aci insert, pni verified") { + val id = process(E164_A, PNI_A, ACI_A, pniVerified = true) + expect(E164_A, PNI_A, ACI_A) + expectPniVerified() + + val record = SignalDatabase.recipients.getRecord(id) + assertEquals(RecipientTable.RegisteredState.REGISTERED, record.registered) + + process(E164_A, PNI_A, ACI_A, pniVerified = false) + expectPniVerified() + } } @Test @@ -164,6 +174,7 @@ class RecipientTableTest_getAndPossiblyMerge { expect(E164_A, PNI_A, ACI_A) expectNoSessionSwitchoverEvent() + expectPniVerified() } test("no match, all fields") { @@ -225,6 +236,8 @@ class RecipientTableTest_getAndPossiblyMerge { given(E164_A, PNI_A, null, pniSession = true) process(E164_A, PNI_A, ACI_A, pniVerified = true) expect(E164_A, PNI_A, ACI_A) + + expectPniVerified() } test("e164 and aci matches, all provided, new pni") { @@ -694,6 +707,8 @@ class RecipientTableTest_getAndPossiblyMerge { expectDeleted() expect(E164_A, PNI_A, ACI_A) + + expectPniVerified() } test("merge, e164+pni & aci, pni session, pni verified") { @@ -706,6 +721,7 @@ class RecipientTableTest_getAndPossiblyMerge { expect(E164_A, PNI_A, ACI_A) expectThreadMergeEvent(E164_A) + expectPniVerified() } test("merge, e164+pni & e164+pni+aci, change number") { @@ -760,6 +776,18 @@ class RecipientTableTest_getAndPossiblyMerge { expectThreadMergeEvent(E164_A) } + test("merge, e164+pni & e164+aci, pni+aci provided, change number") { + given(E164_A, PNI_A, null) + given(E164_B, null, ACI_A) + + process(null, PNI_A, ACI_A) + + expect(E164_A, PNI_A, ACI_A) + + expectThreadMergeEvent(E164_A) + expectChangeNumberEvent() + } + test("merge, e164 + pni reassigned, aci abandoned") { given(E164_A, PNI_A, ACI_A) given(E164_B, PNI_B, ACI_B) @@ -772,6 +800,17 @@ class RecipientTableTest_getAndPossiblyMerge { expectChangeNumberEvent() } + test("merge, e164 follows pni+aci") { + given(E164_A, PNI_A, null) + given(null, null, ACI_A) + + process(null, PNI_A, ACI_A, pniVerified = true) + + expect(E164_A, PNI_A, ACI_A) + expectThreadMergeEvent(E164_A) + expectPniVerified() + } + test("local user, local e164 and aci provided, changeSelf=false, leave e164 alone") { given(E164_SELF, null, ACI_SELF) given(null, null, ACI_A) @@ -874,8 +913,8 @@ class RecipientTableTest_getAndPossiblyMerge { // Thread validation assertEquals(threadIdAci, retrievedThreadId) - Assert.assertNull(SignalDatabase.threads.getThreadIdFor(recipientIdE164)) - Assert.assertNull(SignalDatabase.threads.getThreadRecord(threadIdE164)) + assertNull(SignalDatabase.threads.getThreadIdFor(recipientIdE164)) + assertNull(SignalDatabase.threads.getThreadRecord(threadIdE164)) // SMS validation val sms1: MessageRecord = SignalDatabase.messages.getMessageRecord(smsId1)!! @@ -919,10 +958,10 @@ class RecipientTableTest_getAndPossiblyMerge { // Identity validation assertEquals(identityKeyAci, SignalDatabase.identities.getIdentityStoreRecord(ACI_A.toString())!!.identityKey) - Assert.assertNull(SignalDatabase.identities.getIdentityStoreRecord(E164_A)) + assertNull(SignalDatabase.identities.getIdentityStoreRecord(E164_A)) // Session validation - Assert.assertNotNull(SignalDatabase.sessions.load(ACI_SELF, SignalProtocolAddress(ACI_A.toString(), 1))) + assertNotNull(SignalDatabase.sessions.load(ACI_SELF, SignalProtocolAddress(ACI_A.toString(), 1))) // Reaction validation val reactionsSms: List = SignalDatabase.reactions.getReactions(MessageId(smsId1)) @@ -1037,6 +1076,10 @@ class RecipientTableTest_getAndPossiblyMerge { if (!test.sessionSwitchoverExpected) { test.expectNoSessionSwitchoverEvent() } + + if (!test.pniVerifiedExpected) { + test.expectPniNotVerified() + } } catch (e: Throwable) { if (e.javaClass != exception) { val error = java.lang.AssertionError("[$name] ${e.message}") @@ -1056,6 +1099,7 @@ class RecipientTableTest_getAndPossiblyMerge { var changeNumberExpected = false var threadMergeExpected = false var sessionSwitchoverExpected = false + var pniVerifiedExpected = false init { // Need to delete these first to prevent foreign key crash @@ -1207,6 +1251,24 @@ class RecipientTableTest_getAndPossiblyMerge { assertNull("Unexpected thread merge event!", getLatestThreadMergeEvent(outputRecipientId)) } + fun expectPniVerified() { + assertTrue("Expected PNI to be verified!", isPniVerified(outputRecipientId)) + pniVerifiedExpected = true + } + + fun expectPniNotVerified() { + assertFalse("Expected PNI to be not be verified!", isPniVerified(outputRecipientId)) + } + + private fun isPniVerified(recipientId: RecipientId): Boolean { + return SignalDatabase.rawDatabase + .select(RecipientTable.PNI_SIGNATURE_VERIFIED) + .from(RecipientTable.TABLE_NAME) + .where("${RecipientTable.ID} = ?", recipientId) + .run() + .readToSingleBoolean(false) + } + private fun insert(e164: String?, pni: PNI?, aci: ACI?): RecipientId { val id: Long = SignalDatabase.rawDatabase.insert( RecipientTable.TABLE_NAME, diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt index 5ca43dab..ad44a039 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt @@ -290,7 +290,8 @@ class SmsDatabaseTest_collapseJoinRequestEventsIfPossible { from = sender, timestamp = wallClock, groupId = groupId, - groupContext = groupContext + groupContext = groupContext, + serverGuid = null ) } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt index 3083038c..874877a1 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt @@ -37,7 +37,7 @@ import java.util.Optional * * Handles setting up a mock web server for API calls, and provides mockable versions of [SignalServiceNetworkAccess]. */ -class InstrumentationApplicationDependencyProvider(application: Application, default: ApplicationDependencyProvider) : ApplicationDependencies.Provider by default { +class InstrumentationApplicationDependencyProvider(val application: Application, private val default: ApplicationDependencyProvider) : ApplicationDependencies.Provider by default { private val serviceTrustStore: TrustStore private val uncensoredConfiguration: SignalServiceConfiguration diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt index 8f555697..a4f3cf36 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt @@ -52,7 +52,7 @@ class MessageContentProcessor__recipientStatusTest { processor.process( envelope = MessageContentFuzzer.envelope(envelopeTimestamp), content = MessageContentFuzzer.syncSentTextMessage(initialTextMessage, deliveredTo = listOf(harness.others[0])), - metadata = MessageContentFuzzer.envelopeMetadata(harness.self.id, harness.self.id, groupId), + metadata = MessageContentFuzzer.envelopeMetadata(harness.self.id, harness.self.id, groupId = groupId), serverDeliveredTimestamp = MessageContentFuzzer.fuzzServerDeliveredTimestamp(envelopeTimestamp) ) @@ -64,7 +64,7 @@ class MessageContentProcessor__recipientStatusTest { processor.process( envelope = MessageContentFuzzer.envelope(envelopeTimestamp), content = MessageContentFuzzer.syncSentTextMessage(initialTextMessage, deliveredTo = listOf(harness.others[0], harness.others[1]), recipientUpdate = true), - metadata = MessageContentFuzzer.envelopeMetadata(harness.self.id, harness.self.id, groupId), + metadata = MessageContentFuzzer.envelopeMetadata(harness.self.id, harness.self.id, groupId = groupId), serverDeliveredTimestamp = MessageContentFuzzer.fuzzServerDeliveredTimestamp(envelopeTimestamp) ) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_readSyncs.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_readSyncs.kt new file mode 100644 index 00000000..34c4957c --- /dev/null +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_readSyncs.kt @@ -0,0 +1,225 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.messages + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.mockk.every +import io.mockk.mockkStatic +import io.mockk.slot +import io.mockk.unmockkStatic +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.tm.archive.database.SignalDatabase +import org.tm.archive.jobs.ThreadUpdateJob +import org.tm.archive.recipients.RecipientId +import org.tm.archive.testing.GroupTestingUtils +import org.tm.archive.testing.MessageContentFuzzer +import org.tm.archive.testing.SignalActivityRule +import org.tm.archive.testing.assertIs +import java.util.UUID + +@Suppress("ClassName") +@RunWith(AndroidJUnit4::class) +class SyncMessageProcessorTest_readSyncs { + + @get:Rule + val harness = SignalActivityRule(createGroup = true) + + private lateinit var alice: RecipientId + private lateinit var bob: RecipientId + private lateinit var group: GroupTestingUtils.TestGroupInfo + private lateinit var processor: MessageContentProcessor + + @Before + fun setUp() { + alice = harness.others[0] + bob = harness.others[1] + group = harness.group!! + + processor = MessageContentProcessor(harness.context) + + val threadIdSlot = slot() + mockkStatic(ThreadUpdateJob::class) + every { ThreadUpdateJob.enqueue(capture(threadIdSlot)) } answers { + SignalDatabase.threads.update(threadIdSlot.captured, false) + } + } + + @After + fun tearDown() { + unmockkStatic(ThreadUpdateJob::class) + } + + @Test + fun handleSynchronizeReadMessage() { + val messageHelper = MessageHelper() + + val message1Timestamp = messageHelper.incomingText().timestamp + val message2Timestamp = messageHelper.incomingText().timestamp + + val threadId = SignalDatabase.threads.getThreadIdFor(alice)!! + var threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 2 + + messageHelper.syncReadMessage(alice to message1Timestamp, alice to message2Timestamp) + + threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 0 + } + + @Test + fun handleSynchronizeReadMessageMissingTimestamp() { + val messageHelper = MessageHelper() + + messageHelper.incomingText().timestamp + val message2Timestamp = messageHelper.incomingText().timestamp + + val threadId = SignalDatabase.threads.getThreadIdFor(alice)!! + var threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 2 + + messageHelper.syncReadMessage(alice to message2Timestamp) + + threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 0 + } + + @Test + fun handleSynchronizeReadWithEdits() { + val messageHelper = MessageHelper() + + val message1Timestamp = messageHelper.incomingText().timestamp + messageHelper.syncReadMessage(alice to message1Timestamp) + + val editMessage1Timestamp1 = messageHelper.incomingEditText(message1Timestamp).timestamp + val editMessage1Timestamp2 = messageHelper.incomingEditText(editMessage1Timestamp1).timestamp + + val message2Timestamp = messageHelper.incomingMedia().timestamp + + val threadId = SignalDatabase.threads.getThreadIdFor(alice)!! + var threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 2 + + messageHelper.syncReadMessage(alice to message2Timestamp, alice to editMessage1Timestamp1, alice to editMessage1Timestamp2) + + threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 0 + } + + @Test + fun handleSynchronizeReadWithEditsInGroup() { + val messageHelper = MessageHelper() + + val message1Timestamp = messageHelper.incomingText(sender = alice, destination = group.recipientId).timestamp + + messageHelper.syncReadMessage(alice to message1Timestamp) + + val editMessage1Timestamp1 = messageHelper.incomingEditText(targetTimestamp = message1Timestamp, sender = alice, destination = group.recipientId).timestamp + val editMessage1Timestamp2 = messageHelper.incomingEditText(targetTimestamp = editMessage1Timestamp1, sender = alice, destination = group.recipientId).timestamp + + val message2Timestamp = messageHelper.incomingMedia(sender = bob, destination = group.recipientId).timestamp + + val threadId = SignalDatabase.threads.getThreadIdFor(group.recipientId)!! + var threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 2 + + messageHelper.syncReadMessage(bob to message2Timestamp, alice to editMessage1Timestamp1, alice to editMessage1Timestamp2) + + threadRecord = SignalDatabase.threads.getThreadRecord(threadId)!! + threadRecord.unreadCount assertIs 0 + } + + private inner class MessageHelper(var startTime: Long = System.currentTimeMillis()) { + + fun incomingText(sender: RecipientId = alice, destination: RecipientId = harness.self.id): MessageData { + startTime += 1000 + + val messageData = MessageData(timestamp = startTime) + + processor.process( + envelope = MessageContentFuzzer.envelope(messageData.timestamp, serverGuid = messageData.serverGuid), + content = MessageContentFuzzer.fuzzTextMessage( + sentTimestamp = messageData.timestamp, + groupContextV2 = if (destination == group.recipientId) group.groupV2Context else null + ), + metadata = MessageContentFuzzer.envelopeMetadata( + source = sender, + destination = harness.self.id, + groupId = if (destination == group.recipientId) group.groupId else null + ), + serverDeliveredTimestamp = messageData.timestamp + 10 + ) + + return messageData + } + + fun incomingMedia(sender: RecipientId = alice, destination: RecipientId = harness.self.id): MessageData { + startTime += 1000 + + val messageData = MessageData(timestamp = startTime) + + processor.process( + envelope = MessageContentFuzzer.envelope(messageData.timestamp, serverGuid = messageData.serverGuid), + content = MessageContentFuzzer.fuzzStickerMediaMessage( + sentTimestamp = messageData.timestamp, + groupContextV2 = if (destination == group.recipientId) group.groupV2Context else null + ), + metadata = MessageContentFuzzer.envelopeMetadata( + source = sender, + destination = harness.self.id, + groupId = if (destination == group.recipientId) group.groupId else null + ), + serverDeliveredTimestamp = messageData.timestamp + 10 + ) + + return messageData + } + + fun incomingEditText(targetTimestamp: Long = System.currentTimeMillis(), sender: RecipientId = alice, destination: RecipientId = harness.self.id): MessageData { + startTime += 1000 + + val messageData = MessageData(timestamp = startTime) + + processor.process( + envelope = MessageContentFuzzer.envelope(messageData.timestamp, serverGuid = messageData.serverGuid), + content = MessageContentFuzzer.editTextMessage( + targetTimestamp = targetTimestamp, + editedDataMessage = MessageContentFuzzer.fuzzTextMessage( + sentTimestamp = messageData.timestamp, + groupContextV2 = if (destination == group.recipientId) group.groupV2Context else null + ).dataMessage!! + ), + metadata = MessageContentFuzzer.envelopeMetadata( + source = sender, + destination = harness.self.id, + groupId = if (destination == group.recipientId) group.groupId else null + ), + serverDeliveredTimestamp = messageData.timestamp + 10 + ) + + return messageData + } + + fun syncReadMessage(vararg reads: Pair): MessageData { + startTime += 1000 + val messageData = MessageData(timestamp = startTime) + + processor.process( + envelope = MessageContentFuzzer.envelope(messageData.timestamp, serverGuid = messageData.serverGuid), + content = MessageContentFuzzer.syncReadsMessage(reads.toList()), + metadata = MessageContentFuzzer.envelopeMetadata(harness.self.id, harness.self.id, sourceDeviceId = 2), + serverDeliveredTimestamp = messageData.timestamp + 10 + ) + + return messageData + } + } + + private data class MessageData(val serverGuid: UUID = UUID.randomUUID(), val timestamp: Long) +} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt index f1d60065..3e2ae8c6 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt @@ -57,27 +57,10 @@ class UsernameEditFragmentTest { InstrumentationApplicationDependencyProvider.clearHandlers() } - @Test - fun testUsernameCreationInRegistration() { - val scenario = createScenario(true) - - scenario.moveToState(Lifecycle.State.RESUMED) - - onView(withId(R.id.toolbar)).check { view, noViewFoundException -> - noViewFoundException.assertIsNull() - val toolbar = view as Toolbar - - toolbar.navigationIcon.assertIsNull() - } - - onView(withText(R.string.UsernameEditFragment__add_a_username)).check(matches(isDisplayed())) - onView(withContentDescription(R.string.load_more_header__loading)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))) - } - @Ignore("Flakey espresso test.") @Test fun testUsernameCreationOutsideOfRegistration() { - val scenario = createScenario() + val scenario = createScenario(UsernameEditMode.NORMAL) scenario.moveToState(Lifecycle.State.RESUMED) @@ -108,7 +91,7 @@ class UsernameEditFragmentTest { } ) - val scenario = createScenario(isInRegistration = true) + val scenario = createScenario(UsernameEditMode.NORMAL) scenario.moveToState(Lifecycle.State.RESUMED) onView(withId(R.id.username_text)).perform(typeText(nickname)) @@ -132,8 +115,8 @@ class UsernameEditFragmentTest { onView(withId(R.id.username_done_button)).check(matches(isNotEnabled())) } - private fun createScenario(isInRegistration: Boolean = false): FragmentScenario { - val fragmentArgs = UsernameEditFragmentArgs.Builder().setIsInRegistration(isInRegistration).build().toBundle() + private fun createScenario(mode: UsernameEditMode = UsernameEditMode.NORMAL): FragmentScenario { + val fragmentArgs = UsernameEditFragmentArgs.Builder().setMode(mode).build().toBundle() return launchFragmentInContainer( fragmentArgs = fragmentArgs, themeResId = R.style.Signal_DayNight_NoActionBar diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt index ecd8e96c..8c65294d 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt @@ -12,8 +12,6 @@ import org.tm.archive.database.RecipientTable import org.tm.archive.database.SignalDatabase import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.RecipientId -import org.tm.archive.util.FeatureFlags -import org.tm.archive.util.FeatureFlagsAccessor import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.storage.SignalContactRecord @@ -29,11 +27,10 @@ class ContactRecordProcessorTest { SignalStore.account().setE164(E164_SELF) SignalStore.account().setAci(ACI_SELF) SignalStore.account().setPni(PNI_SELF) - FeatureFlagsAccessor.forceValue(FeatureFlags.PHONE_NUMBER_PRIVACY, true) } @Test - fun process_splitContact_normalSplit() { + fun process_splitContact_normalSplit_twoRecords() { // GIVEN val originalId = SignalDatabase.recipients.getAndPossiblyMerge(ACI_A, PNI_A, E164_A) setStorageId(originalId, STORAGE_ID_A) @@ -69,6 +66,35 @@ class ContactRecordProcessorTest { assertNotEquals(byAci, byE164) } + @Test + fun process_splitContact_normalSplit_oneRecord() { + // GIVEN + val originalId = SignalDatabase.recipients.getAndPossiblyMerge(ACI_A, PNI_A, E164_A) + setStorageId(originalId, STORAGE_ID_A) + + val remote = buildRecord( + STORAGE_ID_B, + ContactRecord( + aci = ACI_A.toString(), + unregisteredAtTimestamp = 100 + ) + ) + + // WHEN + val subject = ContactRecordProcessor() + subject.process(listOf(remote), StorageSyncHelper.KEY_GENERATOR) + + // THEN + val byAci: RecipientId = SignalDatabase.recipients.getByAci(ACI_A).get() + + val byE164: RecipientId = SignalDatabase.recipients.getByE164(E164_A).get() + val byPni: RecipientId = SignalDatabase.recipients.getByPni(PNI_A).get() + + assertEquals(originalId, byAci) + assertEquals(byE164, byPni) + assertNotEquals(byAci, byE164) + } + @Test fun process_splitContact_doNotSplitIfAciRecordIsRegistered() { // GIVEN diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt index e2800800..fd7076c9 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt @@ -40,7 +40,7 @@ class AliceClient(val serviceId: ServiceId, val e164: String, val trustRoot: ECK ApplicationDependencies.getIncomingMessageObserver() .processEnvelope(bufferedStore, envelope, serverDeliveredTimestamp) ?.mapNotNull { it.run() } - ?.forEach { ApplicationDependencies.getJobManager().add(it) } + ?.forEach { it.enqueue() } bufferedStore.flushToDisk() val end = System.currentTimeMillis() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt index 2dab3533..25565323 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt @@ -1,5 +1,6 @@ package org.tm.archive.testing +import okio.ByteString.Companion.toByteString import org.signal.libsignal.zkgroup.groups.GroupMasterKey import org.signal.storageservice.protos.groups.Member import org.signal.storageservice.protos.groups.local.DecryptedGroup @@ -9,6 +10,7 @@ import org.tm.archive.groups.GroupId import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.internal.push.GroupContextV2 import kotlin.random.Random /** @@ -46,5 +48,8 @@ object GroupTestingUtils { return member(aci = requireAci()) } - data class TestGroupInfo(val groupId: GroupId.V2, val masterKey: GroupMasterKey, val recipientId: RecipientId) + data class TestGroupInfo(val groupId: GroupId.V2, val masterKey: GroupMasterKey, val recipientId: RecipientId) { + val groupV2Context: GroupContextV2 + get() = GroupContextV2(masterKey = masterKey.serialize().toByteString(), revision = 0) + } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt index 0e952de5..b839e55f 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt @@ -12,6 +12,7 @@ import org.whispersystems.signalservice.internal.push.AttachmentPointer import org.whispersystems.signalservice.internal.push.BodyRange import org.whispersystems.signalservice.internal.push.Content import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.EditMessage import org.whispersystems.signalservice.internal.push.Envelope import org.whispersystems.signalservice.internal.push.GroupContextV2 import org.whispersystems.signalservice.internal.push.SyncMessage @@ -33,22 +34,22 @@ object MessageContentFuzzer { /** * Create an [Envelope]. */ - fun envelope(timestamp: Long): Envelope { + fun envelope(timestamp: Long, serverGuid: UUID = UUID.randomUUID()): Envelope { return Envelope.Builder() .timestamp(timestamp) .serverTimestamp(timestamp + 5) - .serverGuid(UUID.randomUUID().toString()) + .serverGuid(serverGuid.toString()) .build() } /** * Create metadata to match an [Envelope]. */ - fun envelopeMetadata(source: RecipientId, destination: RecipientId, groupId: GroupId.V2? = null): EnvelopeMetadata { + fun envelopeMetadata(source: RecipientId, destination: RecipientId, sourceDeviceId: Int = 1, groupId: GroupId.V2? = null): EnvelopeMetadata { return EnvelopeMetadata( sourceServiceId = Recipient.resolved(source).requireServiceId(), sourceE164 = null, - sourceDeviceId = 1, + sourceDeviceId = sourceDeviceId, sealedSender = true, groupId = groupId?.decodedId, destinationServiceId = Recipient.resolved(destination).requireServiceId() @@ -60,10 +61,11 @@ object MessageContentFuzzer { * - An expire timer value * - Bold style body ranges */ - fun fuzzTextMessage(groupContextV2: GroupContextV2? = null): Content { + fun fuzzTextMessage(sentTimestamp: Long? = null, groupContextV2: GroupContextV2? = null): Content { return Content.Builder() .dataMessage( DataMessage.Builder().buildWith { + timestamp = sentTimestamp body = string() if (random.nextBoolean()) { expireTimer = random.nextInt(0..28.days.inWholeSeconds.toInt()) @@ -87,6 +89,20 @@ object MessageContentFuzzer { .build() } + /** + * Create an edit message. + */ + fun editTextMessage(targetTimestamp: Long, editedDataMessage: DataMessage): Content { + return Content.Builder() + .editMessage( + EditMessage.Builder().buildWith { + targetSentTimestamp = targetTimestamp + dataMessage = editedDataMessage + } + ) + .build() + } + /** * Create a sync sent text message for the given [DataMessage]. */ @@ -116,6 +132,24 @@ object MessageContentFuzzer { ).build() } + /** + * Create a sync reads message for the given [RecipientId] and message timestamp pairings. + */ + fun syncReadsMessage(timestamps: List>): Content { + return Content + .Builder() + .syncMessage( + SyncMessage.Builder().buildWith { + read = timestamps.map { (senderId, timestamp) -> + SyncMessage.Read.Builder().buildWith { + this.senderAci = Recipient.resolved(senderId).requireAci().toString() + this.timestamp = timestamp + } + } + } + ).build() + } + /** * Create a random media message that may be: * - A text body @@ -184,22 +218,21 @@ object MessageContentFuzzer { } /** - * Create a random media message that can never contain a text body. It may be: - * - A sticker + * Create a random media message that contains a sticker. */ - fun fuzzMediaMessageNoText(previousMessages: List = emptyList()): Content { + fun fuzzStickerMediaMessage(sentTimestamp: Long? = null, groupContextV2: GroupContextV2? = null): Content { return Content.Builder() .dataMessage( DataMessage.Builder().buildWith { - if (random.nextFloat() < 0.9) { - sticker = DataMessage.Sticker.Builder().buildWith { - packId = byteString(length = 24) - packKey = byteString(length = 128) - stickerId = random.nextInt() - data_ = attachmentPointer() - emoji = emojis.random(random) - } + timestamp = sentTimestamp + sticker = DataMessage.Sticker.Builder().buildWith { + packId = byteString(length = 24) + packKey = byteString(length = 128) + stickerId = random.nextInt() + data_ = attachmentPointer() + emoji = emojis.random(random) } + groupV2 = groupContextV2 } ).build() } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt index 0536df77..f69cc6df 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt @@ -141,7 +141,7 @@ class SignalActivityRule(private val othersCount: Int = 4, private val createGro val recipientId = RecipientId.from(SignalServiceAddress(aci, "+15555551%03d".format(i))) SignalDatabase.recipients.setProfileName(recipientId, ProfileName.fromParts("Buddy", "#$i")) SignalDatabase.recipients.setProfileKeyIfAbsent(recipientId, ProfileKeyUtil.createNew()) - SignalDatabase.recipients.setCapabilities(recipientId, SignalServiceProfile.Capabilities(true, true, true, true, true, true, true, true, true)) + SignalDatabase.recipients.setCapabilities(recipientId, SignalServiceProfile.Capabilities(true, true, true)) SignalDatabase.recipients.setProfileSharing(recipientId, true) SignalDatabase.recipients.markRegistered(recipientId, aci) val otherIdentity = IdentityKeyUtil.generateIdentityKeyPair() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt index ecdaac98..7564daaa 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt @@ -2,7 +2,9 @@ package org.tm.archive.testing import org.junit.rules.TestWatcher import org.junit.runner.Description +import org.signal.core.util.deleteAll import org.tm.archive.database.SignalDatabase +import org.tm.archive.database.ThreadTable import org.tm.archive.keyvalue.SignalStore import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI @@ -34,7 +36,8 @@ class SignalDatabaseRule( private fun deleteAllThreads() { if (deleteAllThreadsOnEachRun) { - SignalDatabase.threads.clearForTests() + SignalDatabase.threads.deleteAllConversations() + SignalDatabase.rawDatabase.deleteAll(ThreadTable.TABLE_NAME) } } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/util/FeatureFlagsAccessor.java b/app/src/androidTest/java/org/thoughtcrime/securesms/util/FeatureFlagsAccessor.java index 958d17b3..ce93ac6a 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/util/FeatureFlagsAccessor.java +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/util/FeatureFlagsAccessor.java @@ -6,6 +6,6 @@ package org.tm.archive.util; public final class FeatureFlagsAccessor { public static void forceValue(String key, Object value) { - FeatureFlags.FORCED_VALUES.put(FeatureFlags.PHONE_NUMBER_PRIVACY, true); + FeatureFlags.FORCED_VALUES.put(key, value); } } diff --git a/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt b/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt index 1b329960..730cbd20 100644 --- a/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt +++ b/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt @@ -100,7 +100,7 @@ object TestUsers { val recipientId = RecipientId.from(SignalServiceAddress(aci, "+15555551%03d".format(i))) SignalDatabase.recipients.setProfileName(recipientId, ProfileName.fromParts("Buddy", "#$i")) SignalDatabase.recipients.setProfileKeyIfAbsent(recipientId, ProfileKeyUtil.createNew()) - SignalDatabase.recipients.setCapabilities(recipientId, SignalServiceProfile.Capabilities(true, true, true, true, true, true, true, true, true)) + SignalDatabase.recipients.setCapabilities(recipientId, SignalServiceProfile.Capabilities(true, true, true)) SignalDatabase.recipients.setProfileSharing(recipientId, true) SignalDatabase.recipients.markRegistered(recipientId, aci) val otherIdentity = IdentityKeyUtil.generateIdentityKeyPair() diff --git a/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt b/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt index e7f82ecd..9e60650e 100644 --- a/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt +++ b/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt @@ -118,7 +118,8 @@ class ConversationElementGenerator { null, null, 0, - false + false, + null ) val conversationMessage = ConversationMessageFactory.createWithUnresolvedData( diff --git a/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/InternalConversationTestFragment.kt b/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/InternalConversationTestFragment.kt index ed13671b..3d10e6c0 100644 --- a/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/InternalConversationTestFragment.kt +++ b/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/InternalConversationTestFragment.kt @@ -13,6 +13,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.Observer import androidx.navigation.navGraphViewModels +import com.bumptech.glide.Glide import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.kotlin.subscribeBy import org.signal.core.util.concurrent.LifecycleDisposable @@ -33,6 +34,7 @@ import org.tm.archive.conversation.colors.Colorizer import org.tm.archive.conversation.colors.RecyclerViewColorizer import org.tm.archive.conversation.mutiselect.MultiselectPart import org.tm.archive.conversation.v2.ConversationAdapterV2 +import org.tm.archive.conversation.v2.items.ChatColorsDrawable import org.tm.archive.database.model.InMemoryMessageRecord import org.tm.archive.database.model.MessageRecord import org.tm.archive.database.model.MmsMessageRecord @@ -41,7 +43,6 @@ import org.tm.archive.groups.GroupId import org.tm.archive.groups.GroupMigrationMembershipChange import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.mediapreview.MediaIntentFactory -import org.tm.archive.mms.GlideApp import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.stickers.StickerLocator @@ -61,11 +62,12 @@ class InternalConversationTestFragment : Fragment(R.layout.conversation_test_fra override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val adapter = ConversationAdapterV2( lifecycleOwner = viewLifecycleOwner, - glideRequests = GlideApp.with(this), + requestManager = Glide.with(this), clickListener = ClickListener(), hasWallpaper = springboardViewModel.hasWallpaper.value, colorizer = Colorizer(), - startExpirationTimeout = {} + startExpirationTimeout = {}, + chatColorsDataProvider = { ChatColorsDrawable.ChatColorsData(null, null) } ) if (springboardViewModel.hasWallpaper.value) { @@ -296,5 +298,17 @@ class InternalConversationTestFragment : Fragment(R.layout.conversation_test_fra override fun onItemLongClick(itemView: View?, item: MultiselectPart?) { Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show() } + + override fun onShowSafetyTips(forGroup: Boolean) { + Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show() + } + + override fun onReportSpamLearnMoreClicked() { + Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show() + } + + override fun onMessageRequestAcceptOptionsClicked() { + Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show() + } } } diff --git a/app/src/instrumentation/AndroidManifest.xml b/app/src/instrumentation/AndroidManifest.xml index 93821ec6..8297919d 100644 --- a/app/src/instrumentation/AndroidManifest.xml +++ b/app/src/instrumentation/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + - - - - - - @@ -50,16 +43,10 @@ - - - - - - @@ -76,17 +63,14 @@ - + - - - + - @@ -100,7 +84,6 @@ - + @@ -161,12 +144,6 @@ android:value=".MainActivity" /> - - @@ -186,10 +163,6 @@ - - + + @@ -726,6 +704,7 @@ android:theme="@style/TextSecure.DarkNoActionBar" android:windowSoftInputMode="stateAlwaysHidden|adjustNothing" android:launchMode="singleTop" + android:screenOrientation="portrait" android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode" android:exported="false"/> @@ -769,6 +748,13 @@ android:windowSoftInputMode="stateAlwaysHidden" android:exported="false"/> + + + android:exported="true" + android:excludeFromRecents="true" + android:permission="android.permission.CALL_PHONE" + android:theme="@style/NoAnimation.Theme.BlackScreen" + android:launchMode="singleTask" + android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"> @@ -976,9 +962,8 @@ android:windowSoftInputMode="stateVisible|adjustResize" android:exported="false"/> - + + - - - + + - @@ -1113,12 +1099,6 @@ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" android:exported="false"/> - - - - - - - - - - - - - @@ -1215,13 +1182,6 @@ - - - - - - @@ -1281,11 +1241,6 @@ android:exported="false" android:grantUriPermissions="true" /> - - + + + + + + + + + + diff --git a/app/src/main/assets/emoji/Activity.webp b/app/src/main/assets/emoji/Activity.webp index 4f196644..c1e5a8d3 100644 Binary files a/app/src/main/assets/emoji/Activity.webp and b/app/src/main/assets/emoji/Activity.webp differ diff --git a/app/src/main/assets/emoji/Flags_0.webp b/app/src/main/assets/emoji/Flags_0.webp index 145ae468..a6f70e65 100644 Binary files a/app/src/main/assets/emoji/Flags_0.webp and b/app/src/main/assets/emoji/Flags_0.webp differ diff --git a/app/src/main/assets/emoji/Flags_1.webp b/app/src/main/assets/emoji/Flags_1.webp index 2bc7352d..38bad475 100644 Binary files a/app/src/main/assets/emoji/Flags_1.webp and b/app/src/main/assets/emoji/Flags_1.webp differ diff --git a/app/src/main/assets/emoji/Foods.webp b/app/src/main/assets/emoji/Foods.webp index e2c23097..b88c9b5d 100644 Binary files a/app/src/main/assets/emoji/Foods.webp and b/app/src/main/assets/emoji/Foods.webp differ diff --git a/app/src/main/assets/emoji/Nature.webp b/app/src/main/assets/emoji/Nature.webp index 3c6453e8..213d6be2 100644 Binary files a/app/src/main/assets/emoji/Nature.webp and b/app/src/main/assets/emoji/Nature.webp differ diff --git a/app/src/main/assets/emoji/Objects_0.webp b/app/src/main/assets/emoji/Objects_0.webp index de9266dc..5e4f71e4 100644 Binary files a/app/src/main/assets/emoji/Objects_0.webp and b/app/src/main/assets/emoji/Objects_0.webp differ diff --git a/app/src/main/assets/emoji/Objects_1.webp b/app/src/main/assets/emoji/Objects_1.webp index f34b85f7..22e8f8b5 100644 Binary files a/app/src/main/assets/emoji/Objects_1.webp and b/app/src/main/assets/emoji/Objects_1.webp differ diff --git a/app/src/main/assets/emoji/People_0.webp b/app/src/main/assets/emoji/People_0.webp index d684f3fc..b561b1b9 100644 Binary files a/app/src/main/assets/emoji/People_0.webp and b/app/src/main/assets/emoji/People_0.webp differ diff --git a/app/src/main/assets/emoji/People_1.webp b/app/src/main/assets/emoji/People_1.webp index 14e3dec9..445fba20 100644 Binary files a/app/src/main/assets/emoji/People_1.webp and b/app/src/main/assets/emoji/People_1.webp differ diff --git a/app/src/main/assets/emoji/People_2.webp b/app/src/main/assets/emoji/People_2.webp index 0b09776c..3f8e9d46 100644 Binary files a/app/src/main/assets/emoji/People_2.webp and b/app/src/main/assets/emoji/People_2.webp differ diff --git a/app/src/main/assets/emoji/People_3.webp b/app/src/main/assets/emoji/People_3.webp index 9802774d..e8469bad 100644 Binary files a/app/src/main/assets/emoji/People_3.webp and b/app/src/main/assets/emoji/People_3.webp differ diff --git a/app/src/main/assets/emoji/People_4.webp b/app/src/main/assets/emoji/People_4.webp index cdfed8f0..d19f0465 100644 Binary files a/app/src/main/assets/emoji/People_4.webp and b/app/src/main/assets/emoji/People_4.webp differ diff --git a/app/src/main/assets/emoji/People_5.webp b/app/src/main/assets/emoji/People_5.webp index d0207730..8b799616 100644 Binary files a/app/src/main/assets/emoji/People_5.webp and b/app/src/main/assets/emoji/People_5.webp differ diff --git a/app/src/main/assets/emoji/People_6.webp b/app/src/main/assets/emoji/People_6.webp index 08fbf64f..b27da88d 100644 Binary files a/app/src/main/assets/emoji/People_6.webp and b/app/src/main/assets/emoji/People_6.webp differ diff --git a/app/src/main/assets/emoji/People_7.webp b/app/src/main/assets/emoji/People_7.webp index b1032168..4389ce32 100644 Binary files a/app/src/main/assets/emoji/People_7.webp and b/app/src/main/assets/emoji/People_7.webp differ diff --git a/app/src/main/assets/emoji/People_8.webp b/app/src/main/assets/emoji/People_8.webp index 06df8d0b..5657ba5e 100644 Binary files a/app/src/main/assets/emoji/People_8.webp and b/app/src/main/assets/emoji/People_8.webp differ diff --git a/app/src/main/assets/emoji/People_9.webp b/app/src/main/assets/emoji/People_9.webp index 3d705cf8..91424cc5 100644 Binary files a/app/src/main/assets/emoji/People_9.webp and b/app/src/main/assets/emoji/People_9.webp differ diff --git a/app/src/main/assets/emoji/Places.webp b/app/src/main/assets/emoji/Places.webp index 3baae9ae..59863fc1 100644 Binary files a/app/src/main/assets/emoji/Places.webp and b/app/src/main/assets/emoji/Places.webp differ diff --git a/app/src/main/assets/emoji/Symbols.webp b/app/src/main/assets/emoji/Symbols.webp index 286ce521..49111ddc 100644 Binary files a/app/src/main/assets/emoji/Symbols.webp and b/app/src/main/assets/emoji/Symbols.webp differ diff --git a/app/src/main/assets/emoji/emoji_data.json b/app/src/main/assets/emoji/emoji_data.json index 370fcdb0..1ca0bd21 100644 --- a/app/src/main/assets/emoji/emoji_data.json +++ b/app/src/main/assets/emoji/emoji_data.json @@ -1 +1 @@ -{"emoji":{"People_0":[["d83dde00"],["d83dde03"],["d83dde04"],["d83dde01"],["d83dde06"],["d83dde05"],["d83edd23"],["d83dde02"],["d83dde42"],["d83dde43"],["d83edee0"],["d83dde09"],["d83dde0a"],["d83dde07"],["d83edd70"],["d83dde0d"],["d83edd29"],["d83dde18"],["d83dde17"],["263afe0f"],["d83dde1a"],["d83dde19"],["d83edd72"],["d83dde0b"],["d83dde1b"],["d83dde1c"],["d83edd2a"],["d83dde1d"],["d83edd11"],["d83edd17"],["d83edd2d"],["d83edee2"],["d83edee3"],["d83edd2b"],["d83edd14"],["d83edee1"],["d83edd10"],["d83edd28"],["d83dde10"],["d83dde11"],["d83dde36"],["d83edee5"],["d83dde36200dd83cdf2bfe0f"],["d83dde0f"],["d83dde12"],["d83dde44"],["d83dde2c"],["d83dde2e200dd83ddca8"],["d83edd25"],["d83edee8"],["d83dde0c"],["d83dde14"],["d83dde2a"],["d83edd24"],["d83dde34"],["d83dde37"],["d83edd12"],["d83edd15"],["d83edd22"],["d83edd2e"],["d83edd27"],["d83edd75"],["d83edd76"],["d83edd74"],["d83dde35"],["d83dde35200dd83ddcab"],["d83edd2f"],["d83edd20"],["d83edd73"],["d83edd78"],["d83dde0e"],["d83edd13"],["d83eddd0"],["d83dde15"],["d83edee4"],["d83dde1f"],["d83dde41"],["2639fe0f"],["d83dde2e"],["d83dde2f"],["d83dde32"],["d83dde33"],["d83edd7a"],["d83edd79"],["d83dde26"],["d83dde27"],["d83dde28"],["d83dde30"],["d83dde25"],["d83dde22"],["d83dde2d"],["d83dde31"],["d83dde16"],["d83dde23"],["d83dde1e"],["d83dde13"],["d83dde29"],["d83dde2b"],["d83edd71"],["d83dde24"],["d83dde21"],["d83dde20"],["d83edd2c"],["d83dde08"],["d83ddc7f"],["d83ddc80"],["2620fe0f"],["d83ddca9"],["d83edd21"],["d83ddc79"],["d83ddc7a"],["d83ddc7b"],["d83ddc7d"],["d83ddc7e"],["d83edd16"],["d83dde3a"],["d83dde38"],["d83dde39"],["d83dde3b"],["d83dde3c"],["d83dde3d"],["d83dde40"],["d83dde3f"],["d83dde3e"],["d83dde48"],["d83dde49"],["d83dde4a"],["d83ddc8c"],["d83ddc98"],["d83ddc9d"],["d83ddc96"],["d83ddc97"],["d83ddc93"],["d83ddc9e"],["d83ddc95"],["d83ddc9f"],["2763fe0f"],["d83ddc94"],["2764fe0f200dd83ddd25"],["2764fe0f200dd83ede79"],["2764fe0f"],["d83ede77"],["d83edde1"],["d83ddc9b"],["d83ddc9a"],["d83ddc99"],["d83ede75"],["d83ddc9c"],["d83edd0e"],["d83ddda4"],["d83ede76"],["d83edd0d"],["d83ddc8b"],["d83ddcaf"],["d83ddca2"],["d83ddca5"],["d83ddcab"],["d83ddca6"],["d83ddca8"],["d83ddd73fe0f"],["d83ddcac"],["d83ddc41fe0f200dd83ddde8fe0f"],["d83ddde8fe0f"],["d83dddeffe0f"],["d83ddcad"],["d83ddca4"],["d83ddc4b","d83ddc4bd83cdffb","d83ddc4bd83cdffc","d83ddc4bd83cdffd","d83ddc4bd83cdffe","d83ddc4bd83cdfff"],["d83edd1a","d83edd1ad83cdffb","d83edd1ad83cdffc","d83edd1ad83cdffd","d83edd1ad83cdffe","d83edd1ad83cdfff"],["d83ddd90fe0f","d83ddd90d83cdffb","d83ddd90d83cdffc","d83ddd90d83cdffd","d83ddd90d83cdffe","d83ddd90d83cdfff"],["270b","270bd83cdffb","270bd83cdffc","270bd83cdffd","270bd83cdffe","270bd83cdfff"],["d83ddd96","d83ddd96d83cdffb","d83ddd96d83cdffc","d83ddd96d83cdffd","d83ddd96d83cdffe","d83ddd96d83cdfff"],["d83edef1","d83edef1d83cdffb","d83edef1d83cdffc","d83edef1d83cdffd","d83edef1d83cdffe","d83edef1d83cdfff"],["d83edef2","d83edef2d83cdffb","d83edef2d83cdffc","d83edef2d83cdffd","d83edef2d83cdffe","d83edef2d83cdfff"],["d83edef3","d83edef3d83cdffb","d83edef3d83cdffc","d83edef3d83cdffd","d83edef3d83cdffe","d83edef3d83cdfff"],["d83edef4","d83edef4d83cdffb","d83edef4d83cdffc","d83edef4d83cdffd","d83edef4d83cdffe","d83edef4d83cdfff"],["d83edef7","d83edef7d83cdffb","d83edef7d83cdffc","d83edef7d83cdffd","d83edef7d83cdffe","d83edef7d83cdfff"],["d83edef8","d83edef8d83cdffb","d83edef8d83cdffc","d83edef8d83cdffd","d83edef8d83cdffe","d83edef8d83cdfff"],["d83ddc4c","d83ddc4cd83cdffb","d83ddc4cd83cdffc","d83ddc4cd83cdffd","d83ddc4cd83cdffe","d83ddc4cd83cdfff"],["d83edd0c","d83edd0cd83cdffb","d83edd0cd83cdffc","d83edd0cd83cdffd","d83edd0cd83cdffe","d83edd0cd83cdfff"],["d83edd0f","d83edd0fd83cdffb","d83edd0fd83cdffc","d83edd0fd83cdffd","d83edd0fd83cdffe","d83edd0fd83cdfff"],["270cfe0f","270cd83cdffb","270cd83cdffc","270cd83cdffd","270cd83cdffe","270cd83cdfff"]],"People_1":[["d83edd1e","d83edd1ed83cdffb","d83edd1ed83cdffc","d83edd1ed83cdffd","d83edd1ed83cdffe","d83edd1ed83cdfff"],["d83edef0","d83edef0d83cdffb","d83edef0d83cdffc","d83edef0d83cdffd","d83edef0d83cdffe","d83edef0d83cdfff"],["d83edd1f","d83edd1fd83cdffb","d83edd1fd83cdffc","d83edd1fd83cdffd","d83edd1fd83cdffe","d83edd1fd83cdfff"],["d83edd18","d83edd18d83cdffb","d83edd18d83cdffc","d83edd18d83cdffd","d83edd18d83cdffe","d83edd18d83cdfff"],["d83edd19","d83edd19d83cdffb","d83edd19d83cdffc","d83edd19d83cdffd","d83edd19d83cdffe","d83edd19d83cdfff"],["d83ddc48","d83ddc48d83cdffb","d83ddc48d83cdffc","d83ddc48d83cdffd","d83ddc48d83cdffe","d83ddc48d83cdfff"],["d83ddc49","d83ddc49d83cdffb","d83ddc49d83cdffc","d83ddc49d83cdffd","d83ddc49d83cdffe","d83ddc49d83cdfff"],["d83ddc46","d83ddc46d83cdffb","d83ddc46d83cdffc","d83ddc46d83cdffd","d83ddc46d83cdffe","d83ddc46d83cdfff"],["d83ddd95","d83ddd95d83cdffb","d83ddd95d83cdffc","d83ddd95d83cdffd","d83ddd95d83cdffe","d83ddd95d83cdfff"],["d83ddc47","d83ddc47d83cdffb","d83ddc47d83cdffc","d83ddc47d83cdffd","d83ddc47d83cdffe","d83ddc47d83cdfff"],["261dfe0f","261dd83cdffb","261dd83cdffc","261dd83cdffd","261dd83cdffe","261dd83cdfff"],["d83edef5","d83edef5d83cdffb","d83edef5d83cdffc","d83edef5d83cdffd","d83edef5d83cdffe","d83edef5d83cdfff"],["d83ddc4d","d83ddc4dd83cdffb","d83ddc4dd83cdffc","d83ddc4dd83cdffd","d83ddc4dd83cdffe","d83ddc4dd83cdfff"],["d83ddc4e","d83ddc4ed83cdffb","d83ddc4ed83cdffc","d83ddc4ed83cdffd","d83ddc4ed83cdffe","d83ddc4ed83cdfff"],["270a","270ad83cdffb","270ad83cdffc","270ad83cdffd","270ad83cdffe","270ad83cdfff"],["d83ddc4a","d83ddc4ad83cdffb","d83ddc4ad83cdffc","d83ddc4ad83cdffd","d83ddc4ad83cdffe","d83ddc4ad83cdfff"],["d83edd1b","d83edd1bd83cdffb","d83edd1bd83cdffc","d83edd1bd83cdffd","d83edd1bd83cdffe","d83edd1bd83cdfff"],["d83edd1c","d83edd1cd83cdffb","d83edd1cd83cdffc","d83edd1cd83cdffd","d83edd1cd83cdffe","d83edd1cd83cdfff"],["d83ddc4f","d83ddc4fd83cdffb","d83ddc4fd83cdffc","d83ddc4fd83cdffd","d83ddc4fd83cdffe","d83ddc4fd83cdfff"],["d83dde4c","d83dde4cd83cdffb","d83dde4cd83cdffc","d83dde4cd83cdffd","d83dde4cd83cdffe","d83dde4cd83cdfff"],["d83edef6","d83edef6d83cdffb","d83edef6d83cdffc","d83edef6d83cdffd","d83edef6d83cdffe","d83edef6d83cdfff"],["d83ddc50","d83ddc50d83cdffb","d83ddc50d83cdffc","d83ddc50d83cdffd","d83ddc50d83cdffe","d83ddc50d83cdfff"],["d83edd32","d83edd32d83cdffb","d83edd32d83cdffc","d83edd32d83cdffd","d83edd32d83cdffe","d83edd32d83cdfff"],["d83edd1d","d83edd1dd83cdffb","d83edd1dd83cdffc","d83edd1dd83cdffd","d83edd1dd83cdffe","d83edd1dd83cdfff","d83edef1d83cdffb200dd83edef2d83cdffc","d83edef1d83cdffb200dd83edef2d83cdffd","d83edef1d83cdffb200dd83edef2d83cdffe","d83edef1d83cdffb200dd83edef2d83cdfff","d83edef1d83cdffc200dd83edef2d83cdffb","d83edef1d83cdffc200dd83edef2d83cdffd","d83edef1d83cdffc200dd83edef2d83cdffe","d83edef1d83cdffc200dd83edef2d83cdfff","d83edef1d83cdffd200dd83edef2d83cdffb","d83edef1d83cdffd200dd83edef2d83cdffc","d83edef1d83cdffd200dd83edef2d83cdffe","d83edef1d83cdffd200dd83edef2d83cdfff","d83edef1d83cdffe200dd83edef2d83cdffb","d83edef1d83cdffe200dd83edef2d83cdffc","d83edef1d83cdffe200dd83edef2d83cdffd","d83edef1d83cdffe200dd83edef2d83cdfff","d83edef1d83cdfff200dd83edef2d83cdffb","d83edef1d83cdfff200dd83edef2d83cdffc","d83edef1d83cdfff200dd83edef2d83cdffd","d83edef1d83cdfff200dd83edef2d83cdffe"],["d83dde4f","d83dde4fd83cdffb","d83dde4fd83cdffc","d83dde4fd83cdffd","d83dde4fd83cdffe","d83dde4fd83cdfff"],["270dfe0f","270dd83cdffb","270dd83cdffc","270dd83cdffd","270dd83cdffe","270dd83cdfff"],["d83ddc85","d83ddc85d83cdffb","d83ddc85d83cdffc","d83ddc85d83cdffd","d83ddc85d83cdffe","d83ddc85d83cdfff"],["d83edd33","d83edd33d83cdffb","d83edd33d83cdffc","d83edd33d83cdffd","d83edd33d83cdffe","d83edd33d83cdfff"],["d83ddcaa","d83ddcaad83cdffb","d83ddcaad83cdffc","d83ddcaad83cdffd","d83ddcaad83cdffe","d83ddcaad83cdfff"],["d83eddbe"],["d83eddbf"],["d83eddb5","d83eddb5d83cdffb","d83eddb5d83cdffc","d83eddb5d83cdffd","d83eddb5d83cdffe","d83eddb5d83cdfff"],["d83eddb6","d83eddb6d83cdffb","d83eddb6d83cdffc","d83eddb6d83cdffd","d83eddb6d83cdffe","d83eddb6d83cdfff"],["d83ddc42","d83ddc42d83cdffb","d83ddc42d83cdffc","d83ddc42d83cdffd","d83ddc42d83cdffe","d83ddc42d83cdfff"],["d83eddbb","d83eddbbd83cdffb","d83eddbbd83cdffc","d83eddbbd83cdffd","d83eddbbd83cdffe","d83eddbbd83cdfff"],["d83ddc43","d83ddc43d83cdffb","d83ddc43d83cdffc","d83ddc43d83cdffd","d83ddc43d83cdffe","d83ddc43d83cdfff"],["d83edde0"],["d83edec0"],["d83edec1"],["d83eddb7"],["d83eddb4"],["d83ddc40"],["d83ddc41fe0f"],["d83ddc45"],["d83ddc44"],["d83edee6"],["d83ddc76","d83ddc76d83cdffb","d83ddc76d83cdffc","d83ddc76d83cdffd","d83ddc76d83cdffe","d83ddc76d83cdfff"],["d83eddd2","d83eddd2d83cdffb","d83eddd2d83cdffc","d83eddd2d83cdffd","d83eddd2d83cdffe","d83eddd2d83cdfff"],["d83ddc66","d83ddc66d83cdffb","d83ddc66d83cdffc","d83ddc66d83cdffd","d83ddc66d83cdffe","d83ddc66d83cdfff"]],"People_2":[["d83ddc67","d83ddc67d83cdffb","d83ddc67d83cdffc","d83ddc67d83cdffd","d83ddc67d83cdffe","d83ddc67d83cdfff"],["d83eddd1","d83eddd1d83cdffb","d83eddd1d83cdffc","d83eddd1d83cdffd","d83eddd1d83cdffe","d83eddd1d83cdfff"],["d83ddc71","d83ddc71d83cdffb","d83ddc71d83cdffc","d83ddc71d83cdffd","d83ddc71d83cdffe","d83ddc71d83cdfff"],["d83ddc68","d83ddc68d83cdffb","d83ddc68d83cdffc","d83ddc68d83cdffd","d83ddc68d83cdffe","d83ddc68d83cdfff"],["d83eddd4","d83eddd4d83cdffb","d83eddd4d83cdffc","d83eddd4d83cdffd","d83eddd4d83cdffe","d83eddd4d83cdfff"],["d83eddd4200d2642fe0f","d83eddd4d83cdffb200d2642fe0f","d83eddd4d83cdffc200d2642fe0f","d83eddd4d83cdffd200d2642fe0f","d83eddd4d83cdffe200d2642fe0f","d83eddd4d83cdfff200d2642fe0f"],["d83eddd4200d2640fe0f","d83eddd4d83cdffb200d2640fe0f","d83eddd4d83cdffc200d2640fe0f","d83eddd4d83cdffd200d2640fe0f","d83eddd4d83cdffe200d2640fe0f","d83eddd4d83cdfff200d2640fe0f"],["d83ddc68200dd83eddb0","d83ddc68d83cdffb200dd83eddb0","d83ddc68d83cdffc200dd83eddb0","d83ddc68d83cdffd200dd83eddb0","d83ddc68d83cdffe200dd83eddb0","d83ddc68d83cdfff200dd83eddb0"],["d83ddc68200dd83eddb1","d83ddc68d83cdffb200dd83eddb1","d83ddc68d83cdffc200dd83eddb1","d83ddc68d83cdffd200dd83eddb1","d83ddc68d83cdffe200dd83eddb1","d83ddc68d83cdfff200dd83eddb1"],["d83ddc68200dd83eddb3","d83ddc68d83cdffb200dd83eddb3","d83ddc68d83cdffc200dd83eddb3","d83ddc68d83cdffd200dd83eddb3","d83ddc68d83cdffe200dd83eddb3","d83ddc68d83cdfff200dd83eddb3"],["d83ddc68200dd83eddb2","d83ddc68d83cdffb200dd83eddb2","d83ddc68d83cdffc200dd83eddb2","d83ddc68d83cdffd200dd83eddb2","d83ddc68d83cdffe200dd83eddb2","d83ddc68d83cdfff200dd83eddb2"],["d83ddc69","d83ddc69d83cdffb","d83ddc69d83cdffc","d83ddc69d83cdffd","d83ddc69d83cdffe","d83ddc69d83cdfff"],["d83ddc69200dd83eddb0","d83ddc69d83cdffb200dd83eddb0","d83ddc69d83cdffc200dd83eddb0","d83ddc69d83cdffd200dd83eddb0","d83ddc69d83cdffe200dd83eddb0","d83ddc69d83cdfff200dd83eddb0"],["d83eddd1200dd83eddb0","d83eddd1d83cdffb200dd83eddb0","d83eddd1d83cdffc200dd83eddb0","d83eddd1d83cdffd200dd83eddb0","d83eddd1d83cdffe200dd83eddb0","d83eddd1d83cdfff200dd83eddb0"],["d83ddc69200dd83eddb1","d83ddc69d83cdffb200dd83eddb1","d83ddc69d83cdffc200dd83eddb1","d83ddc69d83cdffd200dd83eddb1","d83ddc69d83cdffe200dd83eddb1","d83ddc69d83cdfff200dd83eddb1"],["d83eddd1200dd83eddb1","d83eddd1d83cdffb200dd83eddb1","d83eddd1d83cdffc200dd83eddb1","d83eddd1d83cdffd200dd83eddb1","d83eddd1d83cdffe200dd83eddb1","d83eddd1d83cdfff200dd83eddb1"],["d83ddc69200dd83eddb3","d83ddc69d83cdffb200dd83eddb3","d83ddc69d83cdffc200dd83eddb3","d83ddc69d83cdffd200dd83eddb3","d83ddc69d83cdffe200dd83eddb3","d83ddc69d83cdfff200dd83eddb3"],["d83eddd1200dd83eddb3","d83eddd1d83cdffb200dd83eddb3","d83eddd1d83cdffc200dd83eddb3","d83eddd1d83cdffd200dd83eddb3","d83eddd1d83cdffe200dd83eddb3","d83eddd1d83cdfff200dd83eddb3"],["d83ddc69200dd83eddb2","d83ddc69d83cdffb200dd83eddb2","d83ddc69d83cdffc200dd83eddb2","d83ddc69d83cdffd200dd83eddb2","d83ddc69d83cdffe200dd83eddb2","d83ddc69d83cdfff200dd83eddb2"],["d83eddd1200dd83eddb2","d83eddd1d83cdffb200dd83eddb2","d83eddd1d83cdffc200dd83eddb2","d83eddd1d83cdffd200dd83eddb2","d83eddd1d83cdffe200dd83eddb2","d83eddd1d83cdfff200dd83eddb2"],["d83ddc71200d2640fe0f","d83ddc71d83cdffb200d2640fe0f","d83ddc71d83cdffc200d2640fe0f","d83ddc71d83cdffd200d2640fe0f","d83ddc71d83cdffe200d2640fe0f","d83ddc71d83cdfff200d2640fe0f"],["d83ddc71200d2642fe0f","d83ddc71d83cdffb200d2642fe0f","d83ddc71d83cdffc200d2642fe0f","d83ddc71d83cdffd200d2642fe0f","d83ddc71d83cdffe200d2642fe0f","d83ddc71d83cdfff200d2642fe0f"],["d83eddd3","d83eddd3d83cdffb","d83eddd3d83cdffc","d83eddd3d83cdffd","d83eddd3d83cdffe","d83eddd3d83cdfff"],["d83ddc74","d83ddc74d83cdffb","d83ddc74d83cdffc","d83ddc74d83cdffd","d83ddc74d83cdffe","d83ddc74d83cdfff"],["d83ddc75","d83ddc75d83cdffb","d83ddc75d83cdffc","d83ddc75d83cdffd","d83ddc75d83cdffe","d83ddc75d83cdfff"],["d83dde4d","d83dde4dd83cdffb","d83dde4dd83cdffc","d83dde4dd83cdffd","d83dde4dd83cdffe","d83dde4dd83cdfff"],["d83dde4d200d2642fe0f","d83dde4dd83cdffb200d2642fe0f","d83dde4dd83cdffc200d2642fe0f","d83dde4dd83cdffd200d2642fe0f","d83dde4dd83cdffe200d2642fe0f","d83dde4dd83cdfff200d2642fe0f"],["d83dde4d200d2640fe0f","d83dde4dd83cdffb200d2640fe0f","d83dde4dd83cdffc200d2640fe0f","d83dde4dd83cdffd200d2640fe0f","d83dde4dd83cdffe200d2640fe0f","d83dde4dd83cdfff200d2640fe0f"],["d83dde4e","d83dde4ed83cdffb","d83dde4ed83cdffc","d83dde4ed83cdffd","d83dde4ed83cdffe","d83dde4ed83cdfff"],["d83dde4e200d2642fe0f","d83dde4ed83cdffb200d2642fe0f","d83dde4ed83cdffc200d2642fe0f","d83dde4ed83cdffd200d2642fe0f","d83dde4ed83cdffe200d2642fe0f","d83dde4ed83cdfff200d2642fe0f"],["d83dde4e200d2640fe0f","d83dde4ed83cdffb200d2640fe0f","d83dde4ed83cdffc200d2640fe0f","d83dde4ed83cdffd200d2640fe0f","d83dde4ed83cdffe200d2640fe0f","d83dde4ed83cdfff200d2640fe0f"],["d83dde45","d83dde45d83cdffb","d83dde45d83cdffc","d83dde45d83cdffd","d83dde45d83cdffe","d83dde45d83cdfff"],["d83dde45200d2642fe0f","d83dde45d83cdffb200d2642fe0f","d83dde45d83cdffc200d2642fe0f","d83dde45d83cdffd200d2642fe0f","d83dde45d83cdffe200d2642fe0f","d83dde45d83cdfff200d2642fe0f"],["d83dde45200d2640fe0f","d83dde45d83cdffb200d2640fe0f","d83dde45d83cdffc200d2640fe0f","d83dde45d83cdffd200d2640fe0f","d83dde45d83cdffe200d2640fe0f","d83dde45d83cdfff200d2640fe0f"],["d83dde46","d83dde46d83cdffb","d83dde46d83cdffc","d83dde46d83cdffd","d83dde46d83cdffe","d83dde46d83cdfff"],["d83dde46200d2642fe0f","d83dde46d83cdffb200d2642fe0f","d83dde46d83cdffc200d2642fe0f","d83dde46d83cdffd200d2642fe0f","d83dde46d83cdffe200d2642fe0f","d83dde46d83cdfff200d2642fe0f"],["d83dde46200d2640fe0f","d83dde46d83cdffb200d2640fe0f","d83dde46d83cdffc200d2640fe0f","d83dde46d83cdffd200d2640fe0f","d83dde46d83cdffe200d2640fe0f","d83dde46d83cdfff200d2640fe0f"],["d83ddc81","d83ddc81d83cdffb","d83ddc81d83cdffc","d83ddc81d83cdffd","d83ddc81d83cdffe","d83ddc81d83cdfff"],["d83ddc81200d2642fe0f","d83ddc81d83cdffb200d2642fe0f","d83ddc81d83cdffc200d2642fe0f","d83ddc81d83cdffd200d2642fe0f","d83ddc81d83cdffe200d2642fe0f","d83ddc81d83cdfff200d2642fe0f"],["d83ddc81200d2640fe0f","d83ddc81d83cdffb200d2640fe0f","d83ddc81d83cdffc200d2640fe0f","d83ddc81d83cdffd200d2640fe0f","d83ddc81d83cdffe200d2640fe0f","d83ddc81d83cdfff200d2640fe0f"],["d83dde4b","d83dde4bd83cdffb","d83dde4bd83cdffc","d83dde4bd83cdffd","d83dde4bd83cdffe","d83dde4bd83cdfff"],["d83dde4b200d2642fe0f","d83dde4bd83cdffb200d2642fe0f","d83dde4bd83cdffc200d2642fe0f","d83dde4bd83cdffd200d2642fe0f","d83dde4bd83cdffe200d2642fe0f","d83dde4bd83cdfff200d2642fe0f"]],"People_3":[["d83dde4b200d2640fe0f","d83dde4bd83cdffb200d2640fe0f","d83dde4bd83cdffc200d2640fe0f","d83dde4bd83cdffd200d2640fe0f","d83dde4bd83cdffe200d2640fe0f","d83dde4bd83cdfff200d2640fe0f"],["d83eddcf","d83eddcfd83cdffb","d83eddcfd83cdffc","d83eddcfd83cdffd","d83eddcfd83cdffe","d83eddcfd83cdfff"],["d83eddcf200d2642fe0f","d83eddcfd83cdffb200d2642fe0f","d83eddcfd83cdffc200d2642fe0f","d83eddcfd83cdffd200d2642fe0f","d83eddcfd83cdffe200d2642fe0f","d83eddcfd83cdfff200d2642fe0f"],["d83eddcf200d2640fe0f","d83eddcfd83cdffb200d2640fe0f","d83eddcfd83cdffc200d2640fe0f","d83eddcfd83cdffd200d2640fe0f","d83eddcfd83cdffe200d2640fe0f","d83eddcfd83cdfff200d2640fe0f"],["d83dde47","d83dde47d83cdffb","d83dde47d83cdffc","d83dde47d83cdffd","d83dde47d83cdffe","d83dde47d83cdfff"],["d83dde47200d2642fe0f","d83dde47d83cdffb200d2642fe0f","d83dde47d83cdffc200d2642fe0f","d83dde47d83cdffd200d2642fe0f","d83dde47d83cdffe200d2642fe0f","d83dde47d83cdfff200d2642fe0f"],["d83dde47200d2640fe0f","d83dde47d83cdffb200d2640fe0f","d83dde47d83cdffc200d2640fe0f","d83dde47d83cdffd200d2640fe0f","d83dde47d83cdffe200d2640fe0f","d83dde47d83cdfff200d2640fe0f"],["d83edd26","d83edd26d83cdffb","d83edd26d83cdffc","d83edd26d83cdffd","d83edd26d83cdffe","d83edd26d83cdfff"],["d83edd26200d2642fe0f","d83edd26d83cdffb200d2642fe0f","d83edd26d83cdffc200d2642fe0f","d83edd26d83cdffd200d2642fe0f","d83edd26d83cdffe200d2642fe0f","d83edd26d83cdfff200d2642fe0f"],["d83edd26200d2640fe0f","d83edd26d83cdffb200d2640fe0f","d83edd26d83cdffc200d2640fe0f","d83edd26d83cdffd200d2640fe0f","d83edd26d83cdffe200d2640fe0f","d83edd26d83cdfff200d2640fe0f"],["d83edd37","d83edd37d83cdffb","d83edd37d83cdffc","d83edd37d83cdffd","d83edd37d83cdffe","d83edd37d83cdfff"],["d83edd37200d2642fe0f","d83edd37d83cdffb200d2642fe0f","d83edd37d83cdffc200d2642fe0f","d83edd37d83cdffd200d2642fe0f","d83edd37d83cdffe200d2642fe0f","d83edd37d83cdfff200d2642fe0f"],["d83edd37200d2640fe0f","d83edd37d83cdffb200d2640fe0f","d83edd37d83cdffc200d2640fe0f","d83edd37d83cdffd200d2640fe0f","d83edd37d83cdffe200d2640fe0f","d83edd37d83cdfff200d2640fe0f"],["d83eddd1200d2695fe0f","d83eddd1d83cdffb200d2695fe0f","d83eddd1d83cdffc200d2695fe0f","d83eddd1d83cdffd200d2695fe0f","d83eddd1d83cdffe200d2695fe0f","d83eddd1d83cdfff200d2695fe0f"],["d83ddc68200d2695fe0f","d83ddc68d83cdffb200d2695fe0f","d83ddc68d83cdffc200d2695fe0f","d83ddc68d83cdffd200d2695fe0f","d83ddc68d83cdffe200d2695fe0f","d83ddc68d83cdfff200d2695fe0f"],["d83ddc69200d2695fe0f","d83ddc69d83cdffb200d2695fe0f","d83ddc69d83cdffc200d2695fe0f","d83ddc69d83cdffd200d2695fe0f","d83ddc69d83cdffe200d2695fe0f","d83ddc69d83cdfff200d2695fe0f"],["d83eddd1200dd83cdf93","d83eddd1d83cdffb200dd83cdf93","d83eddd1d83cdffc200dd83cdf93","d83eddd1d83cdffd200dd83cdf93","d83eddd1d83cdffe200dd83cdf93","d83eddd1d83cdfff200dd83cdf93"],["d83ddc68200dd83cdf93","d83ddc68d83cdffb200dd83cdf93","d83ddc68d83cdffc200dd83cdf93","d83ddc68d83cdffd200dd83cdf93","d83ddc68d83cdffe200dd83cdf93","d83ddc68d83cdfff200dd83cdf93"],["d83ddc69200dd83cdf93","d83ddc69d83cdffb200dd83cdf93","d83ddc69d83cdffc200dd83cdf93","d83ddc69d83cdffd200dd83cdf93","d83ddc69d83cdffe200dd83cdf93","d83ddc69d83cdfff200dd83cdf93"],["d83eddd1200dd83cdfeb","d83eddd1d83cdffb200dd83cdfeb","d83eddd1d83cdffc200dd83cdfeb","d83eddd1d83cdffd200dd83cdfeb","d83eddd1d83cdffe200dd83cdfeb","d83eddd1d83cdfff200dd83cdfeb"],["d83ddc68200dd83cdfeb","d83ddc68d83cdffb200dd83cdfeb","d83ddc68d83cdffc200dd83cdfeb","d83ddc68d83cdffd200dd83cdfeb","d83ddc68d83cdffe200dd83cdfeb","d83ddc68d83cdfff200dd83cdfeb"],["d83ddc69200dd83cdfeb","d83ddc69d83cdffb200dd83cdfeb","d83ddc69d83cdffc200dd83cdfeb","d83ddc69d83cdffd200dd83cdfeb","d83ddc69d83cdffe200dd83cdfeb","d83ddc69d83cdfff200dd83cdfeb"],["d83eddd1200d2696fe0f","d83eddd1d83cdffb200d2696fe0f","d83eddd1d83cdffc200d2696fe0f","d83eddd1d83cdffd200d2696fe0f","d83eddd1d83cdffe200d2696fe0f","d83eddd1d83cdfff200d2696fe0f"],["d83ddc68200d2696fe0f","d83ddc68d83cdffb200d2696fe0f","d83ddc68d83cdffc200d2696fe0f","d83ddc68d83cdffd200d2696fe0f","d83ddc68d83cdffe200d2696fe0f","d83ddc68d83cdfff200d2696fe0f"],["d83ddc69200d2696fe0f","d83ddc69d83cdffb200d2696fe0f","d83ddc69d83cdffc200d2696fe0f","d83ddc69d83cdffd200d2696fe0f","d83ddc69d83cdffe200d2696fe0f","d83ddc69d83cdfff200d2696fe0f"],["d83eddd1200dd83cdf3e","d83eddd1d83cdffb200dd83cdf3e","d83eddd1d83cdffc200dd83cdf3e","d83eddd1d83cdffd200dd83cdf3e","d83eddd1d83cdffe200dd83cdf3e","d83eddd1d83cdfff200dd83cdf3e"],["d83ddc68200dd83cdf3e","d83ddc68d83cdffb200dd83cdf3e","d83ddc68d83cdffc200dd83cdf3e","d83ddc68d83cdffd200dd83cdf3e","d83ddc68d83cdffe200dd83cdf3e","d83ddc68d83cdfff200dd83cdf3e"],["d83ddc69200dd83cdf3e","d83ddc69d83cdffb200dd83cdf3e","d83ddc69d83cdffc200dd83cdf3e","d83ddc69d83cdffd200dd83cdf3e","d83ddc69d83cdffe200dd83cdf3e","d83ddc69d83cdfff200dd83cdf3e"],["d83eddd1200dd83cdf73","d83eddd1d83cdffb200dd83cdf73","d83eddd1d83cdffc200dd83cdf73","d83eddd1d83cdffd200dd83cdf73","d83eddd1d83cdffe200dd83cdf73","d83eddd1d83cdfff200dd83cdf73"],["d83ddc68200dd83cdf73","d83ddc68d83cdffb200dd83cdf73","d83ddc68d83cdffc200dd83cdf73","d83ddc68d83cdffd200dd83cdf73","d83ddc68d83cdffe200dd83cdf73","d83ddc68d83cdfff200dd83cdf73"],["d83ddc69200dd83cdf73","d83ddc69d83cdffb200dd83cdf73","d83ddc69d83cdffc200dd83cdf73","d83ddc69d83cdffd200dd83cdf73","d83ddc69d83cdffe200dd83cdf73","d83ddc69d83cdfff200dd83cdf73"],["d83eddd1200dd83ddd27","d83eddd1d83cdffb200dd83ddd27","d83eddd1d83cdffc200dd83ddd27","d83eddd1d83cdffd200dd83ddd27","d83eddd1d83cdffe200dd83ddd27","d83eddd1d83cdfff200dd83ddd27"],["d83ddc68200dd83ddd27","d83ddc68d83cdffb200dd83ddd27","d83ddc68d83cdffc200dd83ddd27","d83ddc68d83cdffd200dd83ddd27","d83ddc68d83cdffe200dd83ddd27","d83ddc68d83cdfff200dd83ddd27"],["d83ddc69200dd83ddd27","d83ddc69d83cdffb200dd83ddd27","d83ddc69d83cdffc200dd83ddd27","d83ddc69d83cdffd200dd83ddd27","d83ddc69d83cdffe200dd83ddd27","d83ddc69d83cdfff200dd83ddd27"],["d83eddd1200dd83cdfed","d83eddd1d83cdffb200dd83cdfed","d83eddd1d83cdffc200dd83cdfed","d83eddd1d83cdffd200dd83cdfed","d83eddd1d83cdffe200dd83cdfed","d83eddd1d83cdfff200dd83cdfed"],["d83ddc68200dd83cdfed","d83ddc68d83cdffb200dd83cdfed","d83ddc68d83cdffc200dd83cdfed","d83ddc68d83cdffd200dd83cdfed","d83ddc68d83cdffe200dd83cdfed","d83ddc68d83cdfff200dd83cdfed"],["d83ddc69200dd83cdfed","d83ddc69d83cdffb200dd83cdfed","d83ddc69d83cdffc200dd83cdfed","d83ddc69d83cdffd200dd83cdfed","d83ddc69d83cdffe200dd83cdfed","d83ddc69d83cdfff200dd83cdfed"],["d83eddd1200dd83ddcbc","d83eddd1d83cdffb200dd83ddcbc","d83eddd1d83cdffc200dd83ddcbc","d83eddd1d83cdffd200dd83ddcbc","d83eddd1d83cdffe200dd83ddcbc","d83eddd1d83cdfff200dd83ddcbc"],["d83ddc68200dd83ddcbc","d83ddc68d83cdffb200dd83ddcbc","d83ddc68d83cdffc200dd83ddcbc","d83ddc68d83cdffd200dd83ddcbc","d83ddc68d83cdffe200dd83ddcbc","d83ddc68d83cdfff200dd83ddcbc"],["d83ddc69200dd83ddcbc","d83ddc69d83cdffb200dd83ddcbc","d83ddc69d83cdffc200dd83ddcbc","d83ddc69d83cdffd200dd83ddcbc","d83ddc69d83cdffe200dd83ddcbc","d83ddc69d83cdfff200dd83ddcbc"],["d83eddd1200dd83ddd2c","d83eddd1d83cdffb200dd83ddd2c","d83eddd1d83cdffc200dd83ddd2c","d83eddd1d83cdffd200dd83ddd2c","d83eddd1d83cdffe200dd83ddd2c","d83eddd1d83cdfff200dd83ddd2c"],["d83ddc68200dd83ddd2c","d83ddc68d83cdffb200dd83ddd2c","d83ddc68d83cdffc200dd83ddd2c","d83ddc68d83cdffd200dd83ddd2c","d83ddc68d83cdffe200dd83ddd2c","d83ddc68d83cdfff200dd83ddd2c"]],"People_4":[["d83ddc69200dd83ddd2c","d83ddc69d83cdffb200dd83ddd2c","d83ddc69d83cdffc200dd83ddd2c","d83ddc69d83cdffd200dd83ddd2c","d83ddc69d83cdffe200dd83ddd2c","d83ddc69d83cdfff200dd83ddd2c"],["d83eddd1200dd83ddcbb","d83eddd1d83cdffb200dd83ddcbb","d83eddd1d83cdffc200dd83ddcbb","d83eddd1d83cdffd200dd83ddcbb","d83eddd1d83cdffe200dd83ddcbb","d83eddd1d83cdfff200dd83ddcbb"],["d83ddc68200dd83ddcbb","d83ddc68d83cdffb200dd83ddcbb","d83ddc68d83cdffc200dd83ddcbb","d83ddc68d83cdffd200dd83ddcbb","d83ddc68d83cdffe200dd83ddcbb","d83ddc68d83cdfff200dd83ddcbb"],["d83ddc69200dd83ddcbb","d83ddc69d83cdffb200dd83ddcbb","d83ddc69d83cdffc200dd83ddcbb","d83ddc69d83cdffd200dd83ddcbb","d83ddc69d83cdffe200dd83ddcbb","d83ddc69d83cdfff200dd83ddcbb"],["d83eddd1200dd83cdfa4","d83eddd1d83cdffb200dd83cdfa4","d83eddd1d83cdffc200dd83cdfa4","d83eddd1d83cdffd200dd83cdfa4","d83eddd1d83cdffe200dd83cdfa4","d83eddd1d83cdfff200dd83cdfa4"],["d83ddc68200dd83cdfa4","d83ddc68d83cdffb200dd83cdfa4","d83ddc68d83cdffc200dd83cdfa4","d83ddc68d83cdffd200dd83cdfa4","d83ddc68d83cdffe200dd83cdfa4","d83ddc68d83cdfff200dd83cdfa4"],["d83ddc69200dd83cdfa4","d83ddc69d83cdffb200dd83cdfa4","d83ddc69d83cdffc200dd83cdfa4","d83ddc69d83cdffd200dd83cdfa4","d83ddc69d83cdffe200dd83cdfa4","d83ddc69d83cdfff200dd83cdfa4"],["d83eddd1200dd83cdfa8","d83eddd1d83cdffb200dd83cdfa8","d83eddd1d83cdffc200dd83cdfa8","d83eddd1d83cdffd200dd83cdfa8","d83eddd1d83cdffe200dd83cdfa8","d83eddd1d83cdfff200dd83cdfa8"],["d83ddc68200dd83cdfa8","d83ddc68d83cdffb200dd83cdfa8","d83ddc68d83cdffc200dd83cdfa8","d83ddc68d83cdffd200dd83cdfa8","d83ddc68d83cdffe200dd83cdfa8","d83ddc68d83cdfff200dd83cdfa8"],["d83ddc69200dd83cdfa8","d83ddc69d83cdffb200dd83cdfa8","d83ddc69d83cdffc200dd83cdfa8","d83ddc69d83cdffd200dd83cdfa8","d83ddc69d83cdffe200dd83cdfa8","d83ddc69d83cdfff200dd83cdfa8"],["d83eddd1200d2708fe0f","d83eddd1d83cdffb200d2708fe0f","d83eddd1d83cdffc200d2708fe0f","d83eddd1d83cdffd200d2708fe0f","d83eddd1d83cdffe200d2708fe0f","d83eddd1d83cdfff200d2708fe0f"],["d83ddc68200d2708fe0f","d83ddc68d83cdffb200d2708fe0f","d83ddc68d83cdffc200d2708fe0f","d83ddc68d83cdffd200d2708fe0f","d83ddc68d83cdffe200d2708fe0f","d83ddc68d83cdfff200d2708fe0f"],["d83ddc69200d2708fe0f","d83ddc69d83cdffb200d2708fe0f","d83ddc69d83cdffc200d2708fe0f","d83ddc69d83cdffd200d2708fe0f","d83ddc69d83cdffe200d2708fe0f","d83ddc69d83cdfff200d2708fe0f"],["d83eddd1200dd83dde80","d83eddd1d83cdffb200dd83dde80","d83eddd1d83cdffc200dd83dde80","d83eddd1d83cdffd200dd83dde80","d83eddd1d83cdffe200dd83dde80","d83eddd1d83cdfff200dd83dde80"],["d83ddc68200dd83dde80","d83ddc68d83cdffb200dd83dde80","d83ddc68d83cdffc200dd83dde80","d83ddc68d83cdffd200dd83dde80","d83ddc68d83cdffe200dd83dde80","d83ddc68d83cdfff200dd83dde80"],["d83ddc69200dd83dde80","d83ddc69d83cdffb200dd83dde80","d83ddc69d83cdffc200dd83dde80","d83ddc69d83cdffd200dd83dde80","d83ddc69d83cdffe200dd83dde80","d83ddc69d83cdfff200dd83dde80"],["d83eddd1200dd83dde92","d83eddd1d83cdffb200dd83dde92","d83eddd1d83cdffc200dd83dde92","d83eddd1d83cdffd200dd83dde92","d83eddd1d83cdffe200dd83dde92","d83eddd1d83cdfff200dd83dde92"],["d83ddc68200dd83dde92","d83ddc68d83cdffb200dd83dde92","d83ddc68d83cdffc200dd83dde92","d83ddc68d83cdffd200dd83dde92","d83ddc68d83cdffe200dd83dde92","d83ddc68d83cdfff200dd83dde92"],["d83ddc69200dd83dde92","d83ddc69d83cdffb200dd83dde92","d83ddc69d83cdffc200dd83dde92","d83ddc69d83cdffd200dd83dde92","d83ddc69d83cdffe200dd83dde92","d83ddc69d83cdfff200dd83dde92"],["d83ddc6e","d83ddc6ed83cdffb","d83ddc6ed83cdffc","d83ddc6ed83cdffd","d83ddc6ed83cdffe","d83ddc6ed83cdfff"],["d83ddc6e200d2642fe0f","d83ddc6ed83cdffb200d2642fe0f","d83ddc6ed83cdffc200d2642fe0f","d83ddc6ed83cdffd200d2642fe0f","d83ddc6ed83cdffe200d2642fe0f","d83ddc6ed83cdfff200d2642fe0f"],["d83ddc6e200d2640fe0f","d83ddc6ed83cdffb200d2640fe0f","d83ddc6ed83cdffc200d2640fe0f","d83ddc6ed83cdffd200d2640fe0f","d83ddc6ed83cdffe200d2640fe0f","d83ddc6ed83cdfff200d2640fe0f"],["d83ddd75fe0f","d83ddd75d83cdffb","d83ddd75d83cdffc","d83ddd75d83cdffd","d83ddd75d83cdffe","d83ddd75d83cdfff"],["d83ddd75fe0f200d2642fe0f","d83ddd75d83cdffb200d2642fe0f","d83ddd75d83cdffc200d2642fe0f","d83ddd75d83cdffd200d2642fe0f","d83ddd75d83cdffe200d2642fe0f","d83ddd75d83cdfff200d2642fe0f"],["d83ddd75fe0f200d2640fe0f","d83ddd75d83cdffb200d2640fe0f","d83ddd75d83cdffc200d2640fe0f","d83ddd75d83cdffd200d2640fe0f","d83ddd75d83cdffe200d2640fe0f","d83ddd75d83cdfff200d2640fe0f"],["d83ddc82","d83ddc82d83cdffb","d83ddc82d83cdffc","d83ddc82d83cdffd","d83ddc82d83cdffe","d83ddc82d83cdfff"],["d83ddc82200d2642fe0f","d83ddc82d83cdffb200d2642fe0f","d83ddc82d83cdffc200d2642fe0f","d83ddc82d83cdffd200d2642fe0f","d83ddc82d83cdffe200d2642fe0f","d83ddc82d83cdfff200d2642fe0f"],["d83ddc82200d2640fe0f","d83ddc82d83cdffb200d2640fe0f","d83ddc82d83cdffc200d2640fe0f","d83ddc82d83cdffd200d2640fe0f","d83ddc82d83cdffe200d2640fe0f","d83ddc82d83cdfff200d2640fe0f"],["d83edd77","d83edd77d83cdffb","d83edd77d83cdffc","d83edd77d83cdffd","d83edd77d83cdffe","d83edd77d83cdfff"],["d83ddc77","d83ddc77d83cdffb","d83ddc77d83cdffc","d83ddc77d83cdffd","d83ddc77d83cdffe","d83ddc77d83cdfff"],["d83ddc77200d2642fe0f","d83ddc77d83cdffb200d2642fe0f","d83ddc77d83cdffc200d2642fe0f","d83ddc77d83cdffd200d2642fe0f","d83ddc77d83cdffe200d2642fe0f","d83ddc77d83cdfff200d2642fe0f"],["d83ddc77200d2640fe0f","d83ddc77d83cdffb200d2640fe0f","d83ddc77d83cdffc200d2640fe0f","d83ddc77d83cdffd200d2640fe0f","d83ddc77d83cdffe200d2640fe0f","d83ddc77d83cdfff200d2640fe0f"],["d83edec5","d83edec5d83cdffb","d83edec5d83cdffc","d83edec5d83cdffd","d83edec5d83cdffe","d83edec5d83cdfff"],["d83edd34","d83edd34d83cdffb","d83edd34d83cdffc","d83edd34d83cdffd","d83edd34d83cdffe","d83edd34d83cdfff"],["d83ddc78","d83ddc78d83cdffb","d83ddc78d83cdffc","d83ddc78d83cdffd","d83ddc78d83cdffe","d83ddc78d83cdfff"],["d83ddc73","d83ddc73d83cdffb","d83ddc73d83cdffc","d83ddc73d83cdffd","d83ddc73d83cdffe","d83ddc73d83cdfff"],["d83ddc73200d2642fe0f","d83ddc73d83cdffb200d2642fe0f","d83ddc73d83cdffc200d2642fe0f","d83ddc73d83cdffd200d2642fe0f","d83ddc73d83cdffe200d2642fe0f","d83ddc73d83cdfff200d2642fe0f"],["d83ddc73200d2640fe0f","d83ddc73d83cdffb200d2640fe0f","d83ddc73d83cdffc200d2640fe0f","d83ddc73d83cdffd200d2640fe0f","d83ddc73d83cdffe200d2640fe0f","d83ddc73d83cdfff200d2640fe0f"],["d83ddc72","d83ddc72d83cdffb","d83ddc72d83cdffc","d83ddc72d83cdffd","d83ddc72d83cdffe","d83ddc72d83cdfff"],["d83eddd5","d83eddd5d83cdffb","d83eddd5d83cdffc","d83eddd5d83cdffd","d83eddd5d83cdffe","d83eddd5d83cdfff"],["d83edd35","d83edd35d83cdffb","d83edd35d83cdffc","d83edd35d83cdffd","d83edd35d83cdffe","d83edd35d83cdfff"],["d83edd35200d2642fe0f","d83edd35d83cdffb200d2642fe0f","d83edd35d83cdffc200d2642fe0f","d83edd35d83cdffd200d2642fe0f","d83edd35d83cdffe200d2642fe0f","d83edd35d83cdfff200d2642fe0f"]],"People_5":[["d83edd35200d2640fe0f","d83edd35d83cdffb200d2640fe0f","d83edd35d83cdffc200d2640fe0f","d83edd35d83cdffd200d2640fe0f","d83edd35d83cdffe200d2640fe0f","d83edd35d83cdfff200d2640fe0f"],["d83ddc70","d83ddc70d83cdffb","d83ddc70d83cdffc","d83ddc70d83cdffd","d83ddc70d83cdffe","d83ddc70d83cdfff"],["d83ddc70200d2642fe0f","d83ddc70d83cdffb200d2642fe0f","d83ddc70d83cdffc200d2642fe0f","d83ddc70d83cdffd200d2642fe0f","d83ddc70d83cdffe200d2642fe0f","d83ddc70d83cdfff200d2642fe0f"],["d83ddc70200d2640fe0f","d83ddc70d83cdffb200d2640fe0f","d83ddc70d83cdffc200d2640fe0f","d83ddc70d83cdffd200d2640fe0f","d83ddc70d83cdffe200d2640fe0f","d83ddc70d83cdfff200d2640fe0f"],["d83edd30","d83edd30d83cdffb","d83edd30d83cdffc","d83edd30d83cdffd","d83edd30d83cdffe","d83edd30d83cdfff"],["d83edec3","d83edec3d83cdffb","d83edec3d83cdffc","d83edec3d83cdffd","d83edec3d83cdffe","d83edec3d83cdfff"],["d83edec4","d83edec4d83cdffb","d83edec4d83cdffc","d83edec4d83cdffd","d83edec4d83cdffe","d83edec4d83cdfff"],["d83edd31","d83edd31d83cdffb","d83edd31d83cdffc","d83edd31d83cdffd","d83edd31d83cdffe","d83edd31d83cdfff"],["d83ddc69200dd83cdf7c","d83ddc69d83cdffb200dd83cdf7c","d83ddc69d83cdffc200dd83cdf7c","d83ddc69d83cdffd200dd83cdf7c","d83ddc69d83cdffe200dd83cdf7c","d83ddc69d83cdfff200dd83cdf7c"],["d83ddc68200dd83cdf7c","d83ddc68d83cdffb200dd83cdf7c","d83ddc68d83cdffc200dd83cdf7c","d83ddc68d83cdffd200dd83cdf7c","d83ddc68d83cdffe200dd83cdf7c","d83ddc68d83cdfff200dd83cdf7c"],["d83eddd1200dd83cdf7c","d83eddd1d83cdffb200dd83cdf7c","d83eddd1d83cdffc200dd83cdf7c","d83eddd1d83cdffd200dd83cdf7c","d83eddd1d83cdffe200dd83cdf7c","d83eddd1d83cdfff200dd83cdf7c"],["d83ddc7c","d83ddc7cd83cdffb","d83ddc7cd83cdffc","d83ddc7cd83cdffd","d83ddc7cd83cdffe","d83ddc7cd83cdfff"],["d83cdf85","d83cdf85d83cdffb","d83cdf85d83cdffc","d83cdf85d83cdffd","d83cdf85d83cdffe","d83cdf85d83cdfff"],["d83edd36","d83edd36d83cdffb","d83edd36d83cdffc","d83edd36d83cdffd","d83edd36d83cdffe","d83edd36d83cdfff"],["d83eddd1200dd83cdf84","d83eddd1d83cdffb200dd83cdf84","d83eddd1d83cdffc200dd83cdf84","d83eddd1d83cdffd200dd83cdf84","d83eddd1d83cdffe200dd83cdf84","d83eddd1d83cdfff200dd83cdf84"],["d83eddb8","d83eddb8d83cdffb","d83eddb8d83cdffc","d83eddb8d83cdffd","d83eddb8d83cdffe","d83eddb8d83cdfff"],["d83eddb8200d2642fe0f","d83eddb8d83cdffb200d2642fe0f","d83eddb8d83cdffc200d2642fe0f","d83eddb8d83cdffd200d2642fe0f","d83eddb8d83cdffe200d2642fe0f","d83eddb8d83cdfff200d2642fe0f"],["d83eddb8200d2640fe0f","d83eddb8d83cdffb200d2640fe0f","d83eddb8d83cdffc200d2640fe0f","d83eddb8d83cdffd200d2640fe0f","d83eddb8d83cdffe200d2640fe0f","d83eddb8d83cdfff200d2640fe0f"],["d83eddb9","d83eddb9d83cdffb","d83eddb9d83cdffc","d83eddb9d83cdffd","d83eddb9d83cdffe","d83eddb9d83cdfff"],["d83eddb9200d2642fe0f","d83eddb9d83cdffb200d2642fe0f","d83eddb9d83cdffc200d2642fe0f","d83eddb9d83cdffd200d2642fe0f","d83eddb9d83cdffe200d2642fe0f","d83eddb9d83cdfff200d2642fe0f"],["d83eddb9200d2640fe0f","d83eddb9d83cdffb200d2640fe0f","d83eddb9d83cdffc200d2640fe0f","d83eddb9d83cdffd200d2640fe0f","d83eddb9d83cdffe200d2640fe0f","d83eddb9d83cdfff200d2640fe0f"],["d83eddd9","d83eddd9d83cdffb","d83eddd9d83cdffc","d83eddd9d83cdffd","d83eddd9d83cdffe","d83eddd9d83cdfff"],["d83eddd9200d2642fe0f","d83eddd9d83cdffb200d2642fe0f","d83eddd9d83cdffc200d2642fe0f","d83eddd9d83cdffd200d2642fe0f","d83eddd9d83cdffe200d2642fe0f","d83eddd9d83cdfff200d2642fe0f"],["d83eddd9200d2640fe0f","d83eddd9d83cdffb200d2640fe0f","d83eddd9d83cdffc200d2640fe0f","d83eddd9d83cdffd200d2640fe0f","d83eddd9d83cdffe200d2640fe0f","d83eddd9d83cdfff200d2640fe0f"],["d83eddda","d83edddad83cdffb","d83edddad83cdffc","d83edddad83cdffd","d83edddad83cdffe","d83edddad83cdfff"],["d83eddda200d2642fe0f","d83edddad83cdffb200d2642fe0f","d83edddad83cdffc200d2642fe0f","d83edddad83cdffd200d2642fe0f","d83edddad83cdffe200d2642fe0f","d83edddad83cdfff200d2642fe0f"],["d83eddda200d2640fe0f","d83edddad83cdffb200d2640fe0f","d83edddad83cdffc200d2640fe0f","d83edddad83cdffd200d2640fe0f","d83edddad83cdffe200d2640fe0f","d83edddad83cdfff200d2640fe0f"],["d83edddb","d83edddbd83cdffb","d83edddbd83cdffc","d83edddbd83cdffd","d83edddbd83cdffe","d83edddbd83cdfff"],["d83edddb200d2642fe0f","d83edddbd83cdffb200d2642fe0f","d83edddbd83cdffc200d2642fe0f","d83edddbd83cdffd200d2642fe0f","d83edddbd83cdffe200d2642fe0f","d83edddbd83cdfff200d2642fe0f"],["d83edddb200d2640fe0f","d83edddbd83cdffb200d2640fe0f","d83edddbd83cdffc200d2640fe0f","d83edddbd83cdffd200d2640fe0f","d83edddbd83cdffe200d2640fe0f","d83edddbd83cdfff200d2640fe0f"],["d83edddc","d83edddcd83cdffb","d83edddcd83cdffc","d83edddcd83cdffd","d83edddcd83cdffe","d83edddcd83cdfff"],["d83edddc200d2642fe0f","d83edddcd83cdffb200d2642fe0f","d83edddcd83cdffc200d2642fe0f","d83edddcd83cdffd200d2642fe0f","d83edddcd83cdffe200d2642fe0f","d83edddcd83cdfff200d2642fe0f"],["d83edddc200d2640fe0f","d83edddcd83cdffb200d2640fe0f","d83edddcd83cdffc200d2640fe0f","d83edddcd83cdffd200d2640fe0f","d83edddcd83cdffe200d2640fe0f","d83edddcd83cdfff200d2640fe0f"],["d83edddd","d83eddddd83cdffb","d83eddddd83cdffc","d83eddddd83cdffd","d83eddddd83cdffe","d83eddddd83cdfff"],["d83edddd200d2642fe0f","d83eddddd83cdffb200d2642fe0f","d83eddddd83cdffc200d2642fe0f","d83eddddd83cdffd200d2642fe0f","d83eddddd83cdffe200d2642fe0f","d83eddddd83cdfff200d2642fe0f"],["d83edddd200d2640fe0f","d83eddddd83cdffb200d2640fe0f","d83eddddd83cdffc200d2640fe0f","d83eddddd83cdffd200d2640fe0f","d83eddddd83cdffe200d2640fe0f","d83eddddd83cdfff200d2640fe0f"],["d83eddde"],["d83eddde200d2642fe0f"],["d83eddde200d2640fe0f"],["d83edddf"],["d83edddf200d2642fe0f"],["d83edddf200d2640fe0f"],["d83eddcc"],["d83ddc86","d83ddc86d83cdffb","d83ddc86d83cdffc","d83ddc86d83cdffd","d83ddc86d83cdffe","d83ddc86d83cdfff"],["d83ddc86200d2642fe0f","d83ddc86d83cdffb200d2642fe0f","d83ddc86d83cdffc200d2642fe0f","d83ddc86d83cdffd200d2642fe0f","d83ddc86d83cdffe200d2642fe0f","d83ddc86d83cdfff200d2642fe0f"],["d83ddc86200d2640fe0f","d83ddc86d83cdffb200d2640fe0f","d83ddc86d83cdffc200d2640fe0f","d83ddc86d83cdffd200d2640fe0f","d83ddc86d83cdffe200d2640fe0f","d83ddc86d83cdfff200d2640fe0f"],["d83ddc87","d83ddc87d83cdffb","d83ddc87d83cdffc","d83ddc87d83cdffd","d83ddc87d83cdffe","d83ddc87d83cdfff"],["d83ddc87200d2642fe0f","d83ddc87d83cdffb200d2642fe0f","d83ddc87d83cdffc200d2642fe0f","d83ddc87d83cdffd200d2642fe0f","d83ddc87d83cdffe200d2642fe0f","d83ddc87d83cdfff200d2642fe0f"]],"People_6":[["d83ddc87200d2640fe0f","d83ddc87d83cdffb200d2640fe0f","d83ddc87d83cdffc200d2640fe0f","d83ddc87d83cdffd200d2640fe0f","d83ddc87d83cdffe200d2640fe0f","d83ddc87d83cdfff200d2640fe0f"],["d83ddeb6","d83ddeb6d83cdffb","d83ddeb6d83cdffc","d83ddeb6d83cdffd","d83ddeb6d83cdffe","d83ddeb6d83cdfff"],["d83ddeb6200d2642fe0f","d83ddeb6d83cdffb200d2642fe0f","d83ddeb6d83cdffc200d2642fe0f","d83ddeb6d83cdffd200d2642fe0f","d83ddeb6d83cdffe200d2642fe0f","d83ddeb6d83cdfff200d2642fe0f"],["d83ddeb6200d2640fe0f","d83ddeb6d83cdffb200d2640fe0f","d83ddeb6d83cdffc200d2640fe0f","d83ddeb6d83cdffd200d2640fe0f","d83ddeb6d83cdffe200d2640fe0f","d83ddeb6d83cdfff200d2640fe0f"],["d83eddcd","d83eddcdd83cdffb","d83eddcdd83cdffc","d83eddcdd83cdffd","d83eddcdd83cdffe","d83eddcdd83cdfff"],["d83eddcd200d2642fe0f","d83eddcdd83cdffb200d2642fe0f","d83eddcdd83cdffc200d2642fe0f","d83eddcdd83cdffd200d2642fe0f","d83eddcdd83cdffe200d2642fe0f","d83eddcdd83cdfff200d2642fe0f"],["d83eddcd200d2640fe0f","d83eddcdd83cdffb200d2640fe0f","d83eddcdd83cdffc200d2640fe0f","d83eddcdd83cdffd200d2640fe0f","d83eddcdd83cdffe200d2640fe0f","d83eddcdd83cdfff200d2640fe0f"],["d83eddce","d83eddced83cdffb","d83eddced83cdffc","d83eddced83cdffd","d83eddced83cdffe","d83eddced83cdfff"],["d83eddce200d2642fe0f","d83eddced83cdffb200d2642fe0f","d83eddced83cdffc200d2642fe0f","d83eddced83cdffd200d2642fe0f","d83eddced83cdffe200d2642fe0f","d83eddced83cdfff200d2642fe0f"],["d83eddce200d2640fe0f","d83eddced83cdffb200d2640fe0f","d83eddced83cdffc200d2640fe0f","d83eddced83cdffd200d2640fe0f","d83eddced83cdffe200d2640fe0f","d83eddced83cdfff200d2640fe0f"],["d83eddd1200dd83eddaf","d83eddd1d83cdffb200dd83eddaf","d83eddd1d83cdffc200dd83eddaf","d83eddd1d83cdffd200dd83eddaf","d83eddd1d83cdffe200dd83eddaf","d83eddd1d83cdfff200dd83eddaf"],["d83ddc68200dd83eddaf","d83ddc68d83cdffb200dd83eddaf","d83ddc68d83cdffc200dd83eddaf","d83ddc68d83cdffd200dd83eddaf","d83ddc68d83cdffe200dd83eddaf","d83ddc68d83cdfff200dd83eddaf"],["d83ddc69200dd83eddaf","d83ddc69d83cdffb200dd83eddaf","d83ddc69d83cdffc200dd83eddaf","d83ddc69d83cdffd200dd83eddaf","d83ddc69d83cdffe200dd83eddaf","d83ddc69d83cdfff200dd83eddaf"],["d83eddd1200dd83eddbc","d83eddd1d83cdffb200dd83eddbc","d83eddd1d83cdffc200dd83eddbc","d83eddd1d83cdffd200dd83eddbc","d83eddd1d83cdffe200dd83eddbc","d83eddd1d83cdfff200dd83eddbc"],["d83ddc68200dd83eddbc","d83ddc68d83cdffb200dd83eddbc","d83ddc68d83cdffc200dd83eddbc","d83ddc68d83cdffd200dd83eddbc","d83ddc68d83cdffe200dd83eddbc","d83ddc68d83cdfff200dd83eddbc"],["d83ddc69200dd83eddbc","d83ddc69d83cdffb200dd83eddbc","d83ddc69d83cdffc200dd83eddbc","d83ddc69d83cdffd200dd83eddbc","d83ddc69d83cdffe200dd83eddbc","d83ddc69d83cdfff200dd83eddbc"],["d83eddd1200dd83eddbd","d83eddd1d83cdffb200dd83eddbd","d83eddd1d83cdffc200dd83eddbd","d83eddd1d83cdffd200dd83eddbd","d83eddd1d83cdffe200dd83eddbd","d83eddd1d83cdfff200dd83eddbd"],["d83ddc68200dd83eddbd","d83ddc68d83cdffb200dd83eddbd","d83ddc68d83cdffc200dd83eddbd","d83ddc68d83cdffd200dd83eddbd","d83ddc68d83cdffe200dd83eddbd","d83ddc68d83cdfff200dd83eddbd"],["d83ddc69200dd83eddbd","d83ddc69d83cdffb200dd83eddbd","d83ddc69d83cdffc200dd83eddbd","d83ddc69d83cdffd200dd83eddbd","d83ddc69d83cdffe200dd83eddbd","d83ddc69d83cdfff200dd83eddbd"],["d83cdfc3","d83cdfc3d83cdffb","d83cdfc3d83cdffc","d83cdfc3d83cdffd","d83cdfc3d83cdffe","d83cdfc3d83cdfff"],["d83cdfc3200d2642fe0f","d83cdfc3d83cdffb200d2642fe0f","d83cdfc3d83cdffc200d2642fe0f","d83cdfc3d83cdffd200d2642fe0f","d83cdfc3d83cdffe200d2642fe0f","d83cdfc3d83cdfff200d2642fe0f"],["d83cdfc3200d2640fe0f","d83cdfc3d83cdffb200d2640fe0f","d83cdfc3d83cdffc200d2640fe0f","d83cdfc3d83cdffd200d2640fe0f","d83cdfc3d83cdffe200d2640fe0f","d83cdfc3d83cdfff200d2640fe0f"],["d83ddc83","d83ddc83d83cdffb","d83ddc83d83cdffc","d83ddc83d83cdffd","d83ddc83d83cdffe","d83ddc83d83cdfff"],["d83ddd7a","d83ddd7ad83cdffb","d83ddd7ad83cdffc","d83ddd7ad83cdffd","d83ddd7ad83cdffe","d83ddd7ad83cdfff"],["d83ddd74fe0f","d83ddd74d83cdffb","d83ddd74d83cdffc","d83ddd74d83cdffd","d83ddd74d83cdffe","d83ddd74d83cdfff"],["d83ddc6f"],["d83ddc6f200d2642fe0f"],["d83ddc6f200d2640fe0f"],["d83eddd6","d83eddd6d83cdffb","d83eddd6d83cdffc","d83eddd6d83cdffd","d83eddd6d83cdffe","d83eddd6d83cdfff"],["d83eddd6200d2642fe0f","d83eddd6d83cdffb200d2642fe0f","d83eddd6d83cdffc200d2642fe0f","d83eddd6d83cdffd200d2642fe0f","d83eddd6d83cdffe200d2642fe0f","d83eddd6d83cdfff200d2642fe0f"],["d83eddd6200d2640fe0f","d83eddd6d83cdffb200d2640fe0f","d83eddd6d83cdffc200d2640fe0f","d83eddd6d83cdffd200d2640fe0f","d83eddd6d83cdffe200d2640fe0f","d83eddd6d83cdfff200d2640fe0f"],["d83eddd7","d83eddd7d83cdffb","d83eddd7d83cdffc","d83eddd7d83cdffd","d83eddd7d83cdffe","d83eddd7d83cdfff"],["d83eddd7200d2642fe0f","d83eddd7d83cdffb200d2642fe0f","d83eddd7d83cdffc200d2642fe0f","d83eddd7d83cdffd200d2642fe0f","d83eddd7d83cdffe200d2642fe0f","d83eddd7d83cdfff200d2642fe0f"],["d83eddd7200d2640fe0f","d83eddd7d83cdffb200d2640fe0f","d83eddd7d83cdffc200d2640fe0f","d83eddd7d83cdffd200d2640fe0f","d83eddd7d83cdffe200d2640fe0f","d83eddd7d83cdfff200d2640fe0f"],["d83edd3a"],["d83cdfc7","d83cdfc7d83cdffb","d83cdfc7d83cdffc","d83cdfc7d83cdffd","d83cdfc7d83cdffe","d83cdfc7d83cdfff"],["26f7fe0f"],["d83cdfc2","d83cdfc2d83cdffb","d83cdfc2d83cdffc","d83cdfc2d83cdffd","d83cdfc2d83cdffe","d83cdfc2d83cdfff"],["d83cdfccfe0f","d83cdfccd83cdffb","d83cdfccd83cdffc","d83cdfccd83cdffd","d83cdfccd83cdffe","d83cdfccd83cdfff"],["d83cdfccfe0f200d2642fe0f","d83cdfccd83cdffb200d2642fe0f","d83cdfccd83cdffc200d2642fe0f","d83cdfccd83cdffd200d2642fe0f","d83cdfccd83cdffe200d2642fe0f","d83cdfccd83cdfff200d2642fe0f"],["d83cdfccfe0f200d2640fe0f","d83cdfccd83cdffb200d2640fe0f","d83cdfccd83cdffc200d2640fe0f","d83cdfccd83cdffd200d2640fe0f","d83cdfccd83cdffe200d2640fe0f","d83cdfccd83cdfff200d2640fe0f"],["d83cdfc4","d83cdfc4d83cdffb","d83cdfc4d83cdffc","d83cdfc4d83cdffd","d83cdfc4d83cdffe","d83cdfc4d83cdfff"],["d83cdfc4200d2642fe0f","d83cdfc4d83cdffb200d2642fe0f","d83cdfc4d83cdffc200d2642fe0f","d83cdfc4d83cdffd200d2642fe0f","d83cdfc4d83cdffe200d2642fe0f","d83cdfc4d83cdfff200d2642fe0f"],["d83cdfc4200d2640fe0f","d83cdfc4d83cdffb200d2640fe0f","d83cdfc4d83cdffc200d2640fe0f","d83cdfc4d83cdffd200d2640fe0f","d83cdfc4d83cdffe200d2640fe0f","d83cdfc4d83cdfff200d2640fe0f"],["d83ddea3","d83ddea3d83cdffb","d83ddea3d83cdffc","d83ddea3d83cdffd","d83ddea3d83cdffe","d83ddea3d83cdfff"],["d83ddea3200d2642fe0f","d83ddea3d83cdffb200d2642fe0f","d83ddea3d83cdffc200d2642fe0f","d83ddea3d83cdffd200d2642fe0f","d83ddea3d83cdffe200d2642fe0f","d83ddea3d83cdfff200d2642fe0f"]],"People_7":[["d83ddea3200d2640fe0f","d83ddea3d83cdffb200d2640fe0f","d83ddea3d83cdffc200d2640fe0f","d83ddea3d83cdffd200d2640fe0f","d83ddea3d83cdffe200d2640fe0f","d83ddea3d83cdfff200d2640fe0f"],["d83cdfca","d83cdfcad83cdffb","d83cdfcad83cdffc","d83cdfcad83cdffd","d83cdfcad83cdffe","d83cdfcad83cdfff"],["d83cdfca200d2642fe0f","d83cdfcad83cdffb200d2642fe0f","d83cdfcad83cdffc200d2642fe0f","d83cdfcad83cdffd200d2642fe0f","d83cdfcad83cdffe200d2642fe0f","d83cdfcad83cdfff200d2642fe0f"],["d83cdfca200d2640fe0f","d83cdfcad83cdffb200d2640fe0f","d83cdfcad83cdffc200d2640fe0f","d83cdfcad83cdffd200d2640fe0f","d83cdfcad83cdffe200d2640fe0f","d83cdfcad83cdfff200d2640fe0f"],["26f9fe0f","26f9d83cdffb","26f9d83cdffc","26f9d83cdffd","26f9d83cdffe","26f9d83cdfff"],["26f9fe0f200d2642fe0f","26f9d83cdffb200d2642fe0f","26f9d83cdffc200d2642fe0f","26f9d83cdffd200d2642fe0f","26f9d83cdffe200d2642fe0f","26f9d83cdfff200d2642fe0f"],["26f9fe0f200d2640fe0f","26f9d83cdffb200d2640fe0f","26f9d83cdffc200d2640fe0f","26f9d83cdffd200d2640fe0f","26f9d83cdffe200d2640fe0f","26f9d83cdfff200d2640fe0f"],["d83cdfcbfe0f","d83cdfcbd83cdffb","d83cdfcbd83cdffc","d83cdfcbd83cdffd","d83cdfcbd83cdffe","d83cdfcbd83cdfff"],["d83cdfcbfe0f200d2642fe0f","d83cdfcbd83cdffb200d2642fe0f","d83cdfcbd83cdffc200d2642fe0f","d83cdfcbd83cdffd200d2642fe0f","d83cdfcbd83cdffe200d2642fe0f","d83cdfcbd83cdfff200d2642fe0f"],["d83cdfcbfe0f200d2640fe0f","d83cdfcbd83cdffb200d2640fe0f","d83cdfcbd83cdffc200d2640fe0f","d83cdfcbd83cdffd200d2640fe0f","d83cdfcbd83cdffe200d2640fe0f","d83cdfcbd83cdfff200d2640fe0f"],["d83ddeb4","d83ddeb4d83cdffb","d83ddeb4d83cdffc","d83ddeb4d83cdffd","d83ddeb4d83cdffe","d83ddeb4d83cdfff"],["d83ddeb4200d2642fe0f","d83ddeb4d83cdffb200d2642fe0f","d83ddeb4d83cdffc200d2642fe0f","d83ddeb4d83cdffd200d2642fe0f","d83ddeb4d83cdffe200d2642fe0f","d83ddeb4d83cdfff200d2642fe0f"],["d83ddeb4200d2640fe0f","d83ddeb4d83cdffb200d2640fe0f","d83ddeb4d83cdffc200d2640fe0f","d83ddeb4d83cdffd200d2640fe0f","d83ddeb4d83cdffe200d2640fe0f","d83ddeb4d83cdfff200d2640fe0f"],["d83ddeb5","d83ddeb5d83cdffb","d83ddeb5d83cdffc","d83ddeb5d83cdffd","d83ddeb5d83cdffe","d83ddeb5d83cdfff"],["d83ddeb5200d2642fe0f","d83ddeb5d83cdffb200d2642fe0f","d83ddeb5d83cdffc200d2642fe0f","d83ddeb5d83cdffd200d2642fe0f","d83ddeb5d83cdffe200d2642fe0f","d83ddeb5d83cdfff200d2642fe0f"],["d83ddeb5200d2640fe0f","d83ddeb5d83cdffb200d2640fe0f","d83ddeb5d83cdffc200d2640fe0f","d83ddeb5d83cdffd200d2640fe0f","d83ddeb5d83cdffe200d2640fe0f","d83ddeb5d83cdfff200d2640fe0f"],["d83edd38","d83edd38d83cdffb","d83edd38d83cdffc","d83edd38d83cdffd","d83edd38d83cdffe","d83edd38d83cdfff"],["d83edd38200d2642fe0f","d83edd38d83cdffb200d2642fe0f","d83edd38d83cdffc200d2642fe0f","d83edd38d83cdffd200d2642fe0f","d83edd38d83cdffe200d2642fe0f","d83edd38d83cdfff200d2642fe0f"],["d83edd38200d2640fe0f","d83edd38d83cdffb200d2640fe0f","d83edd38d83cdffc200d2640fe0f","d83edd38d83cdffd200d2640fe0f","d83edd38d83cdffe200d2640fe0f","d83edd38d83cdfff200d2640fe0f"],["d83edd3c"],["d83edd3c200d2642fe0f"],["d83edd3c200d2640fe0f"],["d83edd3d","d83edd3dd83cdffb","d83edd3dd83cdffc","d83edd3dd83cdffd","d83edd3dd83cdffe","d83edd3dd83cdfff"],["d83edd3d200d2642fe0f","d83edd3dd83cdffb200d2642fe0f","d83edd3dd83cdffc200d2642fe0f","d83edd3dd83cdffd200d2642fe0f","d83edd3dd83cdffe200d2642fe0f","d83edd3dd83cdfff200d2642fe0f"],["d83edd3d200d2640fe0f","d83edd3dd83cdffb200d2640fe0f","d83edd3dd83cdffc200d2640fe0f","d83edd3dd83cdffd200d2640fe0f","d83edd3dd83cdffe200d2640fe0f","d83edd3dd83cdfff200d2640fe0f"],["d83edd3e","d83edd3ed83cdffb","d83edd3ed83cdffc","d83edd3ed83cdffd","d83edd3ed83cdffe","d83edd3ed83cdfff"],["d83edd3e200d2642fe0f","d83edd3ed83cdffb200d2642fe0f","d83edd3ed83cdffc200d2642fe0f","d83edd3ed83cdffd200d2642fe0f","d83edd3ed83cdffe200d2642fe0f","d83edd3ed83cdfff200d2642fe0f"],["d83edd3e200d2640fe0f","d83edd3ed83cdffb200d2640fe0f","d83edd3ed83cdffc200d2640fe0f","d83edd3ed83cdffd200d2640fe0f","d83edd3ed83cdffe200d2640fe0f","d83edd3ed83cdfff200d2640fe0f"],["d83edd39","d83edd39d83cdffb","d83edd39d83cdffc","d83edd39d83cdffd","d83edd39d83cdffe","d83edd39d83cdfff"],["d83edd39200d2642fe0f","d83edd39d83cdffb200d2642fe0f","d83edd39d83cdffc200d2642fe0f","d83edd39d83cdffd200d2642fe0f","d83edd39d83cdffe200d2642fe0f","d83edd39d83cdfff200d2642fe0f"],["d83edd39200d2640fe0f","d83edd39d83cdffb200d2640fe0f","d83edd39d83cdffc200d2640fe0f","d83edd39d83cdffd200d2640fe0f","d83edd39d83cdffe200d2640fe0f","d83edd39d83cdfff200d2640fe0f"],["d83eddd8","d83eddd8d83cdffb","d83eddd8d83cdffc","d83eddd8d83cdffd","d83eddd8d83cdffe","d83eddd8d83cdfff"],["d83eddd8200d2642fe0f","d83eddd8d83cdffb200d2642fe0f","d83eddd8d83cdffc200d2642fe0f","d83eddd8d83cdffd200d2642fe0f","d83eddd8d83cdffe200d2642fe0f","d83eddd8d83cdfff200d2642fe0f"],["d83eddd8200d2640fe0f","d83eddd8d83cdffb200d2640fe0f","d83eddd8d83cdffc200d2640fe0f","d83eddd8d83cdffd200d2640fe0f","d83eddd8d83cdffe200d2640fe0f","d83eddd8d83cdfff200d2640fe0f"],["d83ddec0","d83ddec0d83cdffb","d83ddec0d83cdffc","d83ddec0d83cdffd","d83ddec0d83cdffe","d83ddec0d83cdfff"],["d83ddecc","d83ddeccd83cdffb","d83ddeccd83cdffc","d83ddeccd83cdffd","d83ddeccd83cdffe","d83ddeccd83cdfff"],["d83eddd1200dd83edd1d200dd83eddd1","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdfff"],["d83ddc6d","d83ddc6dd83cdffb","d83ddc6dd83cdffc","d83ddc6dd83cdffd","d83ddc6dd83cdffe","d83ddc6dd83cdfff","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffe"]],"People_8":[["d83ddc6b","d83ddc6bd83cdffb","d83ddc6bd83cdffc","d83ddc6bd83cdffd","d83ddc6bd83cdffe","d83ddc6bd83cdfff","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffe"],["d83ddc6c","d83ddc6cd83cdffb","d83ddc6cd83cdffc","d83ddc6cd83cdffd","d83ddc6cd83cdffe","d83ddc6cd83cdfff","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffe"],["d83ddc8f","d83ddc8fd83cdffb","d83ddc8fd83cdffc","d83ddc8fd83cdffd","d83ddc8fd83cdffe","d83ddc8fd83cdfff","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe"],["d83ddc69200d2764fe0f200dd83ddc8b200dd83ddc68","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff"],["d83ddc68200d2764fe0f200dd83ddc8b200dd83ddc68","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff"],["d83ddc69200d2764fe0f200dd83ddc8b200dd83ddc69","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff"]],"People_9":[["d83ddc91","d83ddc91d83cdffb","d83ddc91d83cdffc","d83ddc91d83cdffd","d83ddc91d83cdffe","d83ddc91d83cdfff","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffe"],["d83ddc69200d2764fe0f200dd83ddc68","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdfff"],["d83ddc68200d2764fe0f200dd83ddc68","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdfff"],["d83ddc69200d2764fe0f200dd83ddc69","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdfff"],["d83ddc6a"],["d83ddc68200dd83ddc69200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc67"],["d83ddc68200dd83ddc69200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc67200dd83ddc67"],["d83ddc68200dd83ddc68200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc67"],["d83ddc68200dd83ddc68200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc67200dd83ddc67"],["d83ddc69200dd83ddc69200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc67"],["d83ddc69200dd83ddc69200dd83ddc67200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc66200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc67200dd83ddc67"],["d83ddc68200dd83ddc66"],["d83ddc68200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc67"],["d83ddc68200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc67200dd83ddc67"],["d83ddc69200dd83ddc66"],["d83ddc69200dd83ddc66200dd83ddc66"],["d83ddc69200dd83ddc67"],["d83ddc69200dd83ddc67200dd83ddc66"],["d83ddc69200dd83ddc67200dd83ddc67"],["d83ddde3fe0f"],["d83ddc64"],["d83ddc65"],["d83edec2"],["d83ddc63"]],"Nature":[["d83ddc35"],["d83ddc12"],["d83edd8d"],["d83edda7"],["d83ddc36"],["d83ddc15"],["d83eddae"],["d83ddc15200dd83eddba"],["d83ddc29"],["d83ddc3a"],["d83edd8a"],["d83edd9d"],["d83ddc31"],["d83ddc08"],["d83ddc08200d2b1b"],["d83edd81"],["d83ddc2f"],["d83ddc05"],["d83ddc06"],["d83ddc34"],["d83edece"],["d83edecf"],["d83ddc0e"],["d83edd84"],["d83edd93"],["d83edd8c"],["d83eddac"],["d83ddc2e"],["d83ddc02"],["d83ddc03"],["d83ddc04"],["d83ddc37"],["d83ddc16"],["d83ddc17"],["d83ddc3d"],["d83ddc0f"],["d83ddc11"],["d83ddc10"],["d83ddc2a"],["d83ddc2b"],["d83edd99"],["d83edd92"],["d83ddc18"],["d83edda3"],["d83edd8f"],["d83edd9b"],["d83ddc2d"],["d83ddc01"],["d83ddc00"],["d83ddc39"],["d83ddc30"],["d83ddc07"],["d83ddc3ffe0f"],["d83eddab"],["d83edd94"],["d83edd87"],["d83ddc3b"],["d83ddc3b200d2744fe0f"],["d83ddc28"],["d83ddc3c"],["d83edda5"],["d83edda6"],["d83edda8"],["d83edd98"],["d83edda1"],["d83ddc3e"],["d83edd83"],["d83ddc14"],["d83ddc13"],["d83ddc23"],["d83ddc24"],["d83ddc25"],["d83ddc26"],["d83ddc27"],["d83ddd4afe0f"],["d83edd85"],["d83edd86"],["d83edda2"],["d83edd89"],["d83edda4"],["d83edeb6"],["d83edda9"],["d83edd9a"],["d83edd9c"],["d83edebd"],["d83ddc26200d2b1b"],["d83edebf"],["d83ddc38"],["d83ddc0a"],["d83ddc22"],["d83edd8e"],["d83ddc0d"],["d83ddc32"],["d83ddc09"],["d83edd95"],["d83edd96"],["d83ddc33"],["d83ddc0b"],["d83ddc2c"],["d83eddad"],["d83ddc1f"],["d83ddc20"],["d83ddc21"],["d83edd88"],["d83ddc19"],["d83ddc1a"],["d83edeb8"],["d83edebc"],["d83ddc0c"],["d83edd8b"],["d83ddc1b"],["d83ddc1c"],["d83ddc1d"],["d83edeb2"],["d83ddc1e"],["d83edd97"],["d83edeb3"],["d83ddd77fe0f"],["d83ddd78fe0f"],["d83edd82"],["d83edd9f"],["d83edeb0"],["d83edeb1"],["d83edda0"],["d83ddc90"],["d83cdf38"],["d83ddcae"],["d83edeb7"],["d83cdff5fe0f"],["d83cdf39"],["d83edd40"],["d83cdf3a"],["d83cdf3b"],["d83cdf3c"],["d83cdf37"],["d83edebb"],["d83cdf31"],["d83edeb4"],["d83cdf32"],["d83cdf33"],["d83cdf34"],["d83cdf35"],["d83cdf3e"],["d83cdf3f"],["2618fe0f"],["d83cdf40"],["d83cdf41"],["d83cdf42"],["d83cdf43"],["d83edeb9"],["d83edeba"],["d83cdf44"]],"Foods":[["d83cdf47"],["d83cdf48"],["d83cdf49"],["d83cdf4a"],["d83cdf4b"],["d83cdf4c"],["d83cdf4d"],["d83edd6d"],["d83cdf4e"],["d83cdf4f"],["d83cdf50"],["d83cdf51"],["d83cdf52"],["d83cdf53"],["d83eded0"],["d83edd5d"],["d83cdf45"],["d83eded2"],["d83edd65"],["d83edd51"],["d83cdf46"],["d83edd54"],["d83edd55"],["d83cdf3d"],["d83cdf36fe0f"],["d83eded1"],["d83edd52"],["d83edd6c"],["d83edd66"],["d83eddc4"],["d83eddc5"],["d83edd5c"],["d83eded8"],["d83cdf30"],["d83ededa"],["d83ededb"],["d83cdf5e"],["d83edd50"],["d83edd56"],["d83eded3"],["d83edd68"],["d83edd6f"],["d83edd5e"],["d83eddc7"],["d83eddc0"],["d83cdf56"],["d83cdf57"],["d83edd69"],["d83edd53"],["d83cdf54"],["d83cdf5f"],["d83cdf55"],["d83cdf2d"],["d83edd6a"],["d83cdf2e"],["d83cdf2f"],["d83eded4"],["d83edd59"],["d83eddc6"],["d83edd5a"],["d83cdf73"],["d83edd58"],["d83cdf72"],["d83eded5"],["d83edd63"],["d83edd57"],["d83cdf7f"],["d83eddc8"],["d83eddc2"],["d83edd6b"],["d83cdf71"],["d83cdf58"],["d83cdf59"],["d83cdf5a"],["d83cdf5b"],["d83cdf5c"],["d83cdf5d"],["d83cdf60"],["d83cdf62"],["d83cdf63"],["d83cdf64"],["d83cdf65"],["d83edd6e"],["d83cdf61"],["d83edd5f"],["d83edd60"],["d83edd61"],["d83edd80"],["d83edd9e"],["d83edd90"],["d83edd91"],["d83eddaa"],["d83cdf66"],["d83cdf67"],["d83cdf68"],["d83cdf69"],["d83cdf6a"],["d83cdf82"],["d83cdf70"],["d83eddc1"],["d83edd67"],["d83cdf6b"],["d83cdf6c"],["d83cdf6d"],["d83cdf6e"],["d83cdf6f"],["d83cdf7c"],["d83edd5b"],["2615"],["d83eded6"],["d83cdf75"],["d83cdf76"],["d83cdf7e"],["d83cdf77"],["d83cdf78"],["d83cdf79"],["d83cdf7a"],["d83cdf7b"],["d83edd42"],["d83edd43"],["d83eded7"],["d83edd64"],["d83eddcb"],["d83eddc3"],["d83eddc9"],["d83eddca"],["d83edd62"],["d83cdf7dfe0f"],["d83cdf74"],["d83edd44"],["d83ddd2a"],["d83eded9"],["d83cdffa"]],"Places":[["d83cdf0d"],["d83cdf0e"],["d83cdf0f"],["d83cdf10"],["d83dddfafe0f"],["d83dddfe"],["d83edded"],["d83cdfd4fe0f"],["26f0fe0f"],["d83cdf0b"],["d83dddfb"],["d83cdfd5fe0f"],["d83cdfd6fe0f"],["d83cdfdcfe0f"],["d83cdfddfe0f"],["d83cdfdefe0f"],["d83cdfdffe0f"],["d83cdfdbfe0f"],["d83cdfd7fe0f"],["d83eddf1"],["d83edea8"],["d83edeb5"],["d83dded6"],["d83cdfd8fe0f"],["d83cdfdafe0f"],["d83cdfe0"],["d83cdfe1"],["d83cdfe2"],["d83cdfe3"],["d83cdfe4"],["d83cdfe5"],["d83cdfe6"],["d83cdfe8"],["d83cdfe9"],["d83cdfea"],["d83cdfeb"],["d83cdfec"],["d83cdfed"],["d83cdfef"],["d83cdff0"],["d83ddc92"],["d83dddfc"],["d83dddfd"],["26ea"],["d83ddd4c"],["d83dded5"],["d83ddd4d"],["26e9fe0f"],["d83ddd4b"],["26f2"],["26fa"],["d83cdf01"],["d83cdf03"],["d83cdfd9fe0f"],["d83cdf04"],["d83cdf05"],["d83cdf06"],["d83cdf07"],["d83cdf09"],["2668fe0f"],["d83cdfa0"],["d83ddedd"],["d83cdfa1"],["d83cdfa2"],["d83ddc88"],["d83cdfaa"],["d83dde82"],["d83dde83"],["d83dde84"],["d83dde85"],["d83dde86"],["d83dde87"],["d83dde88"],["d83dde89"],["d83dde8a"],["d83dde9d"],["d83dde9e"],["d83dde8b"],["d83dde8c"],["d83dde8d"],["d83dde8e"],["d83dde90"],["d83dde91"],["d83dde92"],["d83dde93"],["d83dde94"],["d83dde95"],["d83dde96"],["d83dde97"],["d83dde98"],["d83dde99"],["d83ddefb"],["d83dde9a"],["d83dde9b"],["d83dde9c"],["d83cdfcefe0f"],["d83cdfcdfe0f"],["d83ddef5"],["d83eddbd"],["d83eddbc"],["d83ddefa"],["d83ddeb2"],["d83ddef4"],["d83ddef9"],["d83ddefc"],["d83dde8f"],["d83ddee3fe0f"],["d83ddee4fe0f"],["d83ddee2fe0f"],["26fd"],["d83ddede"],["d83ddea8"],["d83ddea5"],["d83ddea6"],["d83dded1"],["d83ddea7"],["2693"],["d83ddedf"],["26f5"],["d83ddef6"],["d83ddea4"],["d83ddef3fe0f"],["26f4fe0f"],["d83ddee5fe0f"],["d83ddea2"],["2708fe0f"],["d83ddee9fe0f"],["d83ddeeb"],["d83ddeec"],["d83ede82"],["d83ddcba"],["d83dde81"],["d83dde9f"],["d83ddea0"],["d83ddea1"],["d83ddef0fe0f"],["d83dde80"],["d83ddef8"],["d83ddecefe0f"],["d83eddf3"],["231b"],["23f3"],["231a"],["23f0"],["23f1fe0f"],["23f2fe0f"],["d83ddd70fe0f"],["d83ddd5b"],["d83ddd67"],["d83ddd50"],["d83ddd5c"],["d83ddd51"],["d83ddd5d"],["d83ddd52"],["d83ddd5e"],["d83ddd53"],["d83ddd5f"],["d83ddd54"],["d83ddd60"],["d83ddd55"],["d83ddd61"],["d83ddd56"],["d83ddd62"],["d83ddd57"],["d83ddd63"],["d83ddd58"],["d83ddd64"],["d83ddd59"],["d83ddd65"],["d83ddd5a"],["d83ddd66"],["d83cdf11"],["d83cdf12"],["d83cdf13"],["d83cdf14"],["d83cdf15"],["d83cdf16"],["d83cdf17"],["d83cdf18"],["d83cdf19"],["d83cdf1a"],["d83cdf1b"],["d83cdf1c"],["d83cdf21fe0f"],["2600fe0f"],["d83cdf1d"],["d83cdf1e"],["d83ede90"],["2b50"],["d83cdf1f"],["d83cdf20"],["d83cdf0c"],["2601fe0f"],["26c5"],["26c8fe0f"],["d83cdf24fe0f"],["d83cdf25fe0f"],["d83cdf26fe0f"],["d83cdf27fe0f"],["d83cdf28fe0f"],["d83cdf29fe0f"],["d83cdf2afe0f"],["d83cdf2bfe0f"],["d83cdf2cfe0f"],["d83cdf00"],["d83cdf08"],["d83cdf02"],["2602fe0f"],["2614"],["26f1fe0f"],["26a1"],["2744fe0f"],["2603fe0f"],["26c4"],["2604fe0f"],["d83ddd25"],["d83ddca7"],["d83cdf0a"]],"Activity":[["d83cdf83"],["d83cdf84"],["d83cdf86"],["d83cdf87"],["d83edde8"],["2728"],["d83cdf88"],["d83cdf89"],["d83cdf8a"],["d83cdf8b"],["d83cdf8d"],["d83cdf8e"],["d83cdf8f"],["d83cdf90"],["d83cdf91"],["d83edde7"],["d83cdf80"],["d83cdf81"],["d83cdf97fe0f"],["d83cdf9ffe0f"],["d83cdfab"],["d83cdf96fe0f"],["d83cdfc6"],["d83cdfc5"],["d83edd47"],["d83edd48"],["d83edd49"],["26bd"],["26be"],["d83edd4e"],["d83cdfc0"],["d83cdfd0"],["d83cdfc8"],["d83cdfc9"],["d83cdfbe"],["d83edd4f"],["d83cdfb3"],["d83cdfcf"],["d83cdfd1"],["d83cdfd2"],["d83edd4d"],["d83cdfd3"],["d83cdff8"],["d83edd4a"],["d83edd4b"],["d83edd45"],["26f3"],["26f8fe0f"],["d83cdfa3"],["d83edd3f"],["d83cdfbd"],["d83cdfbf"],["d83ddef7"],["d83edd4c"],["d83cdfaf"],["d83ede80"],["d83ede81"],["d83ddd2b"],["d83cdfb1"],["d83ddd2e"],["d83ede84"],["d83cdfae"],["d83ddd79fe0f"],["d83cdfb0"],["d83cdfb2"],["d83edde9"],["d83eddf8"],["d83ede85"],["d83edea9"],["d83ede86"],["2660fe0f"],["2665fe0f"],["2666fe0f"],["2663fe0f"],["265ffe0f"],["d83cdccf"],["d83cdc04"],["d83cdfb4"],["d83cdfad"],["d83dddbcfe0f"],["d83cdfa8"],["d83eddf5"],["d83edea1"],["d83eddf6"],["d83edea2"]],"Objects_0":[["d83ddc53"],["d83ddd76fe0f"],["d83edd7d"],["d83edd7c"],["d83eddba"],["d83ddc54"],["d83ddc55"],["d83ddc56"],["d83edde3"],["d83edde4"],["d83edde5"],["d83edde6"],["d83ddc57"],["d83ddc58"],["d83edd7b"],["d83ede71"],["d83ede72"],["d83ede73"],["d83ddc59"],["d83ddc5a"],["d83edead"],["d83ddc5b"],["d83ddc5c"],["d83ddc5d"],["d83ddecdfe0f"],["d83cdf92"],["d83ede74"],["d83ddc5e"],["d83ddc5f"],["d83edd7e"],["d83edd7f"],["d83ddc60"],["d83ddc61"],["d83ede70"],["d83ddc62"],["d83edeae"],["d83ddc51"],["d83ddc52"],["d83cdfa9"],["d83cdf93"],["d83edde2"],["d83ede96"],["26d1fe0f"],["d83ddcff"],["d83ddc84"],["d83ddc8d"],["d83ddc8e"],["d83ddd07"],["d83ddd08"],["d83ddd09"],["d83ddd0a"],["d83ddce2"],["d83ddce3"],["d83ddcef"],["d83ddd14"],["d83ddd15"],["d83cdfbc"],["d83cdfb5"],["d83cdfb6"],["d83cdf99fe0f"],["d83cdf9afe0f"],["d83cdf9bfe0f"],["d83cdfa4"],["d83cdfa7"],["d83ddcfb"],["d83cdfb7"],["d83ede97"],["d83cdfb8"],["d83cdfb9"],["d83cdfba"],["d83cdfbb"],["d83ede95"],["d83edd41"],["d83ede98"],["d83ede87"],["d83ede88"],["d83ddcf1"],["d83ddcf2"],["260efe0f"],["d83ddcde"],["d83ddcdf"],["d83ddce0"],["d83ddd0b"],["d83edeab"],["d83ddd0c"],["d83ddcbb"],["d83ddda5fe0f"],["d83ddda8fe0f"],["2328fe0f"],["d83dddb1fe0f"],["d83dddb2fe0f"],["d83ddcbd"],["d83ddcbe"],["d83ddcbf"],["d83ddcc0"],["d83eddee"],["d83cdfa5"],["d83cdf9efe0f"],["d83ddcfdfe0f"],["d83cdfac"],["d83ddcfa"],["d83ddcf7"],["d83ddcf8"],["d83ddcf9"],["d83ddcfc"],["d83ddd0d"],["d83ddd0e"],["d83ddd6ffe0f"],["d83ddca1"],["d83ddd26"],["d83cdfee"],["d83ede94"],["d83ddcd4"],["d83ddcd5"],["d83ddcd6"],["d83ddcd7"],["d83ddcd8"],["d83ddcd9"],["d83ddcda"],["d83ddcd3"],["d83ddcd2"],["d83ddcc3"],["d83ddcdc"],["d83ddcc4"],["d83ddcf0"],["d83ddddefe0f"],["d83ddcd1"],["d83ddd16"],["d83cdff7fe0f"],["d83ddcb0"],["d83ede99"]],"Objects_1":[["d83ddcb4"],["d83ddcb5"],["d83ddcb6"],["d83ddcb7"],["d83ddcb8"],["d83ddcb3"],["d83eddfe"],["d83ddcb9"],["2709fe0f"],["d83ddce7"],["d83ddce8"],["d83ddce9"],["d83ddce4"],["d83ddce5"],["d83ddce6"],["d83ddceb"],["d83ddcea"],["d83ddcec"],["d83ddced"],["d83ddcee"],["d83dddf3fe0f"],["270ffe0f"],["2712fe0f"],["d83ddd8bfe0f"],["d83ddd8afe0f"],["d83ddd8cfe0f"],["d83ddd8dfe0f"],["d83ddcdd"],["d83ddcbc"],["d83ddcc1"],["d83ddcc2"],["d83dddc2fe0f"],["d83ddcc5"],["d83ddcc6"],["d83dddd2fe0f"],["d83dddd3fe0f"],["d83ddcc7"],["d83ddcc8"],["d83ddcc9"],["d83ddcca"],["d83ddccb"],["d83ddccc"],["d83ddccd"],["d83ddcce"],["d83ddd87fe0f"],["d83ddccf"],["d83ddcd0"],["2702fe0f"],["d83dddc3fe0f"],["d83dddc4fe0f"],["d83dddd1fe0f"],["d83ddd12"],["d83ddd13"],["d83ddd0f"],["d83ddd10"],["d83ddd11"],["d83dddddfe0f"],["d83ddd28"],["d83ede93"],["26cffe0f"],["2692fe0f"],["d83ddee0fe0f"],["d83ddde1fe0f"],["2694fe0f"],["d83ddca3"],["d83ede83"],["d83cdff9"],["d83ddee1fe0f"],["d83ede9a"],["d83ddd27"],["d83ede9b"],["d83ddd29"],["2699fe0f"],["d83ddddcfe0f"],["2696fe0f"],["d83eddaf"],["d83ddd17"],["26d3fe0f"],["d83ede9d"],["d83eddf0"],["d83eddf2"],["d83ede9c"],["2697fe0f"],["d83eddea"],["d83eddeb"],["d83eddec"],["d83ddd2c"],["d83ddd2d"],["d83ddce1"],["d83ddc89"],["d83ede78"],["d83ddc8a"],["d83ede79"],["d83ede7c"],["d83ede7a"],["d83ede7b"],["d83ddeaa"],["d83dded7"],["d83ede9e"],["d83ede9f"],["d83ddecffe0f"],["d83ddecbfe0f"],["d83ede91"],["d83ddebd"],["d83edea0"],["d83ddebf"],["d83ddec1"],["d83edea4"],["d83ede92"],["d83eddf4"],["d83eddf7"],["d83eddf9"],["d83eddfa"],["d83eddfb"],["d83edea3"],["d83eddfc"],["d83edee7"],["d83edea5"],["d83eddfd"],["d83eddef"],["d83dded2"],["d83ddeac"],["26b0fe0f"],["d83edea6"],["26b1fe0f"],["d83eddff"],["d83edeac"],["d83dddff"],["d83edea7"],["d83edeaa"]],"Symbols":[["d83cdfe7"],["d83ddeae"],["d83ddeb0"],["267f"],["d83ddeb9"],["d83ddeba"],["d83ddebb"],["d83ddebc"],["d83ddebe"],["d83ddec2"],["d83ddec3"],["d83ddec4"],["d83ddec5"],["26a0fe0f"],["d83ddeb8"],["26d4"],["d83ddeab"],["d83ddeb3"],["d83ddead"],["d83ddeaf"],["d83ddeb1"],["d83ddeb7"],["d83ddcf5"],["d83ddd1e"],["2622fe0f"],["2623fe0f"],["2b06fe0f"],["2197fe0f"],["27a1fe0f"],["2198fe0f"],["2b07fe0f"],["2199fe0f"],["2b05fe0f"],["2196fe0f"],["2195fe0f"],["2194fe0f"],["21a9fe0f"],["21aafe0f"],["2934fe0f"],["2935fe0f"],["d83ddd03"],["d83ddd04"],["d83ddd19"],["d83ddd1a"],["d83ddd1b"],["d83ddd1c"],["d83ddd1d"],["d83dded0"],["269bfe0f"],["d83ddd49fe0f"],["2721fe0f"],["2638fe0f"],["262ffe0f"],["271dfe0f"],["2626fe0f"],["262afe0f"],["262efe0f"],["d83ddd4e"],["d83ddd2f"],["d83edeaf"],["2648"],["2649"],["264a"],["264b"],["264c"],["264d"],["264e"],["264f"],["2650"],["2651"],["2652"],["2653"],["26ce"],["d83ddd00"],["d83ddd01"],["d83ddd02"],["25b6fe0f"],["23e9"],["23edfe0f"],["23effe0f"],["25c0fe0f"],["23ea"],["23eefe0f"],["d83ddd3c"],["23eb"],["d83ddd3d"],["23ec"],["23f8fe0f"],["23f9fe0f"],["23fafe0f"],["23cffe0f"],["d83cdfa6"],["d83ddd05"],["d83ddd06"],["d83ddcf6"],["d83ddedc"],["d83ddcf3"],["d83ddcf4"],["26a7fe0f"],["2716fe0f"],["2795"],["2796"],["2797"],["d83ddff0"],["267efe0f"],["203cfe0f"],["2049fe0f"],["2753"],["2754"],["2755"],["2757"],["3030fe0f"],["d83ddcb1"],["d83ddcb2"],["267bfe0f"],["269cfe0f"],["d83ddd31"],["d83ddcdb"],["d83ddd30"],["2b55"],["2705"],["2611fe0f"],["2714fe0f"],["274c"],["274e"],["27b0"],["27bf"],["303dfe0f"],["2733fe0f"],["2734fe0f"],["2747fe0f"],["00a9fe0f"],["00aefe0f"],["2122fe0f"],["0023fe0f20e3"],["002afe0f20e3"],["0030fe0f20e3"],["0031fe0f20e3"],["0032fe0f20e3"],["0033fe0f20e3"],["0034fe0f20e3"],["0035fe0f20e3"],["0036fe0f20e3"],["0037fe0f20e3"],["0038fe0f20e3"],["0039fe0f20e3"],["d83ddd1f"],["d83ddd20"],["d83ddd21"],["d83ddd22"],["d83ddd23"],["d83ddd24"],["d83cdd70fe0f"],["d83cdd8e"],["d83cdd71fe0f"],["d83cdd91"],["d83cdd92"],["d83cdd93"],["2139fe0f"],["d83cdd94"],["24c2fe0f"],["d83cdd95"],["d83cdd96"],["d83cdd7efe0f"],["d83cdd97"],["d83cdd7ffe0f"],["d83cdd98"],["d83cdd99"],["d83cdd9a"],["d83cde01"],["d83cde02fe0f"],["d83cde37fe0f"],["d83cde36"],["d83cde2f"],["d83cde50"],["d83cde39"],["d83cde1a"],["d83cde32"],["d83cde51"],["d83cde38"],["d83cde34"],["d83cde33"],["3297fe0f"],["3299fe0f"],["d83cde3a"],["d83cde35"],["d83ddd34"],["d83ddfe0"],["d83ddfe1"],["d83ddfe2"],["d83ddd35"],["d83ddfe3"],["d83ddfe4"],["26ab"],["26aa"],["d83ddfe5"],["d83ddfe7"],["d83ddfe8"],["d83ddfe9"],["d83ddfe6"],["d83ddfea"],["d83ddfeb"],["2b1b"],["2b1c"],["25fcfe0f"],["25fbfe0f"],["25fe"],["25fd"],["25aafe0f"],["25abfe0f"],["d83ddd36"],["d83ddd37"],["d83ddd38"],["d83ddd39"],["d83ddd3a"],["d83ddd3b"],["d83ddca0"],["d83ddd18"],["d83ddd33"],["d83ddd32"]],"Flags_0":[["d83cdfc1"],["d83ddea9"],["d83cdf8c"],["d83cdff4"],["d83cdff3fe0f"],["d83cdff3fe0f200dd83cdf08"],["d83cdff3fe0f200d26a7fe0f"],["d83cdff4200d2620fe0f"],["d83cdde6d83cdde8"],["d83cdde6d83cdde9"],["d83cdde6d83cddea"],["d83cdde6d83cddeb"],["d83cdde6d83cddec"],["d83cdde6d83cddee"],["d83cdde6d83cddf1"],["d83cdde6d83cddf2"],["d83cdde6d83cddf4"],["d83cdde6d83cddf6"],["d83cdde6d83cddf7"],["d83cdde6d83cddf8"],["d83cdde6d83cddf9"],["d83cdde6d83cddfa"],["d83cdde6d83cddfc"],["d83cdde6d83cddfd"],["d83cdde6d83cddff"],["d83cdde7d83cdde6"],["d83cdde7d83cdde7"],["d83cdde7d83cdde9"],["d83cdde7d83cddea"],["d83cdde7d83cddeb"],["d83cdde7d83cddec"],["d83cdde7d83cdded"],["d83cdde7d83cddee"],["d83cdde7d83cddef"],["d83cdde7d83cddf1"],["d83cdde7d83cddf2"],["d83cdde7d83cddf3"],["d83cdde7d83cddf4"],["d83cdde7d83cddf6"],["d83cdde7d83cddf7"],["d83cdde7d83cddf8"],["d83cdde7d83cddf9"],["d83cdde7d83cddfb"],["d83cdde7d83cddfc"],["d83cdde7d83cddfe"],["d83cdde7d83cddff"],["d83cdde8d83cdde6"],["d83cdde8d83cdde8"],["d83cdde8d83cdde9"],["d83cdde8d83cddeb"],["d83cdde8d83cddec"],["d83cdde8d83cdded"],["d83cdde8d83cddee"],["d83cdde8d83cddf0"],["d83cdde8d83cddf1"],["d83cdde8d83cddf2"],["d83cdde8d83cddf3"],["d83cdde8d83cddf4"],["d83cdde8d83cddf5"],["d83cdde8d83cddf7"],["d83cdde8d83cddfa"],["d83cdde8d83cddfb"],["d83cdde8d83cddfc"],["d83cdde8d83cddfd"],["d83cdde8d83cddfe"],["d83cdde8d83cddff"],["d83cdde9d83cddea"],["d83cdde9d83cddec"],["d83cdde9d83cddef"],["d83cdde9d83cddf0"],["d83cdde9d83cddf2"],["d83cdde9d83cddf4"],["d83cdde9d83cddff"],["d83cddead83cdde6"],["d83cddead83cdde8"],["d83cddead83cddea"],["d83cddead83cddec"],["d83cddead83cdded"],["d83cddead83cddf7"],["d83cddead83cddf8"],["d83cddead83cddf9"],["d83cddead83cddfa"],["d83cddebd83cddee"],["d83cddebd83cddef"],["d83cddebd83cddf0"],["d83cddebd83cddf2"],["d83cddebd83cddf4"],["d83cddebd83cddf7"],["d83cddecd83cdde6"],["d83cddecd83cdde7"],["d83cddecd83cdde9"],["d83cddecd83cddea"],["d83cddecd83cddeb"],["d83cddecd83cddec"],["d83cddecd83cdded"],["d83cddecd83cddee"],["d83cddecd83cddf1"],["d83cddecd83cddf2"],["d83cddecd83cddf3"],["d83cddecd83cddf5"],["d83cddecd83cddf6"],["d83cddecd83cddf7"],["d83cddecd83cddf8"],["d83cddecd83cddf9"],["d83cddecd83cddfa"],["d83cddecd83cddfc"],["d83cddecd83cddfe"],["d83cddedd83cddf0"],["d83cddedd83cddf2"],["d83cddedd83cddf3"],["d83cddedd83cddf7"],["d83cddedd83cddf9"],["d83cddedd83cddfa"],["d83cddeed83cdde8"],["d83cddeed83cdde9"],["d83cddeed83cddea"],["d83cddeed83cddf1"],["d83cddeed83cddf2"],["d83cddeed83cddf3"],["d83cddeed83cddf4"],["d83cddeed83cddf6"],["d83cddeed83cddf7"],["d83cddeed83cddf8"],["d83cddeed83cddf9"],["d83cddefd83cddea"],["d83cddefd83cddf2"],["d83cddefd83cddf4"],["d83cddefd83cddf5"],["d83cddf0d83cddea"],["d83cddf0d83cddec"],["d83cddf0d83cdded"],["d83cddf0d83cddee"],["d83cddf0d83cddf2"],["d83cddf0d83cddf3"],["d83cddf0d83cddf5"]],"Flags_1":[["d83cddf0d83cddf7"],["d83cddf0d83cddfc"],["d83cddf0d83cddfe"],["d83cddf0d83cddff"],["d83cddf1d83cdde6"],["d83cddf1d83cdde7"],["d83cddf1d83cdde8"],["d83cddf1d83cddee"],["d83cddf1d83cddf0"],["d83cddf1d83cddf7"],["d83cddf1d83cddf8"],["d83cddf1d83cddf9"],["d83cddf1d83cddfa"],["d83cddf1d83cddfb"],["d83cddf1d83cddfe"],["d83cddf2d83cdde6"],["d83cddf2d83cdde8"],["d83cddf2d83cdde9"],["d83cddf2d83cddea"],["d83cddf2d83cddeb"],["d83cddf2d83cddec"],["d83cddf2d83cdded"],["d83cddf2d83cddf0"],["d83cddf2d83cddf1"],["d83cddf2d83cddf2"],["d83cddf2d83cddf3"],["d83cddf2d83cddf4"],["d83cddf2d83cddf5"],["d83cddf2d83cddf6"],["d83cddf2d83cddf7"],["d83cddf2d83cddf8"],["d83cddf2d83cddf9"],["d83cddf2d83cddfa"],["d83cddf2d83cddfb"],["d83cddf2d83cddfc"],["d83cddf2d83cddfd"],["d83cddf2d83cddfe"],["d83cddf2d83cddff"],["d83cddf3d83cdde6"],["d83cddf3d83cdde8"],["d83cddf3d83cddea"],["d83cddf3d83cddeb"],["d83cddf3d83cddec"],["d83cddf3d83cddee"],["d83cddf3d83cddf1"],["d83cddf3d83cddf4"],["d83cddf3d83cddf5"],["d83cddf3d83cddf7"],["d83cddf3d83cddfa"],["d83cddf3d83cddff"],["d83cddf4d83cddf2"],["d83cddf5d83cdde6"],["d83cddf5d83cddea"],["d83cddf5d83cddeb"],["d83cddf5d83cddec"],["d83cddf5d83cdded"],["d83cddf5d83cddf0"],["d83cddf5d83cddf1"],["d83cddf5d83cddf2"],["d83cddf5d83cddf3"],["d83cddf5d83cddf7"],["d83cddf5d83cddf8"],["d83cddf5d83cddf9"],["d83cddf5d83cddfc"],["d83cddf5d83cddfe"],["d83cddf6d83cdde6"],["d83cddf7d83cddea"],["d83cddf7d83cddf4"],["d83cddf7d83cddf8"],["d83cddf7d83cddfa"],["d83cddf7d83cddfc"],["d83cddf8d83cdde6"],["d83cddf8d83cdde7"],["d83cddf8d83cdde8"],["d83cddf8d83cdde9"],["d83cddf8d83cddea"],["d83cddf8d83cddec"],["d83cddf8d83cdded"],["d83cddf8d83cddee"],["d83cddf8d83cddef"],["d83cddf8d83cddf0"],["d83cddf8d83cddf1"],["d83cddf8d83cddf2"],["d83cddf8d83cddf3"],["d83cddf8d83cddf4"],["d83cddf8d83cddf7"],["d83cddf8d83cddf8"],["d83cddf8d83cddf9"],["d83cddf8d83cddfb"],["d83cddf8d83cddfd"],["d83cddf8d83cddfe"],["d83cddf8d83cddff"],["d83cddf9d83cdde6"],["d83cddf9d83cdde8"],["d83cddf9d83cdde9"],["d83cddf9d83cddeb"],["d83cddf9d83cddec"],["d83cddf9d83cdded"],["d83cddf9d83cddef"],["d83cddf9d83cddf0"],["d83cddf9d83cddf1"],["d83cddf9d83cddf2"],["d83cddf9d83cddf3"],["d83cddf9d83cddf4"],["d83cddf9d83cddf7"],["d83cddf9d83cddf9"],["d83cddf9d83cddfb"],["d83cddf9d83cddfc"],["d83cddf9d83cddff"],["d83cddfad83cdde6"],["d83cddfad83cddec"],["d83cddfad83cddf2"],["d83cddfad83cddf3"],["d83cddfad83cddf8"],["d83cddfad83cddfe"],["d83cddfad83cddff"],["d83cddfbd83cdde6"],["d83cddfbd83cdde8"],["d83cddfbd83cddea"],["d83cddfbd83cddec"],["d83cddfbd83cddee"],["d83cddfbd83cddf3"],["d83cddfbd83cddfa"],["d83cddfcd83cddeb"],["d83cddfcd83cddf8"],["d83cddfdd83cddf0"],["d83cddfed83cddea"],["d83cddfed83cddf9"],["d83cddffd83cdde6"],["d83cddffd83cddf2"],["d83cddffd83cddfc"],["d83cdff4db40dc67db40dc62db40dc65db40dc6edb40dc67db40dc7f"],["d83cdff4db40dc67db40dc62db40dc73db40dc63db40dc74db40dc7f"],["d83cdff4db40dc67db40dc62db40dc77db40dc6cdb40dc73db40dc7f"]]},"obsolete":[],"metrics":{"raw_width":66,"raw_height":66,"per_row":16},"densities":["xhdpi"],"format":"webp"} \ No newline at end of file +{"emoji":{"People_0":[["d83dde00"],["d83dde03"],["d83dde04"],["d83dde01"],["d83dde06"],["d83dde05"],["d83edd23"],["d83dde02"],["d83dde42"],["d83dde43"],["d83edee0"],["d83dde09"],["d83dde0a"],["d83dde07"],["d83edd70"],["d83dde0d"],["d83edd29"],["d83dde18"],["d83dde17"],["263afe0f"],["d83dde1a"],["d83dde19"],["d83edd72"],["d83dde0b"],["d83dde1b"],["d83dde1c"],["d83edd2a"],["d83dde1d"],["d83edd11"],["d83edd17"],["d83edd2d"],["d83edee2"],["d83edee3"],["d83edd2b"],["d83edd14"],["d83edee1"],["d83edd10"],["d83edd28"],["d83dde10"],["d83dde11"],["d83dde36"],["d83edee5"],["d83dde36200dd83cdf2bfe0f"],["d83dde0f"],["d83dde12"],["d83dde44"],["d83dde2c"],["d83dde2e200dd83ddca8"],["d83edd25"],["d83edee8"],["d83dde42200d2194fe0f"],["d83dde42200d2195fe0f"],["d83dde0c"],["d83dde14"],["d83dde2a"],["d83edd24"],["d83dde34"],["d83dde37"],["d83edd12"],["d83edd15"],["d83edd22"],["d83edd2e"],["d83edd27"],["d83edd75"],["d83edd76"],["d83edd74"],["d83dde35"],["d83dde35200dd83ddcab"],["d83edd2f"],["d83edd20"],["d83edd73"],["d83edd78"],["d83dde0e"],["d83edd13"],["d83eddd0"],["d83dde15"],["d83edee4"],["d83dde1f"],["d83dde41"],["2639fe0f"],["d83dde2e"],["d83dde2f"],["d83dde32"],["d83dde33"],["d83edd7a"],["d83edd79"],["d83dde26"],["d83dde27"],["d83dde28"],["d83dde30"],["d83dde25"],["d83dde22"],["d83dde2d"],["d83dde31"],["d83dde16"],["d83dde23"],["d83dde1e"],["d83dde13"],["d83dde29"],["d83dde2b"],["d83edd71"],["d83dde24"],["d83dde21"],["d83dde20"],["d83edd2c"],["d83dde08"],["d83ddc7f"],["d83ddc80"],["2620fe0f"],["d83ddca9"],["d83edd21"],["d83ddc79"],["d83ddc7a"],["d83ddc7b"],["d83ddc7d"],["d83ddc7e"],["d83edd16"],["d83dde3a"],["d83dde38"],["d83dde39"],["d83dde3b"],["d83dde3c"],["d83dde3d"],["d83dde40"],["d83dde3f"],["d83dde3e"],["d83dde48"],["d83dde49"],["d83dde4a"],["d83ddc8c"],["d83ddc98"],["d83ddc9d"],["d83ddc96"],["d83ddc97"],["d83ddc93"],["d83ddc9e"],["d83ddc95"],["d83ddc9f"],["2763fe0f"],["d83ddc94"],["2764fe0f200dd83ddd25"],["2764fe0f200dd83ede79"],["2764fe0f"],["d83ede77"],["d83edde1"],["d83ddc9b"],["d83ddc9a"],["d83ddc99"],["d83ede75"],["d83ddc9c"],["d83edd0e"],["d83ddda4"],["d83ede76"],["d83edd0d"],["d83ddc8b"],["d83ddcaf"],["d83ddca2"],["d83ddca5"],["d83ddcab"],["d83ddca6"],["d83ddca8"],["d83ddd73fe0f"],["d83ddcac"],["d83ddc41fe0f200dd83ddde8fe0f"],["d83ddde8fe0f"],["d83dddeffe0f"],["d83ddcad"],["d83ddca4"],["d83ddc4b","d83ddc4bd83cdffb","d83ddc4bd83cdffc","d83ddc4bd83cdffd","d83ddc4bd83cdffe","d83ddc4bd83cdfff"],["d83edd1a","d83edd1ad83cdffb","d83edd1ad83cdffc","d83edd1ad83cdffd","d83edd1ad83cdffe","d83edd1ad83cdfff"],["d83ddd90fe0f","d83ddd90d83cdffb","d83ddd90d83cdffc","d83ddd90d83cdffd","d83ddd90d83cdffe","d83ddd90d83cdfff"],["270b","270bd83cdffb","270bd83cdffc","270bd83cdffd","270bd83cdffe","270bd83cdfff"],["d83ddd96","d83ddd96d83cdffb","d83ddd96d83cdffc","d83ddd96d83cdffd","d83ddd96d83cdffe","d83ddd96d83cdfff"],["d83edef1","d83edef1d83cdffb","d83edef1d83cdffc","d83edef1d83cdffd","d83edef1d83cdffe","d83edef1d83cdfff"],["d83edef2","d83edef2d83cdffb","d83edef2d83cdffc","d83edef2d83cdffd","d83edef2d83cdffe","d83edef2d83cdfff"],["d83edef3","d83edef3d83cdffb","d83edef3d83cdffc","d83edef3d83cdffd","d83edef3d83cdffe","d83edef3d83cdfff"],["d83edef4","d83edef4d83cdffb","d83edef4d83cdffc","d83edef4d83cdffd","d83edef4d83cdffe","d83edef4d83cdfff"],["d83edef7","d83edef7d83cdffb","d83edef7d83cdffc","d83edef7d83cdffd","d83edef7d83cdffe","d83edef7d83cdfff"],["d83edef8","d83edef8d83cdffb","d83edef8d83cdffc","d83edef8d83cdffd","d83edef8d83cdffe","d83edef8d83cdfff"],["d83ddc4c","d83ddc4cd83cdffb","d83ddc4cd83cdffc","d83ddc4cd83cdffd","d83ddc4cd83cdffe","d83ddc4cd83cdfff"],["d83edd0c","d83edd0cd83cdffb","d83edd0cd83cdffc","d83edd0cd83cdffd","d83edd0cd83cdffe","d83edd0cd83cdfff"],["d83edd0f","d83edd0fd83cdffb","d83edd0fd83cdffc","d83edd0fd83cdffd","d83edd0fd83cdffe","d83edd0fd83cdfff"]],"People_1":[["270cfe0f","270cd83cdffb","270cd83cdffc","270cd83cdffd","270cd83cdffe","270cd83cdfff"],["d83edd1e","d83edd1ed83cdffb","d83edd1ed83cdffc","d83edd1ed83cdffd","d83edd1ed83cdffe","d83edd1ed83cdfff"],["d83edef0","d83edef0d83cdffb","d83edef0d83cdffc","d83edef0d83cdffd","d83edef0d83cdffe","d83edef0d83cdfff"],["d83edd1f","d83edd1fd83cdffb","d83edd1fd83cdffc","d83edd1fd83cdffd","d83edd1fd83cdffe","d83edd1fd83cdfff"],["d83edd18","d83edd18d83cdffb","d83edd18d83cdffc","d83edd18d83cdffd","d83edd18d83cdffe","d83edd18d83cdfff"],["d83edd19","d83edd19d83cdffb","d83edd19d83cdffc","d83edd19d83cdffd","d83edd19d83cdffe","d83edd19d83cdfff"],["d83ddc48","d83ddc48d83cdffb","d83ddc48d83cdffc","d83ddc48d83cdffd","d83ddc48d83cdffe","d83ddc48d83cdfff"],["d83ddc49","d83ddc49d83cdffb","d83ddc49d83cdffc","d83ddc49d83cdffd","d83ddc49d83cdffe","d83ddc49d83cdfff"],["d83ddc46","d83ddc46d83cdffb","d83ddc46d83cdffc","d83ddc46d83cdffd","d83ddc46d83cdffe","d83ddc46d83cdfff"],["d83ddd95","d83ddd95d83cdffb","d83ddd95d83cdffc","d83ddd95d83cdffd","d83ddd95d83cdffe","d83ddd95d83cdfff"],["d83ddc47","d83ddc47d83cdffb","d83ddc47d83cdffc","d83ddc47d83cdffd","d83ddc47d83cdffe","d83ddc47d83cdfff"],["261dfe0f","261dd83cdffb","261dd83cdffc","261dd83cdffd","261dd83cdffe","261dd83cdfff"],["d83edef5","d83edef5d83cdffb","d83edef5d83cdffc","d83edef5d83cdffd","d83edef5d83cdffe","d83edef5d83cdfff"],["d83ddc4d","d83ddc4dd83cdffb","d83ddc4dd83cdffc","d83ddc4dd83cdffd","d83ddc4dd83cdffe","d83ddc4dd83cdfff"],["d83ddc4e","d83ddc4ed83cdffb","d83ddc4ed83cdffc","d83ddc4ed83cdffd","d83ddc4ed83cdffe","d83ddc4ed83cdfff"],["270a","270ad83cdffb","270ad83cdffc","270ad83cdffd","270ad83cdffe","270ad83cdfff"],["d83ddc4a","d83ddc4ad83cdffb","d83ddc4ad83cdffc","d83ddc4ad83cdffd","d83ddc4ad83cdffe","d83ddc4ad83cdfff"],["d83edd1b","d83edd1bd83cdffb","d83edd1bd83cdffc","d83edd1bd83cdffd","d83edd1bd83cdffe","d83edd1bd83cdfff"],["d83edd1c","d83edd1cd83cdffb","d83edd1cd83cdffc","d83edd1cd83cdffd","d83edd1cd83cdffe","d83edd1cd83cdfff"],["d83ddc4f","d83ddc4fd83cdffb","d83ddc4fd83cdffc","d83ddc4fd83cdffd","d83ddc4fd83cdffe","d83ddc4fd83cdfff"],["d83dde4c","d83dde4cd83cdffb","d83dde4cd83cdffc","d83dde4cd83cdffd","d83dde4cd83cdffe","d83dde4cd83cdfff"],["d83edef6","d83edef6d83cdffb","d83edef6d83cdffc","d83edef6d83cdffd","d83edef6d83cdffe","d83edef6d83cdfff"],["d83ddc50","d83ddc50d83cdffb","d83ddc50d83cdffc","d83ddc50d83cdffd","d83ddc50d83cdffe","d83ddc50d83cdfff"],["d83edd32","d83edd32d83cdffb","d83edd32d83cdffc","d83edd32d83cdffd","d83edd32d83cdffe","d83edd32d83cdfff"],["d83edd1d","d83edd1dd83cdffb","d83edd1dd83cdffc","d83edd1dd83cdffd","d83edd1dd83cdffe","d83edd1dd83cdfff","d83edef1d83cdffb200dd83edef2d83cdffc","d83edef1d83cdffb200dd83edef2d83cdffd","d83edef1d83cdffb200dd83edef2d83cdffe","d83edef1d83cdffb200dd83edef2d83cdfff","d83edef1d83cdffc200dd83edef2d83cdffb","d83edef1d83cdffc200dd83edef2d83cdffd","d83edef1d83cdffc200dd83edef2d83cdffe","d83edef1d83cdffc200dd83edef2d83cdfff","d83edef1d83cdffd200dd83edef2d83cdffb","d83edef1d83cdffd200dd83edef2d83cdffc","d83edef1d83cdffd200dd83edef2d83cdffe","d83edef1d83cdffd200dd83edef2d83cdfff","d83edef1d83cdffe200dd83edef2d83cdffb","d83edef1d83cdffe200dd83edef2d83cdffc","d83edef1d83cdffe200dd83edef2d83cdffd","d83edef1d83cdffe200dd83edef2d83cdfff","d83edef1d83cdfff200dd83edef2d83cdffb","d83edef1d83cdfff200dd83edef2d83cdffc","d83edef1d83cdfff200dd83edef2d83cdffd","d83edef1d83cdfff200dd83edef2d83cdffe"],["d83dde4f","d83dde4fd83cdffb","d83dde4fd83cdffc","d83dde4fd83cdffd","d83dde4fd83cdffe","d83dde4fd83cdfff"],["270dfe0f","270dd83cdffb","270dd83cdffc","270dd83cdffd","270dd83cdffe","270dd83cdfff"],["d83ddc85","d83ddc85d83cdffb","d83ddc85d83cdffc","d83ddc85d83cdffd","d83ddc85d83cdffe","d83ddc85d83cdfff"],["d83edd33","d83edd33d83cdffb","d83edd33d83cdffc","d83edd33d83cdffd","d83edd33d83cdffe","d83edd33d83cdfff"],["d83ddcaa","d83ddcaad83cdffb","d83ddcaad83cdffc","d83ddcaad83cdffd","d83ddcaad83cdffe","d83ddcaad83cdfff"],["d83eddbe"],["d83eddbf"],["d83eddb5","d83eddb5d83cdffb","d83eddb5d83cdffc","d83eddb5d83cdffd","d83eddb5d83cdffe","d83eddb5d83cdfff"],["d83eddb6","d83eddb6d83cdffb","d83eddb6d83cdffc","d83eddb6d83cdffd","d83eddb6d83cdffe","d83eddb6d83cdfff"],["d83ddc42","d83ddc42d83cdffb","d83ddc42d83cdffc","d83ddc42d83cdffd","d83ddc42d83cdffe","d83ddc42d83cdfff"],["d83eddbb","d83eddbbd83cdffb","d83eddbbd83cdffc","d83eddbbd83cdffd","d83eddbbd83cdffe","d83eddbbd83cdfff"],["d83ddc43","d83ddc43d83cdffb","d83ddc43d83cdffc","d83ddc43d83cdffd","d83ddc43d83cdffe","d83ddc43d83cdfff"],["d83edde0"],["d83edec0"],["d83edec1"],["d83eddb7"],["d83eddb4"],["d83ddc40"],["d83ddc41fe0f"],["d83ddc45"],["d83ddc44"],["d83edee6"],["d83ddc76","d83ddc76d83cdffb","d83ddc76d83cdffc","d83ddc76d83cdffd","d83ddc76d83cdffe","d83ddc76d83cdfff"],["d83eddd2","d83eddd2d83cdffb","d83eddd2d83cdffc","d83eddd2d83cdffd","d83eddd2d83cdffe","d83eddd2d83cdfff"]],"People_2":[["d83ddc66","d83ddc66d83cdffb","d83ddc66d83cdffc","d83ddc66d83cdffd","d83ddc66d83cdffe","d83ddc66d83cdfff"],["d83ddc67","d83ddc67d83cdffb","d83ddc67d83cdffc","d83ddc67d83cdffd","d83ddc67d83cdffe","d83ddc67d83cdfff"],["d83eddd1","d83eddd1d83cdffb","d83eddd1d83cdffc","d83eddd1d83cdffd","d83eddd1d83cdffe","d83eddd1d83cdfff"],["d83ddc71","d83ddc71d83cdffb","d83ddc71d83cdffc","d83ddc71d83cdffd","d83ddc71d83cdffe","d83ddc71d83cdfff"],["d83ddc68","d83ddc68d83cdffb","d83ddc68d83cdffc","d83ddc68d83cdffd","d83ddc68d83cdffe","d83ddc68d83cdfff"],["d83eddd4","d83eddd4d83cdffb","d83eddd4d83cdffc","d83eddd4d83cdffd","d83eddd4d83cdffe","d83eddd4d83cdfff"],["d83eddd4200d2642fe0f","d83eddd4d83cdffb200d2642fe0f","d83eddd4d83cdffc200d2642fe0f","d83eddd4d83cdffd200d2642fe0f","d83eddd4d83cdffe200d2642fe0f","d83eddd4d83cdfff200d2642fe0f"],["d83eddd4200d2640fe0f","d83eddd4d83cdffb200d2640fe0f","d83eddd4d83cdffc200d2640fe0f","d83eddd4d83cdffd200d2640fe0f","d83eddd4d83cdffe200d2640fe0f","d83eddd4d83cdfff200d2640fe0f"],["d83ddc68200dd83eddb0","d83ddc68d83cdffb200dd83eddb0","d83ddc68d83cdffc200dd83eddb0","d83ddc68d83cdffd200dd83eddb0","d83ddc68d83cdffe200dd83eddb0","d83ddc68d83cdfff200dd83eddb0"],["d83ddc68200dd83eddb1","d83ddc68d83cdffb200dd83eddb1","d83ddc68d83cdffc200dd83eddb1","d83ddc68d83cdffd200dd83eddb1","d83ddc68d83cdffe200dd83eddb1","d83ddc68d83cdfff200dd83eddb1"],["d83ddc68200dd83eddb3","d83ddc68d83cdffb200dd83eddb3","d83ddc68d83cdffc200dd83eddb3","d83ddc68d83cdffd200dd83eddb3","d83ddc68d83cdffe200dd83eddb3","d83ddc68d83cdfff200dd83eddb3"],["d83ddc68200dd83eddb2","d83ddc68d83cdffb200dd83eddb2","d83ddc68d83cdffc200dd83eddb2","d83ddc68d83cdffd200dd83eddb2","d83ddc68d83cdffe200dd83eddb2","d83ddc68d83cdfff200dd83eddb2"],["d83ddc69","d83ddc69d83cdffb","d83ddc69d83cdffc","d83ddc69d83cdffd","d83ddc69d83cdffe","d83ddc69d83cdfff"],["d83ddc69200dd83eddb0","d83ddc69d83cdffb200dd83eddb0","d83ddc69d83cdffc200dd83eddb0","d83ddc69d83cdffd200dd83eddb0","d83ddc69d83cdffe200dd83eddb0","d83ddc69d83cdfff200dd83eddb0"],["d83eddd1200dd83eddb0","d83eddd1d83cdffb200dd83eddb0","d83eddd1d83cdffc200dd83eddb0","d83eddd1d83cdffd200dd83eddb0","d83eddd1d83cdffe200dd83eddb0","d83eddd1d83cdfff200dd83eddb0"],["d83ddc69200dd83eddb1","d83ddc69d83cdffb200dd83eddb1","d83ddc69d83cdffc200dd83eddb1","d83ddc69d83cdffd200dd83eddb1","d83ddc69d83cdffe200dd83eddb1","d83ddc69d83cdfff200dd83eddb1"],["d83eddd1200dd83eddb1","d83eddd1d83cdffb200dd83eddb1","d83eddd1d83cdffc200dd83eddb1","d83eddd1d83cdffd200dd83eddb1","d83eddd1d83cdffe200dd83eddb1","d83eddd1d83cdfff200dd83eddb1"],["d83ddc69200dd83eddb3","d83ddc69d83cdffb200dd83eddb3","d83ddc69d83cdffc200dd83eddb3","d83ddc69d83cdffd200dd83eddb3","d83ddc69d83cdffe200dd83eddb3","d83ddc69d83cdfff200dd83eddb3"],["d83eddd1200dd83eddb3","d83eddd1d83cdffb200dd83eddb3","d83eddd1d83cdffc200dd83eddb3","d83eddd1d83cdffd200dd83eddb3","d83eddd1d83cdffe200dd83eddb3","d83eddd1d83cdfff200dd83eddb3"],["d83ddc69200dd83eddb2","d83ddc69d83cdffb200dd83eddb2","d83ddc69d83cdffc200dd83eddb2","d83ddc69d83cdffd200dd83eddb2","d83ddc69d83cdffe200dd83eddb2","d83ddc69d83cdfff200dd83eddb2"],["d83eddd1200dd83eddb2","d83eddd1d83cdffb200dd83eddb2","d83eddd1d83cdffc200dd83eddb2","d83eddd1d83cdffd200dd83eddb2","d83eddd1d83cdffe200dd83eddb2","d83eddd1d83cdfff200dd83eddb2"],["d83ddc71200d2640fe0f","d83ddc71d83cdffb200d2640fe0f","d83ddc71d83cdffc200d2640fe0f","d83ddc71d83cdffd200d2640fe0f","d83ddc71d83cdffe200d2640fe0f","d83ddc71d83cdfff200d2640fe0f"],["d83ddc71200d2642fe0f","d83ddc71d83cdffb200d2642fe0f","d83ddc71d83cdffc200d2642fe0f","d83ddc71d83cdffd200d2642fe0f","d83ddc71d83cdffe200d2642fe0f","d83ddc71d83cdfff200d2642fe0f"],["d83eddd3","d83eddd3d83cdffb","d83eddd3d83cdffc","d83eddd3d83cdffd","d83eddd3d83cdffe","d83eddd3d83cdfff"],["d83ddc74","d83ddc74d83cdffb","d83ddc74d83cdffc","d83ddc74d83cdffd","d83ddc74d83cdffe","d83ddc74d83cdfff"],["d83ddc75","d83ddc75d83cdffb","d83ddc75d83cdffc","d83ddc75d83cdffd","d83ddc75d83cdffe","d83ddc75d83cdfff"],["d83dde4d","d83dde4dd83cdffb","d83dde4dd83cdffc","d83dde4dd83cdffd","d83dde4dd83cdffe","d83dde4dd83cdfff"],["d83dde4d200d2642fe0f","d83dde4dd83cdffb200d2642fe0f","d83dde4dd83cdffc200d2642fe0f","d83dde4dd83cdffd200d2642fe0f","d83dde4dd83cdffe200d2642fe0f","d83dde4dd83cdfff200d2642fe0f"],["d83dde4d200d2640fe0f","d83dde4dd83cdffb200d2640fe0f","d83dde4dd83cdffc200d2640fe0f","d83dde4dd83cdffd200d2640fe0f","d83dde4dd83cdffe200d2640fe0f","d83dde4dd83cdfff200d2640fe0f"],["d83dde4e","d83dde4ed83cdffb","d83dde4ed83cdffc","d83dde4ed83cdffd","d83dde4ed83cdffe","d83dde4ed83cdfff"],["d83dde4e200d2642fe0f","d83dde4ed83cdffb200d2642fe0f","d83dde4ed83cdffc200d2642fe0f","d83dde4ed83cdffd200d2642fe0f","d83dde4ed83cdffe200d2642fe0f","d83dde4ed83cdfff200d2642fe0f"],["d83dde4e200d2640fe0f","d83dde4ed83cdffb200d2640fe0f","d83dde4ed83cdffc200d2640fe0f","d83dde4ed83cdffd200d2640fe0f","d83dde4ed83cdffe200d2640fe0f","d83dde4ed83cdfff200d2640fe0f"],["d83dde45","d83dde45d83cdffb","d83dde45d83cdffc","d83dde45d83cdffd","d83dde45d83cdffe","d83dde45d83cdfff"],["d83dde45200d2642fe0f","d83dde45d83cdffb200d2642fe0f","d83dde45d83cdffc200d2642fe0f","d83dde45d83cdffd200d2642fe0f","d83dde45d83cdffe200d2642fe0f","d83dde45d83cdfff200d2642fe0f"],["d83dde45200d2640fe0f","d83dde45d83cdffb200d2640fe0f","d83dde45d83cdffc200d2640fe0f","d83dde45d83cdffd200d2640fe0f","d83dde45d83cdffe200d2640fe0f","d83dde45d83cdfff200d2640fe0f"],["d83dde46","d83dde46d83cdffb","d83dde46d83cdffc","d83dde46d83cdffd","d83dde46d83cdffe","d83dde46d83cdfff"],["d83dde46200d2642fe0f","d83dde46d83cdffb200d2642fe0f","d83dde46d83cdffc200d2642fe0f","d83dde46d83cdffd200d2642fe0f","d83dde46d83cdffe200d2642fe0f","d83dde46d83cdfff200d2642fe0f"],["d83dde46200d2640fe0f","d83dde46d83cdffb200d2640fe0f","d83dde46d83cdffc200d2640fe0f","d83dde46d83cdffd200d2640fe0f","d83dde46d83cdffe200d2640fe0f","d83dde46d83cdfff200d2640fe0f"],["d83ddc81","d83ddc81d83cdffb","d83ddc81d83cdffc","d83ddc81d83cdffd","d83ddc81d83cdffe","d83ddc81d83cdfff"],["d83ddc81200d2642fe0f","d83ddc81d83cdffb200d2642fe0f","d83ddc81d83cdffc200d2642fe0f","d83ddc81d83cdffd200d2642fe0f","d83ddc81d83cdffe200d2642fe0f","d83ddc81d83cdfff200d2642fe0f"],["d83ddc81200d2640fe0f","d83ddc81d83cdffb200d2640fe0f","d83ddc81d83cdffc200d2640fe0f","d83ddc81d83cdffd200d2640fe0f","d83ddc81d83cdffe200d2640fe0f","d83ddc81d83cdfff200d2640fe0f"],["d83dde4b","d83dde4bd83cdffb","d83dde4bd83cdffc","d83dde4bd83cdffd","d83dde4bd83cdffe","d83dde4bd83cdfff"]],"People_3":[["d83dde4b200d2642fe0f","d83dde4bd83cdffb200d2642fe0f","d83dde4bd83cdffc200d2642fe0f","d83dde4bd83cdffd200d2642fe0f","d83dde4bd83cdffe200d2642fe0f","d83dde4bd83cdfff200d2642fe0f"],["d83dde4b200d2640fe0f","d83dde4bd83cdffb200d2640fe0f","d83dde4bd83cdffc200d2640fe0f","d83dde4bd83cdffd200d2640fe0f","d83dde4bd83cdffe200d2640fe0f","d83dde4bd83cdfff200d2640fe0f"],["d83eddcf","d83eddcfd83cdffb","d83eddcfd83cdffc","d83eddcfd83cdffd","d83eddcfd83cdffe","d83eddcfd83cdfff"],["d83eddcf200d2642fe0f","d83eddcfd83cdffb200d2642fe0f","d83eddcfd83cdffc200d2642fe0f","d83eddcfd83cdffd200d2642fe0f","d83eddcfd83cdffe200d2642fe0f","d83eddcfd83cdfff200d2642fe0f"],["d83eddcf200d2640fe0f","d83eddcfd83cdffb200d2640fe0f","d83eddcfd83cdffc200d2640fe0f","d83eddcfd83cdffd200d2640fe0f","d83eddcfd83cdffe200d2640fe0f","d83eddcfd83cdfff200d2640fe0f"],["d83dde47","d83dde47d83cdffb","d83dde47d83cdffc","d83dde47d83cdffd","d83dde47d83cdffe","d83dde47d83cdfff"],["d83dde47200d2642fe0f","d83dde47d83cdffb200d2642fe0f","d83dde47d83cdffc200d2642fe0f","d83dde47d83cdffd200d2642fe0f","d83dde47d83cdffe200d2642fe0f","d83dde47d83cdfff200d2642fe0f"],["d83dde47200d2640fe0f","d83dde47d83cdffb200d2640fe0f","d83dde47d83cdffc200d2640fe0f","d83dde47d83cdffd200d2640fe0f","d83dde47d83cdffe200d2640fe0f","d83dde47d83cdfff200d2640fe0f"],["d83edd26","d83edd26d83cdffb","d83edd26d83cdffc","d83edd26d83cdffd","d83edd26d83cdffe","d83edd26d83cdfff"],["d83edd26200d2642fe0f","d83edd26d83cdffb200d2642fe0f","d83edd26d83cdffc200d2642fe0f","d83edd26d83cdffd200d2642fe0f","d83edd26d83cdffe200d2642fe0f","d83edd26d83cdfff200d2642fe0f"],["d83edd26200d2640fe0f","d83edd26d83cdffb200d2640fe0f","d83edd26d83cdffc200d2640fe0f","d83edd26d83cdffd200d2640fe0f","d83edd26d83cdffe200d2640fe0f","d83edd26d83cdfff200d2640fe0f"],["d83edd37","d83edd37d83cdffb","d83edd37d83cdffc","d83edd37d83cdffd","d83edd37d83cdffe","d83edd37d83cdfff"],["d83edd37200d2642fe0f","d83edd37d83cdffb200d2642fe0f","d83edd37d83cdffc200d2642fe0f","d83edd37d83cdffd200d2642fe0f","d83edd37d83cdffe200d2642fe0f","d83edd37d83cdfff200d2642fe0f"],["d83edd37200d2640fe0f","d83edd37d83cdffb200d2640fe0f","d83edd37d83cdffc200d2640fe0f","d83edd37d83cdffd200d2640fe0f","d83edd37d83cdffe200d2640fe0f","d83edd37d83cdfff200d2640fe0f"],["d83eddd1200d2695fe0f","d83eddd1d83cdffb200d2695fe0f","d83eddd1d83cdffc200d2695fe0f","d83eddd1d83cdffd200d2695fe0f","d83eddd1d83cdffe200d2695fe0f","d83eddd1d83cdfff200d2695fe0f"],["d83ddc68200d2695fe0f","d83ddc68d83cdffb200d2695fe0f","d83ddc68d83cdffc200d2695fe0f","d83ddc68d83cdffd200d2695fe0f","d83ddc68d83cdffe200d2695fe0f","d83ddc68d83cdfff200d2695fe0f"],["d83ddc69200d2695fe0f","d83ddc69d83cdffb200d2695fe0f","d83ddc69d83cdffc200d2695fe0f","d83ddc69d83cdffd200d2695fe0f","d83ddc69d83cdffe200d2695fe0f","d83ddc69d83cdfff200d2695fe0f"],["d83eddd1200dd83cdf93","d83eddd1d83cdffb200dd83cdf93","d83eddd1d83cdffc200dd83cdf93","d83eddd1d83cdffd200dd83cdf93","d83eddd1d83cdffe200dd83cdf93","d83eddd1d83cdfff200dd83cdf93"],["d83ddc68200dd83cdf93","d83ddc68d83cdffb200dd83cdf93","d83ddc68d83cdffc200dd83cdf93","d83ddc68d83cdffd200dd83cdf93","d83ddc68d83cdffe200dd83cdf93","d83ddc68d83cdfff200dd83cdf93"],["d83ddc69200dd83cdf93","d83ddc69d83cdffb200dd83cdf93","d83ddc69d83cdffc200dd83cdf93","d83ddc69d83cdffd200dd83cdf93","d83ddc69d83cdffe200dd83cdf93","d83ddc69d83cdfff200dd83cdf93"],["d83eddd1200dd83cdfeb","d83eddd1d83cdffb200dd83cdfeb","d83eddd1d83cdffc200dd83cdfeb","d83eddd1d83cdffd200dd83cdfeb","d83eddd1d83cdffe200dd83cdfeb","d83eddd1d83cdfff200dd83cdfeb"],["d83ddc68200dd83cdfeb","d83ddc68d83cdffb200dd83cdfeb","d83ddc68d83cdffc200dd83cdfeb","d83ddc68d83cdffd200dd83cdfeb","d83ddc68d83cdffe200dd83cdfeb","d83ddc68d83cdfff200dd83cdfeb"],["d83ddc69200dd83cdfeb","d83ddc69d83cdffb200dd83cdfeb","d83ddc69d83cdffc200dd83cdfeb","d83ddc69d83cdffd200dd83cdfeb","d83ddc69d83cdffe200dd83cdfeb","d83ddc69d83cdfff200dd83cdfeb"],["d83eddd1200d2696fe0f","d83eddd1d83cdffb200d2696fe0f","d83eddd1d83cdffc200d2696fe0f","d83eddd1d83cdffd200d2696fe0f","d83eddd1d83cdffe200d2696fe0f","d83eddd1d83cdfff200d2696fe0f"],["d83ddc68200d2696fe0f","d83ddc68d83cdffb200d2696fe0f","d83ddc68d83cdffc200d2696fe0f","d83ddc68d83cdffd200d2696fe0f","d83ddc68d83cdffe200d2696fe0f","d83ddc68d83cdfff200d2696fe0f"],["d83ddc69200d2696fe0f","d83ddc69d83cdffb200d2696fe0f","d83ddc69d83cdffc200d2696fe0f","d83ddc69d83cdffd200d2696fe0f","d83ddc69d83cdffe200d2696fe0f","d83ddc69d83cdfff200d2696fe0f"],["d83eddd1200dd83cdf3e","d83eddd1d83cdffb200dd83cdf3e","d83eddd1d83cdffc200dd83cdf3e","d83eddd1d83cdffd200dd83cdf3e","d83eddd1d83cdffe200dd83cdf3e","d83eddd1d83cdfff200dd83cdf3e"],["d83ddc68200dd83cdf3e","d83ddc68d83cdffb200dd83cdf3e","d83ddc68d83cdffc200dd83cdf3e","d83ddc68d83cdffd200dd83cdf3e","d83ddc68d83cdffe200dd83cdf3e","d83ddc68d83cdfff200dd83cdf3e"],["d83ddc69200dd83cdf3e","d83ddc69d83cdffb200dd83cdf3e","d83ddc69d83cdffc200dd83cdf3e","d83ddc69d83cdffd200dd83cdf3e","d83ddc69d83cdffe200dd83cdf3e","d83ddc69d83cdfff200dd83cdf3e"],["d83eddd1200dd83cdf73","d83eddd1d83cdffb200dd83cdf73","d83eddd1d83cdffc200dd83cdf73","d83eddd1d83cdffd200dd83cdf73","d83eddd1d83cdffe200dd83cdf73","d83eddd1d83cdfff200dd83cdf73"],["d83ddc68200dd83cdf73","d83ddc68d83cdffb200dd83cdf73","d83ddc68d83cdffc200dd83cdf73","d83ddc68d83cdffd200dd83cdf73","d83ddc68d83cdffe200dd83cdf73","d83ddc68d83cdfff200dd83cdf73"],["d83ddc69200dd83cdf73","d83ddc69d83cdffb200dd83cdf73","d83ddc69d83cdffc200dd83cdf73","d83ddc69d83cdffd200dd83cdf73","d83ddc69d83cdffe200dd83cdf73","d83ddc69d83cdfff200dd83cdf73"],["d83eddd1200dd83ddd27","d83eddd1d83cdffb200dd83ddd27","d83eddd1d83cdffc200dd83ddd27","d83eddd1d83cdffd200dd83ddd27","d83eddd1d83cdffe200dd83ddd27","d83eddd1d83cdfff200dd83ddd27"],["d83ddc68200dd83ddd27","d83ddc68d83cdffb200dd83ddd27","d83ddc68d83cdffc200dd83ddd27","d83ddc68d83cdffd200dd83ddd27","d83ddc68d83cdffe200dd83ddd27","d83ddc68d83cdfff200dd83ddd27"],["d83ddc69200dd83ddd27","d83ddc69d83cdffb200dd83ddd27","d83ddc69d83cdffc200dd83ddd27","d83ddc69d83cdffd200dd83ddd27","d83ddc69d83cdffe200dd83ddd27","d83ddc69d83cdfff200dd83ddd27"],["d83eddd1200dd83cdfed","d83eddd1d83cdffb200dd83cdfed","d83eddd1d83cdffc200dd83cdfed","d83eddd1d83cdffd200dd83cdfed","d83eddd1d83cdffe200dd83cdfed","d83eddd1d83cdfff200dd83cdfed"],["d83ddc68200dd83cdfed","d83ddc68d83cdffb200dd83cdfed","d83ddc68d83cdffc200dd83cdfed","d83ddc68d83cdffd200dd83cdfed","d83ddc68d83cdffe200dd83cdfed","d83ddc68d83cdfff200dd83cdfed"],["d83ddc69200dd83cdfed","d83ddc69d83cdffb200dd83cdfed","d83ddc69d83cdffc200dd83cdfed","d83ddc69d83cdffd200dd83cdfed","d83ddc69d83cdffe200dd83cdfed","d83ddc69d83cdfff200dd83cdfed"],["d83eddd1200dd83ddcbc","d83eddd1d83cdffb200dd83ddcbc","d83eddd1d83cdffc200dd83ddcbc","d83eddd1d83cdffd200dd83ddcbc","d83eddd1d83cdffe200dd83ddcbc","d83eddd1d83cdfff200dd83ddcbc"],["d83ddc68200dd83ddcbc","d83ddc68d83cdffb200dd83ddcbc","d83ddc68d83cdffc200dd83ddcbc","d83ddc68d83cdffd200dd83ddcbc","d83ddc68d83cdffe200dd83ddcbc","d83ddc68d83cdfff200dd83ddcbc"],["d83ddc69200dd83ddcbc","d83ddc69d83cdffb200dd83ddcbc","d83ddc69d83cdffc200dd83ddcbc","d83ddc69d83cdffd200dd83ddcbc","d83ddc69d83cdffe200dd83ddcbc","d83ddc69d83cdfff200dd83ddcbc"],["d83eddd1200dd83ddd2c","d83eddd1d83cdffb200dd83ddd2c","d83eddd1d83cdffc200dd83ddd2c","d83eddd1d83cdffd200dd83ddd2c","d83eddd1d83cdffe200dd83ddd2c","d83eddd1d83cdfff200dd83ddd2c"]],"People_4":[["d83ddc68200dd83ddd2c","d83ddc68d83cdffb200dd83ddd2c","d83ddc68d83cdffc200dd83ddd2c","d83ddc68d83cdffd200dd83ddd2c","d83ddc68d83cdffe200dd83ddd2c","d83ddc68d83cdfff200dd83ddd2c"],["d83ddc69200dd83ddd2c","d83ddc69d83cdffb200dd83ddd2c","d83ddc69d83cdffc200dd83ddd2c","d83ddc69d83cdffd200dd83ddd2c","d83ddc69d83cdffe200dd83ddd2c","d83ddc69d83cdfff200dd83ddd2c"],["d83eddd1200dd83ddcbb","d83eddd1d83cdffb200dd83ddcbb","d83eddd1d83cdffc200dd83ddcbb","d83eddd1d83cdffd200dd83ddcbb","d83eddd1d83cdffe200dd83ddcbb","d83eddd1d83cdfff200dd83ddcbb"],["d83ddc68200dd83ddcbb","d83ddc68d83cdffb200dd83ddcbb","d83ddc68d83cdffc200dd83ddcbb","d83ddc68d83cdffd200dd83ddcbb","d83ddc68d83cdffe200dd83ddcbb","d83ddc68d83cdfff200dd83ddcbb"],["d83ddc69200dd83ddcbb","d83ddc69d83cdffb200dd83ddcbb","d83ddc69d83cdffc200dd83ddcbb","d83ddc69d83cdffd200dd83ddcbb","d83ddc69d83cdffe200dd83ddcbb","d83ddc69d83cdfff200dd83ddcbb"],["d83eddd1200dd83cdfa4","d83eddd1d83cdffb200dd83cdfa4","d83eddd1d83cdffc200dd83cdfa4","d83eddd1d83cdffd200dd83cdfa4","d83eddd1d83cdffe200dd83cdfa4","d83eddd1d83cdfff200dd83cdfa4"],["d83ddc68200dd83cdfa4","d83ddc68d83cdffb200dd83cdfa4","d83ddc68d83cdffc200dd83cdfa4","d83ddc68d83cdffd200dd83cdfa4","d83ddc68d83cdffe200dd83cdfa4","d83ddc68d83cdfff200dd83cdfa4"],["d83ddc69200dd83cdfa4","d83ddc69d83cdffb200dd83cdfa4","d83ddc69d83cdffc200dd83cdfa4","d83ddc69d83cdffd200dd83cdfa4","d83ddc69d83cdffe200dd83cdfa4","d83ddc69d83cdfff200dd83cdfa4"],["d83eddd1200dd83cdfa8","d83eddd1d83cdffb200dd83cdfa8","d83eddd1d83cdffc200dd83cdfa8","d83eddd1d83cdffd200dd83cdfa8","d83eddd1d83cdffe200dd83cdfa8","d83eddd1d83cdfff200dd83cdfa8"],["d83ddc68200dd83cdfa8","d83ddc68d83cdffb200dd83cdfa8","d83ddc68d83cdffc200dd83cdfa8","d83ddc68d83cdffd200dd83cdfa8","d83ddc68d83cdffe200dd83cdfa8","d83ddc68d83cdfff200dd83cdfa8"],["d83ddc69200dd83cdfa8","d83ddc69d83cdffb200dd83cdfa8","d83ddc69d83cdffc200dd83cdfa8","d83ddc69d83cdffd200dd83cdfa8","d83ddc69d83cdffe200dd83cdfa8","d83ddc69d83cdfff200dd83cdfa8"],["d83eddd1200d2708fe0f","d83eddd1d83cdffb200d2708fe0f","d83eddd1d83cdffc200d2708fe0f","d83eddd1d83cdffd200d2708fe0f","d83eddd1d83cdffe200d2708fe0f","d83eddd1d83cdfff200d2708fe0f"],["d83ddc68200d2708fe0f","d83ddc68d83cdffb200d2708fe0f","d83ddc68d83cdffc200d2708fe0f","d83ddc68d83cdffd200d2708fe0f","d83ddc68d83cdffe200d2708fe0f","d83ddc68d83cdfff200d2708fe0f"],["d83ddc69200d2708fe0f","d83ddc69d83cdffb200d2708fe0f","d83ddc69d83cdffc200d2708fe0f","d83ddc69d83cdffd200d2708fe0f","d83ddc69d83cdffe200d2708fe0f","d83ddc69d83cdfff200d2708fe0f"],["d83eddd1200dd83dde80","d83eddd1d83cdffb200dd83dde80","d83eddd1d83cdffc200dd83dde80","d83eddd1d83cdffd200dd83dde80","d83eddd1d83cdffe200dd83dde80","d83eddd1d83cdfff200dd83dde80"],["d83ddc68200dd83dde80","d83ddc68d83cdffb200dd83dde80","d83ddc68d83cdffc200dd83dde80","d83ddc68d83cdffd200dd83dde80","d83ddc68d83cdffe200dd83dde80","d83ddc68d83cdfff200dd83dde80"],["d83ddc69200dd83dde80","d83ddc69d83cdffb200dd83dde80","d83ddc69d83cdffc200dd83dde80","d83ddc69d83cdffd200dd83dde80","d83ddc69d83cdffe200dd83dde80","d83ddc69d83cdfff200dd83dde80"],["d83eddd1200dd83dde92","d83eddd1d83cdffb200dd83dde92","d83eddd1d83cdffc200dd83dde92","d83eddd1d83cdffd200dd83dde92","d83eddd1d83cdffe200dd83dde92","d83eddd1d83cdfff200dd83dde92"],["d83ddc68200dd83dde92","d83ddc68d83cdffb200dd83dde92","d83ddc68d83cdffc200dd83dde92","d83ddc68d83cdffd200dd83dde92","d83ddc68d83cdffe200dd83dde92","d83ddc68d83cdfff200dd83dde92"],["d83ddc69200dd83dde92","d83ddc69d83cdffb200dd83dde92","d83ddc69d83cdffc200dd83dde92","d83ddc69d83cdffd200dd83dde92","d83ddc69d83cdffe200dd83dde92","d83ddc69d83cdfff200dd83dde92"],["d83ddc6e","d83ddc6ed83cdffb","d83ddc6ed83cdffc","d83ddc6ed83cdffd","d83ddc6ed83cdffe","d83ddc6ed83cdfff"],["d83ddc6e200d2642fe0f","d83ddc6ed83cdffb200d2642fe0f","d83ddc6ed83cdffc200d2642fe0f","d83ddc6ed83cdffd200d2642fe0f","d83ddc6ed83cdffe200d2642fe0f","d83ddc6ed83cdfff200d2642fe0f"],["d83ddc6e200d2640fe0f","d83ddc6ed83cdffb200d2640fe0f","d83ddc6ed83cdffc200d2640fe0f","d83ddc6ed83cdffd200d2640fe0f","d83ddc6ed83cdffe200d2640fe0f","d83ddc6ed83cdfff200d2640fe0f"],["d83ddd75fe0f","d83ddd75d83cdffb","d83ddd75d83cdffc","d83ddd75d83cdffd","d83ddd75d83cdffe","d83ddd75d83cdfff"],["d83ddd75fe0f200d2642fe0f","d83ddd75d83cdffb200d2642fe0f","d83ddd75d83cdffc200d2642fe0f","d83ddd75d83cdffd200d2642fe0f","d83ddd75d83cdffe200d2642fe0f","d83ddd75d83cdfff200d2642fe0f"],["d83ddd75fe0f200d2640fe0f","d83ddd75d83cdffb200d2640fe0f","d83ddd75d83cdffc200d2640fe0f","d83ddd75d83cdffd200d2640fe0f","d83ddd75d83cdffe200d2640fe0f","d83ddd75d83cdfff200d2640fe0f"],["d83ddc82","d83ddc82d83cdffb","d83ddc82d83cdffc","d83ddc82d83cdffd","d83ddc82d83cdffe","d83ddc82d83cdfff"],["d83ddc82200d2642fe0f","d83ddc82d83cdffb200d2642fe0f","d83ddc82d83cdffc200d2642fe0f","d83ddc82d83cdffd200d2642fe0f","d83ddc82d83cdffe200d2642fe0f","d83ddc82d83cdfff200d2642fe0f"],["d83ddc82200d2640fe0f","d83ddc82d83cdffb200d2640fe0f","d83ddc82d83cdffc200d2640fe0f","d83ddc82d83cdffd200d2640fe0f","d83ddc82d83cdffe200d2640fe0f","d83ddc82d83cdfff200d2640fe0f"],["d83edd77","d83edd77d83cdffb","d83edd77d83cdffc","d83edd77d83cdffd","d83edd77d83cdffe","d83edd77d83cdfff"],["d83ddc77","d83ddc77d83cdffb","d83ddc77d83cdffc","d83ddc77d83cdffd","d83ddc77d83cdffe","d83ddc77d83cdfff"],["d83ddc77200d2642fe0f","d83ddc77d83cdffb200d2642fe0f","d83ddc77d83cdffc200d2642fe0f","d83ddc77d83cdffd200d2642fe0f","d83ddc77d83cdffe200d2642fe0f","d83ddc77d83cdfff200d2642fe0f"],["d83ddc77200d2640fe0f","d83ddc77d83cdffb200d2640fe0f","d83ddc77d83cdffc200d2640fe0f","d83ddc77d83cdffd200d2640fe0f","d83ddc77d83cdffe200d2640fe0f","d83ddc77d83cdfff200d2640fe0f"],["d83edec5","d83edec5d83cdffb","d83edec5d83cdffc","d83edec5d83cdffd","d83edec5d83cdffe","d83edec5d83cdfff"],["d83edd34","d83edd34d83cdffb","d83edd34d83cdffc","d83edd34d83cdffd","d83edd34d83cdffe","d83edd34d83cdfff"],["d83ddc78","d83ddc78d83cdffb","d83ddc78d83cdffc","d83ddc78d83cdffd","d83ddc78d83cdffe","d83ddc78d83cdfff"],["d83ddc73","d83ddc73d83cdffb","d83ddc73d83cdffc","d83ddc73d83cdffd","d83ddc73d83cdffe","d83ddc73d83cdfff"],["d83ddc73200d2642fe0f","d83ddc73d83cdffb200d2642fe0f","d83ddc73d83cdffc200d2642fe0f","d83ddc73d83cdffd200d2642fe0f","d83ddc73d83cdffe200d2642fe0f","d83ddc73d83cdfff200d2642fe0f"],["d83ddc73200d2640fe0f","d83ddc73d83cdffb200d2640fe0f","d83ddc73d83cdffc200d2640fe0f","d83ddc73d83cdffd200d2640fe0f","d83ddc73d83cdffe200d2640fe0f","d83ddc73d83cdfff200d2640fe0f"],["d83ddc72","d83ddc72d83cdffb","d83ddc72d83cdffc","d83ddc72d83cdffd","d83ddc72d83cdffe","d83ddc72d83cdfff"],["d83eddd5","d83eddd5d83cdffb","d83eddd5d83cdffc","d83eddd5d83cdffd","d83eddd5d83cdffe","d83eddd5d83cdfff"],["d83edd35","d83edd35d83cdffb","d83edd35d83cdffc","d83edd35d83cdffd","d83edd35d83cdffe","d83edd35d83cdfff"]],"People_5":[["d83edd35200d2642fe0f","d83edd35d83cdffb200d2642fe0f","d83edd35d83cdffc200d2642fe0f","d83edd35d83cdffd200d2642fe0f","d83edd35d83cdffe200d2642fe0f","d83edd35d83cdfff200d2642fe0f"],["d83edd35200d2640fe0f","d83edd35d83cdffb200d2640fe0f","d83edd35d83cdffc200d2640fe0f","d83edd35d83cdffd200d2640fe0f","d83edd35d83cdffe200d2640fe0f","d83edd35d83cdfff200d2640fe0f"],["d83ddc70","d83ddc70d83cdffb","d83ddc70d83cdffc","d83ddc70d83cdffd","d83ddc70d83cdffe","d83ddc70d83cdfff"],["d83ddc70200d2642fe0f","d83ddc70d83cdffb200d2642fe0f","d83ddc70d83cdffc200d2642fe0f","d83ddc70d83cdffd200d2642fe0f","d83ddc70d83cdffe200d2642fe0f","d83ddc70d83cdfff200d2642fe0f"],["d83ddc70200d2640fe0f","d83ddc70d83cdffb200d2640fe0f","d83ddc70d83cdffc200d2640fe0f","d83ddc70d83cdffd200d2640fe0f","d83ddc70d83cdffe200d2640fe0f","d83ddc70d83cdfff200d2640fe0f"],["d83edd30","d83edd30d83cdffb","d83edd30d83cdffc","d83edd30d83cdffd","d83edd30d83cdffe","d83edd30d83cdfff"],["d83edec3","d83edec3d83cdffb","d83edec3d83cdffc","d83edec3d83cdffd","d83edec3d83cdffe","d83edec3d83cdfff"],["d83edec4","d83edec4d83cdffb","d83edec4d83cdffc","d83edec4d83cdffd","d83edec4d83cdffe","d83edec4d83cdfff"],["d83edd31","d83edd31d83cdffb","d83edd31d83cdffc","d83edd31d83cdffd","d83edd31d83cdffe","d83edd31d83cdfff"],["d83ddc69200dd83cdf7c","d83ddc69d83cdffb200dd83cdf7c","d83ddc69d83cdffc200dd83cdf7c","d83ddc69d83cdffd200dd83cdf7c","d83ddc69d83cdffe200dd83cdf7c","d83ddc69d83cdfff200dd83cdf7c"],["d83ddc68200dd83cdf7c","d83ddc68d83cdffb200dd83cdf7c","d83ddc68d83cdffc200dd83cdf7c","d83ddc68d83cdffd200dd83cdf7c","d83ddc68d83cdffe200dd83cdf7c","d83ddc68d83cdfff200dd83cdf7c"],["d83eddd1200dd83cdf7c","d83eddd1d83cdffb200dd83cdf7c","d83eddd1d83cdffc200dd83cdf7c","d83eddd1d83cdffd200dd83cdf7c","d83eddd1d83cdffe200dd83cdf7c","d83eddd1d83cdfff200dd83cdf7c"],["d83ddc7c","d83ddc7cd83cdffb","d83ddc7cd83cdffc","d83ddc7cd83cdffd","d83ddc7cd83cdffe","d83ddc7cd83cdfff"],["d83cdf85","d83cdf85d83cdffb","d83cdf85d83cdffc","d83cdf85d83cdffd","d83cdf85d83cdffe","d83cdf85d83cdfff"],["d83edd36","d83edd36d83cdffb","d83edd36d83cdffc","d83edd36d83cdffd","d83edd36d83cdffe","d83edd36d83cdfff"],["d83eddd1200dd83cdf84","d83eddd1d83cdffb200dd83cdf84","d83eddd1d83cdffc200dd83cdf84","d83eddd1d83cdffd200dd83cdf84","d83eddd1d83cdffe200dd83cdf84","d83eddd1d83cdfff200dd83cdf84"],["d83eddb8","d83eddb8d83cdffb","d83eddb8d83cdffc","d83eddb8d83cdffd","d83eddb8d83cdffe","d83eddb8d83cdfff"],["d83eddb8200d2642fe0f","d83eddb8d83cdffb200d2642fe0f","d83eddb8d83cdffc200d2642fe0f","d83eddb8d83cdffd200d2642fe0f","d83eddb8d83cdffe200d2642fe0f","d83eddb8d83cdfff200d2642fe0f"],["d83eddb8200d2640fe0f","d83eddb8d83cdffb200d2640fe0f","d83eddb8d83cdffc200d2640fe0f","d83eddb8d83cdffd200d2640fe0f","d83eddb8d83cdffe200d2640fe0f","d83eddb8d83cdfff200d2640fe0f"],["d83eddb9","d83eddb9d83cdffb","d83eddb9d83cdffc","d83eddb9d83cdffd","d83eddb9d83cdffe","d83eddb9d83cdfff"],["d83eddb9200d2642fe0f","d83eddb9d83cdffb200d2642fe0f","d83eddb9d83cdffc200d2642fe0f","d83eddb9d83cdffd200d2642fe0f","d83eddb9d83cdffe200d2642fe0f","d83eddb9d83cdfff200d2642fe0f"],["d83eddb9200d2640fe0f","d83eddb9d83cdffb200d2640fe0f","d83eddb9d83cdffc200d2640fe0f","d83eddb9d83cdffd200d2640fe0f","d83eddb9d83cdffe200d2640fe0f","d83eddb9d83cdfff200d2640fe0f"],["d83eddd9","d83eddd9d83cdffb","d83eddd9d83cdffc","d83eddd9d83cdffd","d83eddd9d83cdffe","d83eddd9d83cdfff"],["d83eddd9200d2642fe0f","d83eddd9d83cdffb200d2642fe0f","d83eddd9d83cdffc200d2642fe0f","d83eddd9d83cdffd200d2642fe0f","d83eddd9d83cdffe200d2642fe0f","d83eddd9d83cdfff200d2642fe0f"],["d83eddd9200d2640fe0f","d83eddd9d83cdffb200d2640fe0f","d83eddd9d83cdffc200d2640fe0f","d83eddd9d83cdffd200d2640fe0f","d83eddd9d83cdffe200d2640fe0f","d83eddd9d83cdfff200d2640fe0f"],["d83eddda","d83edddad83cdffb","d83edddad83cdffc","d83edddad83cdffd","d83edddad83cdffe","d83edddad83cdfff"],["d83eddda200d2642fe0f","d83edddad83cdffb200d2642fe0f","d83edddad83cdffc200d2642fe0f","d83edddad83cdffd200d2642fe0f","d83edddad83cdffe200d2642fe0f","d83edddad83cdfff200d2642fe0f"],["d83eddda200d2640fe0f","d83edddad83cdffb200d2640fe0f","d83edddad83cdffc200d2640fe0f","d83edddad83cdffd200d2640fe0f","d83edddad83cdffe200d2640fe0f","d83edddad83cdfff200d2640fe0f"],["d83edddb","d83edddbd83cdffb","d83edddbd83cdffc","d83edddbd83cdffd","d83edddbd83cdffe","d83edddbd83cdfff"],["d83edddb200d2642fe0f","d83edddbd83cdffb200d2642fe0f","d83edddbd83cdffc200d2642fe0f","d83edddbd83cdffd200d2642fe0f","d83edddbd83cdffe200d2642fe0f","d83edddbd83cdfff200d2642fe0f"],["d83edddb200d2640fe0f","d83edddbd83cdffb200d2640fe0f","d83edddbd83cdffc200d2640fe0f","d83edddbd83cdffd200d2640fe0f","d83edddbd83cdffe200d2640fe0f","d83edddbd83cdfff200d2640fe0f"],["d83edddc","d83edddcd83cdffb","d83edddcd83cdffc","d83edddcd83cdffd","d83edddcd83cdffe","d83edddcd83cdfff"],["d83edddc200d2642fe0f","d83edddcd83cdffb200d2642fe0f","d83edddcd83cdffc200d2642fe0f","d83edddcd83cdffd200d2642fe0f","d83edddcd83cdffe200d2642fe0f","d83edddcd83cdfff200d2642fe0f"],["d83edddc200d2640fe0f","d83edddcd83cdffb200d2640fe0f","d83edddcd83cdffc200d2640fe0f","d83edddcd83cdffd200d2640fe0f","d83edddcd83cdffe200d2640fe0f","d83edddcd83cdfff200d2640fe0f"],["d83edddd","d83eddddd83cdffb","d83eddddd83cdffc","d83eddddd83cdffd","d83eddddd83cdffe","d83eddddd83cdfff"],["d83edddd200d2642fe0f","d83eddddd83cdffb200d2642fe0f","d83eddddd83cdffc200d2642fe0f","d83eddddd83cdffd200d2642fe0f","d83eddddd83cdffe200d2642fe0f","d83eddddd83cdfff200d2642fe0f"],["d83edddd200d2640fe0f","d83eddddd83cdffb200d2640fe0f","d83eddddd83cdffc200d2640fe0f","d83eddddd83cdffd200d2640fe0f","d83eddddd83cdffe200d2640fe0f","d83eddddd83cdfff200d2640fe0f"],["d83eddde"],["d83eddde200d2642fe0f"],["d83eddde200d2640fe0f"],["d83edddf"],["d83edddf200d2642fe0f"],["d83edddf200d2640fe0f"],["d83eddcc"],["d83ddc86","d83ddc86d83cdffb","d83ddc86d83cdffc","d83ddc86d83cdffd","d83ddc86d83cdffe","d83ddc86d83cdfff"],["d83ddc86200d2642fe0f","d83ddc86d83cdffb200d2642fe0f","d83ddc86d83cdffc200d2642fe0f","d83ddc86d83cdffd200d2642fe0f","d83ddc86d83cdffe200d2642fe0f","d83ddc86d83cdfff200d2642fe0f"],["d83ddc86200d2640fe0f","d83ddc86d83cdffb200d2640fe0f","d83ddc86d83cdffc200d2640fe0f","d83ddc86d83cdffd200d2640fe0f","d83ddc86d83cdffe200d2640fe0f","d83ddc86d83cdfff200d2640fe0f"],["d83ddc87","d83ddc87d83cdffb","d83ddc87d83cdffc","d83ddc87d83cdffd","d83ddc87d83cdffe","d83ddc87d83cdfff"]],"People_6":[["d83ddc87200d2642fe0f","d83ddc87d83cdffb200d2642fe0f","d83ddc87d83cdffc200d2642fe0f","d83ddc87d83cdffd200d2642fe0f","d83ddc87d83cdffe200d2642fe0f","d83ddc87d83cdfff200d2642fe0f"],["d83ddc87200d2640fe0f","d83ddc87d83cdffb200d2640fe0f","d83ddc87d83cdffc200d2640fe0f","d83ddc87d83cdffd200d2640fe0f","d83ddc87d83cdffe200d2640fe0f","d83ddc87d83cdfff200d2640fe0f"],["d83ddeb6","d83ddeb6d83cdffb","d83ddeb6d83cdffc","d83ddeb6d83cdffd","d83ddeb6d83cdffe","d83ddeb6d83cdfff"],["d83ddeb6200d2642fe0f","d83ddeb6d83cdffb200d2642fe0f","d83ddeb6d83cdffc200d2642fe0f","d83ddeb6d83cdffd200d2642fe0f","d83ddeb6d83cdffe200d2642fe0f","d83ddeb6d83cdfff200d2642fe0f"],["d83ddeb6200d2640fe0f","d83ddeb6d83cdffb200d2640fe0f","d83ddeb6d83cdffc200d2640fe0f","d83ddeb6d83cdffd200d2640fe0f","d83ddeb6d83cdffe200d2640fe0f","d83ddeb6d83cdfff200d2640fe0f"],["d83ddeb6200d27a1fe0f","d83ddeb6d83cdffb200d27a1fe0f","d83ddeb6d83cdffc200d27a1fe0f","d83ddeb6d83cdffd200d27a1fe0f","d83ddeb6d83cdffe200d27a1fe0f","d83ddeb6d83cdfff200d27a1fe0f"],["d83ddeb6200d2640fe0f200d27a1fe0f","d83ddeb6d83cdffb200d2640fe0f200d27a1fe0f","d83ddeb6d83cdffc200d2640fe0f200d27a1fe0f","d83ddeb6d83cdffd200d2640fe0f200d27a1fe0f","d83ddeb6d83cdffe200d2640fe0f200d27a1fe0f","d83ddeb6d83cdfff200d2640fe0f200d27a1fe0f"],["d83ddeb6200d2642fe0f200d27a1fe0f","d83ddeb6d83cdffb200d2642fe0f200d27a1fe0f","d83ddeb6d83cdffc200d2642fe0f200d27a1fe0f","d83ddeb6d83cdffd200d2642fe0f200d27a1fe0f","d83ddeb6d83cdffe200d2642fe0f200d27a1fe0f","d83ddeb6d83cdfff200d2642fe0f200d27a1fe0f"],["d83eddcd","d83eddcdd83cdffb","d83eddcdd83cdffc","d83eddcdd83cdffd","d83eddcdd83cdffe","d83eddcdd83cdfff"],["d83eddcd200d2642fe0f","d83eddcdd83cdffb200d2642fe0f","d83eddcdd83cdffc200d2642fe0f","d83eddcdd83cdffd200d2642fe0f","d83eddcdd83cdffe200d2642fe0f","d83eddcdd83cdfff200d2642fe0f"],["d83eddcd200d2640fe0f","d83eddcdd83cdffb200d2640fe0f","d83eddcdd83cdffc200d2640fe0f","d83eddcdd83cdffd200d2640fe0f","d83eddcdd83cdffe200d2640fe0f","d83eddcdd83cdfff200d2640fe0f"],["d83eddce","d83eddced83cdffb","d83eddced83cdffc","d83eddced83cdffd","d83eddced83cdffe","d83eddced83cdfff"],["d83eddce200d2642fe0f","d83eddced83cdffb200d2642fe0f","d83eddced83cdffc200d2642fe0f","d83eddced83cdffd200d2642fe0f","d83eddced83cdffe200d2642fe0f","d83eddced83cdfff200d2642fe0f"],["d83eddce200d2640fe0f","d83eddced83cdffb200d2640fe0f","d83eddced83cdffc200d2640fe0f","d83eddced83cdffd200d2640fe0f","d83eddced83cdffe200d2640fe0f","d83eddced83cdfff200d2640fe0f"],["d83eddce200d27a1fe0f","d83eddced83cdffb200d27a1fe0f","d83eddced83cdffc200d27a1fe0f","d83eddced83cdffd200d27a1fe0f","d83eddced83cdffe200d27a1fe0f","d83eddced83cdfff200d27a1fe0f"],["d83eddce200d2640fe0f200d27a1fe0f","d83eddced83cdffb200d2640fe0f200d27a1fe0f","d83eddced83cdffc200d2640fe0f200d27a1fe0f","d83eddced83cdffd200d2640fe0f200d27a1fe0f","d83eddced83cdffe200d2640fe0f200d27a1fe0f","d83eddced83cdfff200d2640fe0f200d27a1fe0f"],["d83eddce200d2642fe0f200d27a1fe0f","d83eddced83cdffb200d2642fe0f200d27a1fe0f","d83eddced83cdffc200d2642fe0f200d27a1fe0f","d83eddced83cdffd200d2642fe0f200d27a1fe0f","d83eddced83cdffe200d2642fe0f200d27a1fe0f","d83eddced83cdfff200d2642fe0f200d27a1fe0f"],["d83eddd1200dd83eddaf","d83eddd1d83cdffb200dd83eddaf","d83eddd1d83cdffc200dd83eddaf","d83eddd1d83cdffd200dd83eddaf","d83eddd1d83cdffe200dd83eddaf","d83eddd1d83cdfff200dd83eddaf"],["d83eddd1200dd83eddaf200d27a1fe0f","d83eddd1d83cdffb200dd83eddaf200d27a1fe0f","d83eddd1d83cdffc200dd83eddaf200d27a1fe0f","d83eddd1d83cdffd200dd83eddaf200d27a1fe0f","d83eddd1d83cdffe200dd83eddaf200d27a1fe0f","d83eddd1d83cdfff200dd83eddaf200d27a1fe0f"],["d83ddc68200dd83eddaf","d83ddc68d83cdffb200dd83eddaf","d83ddc68d83cdffc200dd83eddaf","d83ddc68d83cdffd200dd83eddaf","d83ddc68d83cdffe200dd83eddaf","d83ddc68d83cdfff200dd83eddaf"],["d83ddc68200dd83eddaf200d27a1fe0f","d83ddc68d83cdffb200dd83eddaf200d27a1fe0f","d83ddc68d83cdffc200dd83eddaf200d27a1fe0f","d83ddc68d83cdffd200dd83eddaf200d27a1fe0f","d83ddc68d83cdffe200dd83eddaf200d27a1fe0f","d83ddc68d83cdfff200dd83eddaf200d27a1fe0f"],["d83ddc69200dd83eddaf","d83ddc69d83cdffb200dd83eddaf","d83ddc69d83cdffc200dd83eddaf","d83ddc69d83cdffd200dd83eddaf","d83ddc69d83cdffe200dd83eddaf","d83ddc69d83cdfff200dd83eddaf"],["d83ddc69200dd83eddaf200d27a1fe0f","d83ddc69d83cdffb200dd83eddaf200d27a1fe0f","d83ddc69d83cdffc200dd83eddaf200d27a1fe0f","d83ddc69d83cdffd200dd83eddaf200d27a1fe0f","d83ddc69d83cdffe200dd83eddaf200d27a1fe0f","d83ddc69d83cdfff200dd83eddaf200d27a1fe0f"],["d83eddd1200dd83eddbc","d83eddd1d83cdffb200dd83eddbc","d83eddd1d83cdffc200dd83eddbc","d83eddd1d83cdffd200dd83eddbc","d83eddd1d83cdffe200dd83eddbc","d83eddd1d83cdfff200dd83eddbc"],["d83eddd1200dd83eddbc200d27a1fe0f","d83eddd1d83cdffb200dd83eddbc200d27a1fe0f","d83eddd1d83cdffc200dd83eddbc200d27a1fe0f","d83eddd1d83cdffd200dd83eddbc200d27a1fe0f","d83eddd1d83cdffe200dd83eddbc200d27a1fe0f","d83eddd1d83cdfff200dd83eddbc200d27a1fe0f"],["d83ddc68200dd83eddbc","d83ddc68d83cdffb200dd83eddbc","d83ddc68d83cdffc200dd83eddbc","d83ddc68d83cdffd200dd83eddbc","d83ddc68d83cdffe200dd83eddbc","d83ddc68d83cdfff200dd83eddbc"],["d83ddc68200dd83eddbc200d27a1fe0f","d83ddc68d83cdffb200dd83eddbc200d27a1fe0f","d83ddc68d83cdffc200dd83eddbc200d27a1fe0f","d83ddc68d83cdffd200dd83eddbc200d27a1fe0f","d83ddc68d83cdffe200dd83eddbc200d27a1fe0f","d83ddc68d83cdfff200dd83eddbc200d27a1fe0f"],["d83ddc69200dd83eddbc","d83ddc69d83cdffb200dd83eddbc","d83ddc69d83cdffc200dd83eddbc","d83ddc69d83cdffd200dd83eddbc","d83ddc69d83cdffe200dd83eddbc","d83ddc69d83cdfff200dd83eddbc"],["d83ddc69200dd83eddbc200d27a1fe0f","d83ddc69d83cdffb200dd83eddbc200d27a1fe0f","d83ddc69d83cdffc200dd83eddbc200d27a1fe0f","d83ddc69d83cdffd200dd83eddbc200d27a1fe0f","d83ddc69d83cdffe200dd83eddbc200d27a1fe0f","d83ddc69d83cdfff200dd83eddbc200d27a1fe0f"],["d83eddd1200dd83eddbd","d83eddd1d83cdffb200dd83eddbd","d83eddd1d83cdffc200dd83eddbd","d83eddd1d83cdffd200dd83eddbd","d83eddd1d83cdffe200dd83eddbd","d83eddd1d83cdfff200dd83eddbd"],["d83eddd1200dd83eddbd200d27a1fe0f","d83eddd1d83cdffb200dd83eddbd200d27a1fe0f","d83eddd1d83cdffc200dd83eddbd200d27a1fe0f","d83eddd1d83cdffd200dd83eddbd200d27a1fe0f","d83eddd1d83cdffe200dd83eddbd200d27a1fe0f","d83eddd1d83cdfff200dd83eddbd200d27a1fe0f"],["d83ddc68200dd83eddbd","d83ddc68d83cdffb200dd83eddbd","d83ddc68d83cdffc200dd83eddbd","d83ddc68d83cdffd200dd83eddbd","d83ddc68d83cdffe200dd83eddbd","d83ddc68d83cdfff200dd83eddbd"],["d83ddc68200dd83eddbd200d27a1fe0f","d83ddc68d83cdffb200dd83eddbd200d27a1fe0f","d83ddc68d83cdffc200dd83eddbd200d27a1fe0f","d83ddc68d83cdffd200dd83eddbd200d27a1fe0f","d83ddc68d83cdffe200dd83eddbd200d27a1fe0f","d83ddc68d83cdfff200dd83eddbd200d27a1fe0f"],["d83ddc69200dd83eddbd","d83ddc69d83cdffb200dd83eddbd","d83ddc69d83cdffc200dd83eddbd","d83ddc69d83cdffd200dd83eddbd","d83ddc69d83cdffe200dd83eddbd","d83ddc69d83cdfff200dd83eddbd"],["d83ddc69200dd83eddbd200d27a1fe0f","d83ddc69d83cdffb200dd83eddbd200d27a1fe0f","d83ddc69d83cdffc200dd83eddbd200d27a1fe0f","d83ddc69d83cdffd200dd83eddbd200d27a1fe0f","d83ddc69d83cdffe200dd83eddbd200d27a1fe0f","d83ddc69d83cdfff200dd83eddbd200d27a1fe0f"],["d83cdfc3","d83cdfc3d83cdffb","d83cdfc3d83cdffc","d83cdfc3d83cdffd","d83cdfc3d83cdffe","d83cdfc3d83cdfff"],["d83cdfc3200d2642fe0f","d83cdfc3d83cdffb200d2642fe0f","d83cdfc3d83cdffc200d2642fe0f","d83cdfc3d83cdffd200d2642fe0f","d83cdfc3d83cdffe200d2642fe0f","d83cdfc3d83cdfff200d2642fe0f"],["d83cdfc3200d2640fe0f","d83cdfc3d83cdffb200d2640fe0f","d83cdfc3d83cdffc200d2640fe0f","d83cdfc3d83cdffd200d2640fe0f","d83cdfc3d83cdffe200d2640fe0f","d83cdfc3d83cdfff200d2640fe0f"],["d83cdfc3200d27a1fe0f","d83cdfc3d83cdffb200d27a1fe0f","d83cdfc3d83cdffc200d27a1fe0f","d83cdfc3d83cdffd200d27a1fe0f","d83cdfc3d83cdffe200d27a1fe0f","d83cdfc3d83cdfff200d27a1fe0f"],["d83cdfc3200d2640fe0f200d27a1fe0f","d83cdfc3d83cdffb200d2640fe0f200d27a1fe0f","d83cdfc3d83cdffc200d2640fe0f200d27a1fe0f","d83cdfc3d83cdffd200d2640fe0f200d27a1fe0f","d83cdfc3d83cdffe200d2640fe0f200d27a1fe0f","d83cdfc3d83cdfff200d2640fe0f200d27a1fe0f"],["d83cdfc3200d2642fe0f200d27a1fe0f","d83cdfc3d83cdffb200d2642fe0f200d27a1fe0f","d83cdfc3d83cdffc200d2642fe0f200d27a1fe0f","d83cdfc3d83cdffd200d2642fe0f200d27a1fe0f","d83cdfc3d83cdffe200d2642fe0f200d27a1fe0f","d83cdfc3d83cdfff200d2642fe0f200d27a1fe0f"],["d83ddc83","d83ddc83d83cdffb","d83ddc83d83cdffc","d83ddc83d83cdffd","d83ddc83d83cdffe","d83ddc83d83cdfff"]],"People_7":[["d83ddd7a","d83ddd7ad83cdffb","d83ddd7ad83cdffc","d83ddd7ad83cdffd","d83ddd7ad83cdffe","d83ddd7ad83cdfff"],["d83ddd74fe0f","d83ddd74d83cdffb","d83ddd74d83cdffc","d83ddd74d83cdffd","d83ddd74d83cdffe","d83ddd74d83cdfff"],["d83ddc6f"],["d83ddc6f200d2642fe0f"],["d83ddc6f200d2640fe0f"],["d83eddd6","d83eddd6d83cdffb","d83eddd6d83cdffc","d83eddd6d83cdffd","d83eddd6d83cdffe","d83eddd6d83cdfff"],["d83eddd6200d2642fe0f","d83eddd6d83cdffb200d2642fe0f","d83eddd6d83cdffc200d2642fe0f","d83eddd6d83cdffd200d2642fe0f","d83eddd6d83cdffe200d2642fe0f","d83eddd6d83cdfff200d2642fe0f"],["d83eddd6200d2640fe0f","d83eddd6d83cdffb200d2640fe0f","d83eddd6d83cdffc200d2640fe0f","d83eddd6d83cdffd200d2640fe0f","d83eddd6d83cdffe200d2640fe0f","d83eddd6d83cdfff200d2640fe0f"],["d83eddd7","d83eddd7d83cdffb","d83eddd7d83cdffc","d83eddd7d83cdffd","d83eddd7d83cdffe","d83eddd7d83cdfff"],["d83eddd7200d2642fe0f","d83eddd7d83cdffb200d2642fe0f","d83eddd7d83cdffc200d2642fe0f","d83eddd7d83cdffd200d2642fe0f","d83eddd7d83cdffe200d2642fe0f","d83eddd7d83cdfff200d2642fe0f"],["d83eddd7200d2640fe0f","d83eddd7d83cdffb200d2640fe0f","d83eddd7d83cdffc200d2640fe0f","d83eddd7d83cdffd200d2640fe0f","d83eddd7d83cdffe200d2640fe0f","d83eddd7d83cdfff200d2640fe0f"],["d83edd3a"],["d83cdfc7","d83cdfc7d83cdffb","d83cdfc7d83cdffc","d83cdfc7d83cdffd","d83cdfc7d83cdffe","d83cdfc7d83cdfff"],["26f7fe0f"],["d83cdfc2","d83cdfc2d83cdffb","d83cdfc2d83cdffc","d83cdfc2d83cdffd","d83cdfc2d83cdffe","d83cdfc2d83cdfff"],["d83cdfccfe0f","d83cdfccd83cdffb","d83cdfccd83cdffc","d83cdfccd83cdffd","d83cdfccd83cdffe","d83cdfccd83cdfff"],["d83cdfccfe0f200d2642fe0f","d83cdfccd83cdffb200d2642fe0f","d83cdfccd83cdffc200d2642fe0f","d83cdfccd83cdffd200d2642fe0f","d83cdfccd83cdffe200d2642fe0f","d83cdfccd83cdfff200d2642fe0f"],["d83cdfccfe0f200d2640fe0f","d83cdfccd83cdffb200d2640fe0f","d83cdfccd83cdffc200d2640fe0f","d83cdfccd83cdffd200d2640fe0f","d83cdfccd83cdffe200d2640fe0f","d83cdfccd83cdfff200d2640fe0f"],["d83cdfc4","d83cdfc4d83cdffb","d83cdfc4d83cdffc","d83cdfc4d83cdffd","d83cdfc4d83cdffe","d83cdfc4d83cdfff"],["d83cdfc4200d2642fe0f","d83cdfc4d83cdffb200d2642fe0f","d83cdfc4d83cdffc200d2642fe0f","d83cdfc4d83cdffd200d2642fe0f","d83cdfc4d83cdffe200d2642fe0f","d83cdfc4d83cdfff200d2642fe0f"],["d83cdfc4200d2640fe0f","d83cdfc4d83cdffb200d2640fe0f","d83cdfc4d83cdffc200d2640fe0f","d83cdfc4d83cdffd200d2640fe0f","d83cdfc4d83cdffe200d2640fe0f","d83cdfc4d83cdfff200d2640fe0f"],["d83ddea3","d83ddea3d83cdffb","d83ddea3d83cdffc","d83ddea3d83cdffd","d83ddea3d83cdffe","d83ddea3d83cdfff"],["d83ddea3200d2642fe0f","d83ddea3d83cdffb200d2642fe0f","d83ddea3d83cdffc200d2642fe0f","d83ddea3d83cdffd200d2642fe0f","d83ddea3d83cdffe200d2642fe0f","d83ddea3d83cdfff200d2642fe0f"],["d83ddea3200d2640fe0f","d83ddea3d83cdffb200d2640fe0f","d83ddea3d83cdffc200d2640fe0f","d83ddea3d83cdffd200d2640fe0f","d83ddea3d83cdffe200d2640fe0f","d83ddea3d83cdfff200d2640fe0f"],["d83cdfca","d83cdfcad83cdffb","d83cdfcad83cdffc","d83cdfcad83cdffd","d83cdfcad83cdffe","d83cdfcad83cdfff"],["d83cdfca200d2642fe0f","d83cdfcad83cdffb200d2642fe0f","d83cdfcad83cdffc200d2642fe0f","d83cdfcad83cdffd200d2642fe0f","d83cdfcad83cdffe200d2642fe0f","d83cdfcad83cdfff200d2642fe0f"],["d83cdfca200d2640fe0f","d83cdfcad83cdffb200d2640fe0f","d83cdfcad83cdffc200d2640fe0f","d83cdfcad83cdffd200d2640fe0f","d83cdfcad83cdffe200d2640fe0f","d83cdfcad83cdfff200d2640fe0f"],["26f9fe0f","26f9d83cdffb","26f9d83cdffc","26f9d83cdffd","26f9d83cdffe","26f9d83cdfff"],["26f9fe0f200d2642fe0f","26f9d83cdffb200d2642fe0f","26f9d83cdffc200d2642fe0f","26f9d83cdffd200d2642fe0f","26f9d83cdffe200d2642fe0f","26f9d83cdfff200d2642fe0f"],["26f9fe0f200d2640fe0f","26f9d83cdffb200d2640fe0f","26f9d83cdffc200d2640fe0f","26f9d83cdffd200d2640fe0f","26f9d83cdffe200d2640fe0f","26f9d83cdfff200d2640fe0f"],["d83cdfcbfe0f","d83cdfcbd83cdffb","d83cdfcbd83cdffc","d83cdfcbd83cdffd","d83cdfcbd83cdffe","d83cdfcbd83cdfff"],["d83cdfcbfe0f200d2642fe0f","d83cdfcbd83cdffb200d2642fe0f","d83cdfcbd83cdffc200d2642fe0f","d83cdfcbd83cdffd200d2642fe0f","d83cdfcbd83cdffe200d2642fe0f","d83cdfcbd83cdfff200d2642fe0f"],["d83cdfcbfe0f200d2640fe0f","d83cdfcbd83cdffb200d2640fe0f","d83cdfcbd83cdffc200d2640fe0f","d83cdfcbd83cdffd200d2640fe0f","d83cdfcbd83cdffe200d2640fe0f","d83cdfcbd83cdfff200d2640fe0f"],["d83ddeb4","d83ddeb4d83cdffb","d83ddeb4d83cdffc","d83ddeb4d83cdffd","d83ddeb4d83cdffe","d83ddeb4d83cdfff"],["d83ddeb4200d2642fe0f","d83ddeb4d83cdffb200d2642fe0f","d83ddeb4d83cdffc200d2642fe0f","d83ddeb4d83cdffd200d2642fe0f","d83ddeb4d83cdffe200d2642fe0f","d83ddeb4d83cdfff200d2642fe0f"],["d83ddeb4200d2640fe0f","d83ddeb4d83cdffb200d2640fe0f","d83ddeb4d83cdffc200d2640fe0f","d83ddeb4d83cdffd200d2640fe0f","d83ddeb4d83cdffe200d2640fe0f","d83ddeb4d83cdfff200d2640fe0f"],["d83ddeb5","d83ddeb5d83cdffb","d83ddeb5d83cdffc","d83ddeb5d83cdffd","d83ddeb5d83cdffe","d83ddeb5d83cdfff"],["d83ddeb5200d2642fe0f","d83ddeb5d83cdffb200d2642fe0f","d83ddeb5d83cdffc200d2642fe0f","d83ddeb5d83cdffd200d2642fe0f","d83ddeb5d83cdffe200d2642fe0f","d83ddeb5d83cdfff200d2642fe0f"],["d83ddeb5200d2640fe0f","d83ddeb5d83cdffb200d2640fe0f","d83ddeb5d83cdffc200d2640fe0f","d83ddeb5d83cdffd200d2640fe0f","d83ddeb5d83cdffe200d2640fe0f","d83ddeb5d83cdfff200d2640fe0f"],["d83edd38","d83edd38d83cdffb","d83edd38d83cdffc","d83edd38d83cdffd","d83edd38d83cdffe","d83edd38d83cdfff"],["d83edd38200d2642fe0f","d83edd38d83cdffb200d2642fe0f","d83edd38d83cdffc200d2642fe0f","d83edd38d83cdffd200d2642fe0f","d83edd38d83cdffe200d2642fe0f","d83edd38d83cdfff200d2642fe0f"],["d83edd38200d2640fe0f","d83edd38d83cdffb200d2640fe0f","d83edd38d83cdffc200d2640fe0f","d83edd38d83cdffd200d2640fe0f","d83edd38d83cdffe200d2640fe0f","d83edd38d83cdfff200d2640fe0f"],["d83edd3c"],["d83edd3c200d2642fe0f"],["d83edd3c200d2640fe0f"],["d83edd3d","d83edd3dd83cdffb","d83edd3dd83cdffc","d83edd3dd83cdffd","d83edd3dd83cdffe","d83edd3dd83cdfff"],["d83edd3d200d2642fe0f","d83edd3dd83cdffb200d2642fe0f","d83edd3dd83cdffc200d2642fe0f","d83edd3dd83cdffd200d2642fe0f","d83edd3dd83cdffe200d2642fe0f","d83edd3dd83cdfff200d2642fe0f"],["d83edd3d200d2640fe0f","d83edd3dd83cdffb200d2640fe0f","d83edd3dd83cdffc200d2640fe0f","d83edd3dd83cdffd200d2640fe0f","d83edd3dd83cdffe200d2640fe0f","d83edd3dd83cdfff200d2640fe0f"],["d83edd3e","d83edd3ed83cdffb","d83edd3ed83cdffc","d83edd3ed83cdffd","d83edd3ed83cdffe","d83edd3ed83cdfff"]],"People_8":[["d83edd3e200d2642fe0f","d83edd3ed83cdffb200d2642fe0f","d83edd3ed83cdffc200d2642fe0f","d83edd3ed83cdffd200d2642fe0f","d83edd3ed83cdffe200d2642fe0f","d83edd3ed83cdfff200d2642fe0f"],["d83edd3e200d2640fe0f","d83edd3ed83cdffb200d2640fe0f","d83edd3ed83cdffc200d2640fe0f","d83edd3ed83cdffd200d2640fe0f","d83edd3ed83cdffe200d2640fe0f","d83edd3ed83cdfff200d2640fe0f"],["d83edd39","d83edd39d83cdffb","d83edd39d83cdffc","d83edd39d83cdffd","d83edd39d83cdffe","d83edd39d83cdfff"],["d83edd39200d2642fe0f","d83edd39d83cdffb200d2642fe0f","d83edd39d83cdffc200d2642fe0f","d83edd39d83cdffd200d2642fe0f","d83edd39d83cdffe200d2642fe0f","d83edd39d83cdfff200d2642fe0f"],["d83edd39200d2640fe0f","d83edd39d83cdffb200d2640fe0f","d83edd39d83cdffc200d2640fe0f","d83edd39d83cdffd200d2640fe0f","d83edd39d83cdffe200d2640fe0f","d83edd39d83cdfff200d2640fe0f"],["d83eddd8","d83eddd8d83cdffb","d83eddd8d83cdffc","d83eddd8d83cdffd","d83eddd8d83cdffe","d83eddd8d83cdfff"],["d83eddd8200d2642fe0f","d83eddd8d83cdffb200d2642fe0f","d83eddd8d83cdffc200d2642fe0f","d83eddd8d83cdffd200d2642fe0f","d83eddd8d83cdffe200d2642fe0f","d83eddd8d83cdfff200d2642fe0f"],["d83eddd8200d2640fe0f","d83eddd8d83cdffb200d2640fe0f","d83eddd8d83cdffc200d2640fe0f","d83eddd8d83cdffd200d2640fe0f","d83eddd8d83cdffe200d2640fe0f","d83eddd8d83cdfff200d2640fe0f"],["d83ddec0","d83ddec0d83cdffb","d83ddec0d83cdffc","d83ddec0d83cdffd","d83ddec0d83cdffe","d83ddec0d83cdfff"],["d83ddecc","d83ddeccd83cdffb","d83ddeccd83cdffc","d83ddeccd83cdffd","d83ddeccd83cdffe","d83ddeccd83cdfff"],["d83eddd1200dd83edd1d200dd83eddd1","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffb200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffc200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffd200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdffe200dd83edd1d200dd83eddd1d83cdfff","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffb","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffc","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffd","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdffe","d83eddd1d83cdfff200dd83edd1d200dd83eddd1d83cdfff"],["d83ddc6d","d83ddc6dd83cdffb","d83ddc6dd83cdffc","d83ddc6dd83cdffd","d83ddc6dd83cdffe","d83ddc6dd83cdfff","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffb200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffc200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdffe","d83ddc69d83cdffd200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdffe200dd83edd1d200dd83ddc69d83cdfff","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffb","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffc","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffd","d83ddc69d83cdfff200dd83edd1d200dd83ddc69d83cdffe"],["d83ddc6b","d83ddc6bd83cdffb","d83ddc6bd83cdffc","d83ddc6bd83cdffd","d83ddc6bd83cdffe","d83ddc6bd83cdfff","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffb200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffc200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdffe","d83ddc69d83cdffd200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdffe200dd83edd1d200dd83ddc68d83cdfff","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffb","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffc","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffd","d83ddc69d83cdfff200dd83edd1d200dd83ddc68d83cdffe"],["d83ddc6c","d83ddc6cd83cdffb","d83ddc6cd83cdffc","d83ddc6cd83cdffd","d83ddc6cd83cdffe","d83ddc6cd83cdfff","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffb200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffc200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdffe","d83ddc68d83cdffd200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdffe200dd83edd1d200dd83ddc68d83cdfff","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffb","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffc","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffd","d83ddc68d83cdfff200dd83edd1d200dd83ddc68d83cdffe"],["d83ddc8f","d83ddc8fd83cdffb","d83ddc8fd83cdffc","d83ddc8fd83cdffd","d83ddc8fd83cdffe","d83ddc8fd83cdfff","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffb200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffc200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe","d83eddd1d83cdffd200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdffe200d2764fe0f200dd83ddc8b200dd83eddd1d83cdfff","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffb","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffc","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffd","d83eddd1d83cdfff200d2764fe0f200dd83ddc8b200dd83eddd1d83cdffe"],["d83ddc69200d2764fe0f200dd83ddc8b200dd83ddc68","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff"]],"People_9":[["d83ddc68200d2764fe0f200dd83ddc8b200dd83ddc68","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffb","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffc","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffd","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdffe","d83ddc68d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc68d83cdfff"],["d83ddc69200d2764fe0f200dd83ddc8b200dd83ddc69","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc8b200dd83ddc69d83cdfff"],["d83ddc91","d83ddc91d83cdffb","d83ddc91d83cdffc","d83ddc91d83cdffd","d83ddc91d83cdffe","d83ddc91d83cdfff","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffb200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffc200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdffe","d83eddd1d83cdffd200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdffe200d2764fe0f200dd83eddd1d83cdfff","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffb","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffc","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffd","d83eddd1d83cdfff200d2764fe0f200dd83eddd1d83cdffe"],["d83ddc69200d2764fe0f200dd83ddc68","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc68d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc68d83cdfff"],["d83ddc68200d2764fe0f200dd83ddc68","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffb200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffc200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffd200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdffe200d2764fe0f200dd83ddc68d83cdfff","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffb","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffc","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffd","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdffe","d83ddc68d83cdfff200d2764fe0f200dd83ddc68d83cdfff"],["d83ddc69200d2764fe0f200dd83ddc69","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffb200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffc200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffd200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdffe200d2764fe0f200dd83ddc69d83cdfff","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffb","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffc","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffd","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdffe","d83ddc69d83cdfff200d2764fe0f200dd83ddc69d83cdfff"],["d83ddc68200dd83ddc69200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc67"],["d83ddc68200dd83ddc69200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc69200dd83ddc67200dd83ddc67"],["d83ddc68200dd83ddc68200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc67"],["d83ddc68200dd83ddc68200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc68200dd83ddc67200dd83ddc67"],["d83ddc69200dd83ddc69200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc67"],["d83ddc69200dd83ddc69200dd83ddc67200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc66200dd83ddc66"],["d83ddc69200dd83ddc69200dd83ddc67200dd83ddc67"],["d83ddc68200dd83ddc66"],["d83ddc68200dd83ddc66200dd83ddc66"],["d83ddc68200dd83ddc67"],["d83ddc68200dd83ddc67200dd83ddc66"],["d83ddc68200dd83ddc67200dd83ddc67"],["d83ddc69200dd83ddc66"],["d83ddc69200dd83ddc66200dd83ddc66"],["d83ddc69200dd83ddc67"],["d83ddc69200dd83ddc67200dd83ddc66"],["d83ddc69200dd83ddc67200dd83ddc67"],["d83ddde3fe0f"],["d83ddc64"],["d83ddc65"],["d83edec2"],["d83ddc6a"],["d83eddd1200dd83eddd1200dd83eddd2"],["d83eddd1200dd83eddd1200dd83eddd2200dd83eddd2"],["d83eddd1200dd83eddd2"],["d83eddd1200dd83eddd2200dd83eddd2"],["d83ddc63"]],"Nature":[["d83ddc35"],["d83ddc12"],["d83edd8d"],["d83edda7"],["d83ddc36"],["d83ddc15"],["d83eddae"],["d83ddc15200dd83eddba"],["d83ddc29"],["d83ddc3a"],["d83edd8a"],["d83edd9d"],["d83ddc31"],["d83ddc08"],["d83ddc08200d2b1b"],["d83edd81"],["d83ddc2f"],["d83ddc05"],["d83ddc06"],["d83ddc34"],["d83edece"],["d83edecf"],["d83ddc0e"],["d83edd84"],["d83edd93"],["d83edd8c"],["d83eddac"],["d83ddc2e"],["d83ddc02"],["d83ddc03"],["d83ddc04"],["d83ddc37"],["d83ddc16"],["d83ddc17"],["d83ddc3d"],["d83ddc0f"],["d83ddc11"],["d83ddc10"],["d83ddc2a"],["d83ddc2b"],["d83edd99"],["d83edd92"],["d83ddc18"],["d83edda3"],["d83edd8f"],["d83edd9b"],["d83ddc2d"],["d83ddc01"],["d83ddc00"],["d83ddc39"],["d83ddc30"],["d83ddc07"],["d83ddc3ffe0f"],["d83eddab"],["d83edd94"],["d83edd87"],["d83ddc3b"],["d83ddc3b200d2744fe0f"],["d83ddc28"],["d83ddc3c"],["d83edda5"],["d83edda6"],["d83edda8"],["d83edd98"],["d83edda1"],["d83ddc3e"],["d83edd83"],["d83ddc14"],["d83ddc13"],["d83ddc23"],["d83ddc24"],["d83ddc25"],["d83ddc26"],["d83ddc27"],["d83ddd4afe0f"],["d83edd85"],["d83edd86"],["d83edda2"],["d83edd89"],["d83edda4"],["d83edeb6"],["d83edda9"],["d83edd9a"],["d83edd9c"],["d83edebd"],["d83ddc26200d2b1b"],["d83edebf"],["d83ddc26200dd83ddd25"],["d83ddc38"],["d83ddc0a"],["d83ddc22"],["d83edd8e"],["d83ddc0d"],["d83ddc32"],["d83ddc09"],["d83edd95"],["d83edd96"],["d83ddc33"],["d83ddc0b"],["d83ddc2c"],["d83eddad"],["d83ddc1f"],["d83ddc20"],["d83ddc21"],["d83edd88"],["d83ddc19"],["d83ddc1a"],["d83edeb8"],["d83edebc"],["d83ddc0c"],["d83edd8b"],["d83ddc1b"],["d83ddc1c"],["d83ddc1d"],["d83edeb2"],["d83ddc1e"],["d83edd97"],["d83edeb3"],["d83ddd77fe0f"],["d83ddd78fe0f"],["d83edd82"],["d83edd9f"],["d83edeb0"],["d83edeb1"],["d83edda0"],["d83ddc90"],["d83cdf38"],["d83ddcae"],["d83edeb7"],["d83cdff5fe0f"],["d83cdf39"],["d83edd40"],["d83cdf3a"],["d83cdf3b"],["d83cdf3c"],["d83cdf37"],["d83edebb"],["d83cdf31"],["d83edeb4"],["d83cdf32"],["d83cdf33"],["d83cdf34"],["d83cdf35"],["d83cdf3e"],["d83cdf3f"],["2618fe0f"],["d83cdf40"],["d83cdf41"],["d83cdf42"],["d83cdf43"],["d83edeb9"],["d83edeba"],["d83cdf44"]],"Foods":[["d83cdf47"],["d83cdf48"],["d83cdf49"],["d83cdf4a"],["d83cdf4b"],["d83cdf4b200dd83ddfe9"],["d83cdf4c"],["d83cdf4d"],["d83edd6d"],["d83cdf4e"],["d83cdf4f"],["d83cdf50"],["d83cdf51"],["d83cdf52"],["d83cdf53"],["d83eded0"],["d83edd5d"],["d83cdf45"],["d83eded2"],["d83edd65"],["d83edd51"],["d83cdf46"],["d83edd54"],["d83edd55"],["d83cdf3d"],["d83cdf36fe0f"],["d83eded1"],["d83edd52"],["d83edd6c"],["d83edd66"],["d83eddc4"],["d83eddc5"],["d83edd5c"],["d83eded8"],["d83cdf30"],["d83ededa"],["d83ededb"],["d83cdf44200dd83ddfeb"],["d83cdf5e"],["d83edd50"],["d83edd56"],["d83eded3"],["d83edd68"],["d83edd6f"],["d83edd5e"],["d83eddc7"],["d83eddc0"],["d83cdf56"],["d83cdf57"],["d83edd69"],["d83edd53"],["d83cdf54"],["d83cdf5f"],["d83cdf55"],["d83cdf2d"],["d83edd6a"],["d83cdf2e"],["d83cdf2f"],["d83eded4"],["d83edd59"],["d83eddc6"],["d83edd5a"],["d83cdf73"],["d83edd58"],["d83cdf72"],["d83eded5"],["d83edd63"],["d83edd57"],["d83cdf7f"],["d83eddc8"],["d83eddc2"],["d83edd6b"],["d83cdf71"],["d83cdf58"],["d83cdf59"],["d83cdf5a"],["d83cdf5b"],["d83cdf5c"],["d83cdf5d"],["d83cdf60"],["d83cdf62"],["d83cdf63"],["d83cdf64"],["d83cdf65"],["d83edd6e"],["d83cdf61"],["d83edd5f"],["d83edd60"],["d83edd61"],["d83edd80"],["d83edd9e"],["d83edd90"],["d83edd91"],["d83eddaa"],["d83cdf66"],["d83cdf67"],["d83cdf68"],["d83cdf69"],["d83cdf6a"],["d83cdf82"],["d83cdf70"],["d83eddc1"],["d83edd67"],["d83cdf6b"],["d83cdf6c"],["d83cdf6d"],["d83cdf6e"],["d83cdf6f"],["d83cdf7c"],["d83edd5b"],["2615"],["d83eded6"],["d83cdf75"],["d83cdf76"],["d83cdf7e"],["d83cdf77"],["d83cdf78"],["d83cdf79"],["d83cdf7a"],["d83cdf7b"],["d83edd42"],["d83edd43"],["d83eded7"],["d83edd64"],["d83eddcb"],["d83eddc3"],["d83eddc9"],["d83eddca"],["d83edd62"],["d83cdf7dfe0f"],["d83cdf74"],["d83edd44"],["d83ddd2a"],["d83eded9"],["d83cdffa"]],"Places":[["d83cdf0d"],["d83cdf0e"],["d83cdf0f"],["d83cdf10"],["d83dddfafe0f"],["d83dddfe"],["d83edded"],["d83cdfd4fe0f"],["26f0fe0f"],["d83cdf0b"],["d83dddfb"],["d83cdfd5fe0f"],["d83cdfd6fe0f"],["d83cdfdcfe0f"],["d83cdfddfe0f"],["d83cdfdefe0f"],["d83cdfdffe0f"],["d83cdfdbfe0f"],["d83cdfd7fe0f"],["d83eddf1"],["d83edea8"],["d83edeb5"],["d83dded6"],["d83cdfd8fe0f"],["d83cdfdafe0f"],["d83cdfe0"],["d83cdfe1"],["d83cdfe2"],["d83cdfe3"],["d83cdfe4"],["d83cdfe5"],["d83cdfe6"],["d83cdfe8"],["d83cdfe9"],["d83cdfea"],["d83cdfeb"],["d83cdfec"],["d83cdfed"],["d83cdfef"],["d83cdff0"],["d83ddc92"],["d83dddfc"],["d83dddfd"],["26ea"],["d83ddd4c"],["d83dded5"],["d83ddd4d"],["26e9fe0f"],["d83ddd4b"],["26f2"],["26fa"],["d83cdf01"],["d83cdf03"],["d83cdfd9fe0f"],["d83cdf04"],["d83cdf05"],["d83cdf06"],["d83cdf07"],["d83cdf09"],["2668fe0f"],["d83cdfa0"],["d83ddedd"],["d83cdfa1"],["d83cdfa2"],["d83ddc88"],["d83cdfaa"],["d83dde82"],["d83dde83"],["d83dde84"],["d83dde85"],["d83dde86"],["d83dde87"],["d83dde88"],["d83dde89"],["d83dde8a"],["d83dde9d"],["d83dde9e"],["d83dde8b"],["d83dde8c"],["d83dde8d"],["d83dde8e"],["d83dde90"],["d83dde91"],["d83dde92"],["d83dde93"],["d83dde94"],["d83dde95"],["d83dde96"],["d83dde97"],["d83dde98"],["d83dde99"],["d83ddefb"],["d83dde9a"],["d83dde9b"],["d83dde9c"],["d83cdfcefe0f"],["d83cdfcdfe0f"],["d83ddef5"],["d83eddbd"],["d83eddbc"],["d83ddefa"],["d83ddeb2"],["d83ddef4"],["d83ddef9"],["d83ddefc"],["d83dde8f"],["d83ddee3fe0f"],["d83ddee4fe0f"],["d83ddee2fe0f"],["26fd"],["d83ddede"],["d83ddea8"],["d83ddea5"],["d83ddea6"],["d83dded1"],["d83ddea7"],["2693"],["d83ddedf"],["26f5"],["d83ddef6"],["d83ddea4"],["d83ddef3fe0f"],["26f4fe0f"],["d83ddee5fe0f"],["d83ddea2"],["2708fe0f"],["d83ddee9fe0f"],["d83ddeeb"],["d83ddeec"],["d83ede82"],["d83ddcba"],["d83dde81"],["d83dde9f"],["d83ddea0"],["d83ddea1"],["d83ddef0fe0f"],["d83dde80"],["d83ddef8"],["d83ddecefe0f"],["d83eddf3"],["231b"],["23f3"],["231a"],["23f0"],["23f1fe0f"],["23f2fe0f"],["d83ddd70fe0f"],["d83ddd5b"],["d83ddd67"],["d83ddd50"],["d83ddd5c"],["d83ddd51"],["d83ddd5d"],["d83ddd52"],["d83ddd5e"],["d83ddd53"],["d83ddd5f"],["d83ddd54"],["d83ddd60"],["d83ddd55"],["d83ddd61"],["d83ddd56"],["d83ddd62"],["d83ddd57"],["d83ddd63"],["d83ddd58"],["d83ddd64"],["d83ddd59"],["d83ddd65"],["d83ddd5a"],["d83ddd66"],["d83cdf11"],["d83cdf12"],["d83cdf13"],["d83cdf14"],["d83cdf15"],["d83cdf16"],["d83cdf17"],["d83cdf18"],["d83cdf19"],["d83cdf1a"],["d83cdf1b"],["d83cdf1c"],["d83cdf21fe0f"],["2600fe0f"],["d83cdf1d"],["d83cdf1e"],["d83ede90"],["2b50"],["d83cdf1f"],["d83cdf20"],["d83cdf0c"],["2601fe0f"],["26c5"],["26c8fe0f"],["d83cdf24fe0f"],["d83cdf25fe0f"],["d83cdf26fe0f"],["d83cdf27fe0f"],["d83cdf28fe0f"],["d83cdf29fe0f"],["d83cdf2afe0f"],["d83cdf2bfe0f"],["d83cdf2cfe0f"],["d83cdf00"],["d83cdf08"],["d83cdf02"],["2602fe0f"],["2614"],["26f1fe0f"],["26a1"],["2744fe0f"],["2603fe0f"],["26c4"],["2604fe0f"],["d83ddd25"],["d83ddca7"],["d83cdf0a"]],"Activity":[["d83cdf83"],["d83cdf84"],["d83cdf86"],["d83cdf87"],["d83edde8"],["2728"],["d83cdf88"],["d83cdf89"],["d83cdf8a"],["d83cdf8b"],["d83cdf8d"],["d83cdf8e"],["d83cdf8f"],["d83cdf90"],["d83cdf91"],["d83edde7"],["d83cdf80"],["d83cdf81"],["d83cdf97fe0f"],["d83cdf9ffe0f"],["d83cdfab"],["d83cdf96fe0f"],["d83cdfc6"],["d83cdfc5"],["d83edd47"],["d83edd48"],["d83edd49"],["26bd"],["26be"],["d83edd4e"],["d83cdfc0"],["d83cdfd0"],["d83cdfc8"],["d83cdfc9"],["d83cdfbe"],["d83edd4f"],["d83cdfb3"],["d83cdfcf"],["d83cdfd1"],["d83cdfd2"],["d83edd4d"],["d83cdfd3"],["d83cdff8"],["d83edd4a"],["d83edd4b"],["d83edd45"],["26f3"],["26f8fe0f"],["d83cdfa3"],["d83edd3f"],["d83cdfbd"],["d83cdfbf"],["d83ddef7"],["d83edd4c"],["d83cdfaf"],["d83ede80"],["d83ede81"],["d83ddd2b"],["d83cdfb1"],["d83ddd2e"],["d83ede84"],["d83cdfae"],["d83ddd79fe0f"],["d83cdfb0"],["d83cdfb2"],["d83edde9"],["d83eddf8"],["d83ede85"],["d83edea9"],["d83ede86"],["2660fe0f"],["2665fe0f"],["2666fe0f"],["2663fe0f"],["265ffe0f"],["d83cdccf"],["d83cdc04"],["d83cdfb4"],["d83cdfad"],["d83dddbcfe0f"],["d83cdfa8"],["d83eddf5"],["d83edea1"],["d83eddf6"],["d83edea2"]],"Objects_0":[["d83ddc53"],["d83ddd76fe0f"],["d83edd7d"],["d83edd7c"],["d83eddba"],["d83ddc54"],["d83ddc55"],["d83ddc56"],["d83edde3"],["d83edde4"],["d83edde5"],["d83edde6"],["d83ddc57"],["d83ddc58"],["d83edd7b"],["d83ede71"],["d83ede72"],["d83ede73"],["d83ddc59"],["d83ddc5a"],["d83edead"],["d83ddc5b"],["d83ddc5c"],["d83ddc5d"],["d83ddecdfe0f"],["d83cdf92"],["d83ede74"],["d83ddc5e"],["d83ddc5f"],["d83edd7e"],["d83edd7f"],["d83ddc60"],["d83ddc61"],["d83ede70"],["d83ddc62"],["d83edeae"],["d83ddc51"],["d83ddc52"],["d83cdfa9"],["d83cdf93"],["d83edde2"],["d83ede96"],["26d1fe0f"],["d83ddcff"],["d83ddc84"],["d83ddc8d"],["d83ddc8e"],["d83ddd07"],["d83ddd08"],["d83ddd09"],["d83ddd0a"],["d83ddce2"],["d83ddce3"],["d83ddcef"],["d83ddd14"],["d83ddd15"],["d83cdfbc"],["d83cdfb5"],["d83cdfb6"],["d83cdf99fe0f"],["d83cdf9afe0f"],["d83cdf9bfe0f"],["d83cdfa4"],["d83cdfa7"],["d83ddcfb"],["d83cdfb7"],["d83ede97"],["d83cdfb8"],["d83cdfb9"],["d83cdfba"],["d83cdfbb"],["d83ede95"],["d83edd41"],["d83ede98"],["d83ede87"],["d83ede88"],["d83ddcf1"],["d83ddcf2"],["260efe0f"],["d83ddcde"],["d83ddcdf"],["d83ddce0"],["d83ddd0b"],["d83edeab"],["d83ddd0c"],["d83ddcbb"],["d83ddda5fe0f"],["d83ddda8fe0f"],["2328fe0f"],["d83dddb1fe0f"],["d83dddb2fe0f"],["d83ddcbd"],["d83ddcbe"],["d83ddcbf"],["d83ddcc0"],["d83eddee"],["d83cdfa5"],["d83cdf9efe0f"],["d83ddcfdfe0f"],["d83cdfac"],["d83ddcfa"],["d83ddcf7"],["d83ddcf8"],["d83ddcf9"],["d83ddcfc"],["d83ddd0d"],["d83ddd0e"],["d83ddd6ffe0f"],["d83ddca1"],["d83ddd26"],["d83cdfee"],["d83ede94"],["d83ddcd4"],["d83ddcd5"],["d83ddcd6"],["d83ddcd7"],["d83ddcd8"],["d83ddcd9"],["d83ddcda"],["d83ddcd3"],["d83ddcd2"],["d83ddcc3"],["d83ddcdc"],["d83ddcc4"],["d83ddcf0"],["d83ddddefe0f"],["d83ddcd1"],["d83ddd16"],["d83cdff7fe0f"],["d83ddcb0"],["d83ede99"]],"Objects_1":[["d83ddcb4"],["d83ddcb5"],["d83ddcb6"],["d83ddcb7"],["d83ddcb8"],["d83ddcb3"],["d83eddfe"],["d83ddcb9"],["2709fe0f"],["d83ddce7"],["d83ddce8"],["d83ddce9"],["d83ddce4"],["d83ddce5"],["d83ddce6"],["d83ddceb"],["d83ddcea"],["d83ddcec"],["d83ddced"],["d83ddcee"],["d83dddf3fe0f"],["270ffe0f"],["2712fe0f"],["d83ddd8bfe0f"],["d83ddd8afe0f"],["d83ddd8cfe0f"],["d83ddd8dfe0f"],["d83ddcdd"],["d83ddcbc"],["d83ddcc1"],["d83ddcc2"],["d83dddc2fe0f"],["d83ddcc5"],["d83ddcc6"],["d83dddd2fe0f"],["d83dddd3fe0f"],["d83ddcc7"],["d83ddcc8"],["d83ddcc9"],["d83ddcca"],["d83ddccb"],["d83ddccc"],["d83ddccd"],["d83ddcce"],["d83ddd87fe0f"],["d83ddccf"],["d83ddcd0"],["2702fe0f"],["d83dddc3fe0f"],["d83dddc4fe0f"],["d83dddd1fe0f"],["d83ddd12"],["d83ddd13"],["d83ddd0f"],["d83ddd10"],["d83ddd11"],["d83dddddfe0f"],["d83ddd28"],["d83ede93"],["26cffe0f"],["2692fe0f"],["d83ddee0fe0f"],["d83ddde1fe0f"],["2694fe0f"],["d83ddca3"],["d83ede83"],["d83cdff9"],["d83ddee1fe0f"],["d83ede9a"],["d83ddd27"],["d83ede9b"],["d83ddd29"],["2699fe0f"],["d83ddddcfe0f"],["2696fe0f"],["d83eddaf"],["d83ddd17"],["26d3fe0f200dd83ddca5"],["26d3fe0f"],["d83ede9d"],["d83eddf0"],["d83eddf2"],["d83ede9c"],["2697fe0f"],["d83eddea"],["d83eddeb"],["d83eddec"],["d83ddd2c"],["d83ddd2d"],["d83ddce1"],["d83ddc89"],["d83ede78"],["d83ddc8a"],["d83ede79"],["d83ede7c"],["d83ede7a"],["d83ede7b"],["d83ddeaa"],["d83dded7"],["d83ede9e"],["d83ede9f"],["d83ddecffe0f"],["d83ddecbfe0f"],["d83ede91"],["d83ddebd"],["d83edea0"],["d83ddebf"],["d83ddec1"],["d83edea4"],["d83ede92"],["d83eddf4"],["d83eddf7"],["d83eddf9"],["d83eddfa"],["d83eddfb"],["d83edea3"],["d83eddfc"],["d83edee7"],["d83edea5"],["d83eddfd"],["d83eddef"],["d83dded2"],["d83ddeac"],["26b0fe0f"],["d83edea6"],["26b1fe0f"],["d83eddff"],["d83edeac"],["d83dddff"],["d83edea7"],["d83edeaa"]],"Symbols":[["d83cdfe7"],["d83ddeae"],["d83ddeb0"],["267f"],["d83ddeb9"],["d83ddeba"],["d83ddebb"],["d83ddebc"],["d83ddebe"],["d83ddec2"],["d83ddec3"],["d83ddec4"],["d83ddec5"],["26a0fe0f"],["d83ddeb8"],["26d4"],["d83ddeab"],["d83ddeb3"],["d83ddead"],["d83ddeaf"],["d83ddeb1"],["d83ddeb7"],["d83ddcf5"],["d83ddd1e"],["2622fe0f"],["2623fe0f"],["2b06fe0f"],["2197fe0f"],["27a1fe0f"],["2198fe0f"],["2b07fe0f"],["2199fe0f"],["2b05fe0f"],["2196fe0f"],["2195fe0f"],["2194fe0f"],["21a9fe0f"],["21aafe0f"],["2934fe0f"],["2935fe0f"],["d83ddd03"],["d83ddd04"],["d83ddd19"],["d83ddd1a"],["d83ddd1b"],["d83ddd1c"],["d83ddd1d"],["d83dded0"],["269bfe0f"],["d83ddd49fe0f"],["2721fe0f"],["2638fe0f"],["262ffe0f"],["271dfe0f"],["2626fe0f"],["262afe0f"],["262efe0f"],["d83ddd4e"],["d83ddd2f"],["d83edeaf"],["2648"],["2649"],["264a"],["264b"],["264c"],["264d"],["264e"],["264f"],["2650"],["2651"],["2652"],["2653"],["26ce"],["d83ddd00"],["d83ddd01"],["d83ddd02"],["25b6fe0f"],["23e9"],["23edfe0f"],["23effe0f"],["25c0fe0f"],["23ea"],["23eefe0f"],["d83ddd3c"],["23eb"],["d83ddd3d"],["23ec"],["23f8fe0f"],["23f9fe0f"],["23fafe0f"],["23cffe0f"],["d83cdfa6"],["d83ddd05"],["d83ddd06"],["d83ddcf6"],["d83ddedc"],["d83ddcf3"],["d83ddcf4"],["26a7fe0f"],["2716fe0f"],["2795"],["2796"],["2797"],["d83ddff0"],["267efe0f"],["203cfe0f"],["2049fe0f"],["2753"],["2754"],["2755"],["2757"],["3030fe0f"],["d83ddcb1"],["d83ddcb2"],["267bfe0f"],["269cfe0f"],["d83ddd31"],["d83ddcdb"],["d83ddd30"],["2b55"],["2705"],["2611fe0f"],["2714fe0f"],["274c"],["274e"],["27b0"],["27bf"],["303dfe0f"],["2733fe0f"],["2734fe0f"],["2747fe0f"],["00a9fe0f"],["00aefe0f"],["2122fe0f"],["0023fe0f20e3"],["002afe0f20e3"],["0030fe0f20e3"],["0031fe0f20e3"],["0032fe0f20e3"],["0033fe0f20e3"],["0034fe0f20e3"],["0035fe0f20e3"],["0036fe0f20e3"],["0037fe0f20e3"],["0038fe0f20e3"],["0039fe0f20e3"],["d83ddd1f"],["d83ddd20"],["d83ddd21"],["d83ddd22"],["d83ddd23"],["d83ddd24"],["d83cdd70fe0f"],["d83cdd8e"],["d83cdd71fe0f"],["d83cdd91"],["d83cdd92"],["d83cdd93"],["2139fe0f"],["d83cdd94"],["24c2fe0f"],["d83cdd95"],["d83cdd96"],["d83cdd7efe0f"],["d83cdd97"],["d83cdd7ffe0f"],["d83cdd98"],["d83cdd99"],["d83cdd9a"],["d83cde01"],["d83cde02fe0f"],["d83cde37fe0f"],["d83cde36"],["d83cde2f"],["d83cde50"],["d83cde39"],["d83cde1a"],["d83cde32"],["d83cde51"],["d83cde38"],["d83cde34"],["d83cde33"],["3297fe0f"],["3299fe0f"],["d83cde3a"],["d83cde35"],["d83ddd34"],["d83ddfe0"],["d83ddfe1"],["d83ddfe2"],["d83ddd35"],["d83ddfe3"],["d83ddfe4"],["26ab"],["26aa"],["d83ddfe5"],["d83ddfe7"],["d83ddfe8"],["d83ddfe9"],["d83ddfe6"],["d83ddfea"],["d83ddfeb"],["2b1b"],["2b1c"],["25fcfe0f"],["25fbfe0f"],["25fe"],["25fd"],["25aafe0f"],["25abfe0f"],["d83ddd36"],["d83ddd37"],["d83ddd38"],["d83ddd39"],["d83ddd3a"],["d83ddd3b"],["d83ddca0"],["d83ddd18"],["d83ddd33"],["d83ddd32"]],"Flags_0":[["d83cdfc1"],["d83ddea9"],["d83cdf8c"],["d83cdff4"],["d83cdff3fe0f"],["d83cdff3fe0f200dd83cdf08"],["d83cdff3fe0f200d26a7fe0f"],["d83cdff4200d2620fe0f"],["d83cdde6d83cdde8"],["d83cdde6d83cdde9"],["d83cdde6d83cddea"],["d83cdde6d83cddeb"],["d83cdde6d83cddec"],["d83cdde6d83cddee"],["d83cdde6d83cddf1"],["d83cdde6d83cddf2"],["d83cdde6d83cddf4"],["d83cdde6d83cddf6"],["d83cdde6d83cddf7"],["d83cdde6d83cddf8"],["d83cdde6d83cddf9"],["d83cdde6d83cddfa"],["d83cdde6d83cddfc"],["d83cdde6d83cddfd"],["d83cdde6d83cddff"],["d83cdde7d83cdde6"],["d83cdde7d83cdde7"],["d83cdde7d83cdde9"],["d83cdde7d83cddea"],["d83cdde7d83cddeb"],["d83cdde7d83cddec"],["d83cdde7d83cdded"],["d83cdde7d83cddee"],["d83cdde7d83cddef"],["d83cdde7d83cddf1"],["d83cdde7d83cddf2"],["d83cdde7d83cddf3"],["d83cdde7d83cddf4"],["d83cdde7d83cddf6"],["d83cdde7d83cddf7"],["d83cdde7d83cddf8"],["d83cdde7d83cddf9"],["d83cdde7d83cddfb"],["d83cdde7d83cddfc"],["d83cdde7d83cddfe"],["d83cdde7d83cddff"],["d83cdde8d83cdde6"],["d83cdde8d83cdde8"],["d83cdde8d83cdde9"],["d83cdde8d83cddeb"],["d83cdde8d83cddec"],["d83cdde8d83cdded"],["d83cdde8d83cddee"],["d83cdde8d83cddf0"],["d83cdde8d83cddf1"],["d83cdde8d83cddf2"],["d83cdde8d83cddf3"],["d83cdde8d83cddf4"],["d83cdde8d83cddf5"],["d83cdde8d83cddf7"],["d83cdde8d83cddfa"],["d83cdde8d83cddfb"],["d83cdde8d83cddfc"],["d83cdde8d83cddfd"],["d83cdde8d83cddfe"],["d83cdde8d83cddff"],["d83cdde9d83cddea"],["d83cdde9d83cddec"],["d83cdde9d83cddef"],["d83cdde9d83cddf0"],["d83cdde9d83cddf2"],["d83cdde9d83cddf4"],["d83cdde9d83cddff"],["d83cddead83cdde6"],["d83cddead83cdde8"],["d83cddead83cddea"],["d83cddead83cddec"],["d83cddead83cdded"],["d83cddead83cddf7"],["d83cddead83cddf8"],["d83cddead83cddf9"],["d83cddead83cddfa"],["d83cddebd83cddee"],["d83cddebd83cddef"],["d83cddebd83cddf0"],["d83cddebd83cddf2"],["d83cddebd83cddf4"],["d83cddebd83cddf7"],["d83cddecd83cdde6"],["d83cddecd83cdde7"],["d83cddecd83cdde9"],["d83cddecd83cddea"],["d83cddecd83cddeb"],["d83cddecd83cddec"],["d83cddecd83cdded"],["d83cddecd83cddee"],["d83cddecd83cddf1"],["d83cddecd83cddf2"],["d83cddecd83cddf3"],["d83cddecd83cddf5"],["d83cddecd83cddf6"],["d83cddecd83cddf7"],["d83cddecd83cddf8"],["d83cddecd83cddf9"],["d83cddecd83cddfa"],["d83cddecd83cddfc"],["d83cddecd83cddfe"],["d83cddedd83cddf0"],["d83cddedd83cddf2"],["d83cddedd83cddf3"],["d83cddedd83cddf7"],["d83cddedd83cddf9"],["d83cddedd83cddfa"],["d83cddeed83cdde8"],["d83cddeed83cdde9"],["d83cddeed83cddea"],["d83cddeed83cddf1"],["d83cddeed83cddf2"],["d83cddeed83cddf3"],["d83cddeed83cddf4"],["d83cddeed83cddf6"],["d83cddeed83cddf7"],["d83cddeed83cddf8"],["d83cddeed83cddf9"],["d83cddefd83cddea"],["d83cddefd83cddf2"],["d83cddefd83cddf4"],["d83cddefd83cddf5"],["d83cddf0d83cddea"],["d83cddf0d83cddec"],["d83cddf0d83cdded"],["d83cddf0d83cddee"],["d83cddf0d83cddf2"],["d83cddf0d83cddf3"],["d83cddf0d83cddf5"]],"Flags_1":[["d83cddf0d83cddf7"],["d83cddf0d83cddfc"],["d83cddf0d83cddfe"],["d83cddf0d83cddff"],["d83cddf1d83cdde6"],["d83cddf1d83cdde7"],["d83cddf1d83cdde8"],["d83cddf1d83cddee"],["d83cddf1d83cddf0"],["d83cddf1d83cddf7"],["d83cddf1d83cddf8"],["d83cddf1d83cddf9"],["d83cddf1d83cddfa"],["d83cddf1d83cddfb"],["d83cddf1d83cddfe"],["d83cddf2d83cdde6"],["d83cddf2d83cdde8"],["d83cddf2d83cdde9"],["d83cddf2d83cddea"],["d83cddf2d83cddeb"],["d83cddf2d83cddec"],["d83cddf2d83cdded"],["d83cddf2d83cddf0"],["d83cddf2d83cddf1"],["d83cddf2d83cddf2"],["d83cddf2d83cddf3"],["d83cddf2d83cddf4"],["d83cddf2d83cddf5"],["d83cddf2d83cddf6"],["d83cddf2d83cddf7"],["d83cddf2d83cddf8"],["d83cddf2d83cddf9"],["d83cddf2d83cddfa"],["d83cddf2d83cddfb"],["d83cddf2d83cddfc"],["d83cddf2d83cddfd"],["d83cddf2d83cddfe"],["d83cddf2d83cddff"],["d83cddf3d83cdde6"],["d83cddf3d83cdde8"],["d83cddf3d83cddea"],["d83cddf3d83cddeb"],["d83cddf3d83cddec"],["d83cddf3d83cddee"],["d83cddf3d83cddf1"],["d83cddf3d83cddf4"],["d83cddf3d83cddf5"],["d83cddf3d83cddf7"],["d83cddf3d83cddfa"],["d83cddf3d83cddff"],["d83cddf4d83cddf2"],["d83cddf5d83cdde6"],["d83cddf5d83cddea"],["d83cddf5d83cddeb"],["d83cddf5d83cddec"],["d83cddf5d83cdded"],["d83cddf5d83cddf0"],["d83cddf5d83cddf1"],["d83cddf5d83cddf2"],["d83cddf5d83cddf3"],["d83cddf5d83cddf7"],["d83cddf5d83cddf8"],["d83cddf5d83cddf9"],["d83cddf5d83cddfc"],["d83cddf5d83cddfe"],["d83cddf6d83cdde6"],["d83cddf7d83cddea"],["d83cddf7d83cddf4"],["d83cddf7d83cddf8"],["d83cddf7d83cddfa"],["d83cddf7d83cddfc"],["d83cddf8d83cdde6"],["d83cddf8d83cdde7"],["d83cddf8d83cdde8"],["d83cddf8d83cdde9"],["d83cddf8d83cddea"],["d83cddf8d83cddec"],["d83cddf8d83cdded"],["d83cddf8d83cddee"],["d83cddf8d83cddef"],["d83cddf8d83cddf0"],["d83cddf8d83cddf1"],["d83cddf8d83cddf2"],["d83cddf8d83cddf3"],["d83cddf8d83cddf4"],["d83cddf8d83cddf7"],["d83cddf8d83cddf8"],["d83cddf8d83cddf9"],["d83cddf8d83cddfb"],["d83cddf8d83cddfd"],["d83cddf8d83cddfe"],["d83cddf8d83cddff"],["d83cddf9d83cdde6"],["d83cddf9d83cdde8"],["d83cddf9d83cdde9"],["d83cddf9d83cddeb"],["d83cddf9d83cddec"],["d83cddf9d83cdded"],["d83cddf9d83cddef"],["d83cddf9d83cddf0"],["d83cddf9d83cddf1"],["d83cddf9d83cddf2"],["d83cddf9d83cddf3"],["d83cddf9d83cddf4"],["d83cddf9d83cddf7"],["d83cddf9d83cddf9"],["d83cddf9d83cddfb"],["d83cddf9d83cddfc"],["d83cddf9d83cddff"],["d83cddfad83cdde6"],["d83cddfad83cddec"],["d83cddfad83cddf2"],["d83cddfad83cddf3"],["d83cddfad83cddf8"],["d83cddfad83cddfe"],["d83cddfad83cddff"],["d83cddfbd83cdde6"],["d83cddfbd83cdde8"],["d83cddfbd83cddea"],["d83cddfbd83cddec"],["d83cddfbd83cddee"],["d83cddfbd83cddf3"],["d83cddfbd83cddfa"],["d83cddfcd83cddeb"],["d83cddfcd83cddf8"],["d83cddfdd83cddf0"],["d83cddfed83cddea"],["d83cddfed83cddf9"],["d83cddffd83cdde6"],["d83cddffd83cddf2"],["d83cddffd83cddfc"],["d83cdff4db40dc67db40dc62db40dc65db40dc6edb40dc67db40dc7f"],["d83cdff4db40dc67db40dc62db40dc73db40dc63db40dc74db40dc7f"],["d83cdff4db40dc67db40dc62db40dc77db40dc6cdb40dc73db40dc7f"]]},"obsolete":[],"metrics":{"raw_width":66,"raw_height":66,"per_row":16},"densities":["xhdpi"],"format":"webp"} \ No newline at end of file diff --git a/app/src/main/assets/fonts/SignalSymbols-Bold.otf b/app/src/main/assets/fonts/SignalSymbols-Bold.otf new file mode 100644 index 00000000..8aed1da3 Binary files /dev/null and b/app/src/main/assets/fonts/SignalSymbols-Bold.otf differ diff --git a/app/src/main/baseline-prof.txt b/app/src/main/baseline-prof.txt index 96cdd6f5..6e7227f4 100644 --- a/app/src/main/baseline-prof.txt +++ b/app/src/main/baseline-prof.txt @@ -1,35 +1,321 @@ -HPLandroidx/appcompat/app/AppCompatViewInflater;->themifyContext(Landroid/content/Context;Landroid/util/AttributeSet;ZZ)Landroid/content/Context; +HPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawablesWithIntrinsicBounds(IIII)V +HPLandroidx/appcompat/widget/SearchView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +HPLandroidx/constraintlayout/core/ArrayRow;->(Landroidx/constraintlayout/core/Cache;)V HPLandroidx/core/view/ViewGroupKt$descendants$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; -HPLandroidx/core/view/ViewGroupKt;->getDescendants(Landroid/view/ViewGroup;)Lkotlin/sequences/Sequence; +HPLandroidx/core/view/ViewGroupKt$iterator$1;->next()Landroid/view/View; +HPLandroidx/core/view/ViewGroupKt$iterator$1;->next()Ljava/lang/Object; HPLandroidx/customview/poolingcontainer/PoolingContainer;->callPoolingContainerOnRelease(Landroid/view/View;)V HPLandroidx/customview/poolingcontainer/PoolingContainer;->getPoolingContainerListenerHolder(Landroid/view/View;)Landroidx/customview/poolingcontainer/PoolingContainerListenerHolder; HPLandroidx/customview/poolingcontainer/PoolingContainerListenerHolder;->()V -HPLandroidx/customview/poolingcontainer/PoolingContainerListenerHolder;->onRelease()V +HPLandroidx/fragment/app/FragmentManager;->saveAllStateInternal()Landroid/os/Bundle; +HPLandroidx/fragment/app/FragmentStateManager;->saveState()Landroid/os/Bundle; +HPLandroidx/recyclerview/widget/AsyncListDiffer$1$1;->areItemsTheSame(II)Z +HPLandroidx/recyclerview/widget/BatchingListUpdateCallback;->onChanged(IILjava/lang/Object;)V +HPLandroidx/recyclerview/widget/ConcatAdapter;->findRelativeAdapterPositionIn(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)I +HPLandroidx/recyclerview/widget/ConcatAdapter;->getItemViewType(I)I +HPLandroidx/recyclerview/widget/ConcatAdapterController;->findWrapperAndLocalPosition(I)Landroidx/recyclerview/widget/ConcatAdapterController$WrapperAndLocalPosition; +HPLandroidx/recyclerview/widget/ConcatAdapterController;->getItemViewType(I)I +HPLandroidx/recyclerview/widget/ConcatAdapterController;->getLocalAdapterPosition(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)I +HPLandroidx/recyclerview/widget/ConcatAdapterController;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V +HPLandroidx/recyclerview/widget/ConcatAdapterController;->releaseWrapperAndLocalPosition(Landroidx/recyclerview/widget/ConcatAdapterController$WrapperAndLocalPosition;)V +HPLandroidx/recyclerview/widget/DiffUtil;->backward(Landroidx/recyclerview/widget/DiffUtil$Range;Landroidx/recyclerview/widget/DiffUtil$Callback;Landroidx/recyclerview/widget/DiffUtil$CenteredArray;Landroidx/recyclerview/widget/DiffUtil$CenteredArray;I)Landroidx/recyclerview/widget/DiffUtil$Snake; +HPLandroidx/recyclerview/widget/ListAdapter;->getCurrentList()Ljava/util/List; +HPLandroidx/recyclerview/widget/NestedAdapterWrapper;->getItemViewType(I)I +HPLandroidx/recyclerview/widget/RecyclerView;->animateChange(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;ZZ)V +HPLandroidx/recyclerview/widget/RecyclerView;->getChildViewHolder(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; +HPLandroidx/recyclerview/widget/RecyclerView;->viewRangeUpdate(IILjava/lang/Object;)V HPLandroidx/recyclerview/widget/ViewInfoStore;->addToPreLayout(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)V +HPLandroidx/recyclerview/widget/ViewInfoStore;->isDisappearing(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Z HPLandroidx/recyclerview/widget/ViewInfoStore;->popFromLayoutStep(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo; -HPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createMapDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/type/MapType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -HPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/util/Map; -HPLcom/squareup/wire/internal/Internal;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)I -HPLkotlin/collections/AbstractList$IteratorImpl;->next()Ljava/lang/Object; -HPLkotlin/collections/CollectionsKt__IterablesKt;->collectionSizeOrDefault(Ljava/lang/Iterable;I)I +HPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage$WrapperViewTypeLookup;->localToGlobal(I)I +HPLandroidx/savedstate/SavedStateRegistry;->performSave(Landroid/os/Bundle;)V +HPLcom/google/android/material/animation/ArgbEvaluatorCompat;->evaluate(FLjava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; +HPLcom/google/android/material/shape/RelativeCornerSize;->getCornerSize(Landroid/graphics/RectF;)F +HPLcom/google/android/material/shape/RelativeCornerSize;->getMaxCornerSize(Landroid/graphics/RectF;)F +HPLcom/google/common/collect/Sets;->intersection(Ljava/util/Set;Ljava/util/Set;)Lcom/google/common/collect/Sets$SetView; +HPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +HPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->innerSuccess(Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;Ljava/lang/Object;)V +HPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->onNext(Ljava/lang/Object;)V +HPLio/reactivex/rxjava3/internal/operators/observable/ObservableReplay$BoundedReplayBuffer;->removeFirst()V +HPLj$/time/Instant;->atZone(Lj$/time/ZoneId;)Lj$/time/ZonedDateTime; +HPLj$/time/LocalDate;->toEpochDay()J +HPLj$/time/LocalDate;->w()Z +HPLj$/time/LocalDateTime;->v()Lj$/time/LocalDate; +HPLj$/time/ZonedDateTime;->(Lj$/time/LocalDateTime;Lj$/time/ZoneId;Lj$/time/ZoneOffset;)V +HPLj$/time/ZonedDateTime;->m(JILj$/time/ZoneId;)Lj$/time/ZonedDateTime; +HPLj$/time/ZonedDateTime;->n(Lj$/time/Instant;Lj$/time/ZoneId;)Lj$/time/ZonedDateTime; +HPLj$/time/ZonedDateTime;->toLocalDate()Lj$/time/LocalDate; +HPLj$/util/S;->s(Lj$/util/function/Consumer;)Z +HPLj$/util/stream/A1;->l1()Lj$/util/stream/P1; +HPLj$/util/stream/Y1;->n(Lj$/util/function/BinaryOperator;)Lj$/util/Optional; +HPLj$/util/stream/h2;->(Lj$/util/stream/i2;Lj$/util/stream/g2;)V +HPLj$/util/stream/h2;->accept(Ljava/lang/Object;)V +HPLj$/util/stream/h2;->n(J)V HPLkotlin/sequences/SequenceBuilderIterator;->yieldAll(Ljava/util/Iterator;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; -HPLkotlin/sequences/SequenceScope;->yieldAll(Lkotlin/sequences/Sequence;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; -HPLnet/zetetic/database/sqlcipher/SQLiteProgram;->clearBindings()V -HPLnet/zetetic/database/sqlcipher/SQLiteProgram;->getSession()Lnet/zetetic/database/sqlcipher/SQLiteSession; +HPLkotlin/sequences/SequencesKt__SequenceBuilderKt;->sequence(Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; +HPLkotlin/sequences/SequencesKt___SequencesJvmKt$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean; +HPLkotlin/sequences/SequencesKt___SequencesJvmKt$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->getPath()Ljava/lang/String; +HPLorg/signal/core/util/OptionalExtensionsKt;->toOptional(Ljava/lang/Object;)Lj$/util/Optional; +HPLorg/signal/core/util/concurrent/SettableFuture;->(Ljava/lang/Object;)V +HPLorg/signal/core/util/concurrent/SignalExecutors;->$r8$lambda$0Q0afsv1raKIrq3aP-SuMcT2Ad0(Ljava/lang/Runnable;Ljava/util/concurrent/ThreadPoolExecutor;)V HPLorg/signal/core/util/concurrent/SignalExecutors;->lambda$newCachedBoundedExecutor$1(Ljava/lang/Runnable;Ljava/util/concurrent/ThreadPoolExecutor;)V -HPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment;->(Lorg/thoughtcrime/securesms/attachments/AttachmentId;JZZLjava/lang/String;IJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;[B[BILjava/lang/String;ZZZIIZLjava/lang/String;Lorg/thoughtcrime/securesms/stickers/StickerLocator;Lorg/thoughtcrime/securesms/blurhash/BlurHash;Lorg/thoughtcrime/securesms/audio/AudioHash;Lorg/thoughtcrime/securesms/database/AttachmentTable$TransformProperties;IJ)V +HPLorg/signal/core/util/tracing/DebugAnnotation$Builder;->()V +HPLorg/signal/libsignal/protocol/ecc/ECPublicKey;->equals(Ljava/lang/Object;)Z +HPLorg/signal/paging/FixedSizePagingController;->lambda$onDataItemChanged$2(Ljava/lang/Object;)V +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$2;->invoke(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGift;)Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$4;->invoke(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGift;)Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$notAnimated$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$notAnimated$1;->invoke(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGift;)Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->access$getAnimationState$p(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)Ljava/util/Map; +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->applyCorners()V +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->applyCornersForSizeClass2()V +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->getCells()[Lorg/thoughtcrime/securesms/components/ThumbnailView; +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setCellBackgroundColor(I)V +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setRadii(IIII)V +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setRelativeRadii(Lorg/thoughtcrime/securesms/components/ThumbnailView;IIII)V +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setSlide(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/mms/Slide;IZ)V +HPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setSlides(Lcom/bumptech/glide/RequestManager;Ljava/util/List;Z)V +HPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentDate(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/util/Locale;Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentDeliveryStatus(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->dispatchDraw(Landroid/graphics/Canvas;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setCancelTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setClickable(Z)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setConversationColor(I)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setCorners(IIII)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setFocusable(Z)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setImageResource(Lcom/bumptech/glide/RequestManager;Ljava/util/List;ZZ)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setMaximumThumbnailHeight(I)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setMinimumThumbnailWidth(I)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setOnLongClickListener(Landroid/view/View$OnLongClickListener;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setPlayVideoClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setStartTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setThumbnailBounds([I)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setThumbnailClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->showThumbnailView()V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->(ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIII)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->copy$default(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->copy(ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIII)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->(FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIII)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->copy$default(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIIIILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->copy(FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIII)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;Lorg/thoughtcrime/securesms/util/views/Stub;)V +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->copy$default(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;ILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->copy(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->getAlbumViewState()Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; +HPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->getThumbnailViewState()Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; +HPLorg/thoughtcrime/securesms/components/CornerMask;->mask(Landroid/graphics/Canvas;)V +HPLorg/thoughtcrime/securesms/components/Outliner;->draw(Landroid/graphics/Canvas;IIII)V +HPLorg/thoughtcrime/securesms/components/QuoteView;->dismiss()V +HPLorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport2;->m([Ljava/lang/Object;)Ljava/util/List; +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->onMeasure(II)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setBounds(IIII)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setCancelTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setClickable(Z)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setFocusable(Z)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setImageResource(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/mms/Slide;ZZII)Lorg/signal/core/util/concurrent/ListenableFuture; +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setPlayVideoClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setRadii(IIII)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setStartTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V +HPLorg/thoughtcrime/securesms/components/ThumbnailView;->setThumbnailClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V +HPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->getLongestLineWidth(Ljava/lang/CharSequence;)F +HPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setOverflowText(Ljava/lang/CharSequence;)V +HPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setTextSize(IF)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->getTransferState(Ljava/util/List;)I +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->toString()Ljava/lang/String; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1;->(Z)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1;->(Z)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->deriveMode(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->isUpdateToExistingSet(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;Ljava/util/List;)Z +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setCancelClickListener(Landroid/view/View$OnClickListener;)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setClickable(Z)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setFocusable(Z)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setShowSecondaryText(Z)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setSlides(Ljava/util/List;)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setTransferClickListener(Landroid/view/View$OnClickListener;)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setVisible(Z)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->updateState(Lkotlin/jvm/functions/Function1;)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->(ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZ)V +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->copy$default(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->copy(ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZ)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->equals(Ljava/lang/Object;)Z +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->toString()Ljava/lang/String; +HPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->(Landroid/content/Context;Landroid/util/AttributeSet;II)V +HPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->updateOutlineVisibility()V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->bind(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Lj$/util/Optional;Lj$/util/Optional;Lcom/bumptech/glide/RequestManager;Ljava/util/Locale;Ljava/util/Set;Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/String;ZZZZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->forceFooter(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getActiveFooter(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Lorg/thoughtcrime/securesms/components/ConversationItemFooter; +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getGiftId()J +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getOpenableGiftProjection(Z)Lorg/thoughtcrime/securesms/util/Projection; +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getSnapshotProjections(Landroid/view/ViewGroup;ZZ)Lorg/thoughtcrime/securesms/util/ProjectionList; +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasExtraText(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasNoBubble(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isCaptionlessMms(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isEndOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Z)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isFooterVisible(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Z)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isStartOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Z)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isWithinClusteringTime(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->onMeasure(II)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->readDimen(I)I +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setAuthor(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;ZZ)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setBodyText(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/String;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setBubbleState(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;ZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setContactPhoto(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setFooter(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Ljava/util/Locale;ZZ)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setGroupAuthorColor(Lorg/thoughtcrime/securesms/database/model/MessageRecord;ZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setGutterSizes(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setHasBeenQuoted(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setInteractionState(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setMediaAttributes(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;ZZZZ)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setMessageShape(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setMessageSpacing(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setQuote(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setReactions(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setStatusIcons(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setThumbnailCorners(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->shouldInterceptClicks(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->showProjectionArea()V +HPLorg/thoughtcrime/securesms/conversation/ConversationItem;->unbind()V +HPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->onDrawForeground(Landroid/graphics/Canvas;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setQuoteViewProjection(Lorg/thoughtcrime/securesms/util/Projection;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setVideoPlayerProjection(Lorg/thoughtcrime/securesms/util/Projection;)V +HPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getConversationTimestamp()J +HPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->getLatestTimestamp(Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge;Landroidx/recyclerview/widget/LinearLayoutManager;)Lj$/util/Optional; +HPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingBodyTextColor(Landroid/content/Context;Z)I +HPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingGroupSenderColor(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)I +HPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$itemDecoration$1;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->animateChange(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)Z HPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->animatePersistence(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)Z +HPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->animateSlide(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)Z +HPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->onAnimationFinished(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Single;->toSet()Ljava/util/Set; +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->getCurrentSelection(Landroidx/recyclerview/widget/RecyclerView;)Ljava/util/Set; +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->getDifferenceForPart(Ljava/util/Set;Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart;)Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->resolveMultiselectable(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;)Lorg/thoughtcrime/securesms/conversation/mutiselect/Multiselectable; +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->updateChildOffsets(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;)V +HPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->updateMultiselectPartAnimator(Ljava/util/Set;Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart;)V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->bindPayloadsIfAvailable()Z +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getBindable()Lorg/thoughtcrime/securesms/BindableConversationItem; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getColorizerProjections(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/ProjectionList; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getNextMessage()Lj$/util/Optional; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getPreviousMessage()Lj$/util/Optional; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder;->bind(Lorg/thoughtcrime/securesms/conversation/v2/data/IncomingMedia;)V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->bind(Lorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;)V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->consumePulseRequest()Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge$PulseRequest; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getChatColorsData()Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getConversationMessage(I)Lorg/thoughtcrime/securesms/conversation/ConversationMessage; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ThreadHeaderMarginDecoration;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$2;->get()Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5;->invoke()Ljava/lang/Boolean; HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$6;->invoke()Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->invoke()Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$8;->invoke(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->doAfterFirstRender()V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->getHeader(Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->hasHeader(I)Z +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->isFirstUnread(I)Z +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->timestamp(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)J +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->toEpochDay(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)J +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getReminder$lambda$10(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lj$/util/Optional; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getRequestReviewState$lambda$15(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getRequestReviewState(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;)Lio/reactivex/rxjava3/core/Single; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->apply(Lj$/util/Optional;)Lio/reactivex/rxjava3/core/MaybeSource; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$canShowAsBubble$1;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;)Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1;->apply(Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)Lio/reactivex/rxjava3/core/SingleSource; +HPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getChatColorsSnapshot()Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; HPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->equals(Ljava/lang/Object;)Z HPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->equals(Ljava/lang/Object;)Z +HPLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->equals(Ljava/lang/Object;)Z +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean; +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$1;->invoke(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->draw(Landroid/graphics/Canvas;)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getChatColors()Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getOutline(Landroid/graphics/Outline;)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->isSolidColor()Z +HPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->setCorners([F)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->onMeasure(II)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isEndOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->setMessageShape(Lorg/thoughtcrime/securesms/database/model/MessageRecord;ZI)Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$footerDrawable$1;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->bind(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel;)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->getColorizerProjections(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/ProjectionList; +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->invalidateBodyBubbleDrawable(Landroid/view/ViewGroup;)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->invalidateChatColorsDrawable(Landroid/view/ViewGroup;)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->linkifyMessageBody(Landroid/text/Spannable;)V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentBody()V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentSender()V +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getBodyTextColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)I +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->getFooterWidth()I +HPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->onPostMeasure()Z HPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$unregisterObserver$17(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V +HPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->beginTransaction()V +HPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isFailed()Z +HPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPendingInsecureSmsFallback()Z HPLorg/thoughtcrime/securesms/database/model/IdentityRecord;->equals(Ljava/lang/Object;)Z -HPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->equals(Ljava/lang/Object;)Z -HPLorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest;->getCreateTime()J +HPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isRateLimited()Z +HPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isSecure()Z +HPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->isMediaPending()Z +HPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration$onDraw$1;->invoke(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; +HPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration$onDraw$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$RangeComparator;->compare(Ljava/lang/Integer;Ljava/lang/Integer;)I +HPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->getCurrentHolder(I)Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder; +HPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->updateVideoDisplayPositionAndSize(Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4Playable;)V +HPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getMessageFontSize()I +HPLorg/thoughtcrime/securesms/keyvalue/WallpaperValues;->hasWallpaperSet()Z +HPLorg/thoughtcrime/securesms/mms/ImageSlide;->isBorderless()Z HPLorg/thoughtcrime/securesms/mms/Slide;->equals(Ljava/lang/Object;)Z -HPLorg/thoughtcrime/securesms/profiles/ProfileName;->equals(Ljava/lang/Object;)Z -HPLorg/thoughtcrime/securesms/recipients/Recipient;->hasSameContent(Lorg/thoughtcrime/securesms/recipients/Recipient;)Z +HPLorg/thoughtcrime/securesms/mms/Slide;->getTransferState()I +HPLorg/thoughtcrime/securesms/mms/Slide;->hashCode()I +HPLorg/thoughtcrime/securesms/mms/Slide;->isInProgress()Z +HPLorg/thoughtcrime/securesms/mms/Slide;->isPendingDownload()Z +HPLorg/thoughtcrime/securesms/mms/SlideDeck;->getThumbnailSlides()Ljava/util/List; +HPLorg/thoughtcrime/securesms/reactions/ReactionsConversationView;->clear()V +HPLorg/thoughtcrime/securesms/recipients/Recipient;->hasWallpaper()Z +HPLorg/thoughtcrime/securesms/util/BubbleUtil;->canBubble(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/Long;)Z +HPLorg/thoughtcrime/securesms/util/DateUtils;->getSameDayDateFormat()Ljava/text/SimpleDateFormat; +HPLorg/thoughtcrime/securesms/util/DateUtils;->isSameDay(JJ)Z +HPLorg/thoughtcrime/securesms/util/JavaTimeExtensionsKt;->toLocalDate$default(JLj$/time/ZoneId;ILjava/lang/Object;)Lj$/time/LocalDate; +HPLorg/thoughtcrime/securesms/util/JavaTimeExtensionsKt;->toLocalDate(JLj$/time/ZoneId;)Lj$/time/LocalDate; +HPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->updateActiveState$lambda$7$lambda$6(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;IIIILandroid/animation/ValueAnimator;)V +HPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasNoBubble(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z +HPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasOnlyThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z +HPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isBorderless(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z +HPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isEditMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +HPLorg/thoughtcrime/securesms/util/Projection$Corners;->(FFFF)V +HPLorg/thoughtcrime/securesms/util/Projection$Corners;->toRadii()[F +HPLorg/thoughtcrime/securesms/util/ProjectionList;->close()V +HPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getMessageBodyTextSize(Landroid/content/Context;)I +HPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->drawAsTopItemDecoration(Landroid/view/View;Landroid/graphics/Canvas;Landroid/view/View;Landroid/view/View;I)V +HPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->layoutIn(Landroid/view/View;Landroid/view/View;)V +HPLorg/thoughtcrime/securesms/util/ViewUtil;->isRtl(Landroid/view/View;)Z +HPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingBottom(Landroid/view/View;I)V +HPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingEnd(Landroid/view/View;I)V +HPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingStart(Landroid/view/View;I)V +HPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingTop(Landroid/view/View;I)V +HPLorg/thoughtcrime/securesms/util/ViewUtil;->setTopMargin(Landroid/view/View;IZ)V +HPLorg/thoughtcrime/securesms/util/ViewUtil;->updateLayoutParams(Landroid/view/View;II)V +HPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->setPayload(Ljava/util/List;)V +HPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->getItem(I)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel; +HPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->getItemViewType(I)I +HPLorg/thoughtcrime/securesms/util/views/NullableStub;->get()Ljava/lang/Object; +HPLorg/thoughtcrime/securesms/util/views/NullableStub;->require()Ljava/lang/Object; HSPLandroid/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$$ExternalSyntheticThrowCCEIfNotNull0;->m(Ljava/lang/Object;)V HSPLandroid/support/v4/media/session/IMediaSession$Stub;->()V HSPLandroid/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21;->(Landroid/content/Context;Landroid/support/v4/media/session/MediaSessionCompat$Token;)V @@ -44,6 +330,7 @@ HSPLandroid/support/v4/media/session/MediaSessionCompat$Callback;->()V HSPLandroid/support/v4/media/session/MediaSessionCompat$Callback;->setSessionImpl(Landroid/support/v4/media/session/MediaSessionCompat$MediaSessionImpl;Landroid/os/Handler;)V HSPLandroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession;->(Landroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21;)V HSPLandroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21;->(Landroid/content/Context;Ljava/lang/String;Landroidx/versionedparcelable/VersionedParcelable;Landroid/os/Bundle;)V +HSPLandroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21;->getMediaSession()Ljava/lang/Object; HSPLandroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21;->getSessionToken()Landroid/support/v4/media/session/MediaSessionCompat$Token; HSPLandroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21;->setActive(Z)V HSPLandroid/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21;->setCallback(Landroid/support/v4/media/session/MediaSessionCompat$Callback;Landroid/os/Handler;)V @@ -70,6 +357,7 @@ HSPLandroid/support/v4/media/session/MediaSessionCompat$Token;->getToken()Ljava/ HSPLandroid/support/v4/media/session/MediaSessionCompat;->(Landroid/content/Context;Ljava/lang/String;Landroid/content/ComponentName;Landroid/app/PendingIntent;Landroid/os/Bundle;)V HSPLandroid/support/v4/media/session/MediaSessionCompat;->(Landroid/content/Context;Ljava/lang/String;Landroid/content/ComponentName;Landroid/app/PendingIntent;Landroid/os/Bundle;Landroidx/versionedparcelable/VersionedParcelable;)V HSPLandroid/support/v4/media/session/MediaSessionCompat;->getController()Landroid/support/v4/media/session/MediaControllerCompat; +HSPLandroid/support/v4/media/session/MediaSessionCompat;->getMediaSession()Ljava/lang/Object; HSPLandroid/support/v4/media/session/MediaSessionCompat;->getSessionToken()Landroid/support/v4/media/session/MediaSessionCompat$Token; HSPLandroid/support/v4/media/session/MediaSessionCompat;->setActive(Z)V HSPLandroid/support/v4/media/session/MediaSessionCompat;->setCallback(Landroid/support/v4/media/session/MediaSessionCompat$Callback;Landroid/os/Handler;)V @@ -104,21 +392,21 @@ HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;->(Landr HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;->run()V HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda1;->(Landroidx/activity/ComponentActivity;)V HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;->(Landroidx/activity/ComponentActivity;)V -HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;->saveState()Landroid/os/Bundle; HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;->(Landroidx/activity/ComponentActivity;)V HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;->onContextAvailable(Landroid/content/Context;)V HSPLandroidx/activity/ComponentActivity$1;->(Landroidx/activity/ComponentActivity;)V HSPLandroidx/activity/ComponentActivity$2;->(Landroidx/activity/ComponentActivity;)V +HSPLandroidx/activity/ComponentActivity$2;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/activity/ComponentActivity$3;->(Landroidx/activity/ComponentActivity;)V HSPLandroidx/activity/ComponentActivity$3;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/activity/ComponentActivity$4;->(Landroidx/activity/ComponentActivity;)V HSPLandroidx/activity/ComponentActivity$4;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/activity/ComponentActivity$5;->(Landroidx/activity/ComponentActivity;)V -HSPLandroidx/activity/ComponentActivity$5;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V +HSPLandroidx/activity/ComponentActivity$6;->(Landroidx/activity/ComponentActivity;)V +HSPLandroidx/activity/ComponentActivity$6;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/activity/ComponentActivity$Api19Impl;->cancelPendingInputEvents(Landroid/view/View;)V HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->(Landroidx/activity/ComponentActivity;)V HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->activityDestroyed()V -HSPLandroidx/activity/ComponentActivity;->$r8$lambda$OnwlVMZzrLePIRy-6IUDTtLLUV0(Landroidx/activity/ComponentActivity;)Landroid/os/Bundle; HSPLandroidx/activity/ComponentActivity;->$r8$lambda$h2i_RK2mddCIbAsGubaI4eL8_cU(Landroidx/activity/ComponentActivity;Landroid/content/Context;)V HSPLandroidx/activity/ComponentActivity;->()V HSPLandroidx/activity/ComponentActivity;->addMenuProvider(Landroidx/core/view/MenuProvider;)V @@ -138,12 +426,10 @@ HSPLandroidx/activity/ComponentActivity;->getOnBackPressedDispatcher()Landroidx/ HSPLandroidx/activity/ComponentActivity;->getSavedStateRegistry()Landroidx/savedstate/SavedStateRegistry; HSPLandroidx/activity/ComponentActivity;->getViewModelStore()Landroidx/lifecycle/ViewModelStore; HSPLandroidx/activity/ComponentActivity;->invalidateMenu()V -HSPLandroidx/activity/ComponentActivity;->lambda$new$1()Landroid/os/Bundle; HSPLandroidx/activity/ComponentActivity;->lambda$new$2(Landroid/content/Context;)V HSPLandroidx/activity/ComponentActivity;->onCreate(Landroid/os/Bundle;)V HSPLandroidx/activity/ComponentActivity;->onCreatePanelMenu(ILandroid/view/Menu;)Z HSPLandroidx/activity/ComponentActivity;->onPreparePanel(ILandroid/view/View;Landroid/view/Menu;)Z -HSPLandroidx/activity/ComponentActivity;->onSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/activity/ComponentActivity;->removeMenuProvider(Landroidx/core/view/MenuProvider;)V HSPLandroidx/activity/ComponentActivity;->removeOnConfigurationChangedListener(Landroidx/core/util/Consumer;)V HSPLandroidx/activity/ComponentActivity;->removeOnMultiWindowModeChangedListener(Landroidx/core/util/Consumer;)V @@ -155,18 +441,31 @@ HSPLandroidx/activity/FullyDrawnReporter$$ExternalSyntheticLambda0;->(Land HSPLandroidx/activity/FullyDrawnReporter;->(Ljava/util/concurrent/Executor;Lkotlin/jvm/functions/Function0;)V HSPLandroidx/activity/OnBackPressedCallback;->(Z)V HSPLandroidx/activity/OnBackPressedCallback;->addCancellable(Landroidx/activity/Cancellable;)V +HSPLandroidx/activity/OnBackPressedCallback;->getEnabledChangedCallback$activity_release()Lkotlin/jvm/functions/Function0; +HSPLandroidx/activity/OnBackPressedCallback;->isEnabled()Z HSPLandroidx/activity/OnBackPressedCallback;->remove()V HSPLandroidx/activity/OnBackPressedCallback;->removeCancellable(Landroidx/activity/Cancellable;)V HSPLandroidx/activity/OnBackPressedCallback;->setEnabled(Z)V +HSPLandroidx/activity/OnBackPressedCallback;->setEnabledChangedCallback$activity_release(Lkotlin/jvm/functions/Function0;)V HSPLandroidx/activity/OnBackPressedDispatcher$LifecycleOnBackPressedCancellable;->(Landroidx/activity/OnBackPressedDispatcher;Landroidx/lifecycle/Lifecycle;Landroidx/activity/OnBackPressedCallback;)V HSPLandroidx/activity/OnBackPressedDispatcher$LifecycleOnBackPressedCancellable;->cancel()V HSPLandroidx/activity/OnBackPressedDispatcher$LifecycleOnBackPressedCancellable;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/activity/OnBackPressedDispatcher$OnBackPressedCancellable;->(Landroidx/activity/OnBackPressedDispatcher;Landroidx/activity/OnBackPressedCallback;)V HSPLandroidx/activity/OnBackPressedDispatcher$OnBackPressedCancellable;->cancel()V +HSPLandroidx/activity/OnBackPressedDispatcher$addCallback$1;->(Ljava/lang/Object;)V +HSPLandroidx/activity/OnBackPressedDispatcher$addCallback$1;->invoke()Ljava/lang/Object; +HSPLandroidx/activity/OnBackPressedDispatcher$addCallback$1;->invoke()V +HSPLandroidx/activity/OnBackPressedDispatcher$addCancellableCallback$1;->(Ljava/lang/Object;)V +HSPLandroidx/activity/OnBackPressedDispatcher$addCancellableCallback$1;->invoke()Ljava/lang/Object; +HSPLandroidx/activity/OnBackPressedDispatcher$addCancellableCallback$1;->invoke()V HSPLandroidx/activity/OnBackPressedDispatcher;->(Ljava/lang/Runnable;)V +HSPLandroidx/activity/OnBackPressedDispatcher;->(Ljava/lang/Runnable;Landroidx/core/util/Consumer;)V +HSPLandroidx/activity/OnBackPressedDispatcher;->access$getInProgressCallback$p(Landroidx/activity/OnBackPressedDispatcher;)Landroidx/activity/OnBackPressedCallback; HSPLandroidx/activity/OnBackPressedDispatcher;->access$getOnBackPressedCallbacks$p(Landroidx/activity/OnBackPressedDispatcher;)Lkotlin/collections/ArrayDeque; +HSPLandroidx/activity/OnBackPressedDispatcher;->access$updateEnabledCallbacks(Landroidx/activity/OnBackPressedDispatcher;)V HSPLandroidx/activity/OnBackPressedDispatcher;->addCallback(Landroidx/lifecycle/LifecycleOwner;Landroidx/activity/OnBackPressedCallback;)V HSPLandroidx/activity/OnBackPressedDispatcher;->addCancellableCallback$activity_release(Landroidx/activity/OnBackPressedCallback;)Landroidx/activity/Cancellable; +HSPLandroidx/activity/OnBackPressedDispatcher;->updateEnabledCallbacks()V HSPLandroidx/activity/ViewTreeOnBackPressedDispatcherOwner;->set(Landroid/view/View;Landroidx/activity/OnBackPressedDispatcherOwner;)V HSPLandroidx/activity/contextaware/ContextAwareHelper;->()V HSPLandroidx/activity/contextaware/ContextAwareHelper;->addOnContextAvailableListener(Landroidx/activity/contextaware/OnContextAvailableListener;)V @@ -184,7 +483,6 @@ HSPLandroidx/activity/result/ActivityResultRegistry$LifecycleContainer;->addObse HSPLandroidx/activity/result/ActivityResultRegistry;->()V HSPLandroidx/activity/result/ActivityResultRegistry;->bindRcKey(ILjava/lang/String;)V HSPLandroidx/activity/result/ActivityResultRegistry;->generateRandomNumber()I -HSPLandroidx/activity/result/ActivityResultRegistry;->onSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/activity/result/ActivityResultRegistry;->register(Ljava/lang/String;Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher; HSPLandroidx/activity/result/ActivityResultRegistry;->register(Ljava/lang/String;Landroidx/lifecycle/LifecycleOwner;Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher; HSPLandroidx/activity/result/ActivityResultRegistry;->registerKey(Ljava/lang/String;)V @@ -203,7 +501,6 @@ HSPLandroidx/appcompat/app/ActionBar$LayoutParams;->(II)V HSPLandroidx/appcompat/app/ActionBar$LayoutParams;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/appcompat/app/ActionBar;->()V HSPLandroidx/appcompat/app/AppCompatActivity$1;->(Landroidx/appcompat/app/AppCompatActivity;)V -HSPLandroidx/appcompat/app/AppCompatActivity$1;->saveState()Landroid/os/Bundle; HSPLandroidx/appcompat/app/AppCompatActivity$2;->(Landroidx/appcompat/app/AppCompatActivity;)V HSPLandroidx/appcompat/app/AppCompatActivity$2;->onContextAvailable(Landroid/content/Context;)V HSPLandroidx/appcompat/app/AppCompatActivity;->()V @@ -295,7 +592,6 @@ HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onCreateView(Landroid/view/Vi HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onDestroy()V HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onPostCreate(Landroid/os/Bundle;)V HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onPostResume()V -HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onStart()V HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onStop()V HSPLandroidx/appcompat/app/AppCompatDelegateImpl;->onSubDecorInstalled(Landroid/view/ViewGroup;)V @@ -320,6 +616,7 @@ HSPLandroidx/appcompat/app/AppCompatViewInflater;->createImageView(Landroid/cont HSPLandroidx/appcompat/app/AppCompatViewInflater;->createTextView(Landroid/content/Context;Landroid/util/AttributeSet;)Landroidx/appcompat/widget/AppCompatTextView; HSPLandroidx/appcompat/app/AppCompatViewInflater;->createView(Landroid/content/Context;Ljava/lang/String;Landroid/util/AttributeSet;)Landroid/view/View; HSPLandroidx/appcompat/app/AppCompatViewInflater;->createView(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;ZZZZ)Landroid/view/View; +HSPLandroidx/appcompat/app/AppCompatViewInflater;->themifyContext(Landroid/content/Context;Landroid/util/AttributeSet;ZZ)Landroid/content/Context; HSPLandroidx/appcompat/app/AppCompatViewInflater;->verifyNotNull(Landroid/view/View;Ljava/lang/String;)V HSPLandroidx/appcompat/app/AppLocalesMetadataHolderService$Api24Impl;->getDisabledComponentFlag()I HSPLandroidx/appcompat/app/AppLocalesMetadataHolderService;->getServiceInfo(Landroid/content/Context;)Landroid/content/pm/ServiceInfo; @@ -356,10 +653,8 @@ HSPLandroidx/appcompat/view/ContextThemeWrapper;->isEmptyConfiguration(Landroid/ HSPLandroidx/appcompat/view/ContextThemeWrapper;->onApplyThemeResource(Landroid/content/res/Resources$Theme;IZ)V HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->(Landroidx/appcompat/view/SupportMenuInflater;Landroid/view/Menu;)V HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->addItem()V -HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->addSubMenuItem()Landroid/view/SubMenu; HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->getShortcut(Ljava/lang/String;)C HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->hasAddedItem()Z -HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->newInstance(Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->readItem(Landroid/util/AttributeSet;)V HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->resetGroup()V HSPLandroidx/appcompat/view/SupportMenuInflater$MenuState;->setItem(Landroid/view/MenuItem;)V @@ -405,9 +700,7 @@ HSPLandroidx/appcompat/view/menu/MenuBuilder;->(Landroid/content/Context;) HSPLandroidx/appcompat/view/menu/MenuBuilder;->add(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuBuilder;->addInternal(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuBuilder;->addMenuPresenter(Landroidx/appcompat/view/menu/MenuPresenter;Landroid/content/Context;)V -HSPLandroidx/appcompat/view/menu/MenuBuilder;->addSubMenu(IIILjava/lang/CharSequence;)Landroid/view/SubMenu; HSPLandroidx/appcompat/view/menu/MenuBuilder;->clear()V -HSPLandroidx/appcompat/view/menu/MenuBuilder;->clearHeader()V HSPLandroidx/appcompat/view/menu/MenuBuilder;->createNewMenuItem(IIIILjava/lang/CharSequence;I)Landroidx/appcompat/view/menu/MenuItemImpl; HSPLandroidx/appcompat/view/menu/MenuBuilder;->dispatchPresenterUpdate(Z)V HSPLandroidx/appcompat/view/menu/MenuBuilder;->findInsertIndex(Ljava/util/ArrayList;I)I @@ -419,7 +712,6 @@ HSPLandroidx/appcompat/view/menu/MenuBuilder;->getContext()Landroid/content/Cont HSPLandroidx/appcompat/view/menu/MenuBuilder;->getItem(I)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuBuilder;->getNonActionItems()Ljava/util/ArrayList; HSPLandroidx/appcompat/view/menu/MenuBuilder;->getOrdering(I)I -HSPLandroidx/appcompat/view/menu/MenuBuilder;->getResources()Landroid/content/res/Resources; HSPLandroidx/appcompat/view/menu/MenuBuilder;->getVisibleItems()Ljava/util/ArrayList; HSPLandroidx/appcompat/view/menu/MenuBuilder;->hasVisibleItems()Z HSPLandroidx/appcompat/view/menu/MenuBuilder;->onItemActionRequestChanged(Landroidx/appcompat/view/menu/MenuItemImpl;)V @@ -428,8 +720,6 @@ HSPLandroidx/appcompat/view/menu/MenuBuilder;->onItemsChanged(Z)V HSPLandroidx/appcompat/view/menu/MenuBuilder;->removeItem(I)V HSPLandroidx/appcompat/view/menu/MenuBuilder;->removeItemAtInt(IZ)V HSPLandroidx/appcompat/view/menu/MenuBuilder;->setCallback(Landroidx/appcompat/view/menu/MenuBuilder$Callback;)V -HSPLandroidx/appcompat/view/menu/MenuBuilder;->setHeaderInternal(ILjava/lang/CharSequence;ILandroid/graphics/drawable/Drawable;Landroid/view/View;)V -HSPLandroidx/appcompat/view/menu/MenuBuilder;->setHeaderTitleInt(Ljava/lang/CharSequence;)Landroidx/appcompat/view/menu/MenuBuilder; HSPLandroidx/appcompat/view/menu/MenuBuilder;->setOverrideVisibleItems(Z)V HSPLandroidx/appcompat/view/menu/MenuBuilder;->setShortcutsVisibleInner(Z)V HSPLandroidx/appcompat/view/menu/MenuBuilder;->size()I @@ -443,7 +733,6 @@ HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getGroupId()I HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getIcon()Landroid/graphics/drawable/Drawable; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getItemId()I HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getOrdering()I -HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getSubMenu()Landroid/view/SubMenu; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getSupportActionProvider()Landroidx/core/view/ActionProvider; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getTitle()Ljava/lang/CharSequence; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->getTitleCondensed()Ljava/lang/CharSequence; @@ -456,8 +745,6 @@ HSPLandroidx/appcompat/view/menu/MenuItemImpl;->isEnabled()Z HSPLandroidx/appcompat/view/menu/MenuItemImpl;->isVisible()Z HSPLandroidx/appcompat/view/menu/MenuItemImpl;->requestsActionButton()Z HSPLandroidx/appcompat/view/menu/MenuItemImpl;->requiresActionButton()Z -HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setActionView(Landroid/view/View;)Landroid/view/MenuItem; -HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setActionView(Landroid/view/View;)Landroidx/core/internal/view/SupportMenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setAlphabeticShortcut(CI)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setCheckable(Z)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setChecked(Z)Landroid/view/MenuItem; @@ -468,18 +755,12 @@ HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setIcon(I)Landroid/view/MenuItem HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setIconTintList(Landroid/content/res/ColorStateList;)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setIsActionButton(Z)V HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setNumericShortcut(CI)Landroid/view/MenuItem; -HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setOnActionExpandListener(Landroid/view/MenuItem$OnActionExpandListener;)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setShowAsAction(I)V -HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setSubMenu(Landroidx/appcompat/view/menu/SubMenuBuilder;)V -HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setTitle(Ljava/lang/CharSequence;)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setTitleCondensed(Ljava/lang/CharSequence;)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setTooltipText(Ljava/lang/CharSequence;)Landroidx/core/internal/view/SupportMenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setVisible(Z)Landroid/view/MenuItem; HSPLandroidx/appcompat/view/menu/MenuItemImpl;->setVisibleInt(Z)Z HSPLandroidx/appcompat/view/menu/MenuItemImpl;->showsTextAsAction()Z -HSPLandroidx/appcompat/view/menu/SubMenuBuilder;->(Landroid/content/Context;Landroidx/appcompat/view/menu/MenuBuilder;Landroidx/appcompat/view/menu/MenuItemImpl;)V -HSPLandroidx/appcompat/view/menu/SubMenuBuilder;->getItem()Landroid/view/MenuItem; -HSPLandroidx/appcompat/view/menu/SubMenuBuilder;->setHeaderTitle(Ljava/lang/CharSequence;)Landroid/view/SubMenu; HSPLandroidx/appcompat/widget/ActionMenuPresenter$ActionMenuPopupCallback;->(Landroidx/appcompat/widget/ActionMenuPresenter;)V HSPLandroidx/appcompat/widget/ActionMenuPresenter$OverflowMenuButton$1;->(Landroidx/appcompat/widget/ActionMenuPresenter$OverflowMenuButton;Landroid/view/View;Landroidx/appcompat/widget/ActionMenuPresenter;)V HSPLandroidx/appcompat/widget/ActionMenuPresenter$OverflowMenuButton;->(Landroidx/appcompat/widget/ActionMenuPresenter;Landroid/content/Context;)V @@ -492,7 +773,6 @@ HSPLandroidx/appcompat/widget/ActionMenuPresenter;->flagActionItems()Z HSPLandroidx/appcompat/widget/ActionMenuPresenter;->getItemView(Landroidx/appcompat/view/menu/MenuItemImpl;Landroid/view/View;Landroid/view/ViewGroup;)Landroid/view/View; HSPLandroidx/appcompat/widget/ActionMenuPresenter;->getOverflowIcon()Landroid/graphics/drawable/Drawable; HSPLandroidx/appcompat/widget/ActionMenuPresenter;->initForMenu(Landroid/content/Context;Landroidx/appcompat/view/menu/MenuBuilder;)V -HSPLandroidx/appcompat/widget/ActionMenuPresenter;->isOverflowMenuShowing()Z HSPLandroidx/appcompat/widget/ActionMenuPresenter;->setExpandedActionViewsExclusive(Z)V HSPLandroidx/appcompat/widget/ActionMenuPresenter;->setMenuView(Landroidx/appcompat/widget/ActionMenuView;)V HSPLandroidx/appcompat/widget/ActionMenuPresenter;->setReserveOverflow(Z)V @@ -512,7 +792,6 @@ HSPLandroidx/appcompat/widget/ActionMenuView;->generateOverflowButtonLayoutParam HSPLandroidx/appcompat/widget/ActionMenuView;->getMenu()Landroid/view/Menu; HSPLandroidx/appcompat/widget/ActionMenuView;->getOverflowIcon()Landroid/graphics/drawable/Drawable; HSPLandroidx/appcompat/widget/ActionMenuView;->initialize(Landroidx/appcompat/view/menu/MenuBuilder;)V -HSPLandroidx/appcompat/widget/ActionMenuView;->isOverflowMenuShowing()Z HSPLandroidx/appcompat/widget/ActionMenuView;->onLayout(ZIIII)V HSPLandroidx/appcompat/widget/ActionMenuView;->onMeasure(II)V HSPLandroidx/appcompat/widget/ActionMenuView;->peekMenu()Landroidx/appcompat/view/menu/MenuBuilder; @@ -521,12 +800,9 @@ HSPLandroidx/appcompat/widget/ActionMenuView;->setMenuCallbacks(Landroidx/appcom HSPLandroidx/appcompat/widget/ActionMenuView;->setOnMenuItemClickListener(Landroidx/appcompat/widget/ActionMenuView$OnMenuItemClickListener;)V HSPLandroidx/appcompat/widget/ActionMenuView;->setOverflowReserved(Z)V HSPLandroidx/appcompat/widget/ActionMenuView;->setPopupTheme(I)V -HSPLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->()V -HSPLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->initEmojiKeyListener(Landroidx/appcompat/widget/AppCompatEmojiEditTextHelper;)V -HSPLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->setCompoundDrawables(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V HSPLandroidx/appcompat/widget/AppCompatBackgroundHelper;->(Landroid/view/View;)V HSPLandroidx/appcompat/widget/AppCompatBackgroundHelper;->applySupportBackgroundTint()V +HSPLandroidx/appcompat/widget/AppCompatBackgroundHelper;->loadFromAttributes(Landroid/util/AttributeSet;I)V HSPLandroidx/appcompat/widget/AppCompatBackgroundHelper;->onSetBackgroundDrawable(Landroid/graphics/drawable/Drawable;)V HSPLandroidx/appcompat/widget/AppCompatBackgroundHelper;->onSetBackgroundResource(I)V HSPLandroidx/appcompat/widget/AppCompatBackgroundHelper;->setInternalBackgroundTint(Landroid/content/res/ColorStateList;)V @@ -553,7 +829,6 @@ HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->()V HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->arrayContains([II)Z HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->createDrawableFor(Landroidx/appcompat/widget/ResourceManagerInternal;Landroid/content/Context;I)Landroid/graphics/drawable/Drawable; HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->getTintListForDrawableRes(Landroid/content/Context;I)Landroid/content/res/ColorStateList; -HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->getTintModeForDrawableRes(I)Landroid/graphics/PorterDuff$Mode; HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->tintDrawable(Landroid/content/Context;ILandroid/graphics/drawable/Drawable;)Z HSPLandroidx/appcompat/widget/AppCompatDrawableManager$1;->tintDrawableUsingColorFilter(Landroid/content/Context;ILandroid/graphics/drawable/Drawable;)Z HSPLandroidx/appcompat/widget/AppCompatDrawableManager;->()V @@ -630,12 +905,13 @@ HSPLandroidx/appcompat/widget/AppCompatTextHelper$Api17Impl;->getCompoundDrawabl HSPLandroidx/appcompat/widget/AppCompatTextHelper$Api17Impl;->setCompoundDrawablesRelativeWithIntrinsicBounds(Landroid/widget/TextView;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->(Landroid/widget/TextView;)V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->applyCompoundDrawablesTints()V -HSPLandroidx/appcompat/widget/AppCompatTextHelper;->createTintInfo(Landroid/content/Context;Landroidx/appcompat/widget/AppCompatDrawableManager;I)Landroidx/appcompat/widget/TintInfo; +HSPLandroidx/appcompat/widget/AppCompatTextHelper;->loadFromAttributes(Landroid/util/AttributeSet;I)V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->onLayout(ZIIII)V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->onSetCompoundDrawables()V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->onSetTextAppearance(Landroid/content/Context;I)V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->populateSurroundingTextIfNeeded(Landroid/widget/TextView;Landroid/view/inputmethod/InputConnection;Landroid/view/inputmethod/EditorInfo;)V HSPLandroidx/appcompat/widget/AppCompatTextHelper;->setCompoundDrawables(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V +HSPLandroidx/appcompat/widget/AppCompatTextHelper;->updateTypefaceAndStyle(Landroid/content/Context;Landroidx/appcompat/widget/TintTypedArray;)V HSPLandroidx/appcompat/widget/AppCompatTextView;->(Landroid/content/Context;)V HSPLandroidx/appcompat/widget/AppCompatTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/appcompat/widget/AppCompatTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V @@ -652,7 +928,6 @@ HSPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawables(Landroid/ HSPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawablesRelative(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V HSPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawablesRelativeWithIntrinsicBounds(IIII)V HSPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawablesRelativeWithIntrinsicBounds(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V -HSPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawablesWithIntrinsicBounds(IIII)V HSPLandroidx/appcompat/widget/AppCompatTextView;->setCompoundDrawablesWithIntrinsicBounds(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V HSPLandroidx/appcompat/widget/AppCompatTextView;->setEmojiCompatEnabled(Z)V HSPLandroidx/appcompat/widget/AppCompatTextView;->setFilters([Landroid/text/InputFilter;)V @@ -688,7 +963,6 @@ HSPLandroidx/appcompat/widget/FitWindowsFrameLayout;->(Landroid/content/Co HSPLandroidx/appcompat/widget/FitWindowsFrameLayout;->fitSystemWindows(Landroid/graphics/Rect;)Z HSPLandroidx/appcompat/widget/ForwardingListener;->(Landroid/view/View;)V HSPLandroidx/appcompat/widget/ForwardingListener;->onViewAttachedToWindow(Landroid/view/View;)V -HSPLandroidx/appcompat/widget/ForwardingListener;->onViewDetachedFromWindow(Landroid/view/View;)V HSPLandroidx/appcompat/widget/LinearLayoutCompat$LayoutParams;->(II)V HSPLandroidx/appcompat/widget/LinearLayoutCompat$LayoutParams;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/appcompat/widget/LinearLayoutCompat;->(Landroid/content/Context;Landroid/util/AttributeSet;)V @@ -723,7 +997,6 @@ HSPLandroidx/appcompat/widget/ResourceManagerInternal$ColorFilterLruCache;->get( HSPLandroidx/appcompat/widget/ResourceManagerInternal$ColorFilterLruCache;->put(ILandroid/graphics/PorterDuff$Mode;Landroid/graphics/PorterDuffColorFilter;)Landroid/graphics/PorterDuffColorFilter; HSPLandroidx/appcompat/widget/ResourceManagerInternal;->()V HSPLandroidx/appcompat/widget/ResourceManagerInternal;->()V -HSPLandroidx/appcompat/widget/ResourceManagerInternal;->addTintListToCache(Landroid/content/Context;ILandroid/content/res/ColorStateList;)V HSPLandroidx/appcompat/widget/ResourceManagerInternal;->checkVectorDrawableSetup(Landroid/content/Context;)V HSPLandroidx/appcompat/widget/ResourceManagerInternal;->createCacheKey(Landroid/util/TypedValue;)J HSPLandroidx/appcompat/widget/ResourceManagerInternal;->createDrawableIfNeeded(Landroid/content/Context;I)Landroid/graphics/drawable/Drawable; @@ -735,7 +1008,6 @@ HSPLandroidx/appcompat/widget/ResourceManagerInternal;->getDrawable(Landroid/con HSPLandroidx/appcompat/widget/ResourceManagerInternal;->getPorterDuffColorFilter(ILandroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuffColorFilter; HSPLandroidx/appcompat/widget/ResourceManagerInternal;->getTintList(Landroid/content/Context;I)Landroid/content/res/ColorStateList; HSPLandroidx/appcompat/widget/ResourceManagerInternal;->getTintListFromCache(Landroid/content/Context;I)Landroid/content/res/ColorStateList; -HSPLandroidx/appcompat/widget/ResourceManagerInternal;->getTintMode(I)Landroid/graphics/PorterDuff$Mode; HSPLandroidx/appcompat/widget/ResourceManagerInternal;->installDefaultInflateDelegates(Landroidx/appcompat/widget/ResourceManagerInternal;)V HSPLandroidx/appcompat/widget/ResourceManagerInternal;->isVectorDrawable(Landroid/graphics/drawable/Drawable;)Z HSPLandroidx/appcompat/widget/ResourceManagerInternal;->loadDrawableFromDelegates(Landroid/content/Context;I)Landroid/graphics/drawable/Drawable; @@ -749,36 +1021,6 @@ HSPLandroidx/appcompat/widget/RtlSpacingHelper;->getStart()I HSPLandroidx/appcompat/widget/RtlSpacingHelper;->setAbsolute(II)V HSPLandroidx/appcompat/widget/RtlSpacingHelper;->setDirection(Z)V HSPLandroidx/appcompat/widget/RtlSpacingHelper;->setRelative(II)V -HSPLandroidx/appcompat/widget/SearchView$10;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$1;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$2;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$3;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$4;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$5;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$6;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$7;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$8;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$9;->(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete$1;->(Landroidx/appcompat/widget/SearchView$SearchAutoComplete;)V -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->enoughToFilter()Z -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->getSearchViewTextMinWidthDp()I -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->onFinishInflate()V -HSPLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->setSearchView(Landroidx/appcompat/widget/SearchView;)V -HSPLandroidx/appcompat/widget/SearchView;->()V -HSPLandroidx/appcompat/widget/SearchView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLandroidx/appcompat/widget/SearchView;->getDecoratedHint(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; -HSPLandroidx/appcompat/widget/SearchView;->getQueryHint()Ljava/lang/CharSequence; -HSPLandroidx/appcompat/widget/SearchView;->isSubmitAreaEnabled()Z -HSPLandroidx/appcompat/widget/SearchView;->setIconifiedByDefault(Z)V -HSPLandroidx/appcompat/widget/SearchView;->setMaxWidth(I)V -HSPLandroidx/appcompat/widget/SearchView;->updateCloseButton()V -HSPLandroidx/appcompat/widget/SearchView;->updateQueryHint()V -HSPLandroidx/appcompat/widget/SearchView;->updateSubmitArea()V -HSPLandroidx/appcompat/widget/SearchView;->updateSubmitButton(Z)V -HSPLandroidx/appcompat/widget/SearchView;->updateViewsVisibility(Z)V -HSPLandroidx/appcompat/widget/SearchView;->updateVoiceButton(Z)V HSPLandroidx/appcompat/widget/ThemeUtils;->()V HSPLandroidx/appcompat/widget/ThemeUtils;->checkAppCompatTheme(Landroid/view/View;Landroid/content/Context;)V HSPLandroidx/appcompat/widget/TintContextWrapper;->()V @@ -816,9 +1058,6 @@ HSPLandroidx/appcompat/widget/Toolbar$ExpandedActionViewMenuPresenter;->initForM HSPLandroidx/appcompat/widget/Toolbar$ExpandedActionViewMenuPresenter;->updateMenuView(Z)V HSPLandroidx/appcompat/widget/Toolbar$LayoutParams;->(II)V HSPLandroidx/appcompat/widget/Toolbar$LayoutParams;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLandroidx/appcompat/widget/Toolbar$SavedState$1;->()V -HSPLandroidx/appcompat/widget/Toolbar$SavedState;->()V -HSPLandroidx/appcompat/widget/Toolbar$SavedState;->(Landroid/os/Parcelable;)V HSPLandroidx/appcompat/widget/Toolbar;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/appcompat/widget/Toolbar;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLandroidx/appcompat/widget/Toolbar;->addCustomViewsWithGravity(Ljava/util/List;I)V @@ -854,7 +1093,6 @@ HSPLandroidx/appcompat/widget/Toolbar;->getVerticalMargins(Landroid/view/View;)I HSPLandroidx/appcompat/widget/Toolbar;->getViewListMeasuredWidth(Ljava/util/List;[I)I HSPLandroidx/appcompat/widget/Toolbar;->invalidateMenu()V HSPLandroidx/appcompat/widget/Toolbar;->isChildOrHidden(Landroid/view/View;)Z -HSPLandroidx/appcompat/widget/Toolbar;->isOverflowMenuShowing()Z HSPLandroidx/appcompat/widget/Toolbar;->layoutChildLeft(Landroid/view/View;I[II)I HSPLandroidx/appcompat/widget/Toolbar;->layoutChildRight(Landroid/view/View;I[II)I HSPLandroidx/appcompat/widget/Toolbar;->measureChildCollapseMargins(Landroid/view/View;IIII[I)I @@ -864,7 +1102,6 @@ HSPLandroidx/appcompat/widget/Toolbar;->onCreateMenu()V HSPLandroidx/appcompat/widget/Toolbar;->onLayout(ZIIII)V HSPLandroidx/appcompat/widget/Toolbar;->onMeasure(II)V HSPLandroidx/appcompat/widget/Toolbar;->onRtlPropertiesChanged(I)V -HSPLandroidx/appcompat/widget/Toolbar;->onSaveInstanceState()Landroid/os/Parcelable; HSPLandroidx/appcompat/widget/Toolbar;->setBackInvokedCallbackEnabled(Z)V HSPLandroidx/appcompat/widget/Toolbar;->setMenuCallbacks(Landroidx/appcompat/view/menu/MenuPresenter$Callback;Landroidx/appcompat/view/menu/MenuBuilder$Callback;)V HSPLandroidx/appcompat/widget/Toolbar;->setNavigationContentDescription(I)V @@ -984,40 +1221,6 @@ HSPLandroidx/asynclayoutinflater/view/AsyncLayoutInflater;->inflateInternal(ILan HSPLandroidx/asynclayoutinflater/view/AsyncLayoutInflater;->triggerCallbacks(Landroidx/asynclayoutinflater/view/AsyncLayoutInflater$InflateRequest;Landroidx/asynclayoutinflater/view/AsyncLayoutInflater$InflateThread;)V HSPLandroidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi24Impl$OutputConfigurationParamsApi24$$ExternalSyntheticBackport1;->m(J)I HSPLandroidx/camera/view/PreviewView$1$$ExternalSyntheticBackportWithForwarding0;->m(Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;Ljava/lang/Object;)Z -HSPLandroidx/cardview/R$styleable;->()V -HSPLandroidx/cardview/widget/CardView$1;->(Landroidx/cardview/widget/CardView;)V -HSPLandroidx/cardview/widget/CardView$1;->getCardBackground()Landroid/graphics/drawable/Drawable; -HSPLandroidx/cardview/widget/CardView$1;->getCardView()Landroid/view/View; -HSPLandroidx/cardview/widget/CardView$1;->getPreventCornerOverlap()Z -HSPLandroidx/cardview/widget/CardView$1;->getUseCompatPadding()Z -HSPLandroidx/cardview/widget/CardView$1;->setCardBackground(Landroid/graphics/drawable/Drawable;)V -HSPLandroidx/cardview/widget/CardView$1;->setShadowPadding(IIII)V -HSPLandroidx/cardview/widget/CardView;->()V -HSPLandroidx/cardview/widget/CardView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLandroidx/cardview/widget/CardView;->access$001(Landroidx/cardview/widget/CardView;IIII)V -HSPLandroidx/cardview/widget/CardView;->getCardBackgroundColor()Landroid/content/res/ColorStateList; -HSPLandroidx/cardview/widget/CardView;->getCardElevation()F -HSPLandroidx/cardview/widget/CardView;->getContentPaddingBottom()I -HSPLandroidx/cardview/widget/CardView;->getContentPaddingLeft()I -HSPLandroidx/cardview/widget/CardView;->getContentPaddingRight()I -HSPLandroidx/cardview/widget/CardView;->getContentPaddingTop()I -HSPLandroidx/cardview/widget/CardView;->getPreventCornerOverlap()Z -HSPLandroidx/cardview/widget/CardView;->getUseCompatPadding()Z -HSPLandroidx/cardview/widget/CardView;->onMeasure(II)V -HSPLandroidx/cardview/widget/CardView;->setContentPadding(IIII)V -HSPLandroidx/cardview/widget/CardViewApi21Impl;->()V -HSPLandroidx/cardview/widget/CardViewApi21Impl;->getBackgroundColor(Landroidx/cardview/widget/CardViewDelegate;)Landroid/content/res/ColorStateList; -HSPLandroidx/cardview/widget/CardViewApi21Impl;->getCardBackground(Landroidx/cardview/widget/CardViewDelegate;)Landroidx/cardview/widget/RoundRectDrawable; -HSPLandroidx/cardview/widget/CardViewApi21Impl;->getElevation(Landroidx/cardview/widget/CardViewDelegate;)F -HSPLandroidx/cardview/widget/CardViewApi21Impl;->initStatic()V -HSPLandroidx/cardview/widget/CardViewApi21Impl;->initialize(Landroidx/cardview/widget/CardViewDelegate;Landroid/content/Context;Landroid/content/res/ColorStateList;FFF)V -HSPLandroidx/cardview/widget/CardViewApi21Impl;->setMaxElevation(Landroidx/cardview/widget/CardViewDelegate;F)V -HSPLandroidx/cardview/widget/CardViewApi21Impl;->updatePadding(Landroidx/cardview/widget/CardViewDelegate;)V -HSPLandroidx/cardview/widget/RoundRectDrawable;->(Landroid/content/res/ColorStateList;F)V -HSPLandroidx/cardview/widget/RoundRectDrawable;->getColor()Landroid/content/res/ColorStateList; -HSPLandroidx/cardview/widget/RoundRectDrawable;->setBackground(Landroid/content/res/ColorStateList;)V -HSPLandroidx/cardview/widget/RoundRectDrawable;->setPadding(FZZ)V -HSPLandroidx/cardview/widget/RoundRectDrawable;->updateBounds(Landroid/graphics/Rect;)V HSPLandroidx/collection/ArrayMap$EntrySet;->(Landroidx/collection/ArrayMap;)V HSPLandroidx/collection/ArrayMap$EntrySet;->iterator()Ljava/util/Iterator; HSPLandroidx/collection/ArrayMap$MapIterator;->(Landroidx/collection/ArrayMap;)V @@ -1103,11 +1306,8 @@ HSPLandroidx/collection/SimpleArrayMap;->valueAt(I)Ljava/lang/Object; HSPLandroidx/collection/SparseArrayCompat;->()V HSPLandroidx/collection/SparseArrayCompat;->()V HSPLandroidx/collection/SparseArrayCompat;->(I)V -HSPLandroidx/collection/SparseArrayCompat;->append(ILjava/lang/Object;)V -HSPLandroidx/collection/SparseArrayCompat;->containsValue(Ljava/lang/Object;)Z HSPLandroidx/collection/SparseArrayCompat;->get(I)Ljava/lang/Object; HSPLandroidx/collection/SparseArrayCompat;->get(ILjava/lang/Object;)Ljava/lang/Object; -HSPLandroidx/collection/SparseArrayCompat;->indexOfValue(Ljava/lang/Object;)I HSPLandroidx/collection/SparseArrayCompat;->keyAt(I)I HSPLandroidx/collection/SparseArrayCompat;->put(ILjava/lang/Object;)V HSPLandroidx/collection/SparseArrayCompat;->size()I @@ -1129,6 +1329,7 @@ HSPLandroidx/compose/ui/text/platform/extensions/LocaleListHelperMethods$$Extern HSPLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper$$ExternalSyntheticBackportWithForwarding0;->m(Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->()V HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->(Landroidx/constraintlayout/core/ArrayRow;Landroidx/constraintlayout/core/Cache;)V +HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->add(Landroidx/constraintlayout/core/SolverVariable;FZ)V HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->clear()V HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->contains(Landroidx/constraintlayout/core/SolverVariable;)Z HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->divideByAmount(F)V @@ -1137,7 +1338,6 @@ HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->getCurrentSize()I HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->getVariable(I)Landroidx/constraintlayout/core/SolverVariable; HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->getVariableValue(I)F HSPLandroidx/constraintlayout/core/ArrayLinkedVariables;->invert()V -HSPLandroidx/constraintlayout/core/ArrayRow;->(Landroidx/constraintlayout/core/Cache;)V HSPLandroidx/constraintlayout/core/ArrayRow;->addError(Landroidx/constraintlayout/core/LinearSystem;I)Landroidx/constraintlayout/core/ArrayRow; HSPLandroidx/constraintlayout/core/ArrayRow;->addSingleError(Landroidx/constraintlayout/core/SolverVariable;I)Landroidx/constraintlayout/core/ArrayRow; HSPLandroidx/constraintlayout/core/ArrayRow;->chooseSubject(Landroidx/constraintlayout/core/LinearSystem;)Z @@ -1154,7 +1354,6 @@ HSPLandroidx/constraintlayout/core/ArrayRow;->hasKeyVariable()Z HSPLandroidx/constraintlayout/core/ArrayRow;->hasVariable(Landroidx/constraintlayout/core/SolverVariable;)Z HSPLandroidx/constraintlayout/core/ArrayRow;->isEmpty()Z HSPLandroidx/constraintlayout/core/ArrayRow;->isNew(Landroidx/constraintlayout/core/SolverVariable;Landroidx/constraintlayout/core/LinearSystem;)Z -HSPLandroidx/constraintlayout/core/ArrayRow;->pivot(Landroidx/constraintlayout/core/SolverVariable;)V HSPLandroidx/constraintlayout/core/ArrayRow;->reset()V HSPLandroidx/constraintlayout/core/ArrayRow;->updateFromFinalVariable(Landroidx/constraintlayout/core/LinearSystem;Landroidx/constraintlayout/core/SolverVariable;Z)V HSPLandroidx/constraintlayout/core/Cache;->()V @@ -1203,6 +1402,7 @@ HSPLandroidx/constraintlayout/core/PriorityGoalRow;->clear()V HSPLandroidx/constraintlayout/core/PriorityGoalRow;->getPivotCandidate(Landroidx/constraintlayout/core/LinearSystem;[Z)Landroidx/constraintlayout/core/SolverVariable; HSPLandroidx/constraintlayout/core/PriorityGoalRow;->isEmpty()Z HSPLandroidx/constraintlayout/core/PriorityGoalRow;->removeGoal(Landroidx/constraintlayout/core/SolverVariable;)V +HSPLandroidx/constraintlayout/core/PriorityGoalRow;->updateFromRow(Landroidx/constraintlayout/core/LinearSystem;Landroidx/constraintlayout/core/ArrayRow;Z)V HSPLandroidx/constraintlayout/core/SolverVariable$Type;->()V HSPLandroidx/constraintlayout/core/SolverVariable$Type;->(Ljava/lang/String;I)V HSPLandroidx/constraintlayout/core/SolverVariable;->()V @@ -1225,7 +1425,6 @@ HSPLandroidx/constraintlayout/core/widgets/Chain;->applyChainConstraints(Landroi HSPLandroidx/constraintlayout/core/widgets/Chain;->applyChainConstraints(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;Landroidx/constraintlayout/core/LinearSystem;Ljava/util/ArrayList;I)V HSPLandroidx/constraintlayout/core/widgets/ChainHead;->(Landroidx/constraintlayout/core/widgets/ConstraintWidget;IZ)V HSPLandroidx/constraintlayout/core/widgets/ChainHead;->define()V -HSPLandroidx/constraintlayout/core/widgets/ChainHead;->defineChainProperties()V HSPLandroidx/constraintlayout/core/widgets/ChainHead;->isMatchConstraintEqualityCandidate(Landroidx/constraintlayout/core/widgets/ConstraintWidget;I)Z HSPLandroidx/constraintlayout/core/widgets/ConstraintAnchor$1;->()V HSPLandroidx/constraintlayout/core/widgets/ConstraintAnchor$Type;->()V @@ -1356,6 +1555,7 @@ HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->invalidat HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->isHeightMeasuredTooSmall()Z HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->isRtl()Z HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->isWidthMeasuredTooSmall()Z +HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->layout()V HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->measure(IIIIIIIII)J HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->measure(ILandroidx/constraintlayout/core/widgets/ConstraintWidget;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measure;I)Z HSPLandroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;->optimizeFor(I)Z @@ -1395,6 +1595,7 @@ HSPLandroidx/constraintlayout/core/widgets/WidgetContainer;->resetSolverVariable HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measure;->()V HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measure;->()V HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure;->(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;)V +HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure;->measure(Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;Landroidx/constraintlayout/core/widgets/ConstraintWidget;I)Z HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure;->measureChildren(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;)V HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure;->solveLinearSystem(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;Ljava/lang/String;III)V HSPLandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure;->solverMeasure(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;IIIIIIIII)J @@ -1404,6 +1605,7 @@ HSPLandroidx/constraintlayout/core/widgets/analyzer/DependencyGraph;->invalidate HSPLandroidx/constraintlayout/core/widgets/analyzer/DependencyGraph;->invalidateMeasures()V HSPLandroidx/constraintlayout/core/widgets/analyzer/DependencyGraph;->setMeasurer(Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;)V HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->()V +HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->canMeasure(ILandroidx/constraintlayout/core/widgets/ConstraintWidget;)Z HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->horizontalSolvingPass(ILandroidx/constraintlayout/core/widgets/ConstraintWidget;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;Z)V HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->solveBarrier(ILandroidx/constraintlayout/core/widgets/Barrier;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;IZ)V HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->solveHorizontalCenterConstraints(ILandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;Landroidx/constraintlayout/core/widgets/ConstraintWidget;Z)V @@ -1411,6 +1613,7 @@ HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->solveHorizontalMatc HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->solveVerticalCenterConstraints(ILandroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;Landroidx/constraintlayout/core/widgets/ConstraintWidget;)V HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->solveVerticalMatchConstraint(ILandroidx/constraintlayout/core/widgets/ConstraintWidget;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;Landroidx/constraintlayout/core/widgets/ConstraintWidget;)V HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->solvingPass(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;)V +HSPLandroidx/constraintlayout/core/widgets/analyzer/Direct;->verticalSolvingPass(ILandroidx/constraintlayout/core/widgets/ConstraintWidget;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measurer;)V HSPLandroidx/constraintlayout/widget/Barrier;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/constraintlayout/widget/Barrier;->init(Landroid/util/AttributeSet;)V HSPLandroidx/constraintlayout/widget/Barrier;->resolveRtl(Landroidx/constraintlayout/core/widgets/ConstraintWidget;Z)V @@ -1433,18 +1636,16 @@ HSPLandroidx/constraintlayout/widget/ConstraintHelper;->updatePreLayout(Landroid HSPLandroidx/constraintlayout/widget/ConstraintHelper;->validateParams()V HSPLandroidx/constraintlayout/widget/ConstraintLayout$1;->()V HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;->()V -HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->validate()V HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->(Landroidx/constraintlayout/widget/ConstraintLayout;Landroidx/constraintlayout/widget/ConstraintLayout;)V HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->captureLayoutInfo(IIIIII)V HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->didMeasures()V HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->isSimilarSpec(III)Z -HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/core/widgets/ConstraintWidget;Landroidx/constraintlayout/core/widgets/analyzer/BasicMeasure$Measure;)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->()V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->access$000(Landroidx/constraintlayout/widget/ConstraintLayout;)I HSPLandroidx/constraintlayout/widget/ConstraintLayout;->access$100(Landroidx/constraintlayout/widget/ConstraintLayout;)Ljava/util/ArrayList; -HSPLandroidx/constraintlayout/widget/ConstraintLayout;->applyConstraintsFromLayoutParams(ZLandroid/view/View;Landroidx/constraintlayout/core/widgets/ConstraintWidget;Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;Landroid/util/SparseArray;)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->checkLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Z HSPLandroidx/constraintlayout/widget/ConstraintLayout;->dispatchDraw(Landroid/graphics/Canvas;)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->generateLayoutParams(Landroid/util/AttributeSet;)Landroid/view/ViewGroup$LayoutParams; @@ -1462,6 +1663,7 @@ HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onViewRemoved(Landroid/v HSPLandroidx/constraintlayout/widget/ConstraintLayout;->requestLayout()V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->resolveMeasuredDimension(IIIIZZ)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->resolveSystem(Landroidx/constraintlayout/core/widgets/ConstraintWidgetContainer;III)V +HSPLandroidx/constraintlayout/widget/ConstraintLayout;->setChildrenConstraints()V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->setConstraintSet(Landroidx/constraintlayout/widget/ConstraintSet;)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->setId(I)V HSPLandroidx/constraintlayout/widget/ConstraintLayout;->setMinHeight(I)V @@ -1522,9 +1724,6 @@ HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$LayoutParams;->setNested HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$LayoutParams;->shouldDodge(Landroid/view/View;I)Z HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$OnPreDrawListener;->(Landroidx/coordinatorlayout/widget/CoordinatorLayout;)V HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$OnPreDrawListener;->onPreDraw()Z -HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState$1;->()V -HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState;->()V -HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState;->(Landroid/os/Parcelable;)V HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$ViewElevationComparator;->()V HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$ViewElevationComparator;->compare(Landroid/view/View;Landroid/view/View;)I HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout$ViewElevationComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I @@ -1560,7 +1759,6 @@ HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onLayoutChild(Landroid HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onMeasure(II)V HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onMeasureChild(Landroid/view/View;IIII)V HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onNestedScrollAccepted(Landroid/view/View;Landroid/view/View;II)V -HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onSaveInstanceState()Landroid/os/Parcelable; HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onStartNestedScroll(Landroid/view/View;Landroid/view/View;II)Z HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onStopNestedScroll(Landroid/view/View;I)V HSPLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onTouchEvent(Landroid/view/MotionEvent;)Z @@ -1596,11 +1794,8 @@ HSPLandroidx/core/app/ActivityCompat;->startPostponedEnterTransition(Landroid/ap HSPLandroidx/core/app/AppOpsManagerCompat$Api23Impl$$ExternalSyntheticApiModelOutline1;->m(Ljava/lang/String;)Ljava/lang/String; HSPLandroidx/core/app/AppOpsManagerCompat$Api23Impl;->permissionToOp(Ljava/lang/String;)Ljava/lang/String; HSPLandroidx/core/app/AppOpsManagerCompat;->permissionToOp(Ljava/lang/String;)Ljava/lang/String; -HSPLandroidx/core/app/BundleCompat;->getBinder(Landroid/os/Bundle;Ljava/lang/String;)Landroid/os/IBinder; -HSPLandroidx/core/app/BundleCompat;->putBinder(Landroid/os/Bundle;Ljava/lang/String;Landroid/os/IBinder;)V HSPLandroidx/core/app/ComponentActivity;->()V HSPLandroidx/core/app/ComponentActivity;->onCreate(Landroid/os/Bundle;)V -HSPLandroidx/core/app/ComponentActivity;->onSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/core/app/CoreComponentFactory;->()V HSPLandroidx/core/app/CoreComponentFactory;->checkCompatWrapper(Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity; @@ -1705,18 +1900,6 @@ HSPLandroidx/core/graphics/drawable/DrawableCompat;->unwrap(Landroid/graphics/dr HSPLandroidx/core/graphics/drawable/DrawableCompat;->wrap(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable; HSPLandroidx/core/math/MathUtils;->clamp(FFF)F HSPLandroidx/core/math/MathUtils;->clamp(III)I -HSPLandroidx/core/os/BuildCompat$Api30Impl$$ExternalSyntheticApiModelOutline0;->m(I)I -HSPLandroidx/core/os/BuildCompat$Api30Impl;->()V -HSPLandroidx/core/os/BuildCompat$Api30Impl;->()V -HSPLandroidx/core/os/BuildCompat$Api30Impl;->getExtensionVersion(I)I -HSPLandroidx/core/os/BuildCompat;->()V -HSPLandroidx/core/os/BuildCompat;->()V -HSPLandroidx/core/os/BuildCompat;->isAtLeastT()Z -HSPLandroidx/core/os/BundleCompat$Api18Impl;->getBinder(Landroid/os/Bundle;Ljava/lang/String;)Landroid/os/IBinder; -HSPLandroidx/core/os/BundleCompat$Api18Impl;->putBinder(Landroid/os/Bundle;Ljava/lang/String;Landroid/os/IBinder;)V -HSPLandroidx/core/os/BundleCompat;->getBinder(Landroid/os/Bundle;Ljava/lang/String;)Landroid/os/IBinder; -HSPLandroidx/core/os/BundleCompat;->putBinder(Landroid/os/Bundle;Ljava/lang/String;Landroid/os/IBinder;)V -HSPLandroidx/core/os/BundleKt;->bundleOf([Lkotlin/Pair;)Landroid/os/Bundle; HSPLandroidx/core/os/CancellationSignal;->()V HSPLandroidx/core/os/CancellationSignal;->setOnCancelListener(Landroidx/core/os/CancellationSignal$OnCancelListener;)V HSPLandroidx/core/os/CancellationSignal;->waitForCancelFinishedLocked()V @@ -1749,10 +1932,6 @@ HSPLandroidx/core/os/TraceCompat;->endSection()V HSPLandroidx/core/os/UserManagerCompat$Api24Impl$$ExternalSyntheticApiModelOutline0;->m(Landroid/os/UserManager;)Z HSPLandroidx/core/os/UserManagerCompat$Api24Impl;->isUserUnlocked(Landroid/content/Context;)Z HSPLandroidx/core/os/UserManagerCompat;->isUserUnlocked(Landroid/content/Context;)Z -HSPLandroidx/core/text/util/LinkifyCompat$$ExternalSyntheticLambda0;->()V -HSPLandroidx/core/text/util/LinkifyCompat;->()V -HSPLandroidx/core/text/util/LinkifyCompat;->addLinks(Landroid/text/Spannable;I)Z -HSPLandroidx/core/text/util/LinkifyCompat;->shouldAddLinksFallbackToFramework()Z HSPLandroidx/core/util/ObjectsCompat$Api19Impl;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z HSPLandroidx/core/util/ObjectsCompat$Api19Impl;->hash([Ljava/lang/Object;)I HSPLandroidx/core/util/ObjectsCompat;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z @@ -1822,6 +2001,7 @@ HSPLandroidx/core/view/NestedScrollingChildHelper;->isNestedScrollingEnabled()Z HSPLandroidx/core/view/NestedScrollingChildHelper;->setNestedScrollingEnabled(Z)V HSPLandroidx/core/view/NestedScrollingChildHelper;->setNestedScrollingParentForType(ILandroid/view/ViewParent;)V HSPLandroidx/core/view/NestedScrollingChildHelper;->startNestedScroll(II)Z +HSPLandroidx/core/view/NestedScrollingChildHelper;->stopNestedScroll()V HSPLandroidx/core/view/NestedScrollingChildHelper;->stopNestedScroll(I)V HSPLandroidx/core/view/NestedScrollingParentHelper;->(Landroid/view/ViewGroup;)V HSPLandroidx/core/view/NestedScrollingParentHelper;->onNestedScrollAccepted(Landroid/view/View;Landroid/view/View;II)V @@ -1961,14 +2141,11 @@ HSPLandroidx/core/view/ViewGroupKt$children$1;->(Landroid/view/ViewGroup;) HSPLandroidx/core/view/ViewGroupKt$children$1;->iterator()Ljava/util/Iterator; HSPLandroidx/core/view/ViewGroupKt$iterator$1;->(Landroid/view/ViewGroup;)V HSPLandroidx/core/view/ViewGroupKt$iterator$1;->hasNext()Z -HSPLandroidx/core/view/ViewGroupKt$iterator$1;->next()Landroid/view/View; -HSPLandroidx/core/view/ViewGroupKt$iterator$1;->next()Ljava/lang/Object; HSPLandroidx/core/view/ViewGroupKt;->getChildren(Landroid/view/ViewGroup;)Lkotlin/sequences/Sequence; HSPLandroidx/core/view/ViewGroupKt;->iterator(Landroid/view/ViewGroup;)Ljava/util/Iterator; HSPLandroidx/core/view/ViewKt$doOnPreDraw$1;->(Lkotlin/jvm/functions/Function1;Landroid/view/View;)V HSPLandroidx/core/view/ViewKt$doOnPreDraw$1;->run()V HSPLandroidx/core/view/ViewKt;->doOnPreDraw(Landroid/view/View;Lkotlin/jvm/functions/Function1;)Landroidx/core/view/OneShotPreDrawListener; -HSPLandroidx/core/view/ViewKt;->isVisible(Landroid/view/View;)Z HSPLandroidx/core/view/ViewParentCompat;->onNestedScrollAccepted(Landroid/view/ViewParent;Landroid/view/View;Landroid/view/View;II)V HSPLandroidx/core/view/ViewParentCompat;->onStartNestedScroll(Landroid/view/ViewParent;Landroid/view/View;Landroid/view/View;II)Z HSPLandroidx/core/view/ViewParentCompat;->onStopNestedScroll(Landroid/view/ViewParent;Landroid/view/View;I)V @@ -2099,13 +2276,8 @@ HSPLandroidx/core/widget/TextViewCompat;->setLineHeight(Landroid/widget/TextView HSPLandroidx/core/widget/TextViewCompat;->wrapCustomSelectionActionModeCallback(Landroid/widget/TextView;Landroid/view/ActionMode$Callback;)Landroid/view/ActionMode$Callback; HSPLandroidx/core/widget/TextViewOnReceiveContentListener;->()V HSPLandroidx/customview/poolingcontainer/PoolingContainer;->()V +HSPLandroidx/customview/poolingcontainer/PoolingContainer;->callPoolingContainerOnReleaseForChildren(Landroid/view/ViewGroup;)V HSPLandroidx/customview/poolingcontainer/PoolingContainer;->setPoolingContainer(Landroid/view/View;Z)V -HSPLandroidx/customview/view/AbsSavedState$1;->()V -HSPLandroidx/customview/view/AbsSavedState$2;->()V -HSPLandroidx/customview/view/AbsSavedState;->()V -HSPLandroidx/customview/view/AbsSavedState;->()V -HSPLandroidx/customview/view/AbsSavedState;->(Landroid/os/Parcelable;)V -HSPLandroidx/customview/view/AbsSavedState;->(Landroidx/customview/view/AbsSavedState$1;)V HSPLandroidx/customview/widget/ExploreByTouchHelper$1;->()V HSPLandroidx/customview/widget/ExploreByTouchHelper$2;->()V HSPLandroidx/customview/widget/ExploreByTouchHelper;->()V @@ -2176,7 +2348,6 @@ HSPLandroidx/emoji2/text/SpannableBuilder$WatcherWrapper;->(Ljava/lang/Obj HSPLandroidx/emoji2/text/SpannableBuilder$WatcherWrapper;->onSpanAdded(Landroid/text/Spannable;Ljava/lang/Object;II)V HSPLandroidx/emoji2/text/SpannableBuilder;->(Ljava/lang/Class;Ljava/lang/CharSequence;)V HSPLandroidx/emoji2/text/SpannableBuilder;->create(Ljava/lang/Class;Ljava/lang/CharSequence;)Landroidx/emoji2/text/SpannableBuilder; -HSPLandroidx/emoji2/text/SpannableBuilder;->getSpanEnd(Ljava/lang/Object;)I HSPLandroidx/emoji2/text/SpannableBuilder;->getSpanFlags(Ljava/lang/Object;)I HSPLandroidx/emoji2/text/SpannableBuilder;->getSpanStart(Ljava/lang/Object;)I HSPLandroidx/emoji2/text/SpannableBuilder;->getSpans(IILjava/lang/Class;)[Ljava/lang/Object; @@ -2267,7 +2438,6 @@ HSPLandroidx/fragment/app/Fragment$7;->apply(Ljava/lang/Void;)Landroidx/activity HSPLandroidx/fragment/app/Fragment$9;->(Landroidx/fragment/app/Fragment;Landroidx/arch/core/util/Function;Ljava/util/concurrent/atomic/AtomicReference;Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)V HSPLandroidx/fragment/app/Fragment$9;->onPreAttached()V HSPLandroidx/fragment/app/Fragment$AnimationInfo;->()V -HSPLandroidx/fragment/app/Fragment$Api19Impl;->cancelPendingInputEvents(Landroid/view/View;)V HSPLandroidx/fragment/app/Fragment$OnPreAttachedListener;->()V HSPLandroidx/fragment/app/Fragment$OnPreAttachedListener;->(Landroidx/fragment/app/Fragment$1;)V HSPLandroidx/fragment/app/Fragment;->$r8$lambda$Cl7MxTaA6NVZ8I5KAGBxRTLl1sc(Landroidx/fragment/app/Fragment;)V @@ -2284,7 +2454,6 @@ HSPLandroidx/fragment/app/Fragment;->getChildFragmentManager()Landroidx/fragment HSPLandroidx/fragment/app/Fragment;->getContext()Landroid/content/Context; HSPLandroidx/fragment/app/Fragment;->getDefaultViewModelCreationExtras()Landroidx/lifecycle/viewmodel/CreationExtras; HSPLandroidx/fragment/app/Fragment;->getFocusedView()Landroid/view/View; -HSPLandroidx/fragment/app/Fragment;->getHost()Ljava/lang/Object; HSPLandroidx/fragment/app/Fragment;->getId()I HSPLandroidx/fragment/app/Fragment;->getLayoutInflater(Landroid/os/Bundle;)Landroid/view/LayoutInflater; HSPLandroidx/fragment/app/Fragment;->getLifecycle()Landroidx/lifecycle/Lifecycle; @@ -2317,13 +2486,12 @@ HSPLandroidx/fragment/app/Fragment;->onAttachFragment(Landroidx/fragment/app/Fra HSPLandroidx/fragment/app/Fragment;->onCreate(Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->onCreateView(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View; HSPLandroidx/fragment/app/Fragment;->onGetLayoutInflater(Landroid/os/Bundle;)Landroid/view/LayoutInflater; +HSPLandroidx/fragment/app/Fragment;->onInflate(Landroid/app/Activity;Landroid/util/AttributeSet;Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->onInflate(Landroid/content/Context;Landroid/util/AttributeSet;Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->onPause()V HSPLandroidx/fragment/app/Fragment;->onPrimaryNavigationFragmentChanged(Z)V HSPLandroidx/fragment/app/Fragment;->onResume()V -HSPLandroidx/fragment/app/Fragment;->onSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->onStart()V -HSPLandroidx/fragment/app/Fragment;->onStop()V HSPLandroidx/fragment/app/Fragment;->onViewCreated(Landroid/view/View;Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->onViewStateRestored(Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->performActivityCreated(Landroid/os/Bundle;)V @@ -2336,9 +2504,7 @@ HSPLandroidx/fragment/app/Fragment;->performPause()V HSPLandroidx/fragment/app/Fragment;->performPrepareOptionsMenu(Landroid/view/Menu;)Z HSPLandroidx/fragment/app/Fragment;->performPrimaryNavigationFragmentChanged()V HSPLandroidx/fragment/app/Fragment;->performResume()V -HSPLandroidx/fragment/app/Fragment;->performSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/fragment/app/Fragment;->performStart()V -HSPLandroidx/fragment/app/Fragment;->performStop()V HSPLandroidx/fragment/app/Fragment;->performViewCreated()V HSPLandroidx/fragment/app/Fragment;->prepareCallInternal(Landroidx/activity/result/contract/ActivityResultContract;Landroidx/arch/core/util/Function;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher; HSPLandroidx/fragment/app/Fragment;->registerForActivityResult(Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher; @@ -2359,7 +2525,6 @@ HSPLandroidx/fragment/app/Fragment;->setPopDirection(Z)V HSPLandroidx/fragment/app/Fragment;->setPostOnViewCreatedAlpha(F)V HSPLandroidx/fragment/app/Fragment;->setSharedElementNames(Ljava/util/ArrayList;Ljava/util/ArrayList;)V HSPLandroidx/fragment/app/FragmentActivity$$ExternalSyntheticLambda0;->(Landroidx/fragment/app/FragmentActivity;)V -HSPLandroidx/fragment/app/FragmentActivity$$ExternalSyntheticLambda0;->saveState()Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentActivity$$ExternalSyntheticLambda1;->(Landroidx/fragment/app/FragmentActivity;)V HSPLandroidx/fragment/app/FragmentActivity$$ExternalSyntheticLambda2;->(Landroidx/fragment/app/FragmentActivity;)V HSPLandroidx/fragment/app/FragmentActivity$$ExternalSyntheticLambda3;->(Landroidx/fragment/app/FragmentActivity;)V @@ -2378,8 +2543,6 @@ HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->getViewModelStore()La HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->invalidateMenu()V HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onAttachFragment(Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onFindViewById(I)Landroid/view/View; -HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onGetHost()Landroidx/fragment/app/FragmentActivity; -HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onGetHost()Ljava/lang/Object; HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onGetLayoutInflater()Landroid/view/LayoutInflater; HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onHasView()Z HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onSupportInvalidateOptionsMenu()V @@ -2389,12 +2552,10 @@ HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->removeOnMultiWindowMo HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->removeOnPictureInPictureModeChangedListener(Landroidx/core/util/Consumer;)V HSPLandroidx/fragment/app/FragmentActivity$HostCallbacks;->removeOnTrimMemoryListener(Landroidx/core/util/Consumer;)V HSPLandroidx/fragment/app/FragmentActivity;->$r8$lambda$euPNEtWNfVdMY89Jt5kWt_WEHqw(Landroidx/fragment/app/FragmentActivity;Landroid/content/Context;)V -HSPLandroidx/fragment/app/FragmentActivity;->$r8$lambda$t3WwJ1XbNlapyNW0l552nMkkXdo(Landroidx/fragment/app/FragmentActivity;)Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentActivity;->()V HSPLandroidx/fragment/app/FragmentActivity;->dispatchFragmentsOnCreateView(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/view/View; HSPLandroidx/fragment/app/FragmentActivity;->getSupportFragmentManager()Landroidx/fragment/app/FragmentManager; HSPLandroidx/fragment/app/FragmentActivity;->init()V -HSPLandroidx/fragment/app/FragmentActivity;->lambda$init$0()Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentActivity;->lambda$init$3(Landroid/content/Context;)V HSPLandroidx/fragment/app/FragmentActivity;->markFragmentsCreated()V HSPLandroidx/fragment/app/FragmentActivity;->markState(Landroidx/fragment/app/FragmentManager;Landroidx/lifecycle/Lifecycle$State;)Z @@ -2455,16 +2616,13 @@ HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragm HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentPreAttached(Landroidx/fragment/app/Fragment;Z)V HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentPreCreated(Landroidx/fragment/app/Fragment;Landroid/os/Bundle;Z)V HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentResumed(Landroidx/fragment/app/Fragment;Z)V -HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentSaveInstanceState(Landroidx/fragment/app/Fragment;Landroid/os/Bundle;Z)V HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentStarted(Landroidx/fragment/app/Fragment;Z)V -HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentStopped(Landroidx/fragment/app/Fragment;Z)V HSPLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentViewCreated(Landroidx/fragment/app/Fragment;Landroid/view/View;Landroid/os/Bundle;Z)V HSPLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda0;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda1;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda2;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda3;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda4;->(Landroidx/fragment/app/FragmentManager;)V -HSPLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda4;->saveState()Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentManager$10;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$1;->(Landroidx/fragment/app/FragmentManager;Z)V HSPLandroidx/fragment/app/FragmentManager$2;->(Landroidx/fragment/app/FragmentManager;)V @@ -2475,18 +2633,13 @@ HSPLandroidx/fragment/app/FragmentManager$3;->instantiate(Ljava/lang/ClassLoader HSPLandroidx/fragment/app/FragmentManager$4;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$4;->createController(Landroid/view/ViewGroup;)Landroidx/fragment/app/SpecialEffectsController; HSPLandroidx/fragment/app/FragmentManager$5;->(Landroidx/fragment/app/FragmentManager;)V -HSPLandroidx/fragment/app/FragmentManager$6;->(Landroidx/fragment/app/FragmentManager;Ljava/lang/String;Landroidx/fragment/app/FragmentResultListener;Landroidx/lifecycle/Lifecycle;)V -HSPLandroidx/fragment/app/FragmentManager$6;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/fragment/app/FragmentManager$7;->(Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V HSPLandroidx/fragment/app/FragmentManager$7;->onAttachFragment(Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V HSPLandroidx/fragment/app/FragmentManager$8;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$9;->(Landroidx/fragment/app/FragmentManager;)V HSPLandroidx/fragment/app/FragmentManager$FragmentIntentSenderContract;->()V -HSPLandroidx/fragment/app/FragmentManager$LifecycleAwareResultListener;->(Landroidx/lifecycle/Lifecycle;Landroidx/fragment/app/FragmentResultListener;Landroidx/lifecycle/LifecycleEventObserver;)V -HSPLandroidx/fragment/app/FragmentManager;->$r8$lambda$sido8p6zuWx0PQxIkv4qM-BRiGM(Landroidx/fragment/app/FragmentManager;)Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentManager;->()V HSPLandroidx/fragment/app/FragmentManager;->()V -HSPLandroidx/fragment/app/FragmentManager;->access$000(Landroidx/fragment/app/FragmentManager;)Ljava/util/Map; HSPLandroidx/fragment/app/FragmentManager;->addFragment(Landroidx/fragment/app/Fragment;)Landroidx/fragment/app/FragmentStateManager; HSPLandroidx/fragment/app/FragmentManager;->addFragmentOnAttachListener(Landroidx/fragment/app/FragmentOnAttachListener;)V HSPLandroidx/fragment/app/FragmentManager;->addOnBackStackChangedListener(Landroidx/fragment/app/FragmentManager$OnBackStackChangedListener;)V @@ -2526,7 +2679,6 @@ HSPLandroidx/fragment/app/FragmentManager;->findActiveFragment(Ljava/lang/String HSPLandroidx/fragment/app/FragmentManager;->findFragment(Landroid/view/View;)Landroidx/fragment/app/Fragment; HSPLandroidx/fragment/app/FragmentManager;->findFragmentById(I)Landroidx/fragment/app/Fragment; HSPLandroidx/fragment/app/FragmentManager;->findViewFragment(Landroid/view/View;)Landroidx/fragment/app/Fragment; -HSPLandroidx/fragment/app/FragmentManager;->forcePostponedTransactions()V HSPLandroidx/fragment/app/FragmentManager;->generateOpsForPendingActions(Ljava/util/ArrayList;Ljava/util/ArrayList;)Z HSPLandroidx/fragment/app/FragmentManager;->getBackStackEntryCount()I HSPLandroidx/fragment/app/FragmentManager;->getChildNonConfig(Landroidx/fragment/app/Fragment;)Landroidx/fragment/app/FragmentManagerViewModel; @@ -2549,23 +2701,17 @@ HSPLandroidx/fragment/app/FragmentManager;->isParentMenuVisible(Landroidx/fragme HSPLandroidx/fragment/app/FragmentManager;->isPrimaryNavigation(Landroidx/fragment/app/Fragment;)Z HSPLandroidx/fragment/app/FragmentManager;->isStateAtLeast(I)Z HSPLandroidx/fragment/app/FragmentManager;->isStateSaved()Z -HSPLandroidx/fragment/app/FragmentManager;->lambda$attachController$4()Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentManager;->moveToState(IZ)V HSPLandroidx/fragment/app/FragmentManager;->noteStateNotSaved()V HSPLandroidx/fragment/app/FragmentManager;->onContainerAvailable(Landroidx/fragment/app/FragmentContainerView;)V HSPLandroidx/fragment/app/FragmentManager;->performPendingDeferredStart(Landroidx/fragment/app/FragmentStateManager;)V HSPLandroidx/fragment/app/FragmentManager;->removeRedundantOperationsAndExecute(Ljava/util/ArrayList;Ljava/util/ArrayList;)V -HSPLandroidx/fragment/app/FragmentManager;->saveAllStateInternal()Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentManager;->scheduleCommit()V HSPLandroidx/fragment/app/FragmentManager;->setExitAnimationOrder(Landroidx/fragment/app/Fragment;Z)V -HSPLandroidx/fragment/app/FragmentManager;->setFragmentResultListener(Ljava/lang/String;Landroidx/lifecycle/LifecycleOwner;Landroidx/fragment/app/FragmentResultListener;)V HSPLandroidx/fragment/app/FragmentManager;->setPrimaryNavigationFragment(Landroidx/fragment/app/Fragment;)V HSPLandroidx/fragment/app/FragmentManager;->startPendingDeferredFragments()V HSPLandroidx/fragment/app/FragmentManager;->updateOnBackPressedCallbackEnabled()V HSPLandroidx/fragment/app/FragmentManagerImpl;->()V -HSPLandroidx/fragment/app/FragmentManagerState$1;->()V -HSPLandroidx/fragment/app/FragmentManagerState;->()V -HSPLandroidx/fragment/app/FragmentManagerState;->()V HSPLandroidx/fragment/app/FragmentManagerViewModel$1;->()V HSPLandroidx/fragment/app/FragmentManagerViewModel$1;->create(Ljava/lang/Class;)Landroidx/lifecycle/ViewModel; HSPLandroidx/fragment/app/FragmentManagerViewModel$1;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel; @@ -2577,9 +2723,6 @@ HSPLandroidx/fragment/app/FragmentManagerViewModel;->getViewModelStore(Landroidx HSPLandroidx/fragment/app/FragmentManagerViewModel;->isCleared()Z HSPLandroidx/fragment/app/FragmentManagerViewModel;->onCleared()V HSPLandroidx/fragment/app/FragmentManagerViewModel;->setIsStateSaved(Z)V -HSPLandroidx/fragment/app/FragmentState$1;->()V -HSPLandroidx/fragment/app/FragmentState;->()V -HSPLandroidx/fragment/app/FragmentState;->(Landroidx/fragment/app/Fragment;)V HSPLandroidx/fragment/app/FragmentStateManager$1;->(Landroidx/fragment/app/FragmentStateManager;Landroid/view/View;)V HSPLandroidx/fragment/app/FragmentStateManager$1;->onViewAttachedToWindow(Landroid/view/View;)V HSPLandroidx/fragment/app/FragmentStateManager$2;->()V @@ -2597,11 +2740,8 @@ HSPLandroidx/fragment/app/FragmentStateManager;->moveToExpectedState()V HSPLandroidx/fragment/app/FragmentStateManager;->pause()V HSPLandroidx/fragment/app/FragmentStateManager;->restoreState(Ljava/lang/ClassLoader;)V HSPLandroidx/fragment/app/FragmentStateManager;->resume()V -HSPLandroidx/fragment/app/FragmentStateManager;->saveState()Landroid/os/Bundle; -HSPLandroidx/fragment/app/FragmentStateManager;->saveViewState()V HSPLandroidx/fragment/app/FragmentStateManager;->setFragmentManagerState(I)V HSPLandroidx/fragment/app/FragmentStateManager;->start()V -HSPLandroidx/fragment/app/FragmentStateManager;->stop()V HSPLandroidx/fragment/app/FragmentStore;->()V HSPLandroidx/fragment/app/FragmentStore;->addFragment(Landroidx/fragment/app/Fragment;)V HSPLandroidx/fragment/app/FragmentStore;->burpActive()V @@ -2612,14 +2752,11 @@ HSPLandroidx/fragment/app/FragmentStore;->findFragmentById(I)Landroidx/fragment/ HSPLandroidx/fragment/app/FragmentStore;->findFragmentIndexInContainer(Landroidx/fragment/app/Fragment;)I HSPLandroidx/fragment/app/FragmentStore;->getActiveFragmentStateManagers()Ljava/util/List; HSPLandroidx/fragment/app/FragmentStore;->getActiveFragments()Ljava/util/List; -HSPLandroidx/fragment/app/FragmentStore;->getAllSavedState()Ljava/util/HashMap; HSPLandroidx/fragment/app/FragmentStore;->getFragmentStateManager(Ljava/lang/String;)Landroidx/fragment/app/FragmentStateManager; HSPLandroidx/fragment/app/FragmentStore;->getFragments()Ljava/util/List; HSPLandroidx/fragment/app/FragmentStore;->getNonConfig()Landroidx/fragment/app/FragmentManagerViewModel; HSPLandroidx/fragment/app/FragmentStore;->makeActive(Landroidx/fragment/app/FragmentStateManager;)V HSPLandroidx/fragment/app/FragmentStore;->moveToExpectedState()V -HSPLandroidx/fragment/app/FragmentStore;->saveActiveFragments()Ljava/util/ArrayList; -HSPLandroidx/fragment/app/FragmentStore;->saveAddedFragments()Ljava/util/ArrayList; HSPLandroidx/fragment/app/FragmentStore;->setNonConfig(Landroidx/fragment/app/FragmentManagerViewModel;)V HSPLandroidx/fragment/app/FragmentStore;->setSavedState(Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle; HSPLandroidx/fragment/app/FragmentTransaction$Op;->(ILandroidx/fragment/app/Fragment;)V @@ -2640,8 +2777,6 @@ HSPLandroidx/fragment/app/FragmentViewLifecycleOwner;->getSavedStateRegistry()La HSPLandroidx/fragment/app/FragmentViewLifecycleOwner;->handleLifecycleEvent(Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/fragment/app/FragmentViewLifecycleOwner;->initialize()V HSPLandroidx/fragment/app/FragmentViewLifecycleOwner;->performRestore(Landroid/os/Bundle;)V -HSPLandroidx/fragment/app/FragmentViewLifecycleOwner;->performSave(Landroid/os/Bundle;)V -HSPLandroidx/fragment/app/FragmentViewLifecycleOwner;->setCurrentState(Landroidx/lifecycle/Lifecycle$State;)V HSPLandroidx/fragment/app/FragmentViewModelLazyKt;->access$viewModels$lambda-1(Lkotlin/Lazy;)Landroidx/lifecycle/ViewModelStoreOwner; HSPLandroidx/fragment/app/FragmentViewModelLazyKt;->createViewModelLazy(Landroidx/fragment/app/Fragment;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy; HSPLandroidx/fragment/app/FragmentViewModelLazyKt;->viewModels$lambda-1(Lkotlin/Lazy;)Landroidx/lifecycle/ViewModelStoreOwner; @@ -2694,7 +2829,6 @@ HSPLandroidx/fragment/app/SpecialEffectsController;->executePendingOperations()V HSPLandroidx/fragment/app/SpecialEffectsController;->findPendingOperation(Landroidx/fragment/app/Fragment;)Landroidx/fragment/app/SpecialEffectsController$Operation; HSPLandroidx/fragment/app/SpecialEffectsController;->findRunningOperation(Landroidx/fragment/app/Fragment;)Landroidx/fragment/app/SpecialEffectsController$Operation; HSPLandroidx/fragment/app/SpecialEffectsController;->forceCompleteAllOperations()V -HSPLandroidx/fragment/app/SpecialEffectsController;->forcePostponedExecutePendingOperations()V HSPLandroidx/fragment/app/SpecialEffectsController;->getAwaitingCompletionLifecycleImpact(Landroidx/fragment/app/FragmentStateManager;)Landroidx/fragment/app/SpecialEffectsController$Operation$LifecycleImpact; HSPLandroidx/fragment/app/SpecialEffectsController;->getOrCreateController(Landroid/view/ViewGroup;Landroidx/fragment/app/FragmentManager;)Landroidx/fragment/app/SpecialEffectsController; HSPLandroidx/fragment/app/SpecialEffectsController;->getOrCreateController(Landroid/view/ViewGroup;Landroidx/fragment/app/SpecialEffectsControllerFactory;)Landroidx/fragment/app/SpecialEffectsController; @@ -2715,9 +2849,6 @@ HSPLandroidx/interpolator/view/animation/LookupTableInterpolator;->getInterpolat HSPLandroidx/lifecycle/AbstractSavedStateViewModelFactory$Companion;->()V HSPLandroidx/lifecycle/AbstractSavedStateViewModelFactory$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->()V -HSPLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->(Landroidx/savedstate/SavedStateRegistryOwner;Landroid/os/Bundle;)V -HSPLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel; -HSPLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->create(Ljava/lang/String;Ljava/lang/Class;)Landroidx/lifecycle/ViewModel; HSPLandroidx/lifecycle/AndroidViewModel;->(Landroid/app/Application;)V HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->(Ljava/util/Map;)V HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeCallbacks(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V @@ -2736,7 +2867,6 @@ HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onCreate(Landroid HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onPause(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onResume(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStart(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V -HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStop(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V HSPLandroidx/lifecycle/DefaultLifecycleObserverAdapter$WhenMappings;->()V HSPLandroidx/lifecycle/DefaultLifecycleObserverAdapter;->(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V HSPLandroidx/lifecycle/DefaultLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V @@ -2745,14 +2875,11 @@ HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityCreated(Landr HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityDestroyed(Landroid/app/Activity;)V HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityPaused(Landroid/app/Activity;)V HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V -HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V HSPLandroidx/lifecycle/LegacySavedStateHandleController;->()V HSPLandroidx/lifecycle/LegacySavedStateHandleController;->()V HSPLandroidx/lifecycle/LegacySavedStateHandleController;->attachHandleIfNeeded(Landroidx/lifecycle/ViewModel;Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;)V -HSPLandroidx/lifecycle/LegacySavedStateHandleController;->create(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;Ljava/lang/String;Landroid/os/Bundle;)Landroidx/lifecycle/SavedStateHandleController; -HSPLandroidx/lifecycle/LegacySavedStateHandleController;->tryToAddRecreator(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;)V HSPLandroidx/lifecycle/Lifecycle$Event$Companion$WhenMappings;->()V HSPLandroidx/lifecycle/Lifecycle$Event$Companion;->()V HSPLandroidx/lifecycle/Lifecycle$Event$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -2792,7 +2919,6 @@ HSPLandroidx/lifecycle/LifecycleRegistry;->forwardPass(Landroidx/lifecycle/Lifec HSPLandroidx/lifecycle/LifecycleRegistry;->getCurrentState()Landroidx/lifecycle/Lifecycle$State; HSPLandroidx/lifecycle/LifecycleRegistry;->handleLifecycleEvent(Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/lifecycle/LifecycleRegistry;->isSynced()Z -HSPLandroidx/lifecycle/LifecycleRegistry;->markState(Landroidx/lifecycle/Lifecycle$State;)V HSPLandroidx/lifecycle/LifecycleRegistry;->moveToState(Landroidx/lifecycle/Lifecycle$State;)V HSPLandroidx/lifecycle/LifecycleRegistry;->popParentState()V HSPLandroidx/lifecycle/LifecycleRegistry;->pushParentState(Landroidx/lifecycle/Lifecycle$State;)V @@ -2826,6 +2952,7 @@ HSPLandroidx/lifecycle/LiveData;->dispatchingValue(Landroidx/lifecycle/LiveData$ HSPLandroidx/lifecycle/LiveData;->getValue()Ljava/lang/Object; HSPLandroidx/lifecycle/LiveData;->getVersion()I HSPLandroidx/lifecycle/LiveData;->hasActiveObservers()Z +HSPLandroidx/lifecycle/LiveData;->isInitialized()Z HSPLandroidx/lifecycle/LiveData;->observe(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Observer;)V HSPLandroidx/lifecycle/LiveData;->observeForever(Landroidx/lifecycle/Observer;)V HSPLandroidx/lifecycle/LiveData;->onActive()V @@ -2840,7 +2967,6 @@ HSPLandroidx/lifecycle/MediatorLiveData$Source;->unplug()V HSPLandroidx/lifecycle/MediatorLiveData;->()V HSPLandroidx/lifecycle/MediatorLiveData;->addSource(Landroidx/lifecycle/LiveData;Landroidx/lifecycle/Observer;)V HSPLandroidx/lifecycle/MediatorLiveData;->onActive()V -HSPLandroidx/lifecycle/MediatorLiveData;->onInactive()V HSPLandroidx/lifecycle/MediatorLiveData;->removeSource(Landroidx/lifecycle/LiveData;)V HSPLandroidx/lifecycle/MutableLiveData;->()V HSPLandroidx/lifecycle/MutableLiveData;->(Ljava/lang/Object;)V @@ -2900,7 +3026,6 @@ HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPreDestroye HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPrePaused(Landroid/app/Activity;)V HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPreStopped(Landroid/app/Activity;)V HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V -HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V HSPLandroidx/lifecycle/ReportFragment;->()V @@ -2916,30 +3041,13 @@ HSPLandroidx/lifecycle/ReportFragment;->onPause()V HSPLandroidx/lifecycle/ReportFragment;->onResume()V HSPLandroidx/lifecycle/ReportFragment;->onStart()V HSPLandroidx/lifecycle/ReportFragment;->onStop()V -HSPLandroidx/lifecycle/SavedStateHandle$$ExternalSyntheticLambda0;->(Landroidx/lifecycle/SavedStateHandle;)V -HSPLandroidx/lifecycle/SavedStateHandle$Companion;->()V -HSPLandroidx/lifecycle/SavedStateHandle$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLandroidx/lifecycle/SavedStateHandle$Companion;->createHandle(Landroid/os/Bundle;Landroid/os/Bundle;)Landroidx/lifecycle/SavedStateHandle; -HSPLandroidx/lifecycle/SavedStateHandle$Companion;->validateValue(Ljava/lang/Object;)Z -HSPLandroidx/lifecycle/SavedStateHandle;->()V -HSPLandroidx/lifecycle/SavedStateHandle;->()V -HSPLandroidx/lifecycle/SavedStateHandle;->access$getACCEPTABLE_CLASSES$cp()[Ljava/lang/Class; -HSPLandroidx/lifecycle/SavedStateHandle;->get(Ljava/lang/String;)Ljava/lang/Object; -HSPLandroidx/lifecycle/SavedStateHandle;->savedStateProvider()Landroidx/savedstate/SavedStateRegistry$SavedStateProvider; -HSPLandroidx/lifecycle/SavedStateHandle;->set(Ljava/lang/String;Ljava/lang/Object;)V HSPLandroidx/lifecycle/SavedStateHandleAttacher;->(Landroidx/lifecycle/SavedStateHandlesProvider;)V HSPLandroidx/lifecycle/SavedStateHandleAttacher;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V -HSPLandroidx/lifecycle/SavedStateHandleController;->(Ljava/lang/String;Landroidx/lifecycle/SavedStateHandle;)V -HSPLandroidx/lifecycle/SavedStateHandleController;->attachToLifecycle(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;)V -HSPLandroidx/lifecycle/SavedStateHandleController;->getHandle()Landroidx/lifecycle/SavedStateHandle; -HSPLandroidx/lifecycle/SavedStateHandleController;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/lifecycle/SavedStateHandleSupport$DEFAULT_ARGS_KEY$1;->()V HSPLandroidx/lifecycle/SavedStateHandleSupport$SAVED_STATE_REGISTRY_OWNER_KEY$1;->()V HSPLandroidx/lifecycle/SavedStateHandleSupport$VIEW_MODEL_STORE_OWNER_KEY$1;->()V -HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;->()V -HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;->()V -HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;->invoke(Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/SavedStateHandlesVM; -HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1;->()V +HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel; HSPLandroidx/lifecycle/SavedStateHandleSupport;->()V HSPLandroidx/lifecycle/SavedStateHandleSupport;->enableSavedStateHandles(Landroidx/savedstate/SavedStateRegistryOwner;)V HSPLandroidx/lifecycle/SavedStateHandleSupport;->getSavedStateHandlesVM(Landroidx/lifecycle/ViewModelStoreOwner;)Landroidx/lifecycle/SavedStateHandlesVM; @@ -2949,9 +3057,7 @@ HSPLandroidx/lifecycle/SavedStateHandlesProvider$viewModel$2;->invoke()Ljava/lan HSPLandroidx/lifecycle/SavedStateHandlesProvider;->(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/ViewModelStoreOwner;)V HSPLandroidx/lifecycle/SavedStateHandlesProvider;->getViewModel()Landroidx/lifecycle/SavedStateHandlesVM; HSPLandroidx/lifecycle/SavedStateHandlesProvider;->performRestore()V -HSPLandroidx/lifecycle/SavedStateHandlesProvider;->saveState()Landroid/os/Bundle; HSPLandroidx/lifecycle/SavedStateHandlesVM;->()V -HSPLandroidx/lifecycle/SavedStateHandlesVM;->getHandles()Ljava/util/Map; HSPLandroidx/lifecycle/SavedStateViewModelFactory;->(Landroid/app/Application;Landroidx/savedstate/SavedStateRegistryOwner;Landroid/os/Bundle;)V HSPLandroidx/lifecycle/SavedStateViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel; HSPLandroidx/lifecycle/SavedStateViewModelFactory;->onRequery(Landroidx/lifecycle/ViewModel;)V @@ -2964,18 +3070,18 @@ HSPLandroidx/lifecycle/Transformations$map$1;->invoke(Ljava/lang/Object;)Ljava/l HSPLandroidx/lifecycle/Transformations$map$1;->invoke(Ljava/lang/Object;)V HSPLandroidx/lifecycle/Transformations$sam$androidx_lifecycle_Observer$0;->(Lkotlin/jvm/functions/Function1;)V HSPLandroidx/lifecycle/Transformations$sam$androidx_lifecycle_Observer$0;->onChanged(Ljava/lang/Object;)V -HSPLandroidx/lifecycle/Transformations$switchMap$1$onChanged$1;->(Landroidx/lifecycle/MediatorLiveData;)V -HSPLandroidx/lifecycle/Transformations$switchMap$1$onChanged$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLandroidx/lifecycle/Transformations$switchMap$1$onChanged$1;->invoke(Ljava/lang/Object;)V -HSPLandroidx/lifecycle/Transformations$switchMap$1;->(Lkotlin/jvm/functions/Function1;Landroidx/lifecycle/MediatorLiveData;)V -HSPLandroidx/lifecycle/Transformations$switchMap$1;->onChanged(Ljava/lang/Object;)V +HSPLandroidx/lifecycle/Transformations$switchMap$1$1;->(Landroidx/lifecycle/MediatorLiveData;)V +HSPLandroidx/lifecycle/Transformations$switchMap$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLandroidx/lifecycle/Transformations$switchMap$1$1;->invoke(Ljava/lang/Object;)V +HSPLandroidx/lifecycle/Transformations$switchMap$1;->(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/Ref$ObjectRef;Landroidx/lifecycle/MediatorLiveData;)V +HSPLandroidx/lifecycle/Transformations$switchMap$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLandroidx/lifecycle/Transformations$switchMap$1;->invoke(Ljava/lang/Object;)V HSPLandroidx/lifecycle/Transformations;->map(Landroidx/lifecycle/LiveData;Lkotlin/jvm/functions/Function1;)Landroidx/lifecycle/LiveData; HSPLandroidx/lifecycle/Transformations;->switchMap(Landroidx/lifecycle/LiveData;Lkotlin/jvm/functions/Function1;)Landroidx/lifecycle/LiveData; HSPLandroidx/lifecycle/ViewModel;->()V HSPLandroidx/lifecycle/ViewModel;->clear()V HSPLandroidx/lifecycle/ViewModel;->getTag(Ljava/lang/String;)Ljava/lang/Object; HSPLandroidx/lifecycle/ViewModel;->onCleared()V -HSPLandroidx/lifecycle/ViewModel;->setTagIfAbsent(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/lifecycle/ViewModelLazy;->(Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V HSPLandroidx/lifecycle/ViewModelLazy;->getValue()Landroidx/lifecycle/ViewModel; HSPLandroidx/lifecycle/ViewModelLazy;->getValue()Ljava/lang/Object; @@ -3062,6 +3168,7 @@ HSPLandroidx/media/AudioAttributesImplApi26$Builder;->setUsage(I)Landroidx/media HSPLandroidx/media/AudioAttributesImplApi26;->(Landroid/media/AudioAttributes;)V HSPLandroidx/media/MediaBrowserServiceCompat$BrowserRoot;->(Ljava/lang/String;Landroid/os/Bundle;)V HSPLandroidx/media/MediaSessionManager$RemoteUserInfo;->(Ljava/lang/String;II)V +HSPLandroidx/media/MediaSessionManager$RemoteUserInfo;->getPackageName()Ljava/lang/String; HSPLandroidx/media/MediaSessionManager$RemoteUserInfo;->hashCode()I HSPLandroidx/media/MediaSessionManager;->()V HSPLandroidx/media/MediaSessionManager;->(Landroid/content/Context;)V @@ -3086,6 +3193,7 @@ HSPLandroidx/media/MediaSessionManagerImplBase;->getContext()Landroid/content/Co HSPLandroidx/media/MediaSessionManagerImplBase;->isEnabledNotificationListener(Landroidx/media/MediaSessionManager$RemoteUserInfoImpl;)Z HSPLandroidx/media/MediaSessionManagerImplBase;->isPermissionGranted(Landroidx/media/MediaSessionManager$RemoteUserInfoImpl;Ljava/lang/String;)Z HSPLandroidx/media/MediaSessionManagerImplBase;->isTrustedForMediaControl(Landroidx/media/MediaSessionManager$RemoteUserInfoImpl;)Z +HSPLandroidx/media/session/MediaButtonReceiver;->getMediaButtonReceiverComponent(Landroid/content/Context;)Landroid/content/ComponentName; HSPLandroidx/media3/common/AdPlaybackState$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/AdPlaybackState$AdGroup$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/AdPlaybackState$AdGroup;->()V @@ -3097,21 +3205,14 @@ HSPLandroidx/media3/common/AdPlaybackState$AdGroup;->withAdCount(I)Landroidx/med HSPLandroidx/media3/common/AdPlaybackState;->()V HSPLandroidx/media3/common/AdPlaybackState;->(Ljava/lang/Object;[Landroidx/media3/common/AdPlaybackState$AdGroup;JJI)V HSPLandroidx/media3/common/AudioAttributes$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/AudioAttributes$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/common/AudioAttributes$Builder;->()V HSPLandroidx/media3/common/AudioAttributes$Builder;->build()Landroidx/media3/common/AudioAttributes; -HSPLandroidx/media3/common/AudioAttributes$Builder;->setAllowedCapturePolicy(I)Landroidx/media3/common/AudioAttributes$Builder; HSPLandroidx/media3/common/AudioAttributes$Builder;->setContentType(I)Landroidx/media3/common/AudioAttributes$Builder; -HSPLandroidx/media3/common/AudioAttributes$Builder;->setFlags(I)Landroidx/media3/common/AudioAttributes$Builder; -HSPLandroidx/media3/common/AudioAttributes$Builder;->setSpatializationBehavior(I)Landroidx/media3/common/AudioAttributes$Builder; HSPLandroidx/media3/common/AudioAttributes$Builder;->setUsage(I)Landroidx/media3/common/AudioAttributes$Builder; -HSPLandroidx/media3/common/AudioAttributes;->$r8$lambda$IxEfUga_GP6gJ5C1HBeYWhMBgjA(Landroid/os/Bundle;)Landroidx/media3/common/AudioAttributes; HSPLandroidx/media3/common/AudioAttributes;->()V HSPLandroidx/media3/common/AudioAttributes;->(IIIII)V HSPLandroidx/media3/common/AudioAttributes;->(IIIIILandroidx/media3/common/AudioAttributes$1;)V HSPLandroidx/media3/common/AudioAttributes;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/AudioAttributes;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/common/AudioAttributes; -HSPLandroidx/media3/common/AudioAttributes;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/AuxEffectInfo;->(IF)V HSPLandroidx/media3/common/BasePlayer;->()V HSPLandroidx/media3/common/BasePlayer;->canAdvertiseSession()Z @@ -3121,13 +3222,7 @@ HSPLandroidx/media3/common/BasePlayer;->getCurrentLiveOffset()J HSPLandroidx/media3/common/BasePlayer;->getCurrentMediaItem()Landroidx/media3/common/MediaItem; HSPLandroidx/media3/common/BasePlayer;->isCommandAvailable(I)Z HSPLandroidx/media3/common/BasePlayer;->isPlaying()Z -HSPLandroidx/media3/common/BundleListRetriever$$ExternalSyntheticApiModelOutline0;->m()I -HSPLandroidx/media3/common/BundleListRetriever;->()V -HSPLandroidx/media3/common/BundleListRetriever;->(Ljava/util/List;)V -HSPLandroidx/media3/common/BundleListRetriever;->getList(Landroid/os/IBinder;)Lcom/google/common/collect/ImmutableList; -HSPLandroidx/media3/common/BundleListRetriever;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z HSPLandroidx/media3/common/DeviceInfo$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/DeviceInfo$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/common/DeviceInfo$Builder;->(I)V HSPLandroidx/media3/common/DeviceInfo$Builder;->access$100(Landroidx/media3/common/DeviceInfo$Builder;)I HSPLandroidx/media3/common/DeviceInfo$Builder;->access$200(Landroidx/media3/common/DeviceInfo$Builder;)I @@ -3136,14 +3231,10 @@ HSPLandroidx/media3/common/DeviceInfo$Builder;->access$400(Landroidx/media3/comm HSPLandroidx/media3/common/DeviceInfo$Builder;->build()Landroidx/media3/common/DeviceInfo; HSPLandroidx/media3/common/DeviceInfo$Builder;->setMaxVolume(I)Landroidx/media3/common/DeviceInfo$Builder; HSPLandroidx/media3/common/DeviceInfo$Builder;->setMinVolume(I)Landroidx/media3/common/DeviceInfo$Builder; -HSPLandroidx/media3/common/DeviceInfo$Builder;->setRoutingControllerId(Ljava/lang/String;)Landroidx/media3/common/DeviceInfo$Builder; -HSPLandroidx/media3/common/DeviceInfo;->$r8$lambda$e-s9fExKmRNsngBsAX6K_nAXCig(Landroid/os/Bundle;)Landroidx/media3/common/DeviceInfo; HSPLandroidx/media3/common/DeviceInfo;->()V HSPLandroidx/media3/common/DeviceInfo;->(Landroidx/media3/common/DeviceInfo$Builder;)V HSPLandroidx/media3/common/DeviceInfo;->(Landroidx/media3/common/DeviceInfo$Builder;Landroidx/media3/common/DeviceInfo$1;)V HSPLandroidx/media3/common/DeviceInfo;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/DeviceInfo;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/common/DeviceInfo; -HSPLandroidx/media3/common/DeviceInfo;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/FlagSet$Builder;->()V HSPLandroidx/media3/common/FlagSet$Builder;->add(I)Landroidx/media3/common/FlagSet$Builder; HSPLandroidx/media3/common/FlagSet$Builder;->addAll(Landroidx/media3/common/FlagSet;)Landroidx/media3/common/FlagSet$Builder; @@ -3200,6 +3291,7 @@ HSPLandroidx/media3/common/ForwardingPlayer;->isCommandAvailable(I)Z HSPLandroidx/media3/common/ForwardingPlayer;->isLoading()Z HSPLandroidx/media3/common/ForwardingPlayer;->isPlaying()Z HSPLandroidx/media3/common/ForwardingPlayer;->isPlayingAd()Z +HSPLandroidx/media3/common/ForwardingPlayer;->setAudioAttributes(Landroidx/media3/common/AudioAttributes;Z)V HSPLandroidx/media3/common/MediaItem$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/MediaItem$Builder;->()V HSPLandroidx/media3/common/MediaItem$Builder;->build()Landroidx/media3/common/MediaItem; @@ -3238,8 +3330,8 @@ HSPLandroidx/media3/common/MediaItem$LiveConfiguration;->(Landroidx/media3 HSPLandroidx/media3/common/MediaItem$LiveConfiguration;->(Landroidx/media3/common/MediaItem$LiveConfiguration$Builder;Landroidx/media3/common/MediaItem$1;)V HSPLandroidx/media3/common/MediaItem$LocalConfiguration$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/MediaItem$LocalConfiguration;->()V -HSPLandroidx/media3/common/MediaItem$LocalConfiguration;->(Landroid/net/Uri;Ljava/lang/String;Landroidx/media3/common/MediaItem$DrmConfiguration;Landroidx/media3/common/MediaItem$AdsConfiguration;Ljava/util/List;Ljava/lang/String;Lcom/google/common/collect/ImmutableList;Ljava/lang/Object;)V -HSPLandroidx/media3/common/MediaItem$LocalConfiguration;->(Landroid/net/Uri;Ljava/lang/String;Landroidx/media3/common/MediaItem$DrmConfiguration;Landroidx/media3/common/MediaItem$AdsConfiguration;Ljava/util/List;Ljava/lang/String;Lcom/google/common/collect/ImmutableList;Ljava/lang/Object;Landroidx/media3/common/MediaItem$1;)V +HSPLandroidx/media3/common/MediaItem$LocalConfiguration;->(Landroid/net/Uri;Ljava/lang/String;Landroidx/media3/common/MediaItem$DrmConfiguration;Landroidx/media3/common/MediaItem$AdsConfiguration;Ljava/util/List;Ljava/lang/String;Lcom/google/common/collect/ImmutableList;Ljava/lang/Object;J)V +HSPLandroidx/media3/common/MediaItem$LocalConfiguration;->(Landroid/net/Uri;Ljava/lang/String;Landroidx/media3/common/MediaItem$DrmConfiguration;Landroidx/media3/common/MediaItem$AdsConfiguration;Ljava/util/List;Ljava/lang/String;Lcom/google/common/collect/ImmutableList;Ljava/lang/Object;JLandroidx/media3/common/MediaItem$1;)V HSPLandroidx/media3/common/MediaItem$RequestMetadata$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/MediaItem$RequestMetadata$Builder;->()V HSPLandroidx/media3/common/MediaItem$RequestMetadata$Builder;->access$4600(Landroidx/media3/common/MediaItem$RequestMetadata$Builder;)Landroid/net/Uri; @@ -3255,7 +3347,6 @@ HSPLandroidx/media3/common/MediaItem;->(Ljava/lang/String;Landroidx/media3 HSPLandroidx/media3/common/MediaLibraryInfo;->()V HSPLandroidx/media3/common/MediaLibraryInfo;->registerModule(Ljava/lang/String;)V HSPLandroidx/media3/common/MediaMetadata$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/MediaMetadata$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/common/MediaMetadata$Builder;->()V HSPLandroidx/media3/common/MediaMetadata$Builder;->access$100(Landroidx/media3/common/MediaMetadata$Builder;)Ljava/lang/Boolean; HSPLandroidx/media3/common/MediaMetadata$Builder;->access$1000(Landroidx/media3/common/MediaMetadata$Builder;)Ljava/lang/CharSequence; @@ -3291,201 +3382,121 @@ HSPLandroidx/media3/common/MediaMetadata$Builder;->access$700(Landroidx/media3/c HSPLandroidx/media3/common/MediaMetadata$Builder;->access$800(Landroidx/media3/common/MediaMetadata$Builder;)Ljava/lang/CharSequence; HSPLandroidx/media3/common/MediaMetadata$Builder;->access$900(Landroidx/media3/common/MediaMetadata$Builder;)Ljava/lang/CharSequence; HSPLandroidx/media3/common/MediaMetadata$Builder;->build()Landroidx/media3/common/MediaMetadata; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setAlbumArtist(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setAlbumTitle(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setArtist(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setArtworkData([BLjava/lang/Integer;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setArtworkUri(Landroid/net/Uri;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setCompilation(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setComposer(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setConductor(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setDescription(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setDisplayTitle(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setExtras(Landroid/os/Bundle;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setGenre(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setStation(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setSubtitle(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setTitle(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata$Builder;->setWriter(Ljava/lang/CharSequence;)Landroidx/media3/common/MediaMetadata$Builder; -HSPLandroidx/media3/common/MediaMetadata;->$r8$lambda$Ec-q2JvXpG5rf68mVuy5gy0CxNI(Landroid/os/Bundle;)Landroidx/media3/common/MediaMetadata; HSPLandroidx/media3/common/MediaMetadata;->()V HSPLandroidx/media3/common/MediaMetadata;->(Landroidx/media3/common/MediaMetadata$Builder;)V HSPLandroidx/media3/common/MediaMetadata;->(Landroidx/media3/common/MediaMetadata$Builder;Landroidx/media3/common/MediaMetadata$1;)V HSPLandroidx/media3/common/MediaMetadata;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/MediaMetadata;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/MediaMetadata; -HSPLandroidx/media3/common/MediaMetadata;->toBundle()Landroid/os/Bundle; -HSPLandroidx/media3/common/MediaPeriodId;->(Ljava/lang/Object;)V -HSPLandroidx/media3/common/MediaPeriodId;->(Ljava/lang/Object;IIJI)V -HSPLandroidx/media3/common/MediaPeriodId;->(Ljava/lang/Object;J)V -HSPLandroidx/media3/common/MediaPeriodId;->isAd()Z HSPLandroidx/media3/common/MimeTypes;->()V HSPLandroidx/media3/common/MimeTypes;->getTopLevelType(Ljava/lang/String;)Ljava/lang/String; HSPLandroidx/media3/common/MimeTypes;->isVideo(Ljava/lang/String;)Z HSPLandroidx/media3/common/PlaybackParameters$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/PlaybackParameters$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; -HSPLandroidx/media3/common/PlaybackParameters;->$r8$lambda$6vPIxCCjO7c5-B_Z0gVO2CDn6RU(Landroid/os/Bundle;)Landroidx/media3/common/PlaybackParameters; HSPLandroidx/media3/common/PlaybackParameters;->()V HSPLandroidx/media3/common/PlaybackParameters;->(F)V HSPLandroidx/media3/common/PlaybackParameters;->(FF)V HSPLandroidx/media3/common/PlaybackParameters;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/PlaybackParameters;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/common/PlaybackParameters; -HSPLandroidx/media3/common/PlaybackParameters;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/Player$Commands$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/Player$Commands$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/common/Player$Commands$Builder;->()V HSPLandroidx/media3/common/Player$Commands$Builder;->()V +HSPLandroidx/media3/common/Player$Commands$Builder;->(Landroidx/media3/common/Player$Commands;)V +HSPLandroidx/media3/common/Player$Commands$Builder;->(Landroidx/media3/common/Player$Commands;Landroidx/media3/common/Player$1;)V HSPLandroidx/media3/common/Player$Commands$Builder;->add(I)Landroidx/media3/common/Player$Commands$Builder; HSPLandroidx/media3/common/Player$Commands$Builder;->addAll(Landroidx/media3/common/Player$Commands;)Landroidx/media3/common/Player$Commands$Builder; HSPLandroidx/media3/common/Player$Commands$Builder;->addAll([I)Landroidx/media3/common/Player$Commands$Builder; +HSPLandroidx/media3/common/Player$Commands$Builder;->addAllCommands()Landroidx/media3/common/Player$Commands$Builder; HSPLandroidx/media3/common/Player$Commands$Builder;->addIf(IZ)Landroidx/media3/common/Player$Commands$Builder; HSPLandroidx/media3/common/Player$Commands$Builder;->build()Landroidx/media3/common/Player$Commands; -HSPLandroidx/media3/common/Player$Commands;->$r8$lambda$bJbd4g5aXZ6YObv0AuEljNycW2Y(Landroid/os/Bundle;)Landroidx/media3/common/Player$Commands; HSPLandroidx/media3/common/Player$Commands;->()V HSPLandroidx/media3/common/Player$Commands;->(Landroidx/media3/common/FlagSet;)V HSPLandroidx/media3/common/Player$Commands;->(Landroidx/media3/common/FlagSet;Landroidx/media3/common/Player$1;)V HSPLandroidx/media3/common/Player$Commands;->access$000(Landroidx/media3/common/Player$Commands;)Landroidx/media3/common/FlagSet; +HSPLandroidx/media3/common/Player$Commands;->buildUpon()Landroidx/media3/common/Player$Commands$Builder; HSPLandroidx/media3/common/Player$Commands;->contains(I)Z -HSPLandroidx/media3/common/Player$Commands;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Player$Commands; HSPLandroidx/media3/common/Player$Commands;->get(I)I HSPLandroidx/media3/common/Player$Commands;->size()I -HSPLandroidx/media3/common/Player$Commands;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/Player$Events;->(Landroidx/media3/common/FlagSet;)V HSPLandroidx/media3/common/Player$PositionInfo$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/Player$PositionInfo$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; -HSPLandroidx/media3/common/Player$PositionInfo;->$r8$lambda$ks0iIBi1LeOOEMD3eahHAGMFmeY(Landroid/os/Bundle;)Landroidx/media3/common/Player$PositionInfo; HSPLandroidx/media3/common/Player$PositionInfo;->()V HSPLandroidx/media3/common/Player$PositionInfo;->(Ljava/lang/Object;ILandroidx/media3/common/MediaItem;Ljava/lang/Object;IJJII)V HSPLandroidx/media3/common/Player$PositionInfo;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/Player$PositionInfo;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Player$PositionInfo; -HSPLandroidx/media3/common/Player$PositionInfo;->toBundle(ZZ)Landroid/os/Bundle; +HSPLandroidx/media3/common/Player$PositionInfo;->equalsForBundling(Landroidx/media3/common/Player$PositionInfo;)Z +HSPLandroidx/media3/common/Player$PositionInfo;->filterByAvailableCommands(ZZ)Landroidx/media3/common/Player$PositionInfo; HSPLandroidx/media3/common/Timeline$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/Timeline$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/common/Timeline$1;->()V -HSPLandroidx/media3/common/Timeline$1;->getPeriodCount()I HSPLandroidx/media3/common/Timeline$1;->getWindowCount()I HSPLandroidx/media3/common/Timeline$Period$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/Timeline$Period;->()V HSPLandroidx/media3/common/Timeline$Period;->()V -HSPLandroidx/media3/common/Timeline$RemotableTimeline;->(Lcom/google/common/collect/ImmutableList;Lcom/google/common/collect/ImmutableList;[I)V -HSPLandroidx/media3/common/Timeline$RemotableTimeline;->getFirstWindowIndex(Z)I -HSPLandroidx/media3/common/Timeline$RemotableTimeline;->getLastWindowIndex(Z)I -HSPLandroidx/media3/common/Timeline$RemotableTimeline;->getPeriodCount()I -HSPLandroidx/media3/common/Timeline$RemotableTimeline;->getWindowCount()I HSPLandroidx/media3/common/Timeline$Window$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/Timeline$Window;->()V HSPLandroidx/media3/common/Timeline$Window;->()V -HSPLandroidx/media3/common/Timeline;->$r8$lambda$IosUR-LlCTyBXD6bufNR07UK3iY(Landroid/os/Bundle;)Landroidx/media3/common/Timeline; HSPLandroidx/media3/common/Timeline;->()V HSPLandroidx/media3/common/Timeline;->()V HSPLandroidx/media3/common/Timeline;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/Timeline;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Timeline; -HSPLandroidx/media3/common/Timeline;->fromBundleListRetriever(Landroidx/media3/common/Bundleable$Creator;Landroid/os/IBinder;)Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/common/Timeline;->isEmpty()Z -HSPLandroidx/media3/common/Timeline;->toBundle()Landroid/os/Bundle; -HSPLandroidx/media3/common/TrackSelectionOverride$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/TrackSelectionOverride;->()V HSPLandroidx/media3/common/TrackSelectionParameters$$ExternalSyntheticLambda0;->()V +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;->()V +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;->access$3100(Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;->access$3200(Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;)Z +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;->access$3300(Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;)Z +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;->build()Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences; +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences;->()V +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences;->(Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;)V +HSPLandroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences;->(Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder;Landroidx/media3/common/TrackSelectionParameters$1;)V HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->()V HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->(Landroid/content/Context;)V -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->(Landroid/os/Bundle;)V -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$2600(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$2700(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$2800(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$2900(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3000(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3100(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3200(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3300(Landroidx/media3/common/TrackSelectionParameters$Builder;)I HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3400(Landroidx/media3/common/TrackSelectionParameters$Builder;)I HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3500(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3600(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3700(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3600(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3700(Landroidx/media3/common/TrackSelectionParameters$Builder;)I HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3800(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3900(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$3900(Landroidx/media3/common/TrackSelectionParameters$Builder;)I HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4000(Landroidx/media3/common/TrackSelectionParameters$Builder;)I HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4100(Landroidx/media3/common/TrackSelectionParameters$Builder;)I HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4200(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4300(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4400(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4500(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4300(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4400(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4500(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4600(Landroidx/media3/common/TrackSelectionParameters$Builder;)I -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4700(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4800(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4900(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5000(Landroidx/media3/common/TrackSelectionParameters$Builder;)Ljava/util/HashMap; -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5100(Landroidx/media3/common/TrackSelectionParameters$Builder;)Ljava/util/HashSet; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4700(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4800(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$4900(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5000(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5100(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5200(Landroidx/media3/common/TrackSelectionParameters$Builder;)Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5300(Landroidx/media3/common/TrackSelectionParameters$Builder;)Lcom/google/common/collect/ImmutableList; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5400(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5500(Landroidx/media3/common/TrackSelectionParameters$Builder;)I +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5600(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5700(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5800(Landroidx/media3/common/TrackSelectionParameters$Builder;)Z +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$5900(Landroidx/media3/common/TrackSelectionParameters$Builder;)Ljava/util/HashMap; +HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->access$6000(Landroidx/media3/common/TrackSelectionParameters$Builder;)Ljava/util/HashSet; HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->build()Landroidx/media3/common/TrackSelectionParameters; -HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->normalizeLanguageCodes([Ljava/lang/String;)Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(Landroid/content/Context;)Landroidx/media3/common/TrackSelectionParameters$Builder; HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettingsV19(Landroid/content/Context;)V HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->setViewportSize(IIZ)Landroidx/media3/common/TrackSelectionParameters$Builder; HSPLandroidx/media3/common/TrackSelectionParameters$Builder;->setViewportSizeToPhysicalDisplaySize(Landroid/content/Context;Z)Landroidx/media3/common/TrackSelectionParameters$Builder; HSPLandroidx/media3/common/TrackSelectionParameters;->()V HSPLandroidx/media3/common/TrackSelectionParameters;->(Landroidx/media3/common/TrackSelectionParameters$Builder;)V -HSPLandroidx/media3/common/TrackSelectionParameters;->access$000()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$100()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1000()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1100()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1200()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1300()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1400()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1500()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1600()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1700()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1800()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$1900()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$200()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$2000()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$2100()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$2200()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$2300()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$2400()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$2500()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$300()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$400()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$500()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$600()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$700()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$800()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->access$900()Ljava/lang/String; -HSPLandroidx/media3/common/TrackSelectionParameters;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/TrackSelectionParameters;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/TrackSelectionParameters; -HSPLandroidx/media3/common/TrackSelectionParameters;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/Tracks$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/Tracks;->()V HSPLandroidx/media3/common/Tracks;->(Ljava/util/List;)V HSPLandroidx/media3/common/Tracks;->equals(Ljava/lang/Object;)Z HSPLandroidx/media3/common/Tracks;->getGroups()Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/common/VideoSize$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/VideoSize$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; -HSPLandroidx/media3/common/VideoSize;->$r8$lambda$EPOa8Ks164XW2JtBknEKhMky65c(Landroid/os/Bundle;)Landroidx/media3/common/VideoSize; HSPLandroidx/media3/common/VideoSize;->()V HSPLandroidx/media3/common/VideoSize;->(II)V HSPLandroidx/media3/common/VideoSize;->(IIIF)V HSPLandroidx/media3/common/VideoSize;->equals(Ljava/lang/Object;)Z -HSPLandroidx/media3/common/VideoSize;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/common/VideoSize; -HSPLandroidx/media3/common/VideoSize;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/audio/AudioProcessor$AudioFormat;->()V HSPLandroidx/media3/common/audio/AudioProcessor$AudioFormat;->(III)V HSPLandroidx/media3/common/audio/AudioProcessor;->()V HSPLandroidx/media3/common/audio/BaseAudioProcessor;->()V HSPLandroidx/media3/common/audio/SonicAudioProcessor;->()V HSPLandroidx/media3/common/audio/ToInt16PcmAudioProcessor;->()V -HSPLandroidx/media3/common/text/Cue$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/text/Cue$Builder;->()V -HSPLandroidx/media3/common/text/Cue$Builder;->build()Landroidx/media3/common/text/Cue; -HSPLandroidx/media3/common/text/Cue$Builder;->setText(Ljava/lang/CharSequence;)Landroidx/media3/common/text/Cue$Builder; -HSPLandroidx/media3/common/text/Cue;->()V -HSPLandroidx/media3/common/text/Cue;->(Ljava/lang/CharSequence;Landroid/text/Layout$Alignment;Landroid/text/Layout$Alignment;Landroid/graphics/Bitmap;FIIFIIFFFZIIF)V -HSPLandroidx/media3/common/text/Cue;->(Ljava/lang/CharSequence;Landroid/text/Layout$Alignment;Landroid/text/Layout$Alignment;Landroid/graphics/Bitmap;FIIFIIFFFZIIFLandroidx/media3/common/text/Cue$1;)V HSPLandroidx/media3/common/text/CueGroup$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/common/text/CueGroup$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; -HSPLandroidx/media3/common/text/CueGroup;->$r8$lambda$Origctfy90sr8FmfUYUQlslcvXo(Landroid/os/Bundle;)Landroidx/media3/common/text/CueGroup; HSPLandroidx/media3/common/text/CueGroup;->()V HSPLandroidx/media3/common/text/CueGroup;->(Ljava/util/List;J)V -HSPLandroidx/media3/common/text/CueGroup;->filterOutBitmapCues(Ljava/util/List;)Lcom/google/common/collect/ImmutableList; -HSPLandroidx/media3/common/text/CueGroup;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/text/CueGroup; -HSPLandroidx/media3/common/text/CueGroup;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/common/util/Assertions;->checkArgument(Z)V HSPLandroidx/media3/common/util/Assertions;->checkArgument(ZLjava/lang/Object;)V HSPLandroidx/media3/common/util/Assertions;->checkIndex(III)I @@ -3499,7 +3510,6 @@ HSPLandroidx/media3/common/util/BundleUtil;->putBinder(Landroid/os/Bundle;Ljava/ HSPLandroidx/media3/common/util/BundleableUtil$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/common/util/BundleableUtil$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/media3/common/util/BundleableUtil;->fromBundleList(Landroidx/media3/common/Bundleable$Creator;Ljava/util/List;)Lcom/google/common/collect/ImmutableList; -HSPLandroidx/media3/common/util/BundleableUtil;->toBundleArrayList(Ljava/util/Collection;)Ljava/util/ArrayList; HSPLandroidx/media3/common/util/BundleableUtil;->toBundleList(Ljava/util/List;)Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/common/util/BundleableUtil;->toBundleList(Ljava/util/List;Lcom/google/common/base/Function;)Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/common/util/Clock;->()V @@ -3515,7 +3525,6 @@ HSPLandroidx/media3/common/util/ListenerSet$ListenerHolder;->(Ljava/lang/O HSPLandroidx/media3/common/util/ListenerSet$ListenerHolder;->equals(Ljava/lang/Object;)Z HSPLandroidx/media3/common/util/ListenerSet$ListenerHolder;->invoke(ILandroidx/media3/common/util/ListenerSet$Event;)V HSPLandroidx/media3/common/util/ListenerSet$ListenerHolder;->iterationFinished(Landroidx/media3/common/util/ListenerSet$IterationFinishedEvent;)V -HSPLandroidx/media3/common/util/ListenerSet$ListenerHolder;->release(Landroidx/media3/common/util/ListenerSet$IterationFinishedEvent;)V HSPLandroidx/media3/common/util/ListenerSet;->$r8$lambda$AlaP-gu7Lfe4GahLPmVnd_l2pLA(Ljava/util/concurrent/CopyOnWriteArraySet;ILandroidx/media3/common/util/ListenerSet$Event;)V HSPLandroidx/media3/common/util/ListenerSet;->$r8$lambda$bio3pd12v5B_9b5UeFaPn9XBQ90(Landroidx/media3/common/util/ListenerSet;Landroid/os/Message;)Z HSPLandroidx/media3/common/util/ListenerSet;->(Landroid/os/Looper;Landroidx/media3/common/util/Clock;Landroidx/media3/common/util/ListenerSet$IterationFinishedEvent;)V @@ -3527,13 +3536,14 @@ HSPLandroidx/media3/common/util/ListenerSet;->flushEvents()V HSPLandroidx/media3/common/util/ListenerSet;->handleMessage(Landroid/os/Message;)Z HSPLandroidx/media3/common/util/ListenerSet;->lambda$queueEvent$0(Ljava/util/concurrent/CopyOnWriteArraySet;ILandroidx/media3/common/util/ListenerSet$Event;)V HSPLandroidx/media3/common/util/ListenerSet;->queueEvent(ILandroidx/media3/common/util/ListenerSet$Event;)V -HSPLandroidx/media3/common/util/ListenerSet;->release()V HSPLandroidx/media3/common/util/ListenerSet;->sendEvent(ILandroidx/media3/common/util/ListenerSet$Event;)V HSPLandroidx/media3/common/util/ListenerSet;->verifyCurrentThread()V HSPLandroidx/media3/common/util/Log$Logger$1;->()V -HSPLandroidx/media3/common/util/Log$Logger$1;->i(Ljava/lang/String;Ljava/lang/String;)V +HSPLandroidx/media3/common/util/Log$Logger$1;->i(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V HSPLandroidx/media3/common/util/Log$Logger;->()V HSPLandroidx/media3/common/util/Log;->()V +HSPLandroidx/media3/common/util/Log;->appendThrowableString(Ljava/lang/String;Ljava/lang/Throwable;)Ljava/lang/String; +HSPLandroidx/media3/common/util/Log;->getThrowableString(Ljava/lang/Throwable;)Ljava/lang/String; HSPLandroidx/media3/common/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)V HSPLandroidx/media3/common/util/NetworkTypeObserver$$ExternalSyntheticLambda0;->(Landroidx/media3/common/util/NetworkTypeObserver;Landroidx/media3/common/util/NetworkTypeObserver$Listener;)V HSPLandroidx/media3/common/util/NetworkTypeObserver$$ExternalSyntheticLambda0;->run()V @@ -3584,8 +3594,6 @@ HSPLandroidx/media3/common/util/Util$$ExternalSyntheticApiModelOutline4;->m(Land HSPLandroidx/media3/common/util/Util;->()V HSPLandroidx/media3/common/util/Util;->areEqual(Ljava/lang/Object;Ljava/lang/Object;)Z HSPLandroidx/media3/common/util/Util;->createHandler(Landroid/os/Looper;Landroid/os/Handler$Callback;)Landroid/os/Handler; -HSPLandroidx/media3/common/util/Util;->createHandlerForCurrentLooper()Landroid/os/Handler; -HSPLandroidx/media3/common/util/Util;->createHandlerForCurrentLooper(Landroid/os/Handler$Callback;)Landroid/os/Handler; HSPLandroidx/media3/common/util/Util;->generateAudioSessionIdV21(Landroid/content/Context;)I HSPLandroidx/media3/common/util/Util;->getCountryCode(Landroid/content/Context;)Ljava/lang/String; HSPLandroidx/media3/common/util/Util;->getCurrentDisplayModeSize(Landroid/content/Context;)Landroid/graphics/Point; @@ -3599,7 +3607,19 @@ HSPLandroidx/media3/common/util/Util;->isEncodingLinearPcm(I)Z HSPLandroidx/media3/common/util/Util;->isTv(Landroid/content/Context;)Z HSPLandroidx/media3/common/util/Util;->msToUs(J)J HSPLandroidx/media3/common/util/Util;->postOrRun(Landroid/os/Handler;Ljava/lang/Runnable;)Z +HSPLandroidx/media3/common/util/Util;->shouldShowPlayButton(Landroidx/media3/common/Player;Z)Z HSPLandroidx/media3/common/util/Util;->usToMs(J)J +HSPLandroidx/media3/datasource/DataSourceBitmapLoader$$ExternalSyntheticLambda0;->()V +HSPLandroidx/media3/datasource/DataSourceBitmapLoader$$ExternalSyntheticLambda0;->get()Ljava/lang/Object; +HSPLandroidx/media3/datasource/DataSourceBitmapLoader;->$r8$lambda$5oU0w6Wyi1QAQIwNfmTcRBDVUHo()Lcom/google/common/util/concurrent/ListeningExecutorService; +HSPLandroidx/media3/datasource/DataSourceBitmapLoader;->()V +HSPLandroidx/media3/datasource/DataSourceBitmapLoader;->(Landroid/content/Context;)V +HSPLandroidx/media3/datasource/DataSourceBitmapLoader;->(Lcom/google/common/util/concurrent/ListeningExecutorService;Landroidx/media3/datasource/DataSource$Factory;)V +HSPLandroidx/media3/datasource/DataSourceBitmapLoader;->lambda$static$0()Lcom/google/common/util/concurrent/ListeningExecutorService; +HSPLandroidx/media3/datasource/DefaultDataSource$Factory;->(Landroid/content/Context;)V +HSPLandroidx/media3/datasource/DefaultDataSource$Factory;->(Landroid/content/Context;Landroidx/media3/datasource/DataSource$Factory;)V +HSPLandroidx/media3/datasource/DefaultHttpDataSource$Factory;->()V +HSPLandroidx/media3/datasource/HttpDataSource$RequestProperties;->()V HSPLandroidx/media3/decoder/Buffer;->()V HSPLandroidx/media3/decoder/CryptoInfo$PatternHolderV24$$ExternalSyntheticApiModelOutline0;->m(II)Landroid/media/MediaCodec$CryptoInfo$Pattern; HSPLandroidx/media3/decoder/CryptoInfo$PatternHolderV24$$ExternalSyntheticApiModelOutline1;->m()V @@ -3615,11 +3635,6 @@ HSPLandroidx/media3/decoder/DecoderInputBuffer;->newNoDataInstance()Landroidx/me HSPLandroidx/media3/exoplayer/AudioBecomingNoisyManager$AudioBecomingNoisyReceiver;->(Landroidx/media3/exoplayer/AudioBecomingNoisyManager;Landroid/os/Handler;Landroidx/media3/exoplayer/AudioBecomingNoisyManager$EventListener;)V HSPLandroidx/media3/exoplayer/AudioBecomingNoisyManager;->(Landroid/content/Context;Landroid/os/Handler;Landroidx/media3/exoplayer/AudioBecomingNoisyManager$EventListener;)V HSPLandroidx/media3/exoplayer/AudioBecomingNoisyManager;->setEnabled(Z)V -HSPLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline1;->m(I)Landroid/media/AudioFocusRequest$Builder; -HSPLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline2;->m()V -HSPLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline3;->m(Landroid/media/AudioFocusRequest$Builder;Landroid/media/AudioAttributes;)Landroid/media/AudioFocusRequest$Builder; -HSPLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline5;->m(Landroid/media/AudioFocusRequest$Builder;Landroid/media/AudioManager$OnAudioFocusChangeListener;)Landroid/media/AudioFocusRequest$Builder; -HSPLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline6;->m(Landroid/media/AudioFocusRequest$Builder;)Landroid/media/AudioFocusRequest; HSPLandroidx/media3/exoplayer/AudioFocusManager$AudioFocusListener;->(Landroidx/media3/exoplayer/AudioFocusManager;Landroid/os/Handler;)V HSPLandroidx/media3/exoplayer/AudioFocusManager;->(Landroid/content/Context;Landroid/os/Handler;Landroidx/media3/exoplayer/AudioFocusManager$PlayerControl;)V HSPLandroidx/media3/exoplayer/AudioFocusManager;->abandonAudioFocusIfHeld()V @@ -3630,8 +3645,9 @@ HSPLandroidx/media3/exoplayer/AudioFocusManager;->updateAudioFocus(ZI)I HSPLandroidx/media3/exoplayer/BaseRenderer;->(I)V HSPLandroidx/media3/exoplayer/BaseRenderer;->getCapabilities()Landroidx/media3/exoplayer/RendererCapabilities; HSPLandroidx/media3/exoplayer/BaseRenderer;->getTrackType()I -HSPLandroidx/media3/exoplayer/BaseRenderer;->init(ILandroidx/media3/exoplayer/analytics/PlayerId;)V +HSPLandroidx/media3/exoplayer/BaseRenderer;->init(ILandroidx/media3/exoplayer/analytics/PlayerId;Landroidx/media3/common/util/Clock;)V HSPLandroidx/media3/exoplayer/BaseRenderer;->setListener(Landroidx/media3/exoplayer/RendererCapabilities$Listener;)V +HSPLandroidx/media3/exoplayer/DecoderCounters;->()V HSPLandroidx/media3/exoplayer/DefaultLivePlaybackSpeedControl$Builder;->()V HSPLandroidx/media3/exoplayer/DefaultLivePlaybackSpeedControl$Builder;->build()Landroidx/media3/exoplayer/DefaultLivePlaybackSpeedControl; HSPLandroidx/media3/exoplayer/DefaultLivePlaybackSpeedControl;->(FFJFJJF)V @@ -3687,11 +3703,13 @@ HSPLandroidx/media3/exoplayer/ExoPlayer$Builder;->setHandleAudioBecomingNoisy(Z) HSPLandroidx/media3/exoplayer/ExoPlayer$Builder;->setLoadControl(Landroidx/media3/exoplayer/LoadControl;)Landroidx/media3/exoplayer/ExoPlayer$Builder; HSPLandroidx/media3/exoplayer/ExoPlayer$Builder;->setMediaSourceFactory(Landroidx/media3/exoplayer/source/MediaSource$Factory;)Landroidx/media3/exoplayer/ExoPlayer$Builder; HSPLandroidx/media3/exoplayer/ExoPlayer$Builder;->setRenderersFactory(Landroidx/media3/exoplayer/RenderersFactory;)Landroidx/media3/exoplayer/ExoPlayer$Builder; -HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda15;->(Landroidx/media3/common/AudioAttributes;)V -HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda15;->invoke(Ljava/lang/Object;)V -HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda17;->(Landroidx/media3/exoplayer/ExoPlayerImpl;)V -HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda17;->invoke(Ljava/lang/Object;Landroidx/media3/common/FlagSet;)V +HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticApiModelOutline0;->m(Landroid/media/AudioManager;I)[Landroid/media/AudioDeviceInfo; +HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda16;->(Landroidx/media3/common/AudioAttributes;)V +HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda16;->invoke(Ljava/lang/Object;)V HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda18;->(Landroidx/media3/exoplayer/ExoPlayerImpl;)V +HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda18;->invoke(Ljava/lang/Object;Landroidx/media3/common/FlagSet;)V +HSPLandroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda19;->(Landroidx/media3/exoplayer/ExoPlayerImpl;)V +HSPLandroidx/media3/exoplayer/ExoPlayerImpl$Api23$$ExternalSyntheticApiModelOutline0;->m(Landroid/media/AudioDeviceInfo;)I HSPLandroidx/media3/exoplayer/ExoPlayerImpl$Api31$$ExternalSyntheticApiModelOutline0;->m()Landroid/media/metrics/LogSessionId; HSPLandroidx/media3/exoplayer/ExoPlayerImpl$Api31;->registerMediaMetricsListener(Landroid/content/Context;Landroidx/media3/exoplayer/ExoPlayerImpl;Z)Landroidx/media3/exoplayer/analytics/PlayerId; HSPLandroidx/media3/exoplayer/ExoPlayerImpl$ComponentListener;->(Landroidx/media3/exoplayer/ExoPlayerImpl;)V @@ -3705,6 +3723,7 @@ HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->(Landroidx/media3/exoplayer/ HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->addAnalyticsListener(Landroidx/media3/exoplayer/analytics/AnalyticsListener;)V HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->addAudioOffloadListener(Landroidx/media3/exoplayer/ExoPlayer$AudioOffloadListener;)V HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->addListener(Landroidx/media3/common/Player$Listener;)V +HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->computePlaybackSuppressionReason(ZI)I HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->createDeviceInfo(Landroidx/media3/exoplayer/StreamVolumeManager;)Landroidx/media3/common/DeviceInfo; HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->createMessageInternal(Landroidx/media3/exoplayer/PlayerMessage$Target;)Landroidx/media3/exoplayer/PlayerMessage; HSPLandroidx/media3/exoplayer/ExoPlayerImpl;->getApplicationLooper()Landroid/os/Looper; @@ -3801,23 +3820,23 @@ HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSynth HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda26;->invoke(Ljava/lang/Object;Landroidx/media3/common/FlagSet;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda49;->(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;Landroidx/media3/common/AudioAttributes;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda49;->invoke(Ljava/lang/Object;)V -HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda62;->(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;IJJ)V -HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda62;->invoke(Ljava/lang/Object;)V +HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda67;->(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;IJJ)V +HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda67;->invoke(Ljava/lang/Object;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$MediaPeriodQueueTracker;->(Landroidx/media3/common/Timeline$Period;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$MediaPeriodQueueTracker;->getCurrentPlayerMediaPeriod()Landroidx/media3/exoplayer/source/MediaSource$MediaPeriodId; HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$MediaPeriodQueueTracker;->getLoadingMediaPeriod()Landroidx/media3/exoplayer/source/MediaSource$MediaPeriodId; HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$MediaPeriodQueueTracker;->getReadingMediaPeriod()Landroidx/media3/exoplayer/source/MediaSource$MediaPeriodId; -HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->$r8$lambda$hfAWm6MUDbNyP2cV6lG0IbYKl0w(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;IJJLandroidx/media3/exoplayer/analytics/AnalyticsListener;)V +HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->$r8$lambda$ePy0AIO8UW-xy9MiygZkuaitgYQ(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;IJJLandroidx/media3/exoplayer/analytics/AnalyticsListener;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->$r8$lambda$jkdNgF6pLu9A9h86YXT1MXSbNQs(Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;Landroidx/media3/common/Player;Landroidx/media3/exoplayer/analytics/AnalyticsListener;Landroidx/media3/common/FlagSet;)V -HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->$r8$lambda$nj7KUQ0JGKqZoRhLx02F6ycdSf0(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;Landroidx/media3/common/AudioAttributes;Landroidx/media3/exoplayer/analytics/AnalyticsListener;)V +HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->$r8$lambda$sGolLeq9t66qzdTT2dT-to4LkZE(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;Landroidx/media3/common/AudioAttributes;Landroidx/media3/exoplayer/analytics/AnalyticsListener;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->(Landroidx/media3/common/util/Clock;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->addListener(Landroidx/media3/exoplayer/analytics/AnalyticsListener;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->generateEventTime(Landroidx/media3/common/Timeline;ILandroidx/media3/exoplayer/source/MediaSource$MediaPeriodId;)Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime; HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->generateEventTime(Landroidx/media3/exoplayer/source/MediaSource$MediaPeriodId;)Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime; HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->generateLoadingMediaPeriodEventTime()Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime; HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->generateReadingMediaPeriodEventTime()Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime; -HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->lambda$onAudioAttributesChanged$55(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;Landroidx/media3/common/AudioAttributes;Landroidx/media3/exoplayer/analytics/AnalyticsListener;)V -HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->lambda$onBandwidthSample$60(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;IJJLandroidx/media3/exoplayer/analytics/AnalyticsListener;)V +HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->lambda$onAudioAttributesChanged$57(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;Landroidx/media3/common/AudioAttributes;Landroidx/media3/exoplayer/analytics/AnalyticsListener;)V +HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->lambda$onBandwidthSample$62(Landroidx/media3/exoplayer/analytics/AnalyticsListener$EventTime;IJJLandroidx/media3/exoplayer/analytics/AnalyticsListener;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->lambda$setPlayer$1(Landroidx/media3/common/Player;Landroidx/media3/exoplayer/analytics/AnalyticsListener;Landroidx/media3/common/FlagSet;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->onAudioAttributesChanged(Landroidx/media3/common/AudioAttributes;)V HSPLandroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector;->onBandwidthSample(IJJ)V @@ -3859,8 +3878,6 @@ HSPLandroidx/media3/exoplayer/analytics/PlayerId$LogSessionIdApi31;->(Land HSPLandroidx/media3/exoplayer/analytics/PlayerId;->()V HSPLandroidx/media3/exoplayer/analytics/PlayerId;->(Landroid/media/metrics/LogSessionId;)V HSPLandroidx/media3/exoplayer/analytics/PlayerId;->(Landroidx/media3/exoplayer/analytics/PlayerId$LogSessionIdApi31;)V -HSPLandroidx/media3/exoplayer/audio/AudioCapabilities$Api23$$ExternalSyntheticApiModelOutline0;->m(Landroid/media/AudioManager;I)[Landroid/media/AudioDeviceInfo; -HSPLandroidx/media3/exoplayer/audio/AudioCapabilities$Api23$$ExternalSyntheticApiModelOutline1;->m(Landroid/media/AudioDeviceInfo;)I HSPLandroidx/media3/exoplayer/audio/AudioCapabilities$Api23;->getAllBluetoothDeviceTypes()Lcom/google/common/collect/ImmutableSet; HSPLandroidx/media3/exoplayer/audio/AudioCapabilities$Api23;->isBluetoothConnected(Landroid/content/Context;)Z HSPLandroidx/media3/exoplayer/audio/AudioCapabilities;->()V @@ -3871,19 +3888,19 @@ HSPLandroidx/media3/exoplayer/audio/AudioCapabilities;->getCapabilities(Landroid HSPLandroidx/media3/exoplayer/audio/AudioRendererEventListener$EventDispatcher;->(Landroid/os/Handler;Landroidx/media3/exoplayer/audio/AudioRendererEventListener;)V HSPLandroidx/media3/exoplayer/audio/AudioTrackPositionTracker;->(Landroidx/media3/exoplayer/audio/AudioTrackPositionTracker$Listener;)V HSPLandroidx/media3/exoplayer/audio/ChannelMappingAudioProcessor;->()V +HSPLandroidx/media3/exoplayer/audio/DefaultAudioOffloadSupportProvider;->(Landroid/content/Context;)V HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$AudioTrackBufferSizeProvider;->()V -HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->()V +HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->(Landroid/content/Context;)V HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$100(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Landroid/content/Context; -HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$200(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Landroidx/media3/exoplayer/audio/AudioCapabilities; +HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$1000(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Landroidx/media3/exoplayer/ExoPlayer$AudioOffloadListener; HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$300(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Landroidx/media3/common/audio/AudioProcessorChain; HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$400(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Z HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$500(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Z -HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$600(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)I +HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$600(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Landroidx/media3/exoplayer/audio/DefaultAudioSink$AudioTrackBufferSizeProvider; +HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->access$700(Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;)Landroidx/media3/exoplayer/audio/DefaultAudioSink$AudioOffloadSupportProvider; HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->build()Landroidx/media3/exoplayer/audio/DefaultAudioSink; -HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->setAudioCapabilities(Landroidx/media3/exoplayer/audio/AudioCapabilities;)Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder; HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->setEnableAudioTrackPlaybackParams(Z)Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder; HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->setEnableFloatOutput(Z)Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder; -HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$Builder;->setOffloadMode(I)Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder; HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$DefaultAudioProcessorChain;->([Landroidx/media3/common/audio/AudioProcessor;)V HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$DefaultAudioProcessorChain;->([Landroidx/media3/common/audio/AudioProcessor;Landroidx/media3/exoplayer/audio/SilenceSkippingAudioProcessor;Landroidx/media3/common/audio/SonicAudioProcessor;)V HSPLandroidx/media3/exoplayer/audio/DefaultAudioSink$MediaPositionParameters;->(Landroidx/media3/common/PlaybackParameters;JJ)V @@ -3910,12 +3927,14 @@ HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder; HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;->access$300(Landroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;)I HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;->access$400(Landroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;)I HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;->access$500(Landroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;)I +HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;->access$600(Landroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;)I HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;->build()Landroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider; HSPLandroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider;->(Landroidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider$Builder;)V HSPLandroidx/media3/exoplayer/audio/MediaCodecAudioRenderer$AudioSinkListener;->(Landroidx/media3/exoplayer/audio/MediaCodecAudioRenderer;)V HSPLandroidx/media3/exoplayer/audio/MediaCodecAudioRenderer$AudioSinkListener;->(Landroidx/media3/exoplayer/audio/MediaCodecAudioRenderer;Landroidx/media3/exoplayer/audio/MediaCodecAudioRenderer$1;)V HSPLandroidx/media3/exoplayer/audio/MediaCodecAudioRenderer;->(Landroid/content/Context;Landroidx/media3/exoplayer/mediacodec/MediaCodecAdapter$Factory;Landroidx/media3/exoplayer/mediacodec/MediaCodecSelector;ZLandroid/os/Handler;Landroidx/media3/exoplayer/audio/AudioRendererEventListener;Landroidx/media3/exoplayer/audio/AudioSink;)V HSPLandroidx/media3/exoplayer/audio/MediaCodecAudioRenderer;->handleMessage(ILjava/lang/Object;)V +HSPLandroidx/media3/exoplayer/audio/OggOpusAudioPacketizer;->()V HSPLandroidx/media3/exoplayer/audio/OggOpusAudioPacketizer;->()V HSPLandroidx/media3/exoplayer/audio/SilenceSkippingAudioProcessor;->()V HSPLandroidx/media3/exoplayer/audio/SilenceSkippingAudioProcessor;->(JJS)V @@ -3942,7 +3961,6 @@ HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecRenderer$OutputStreamInfo;->< HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecRenderer;->()V HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecRenderer;->(ILandroidx/media3/exoplayer/mediacodec/MediaCodecAdapter$Factory;Landroidx/media3/exoplayer/mediacodec/MediaCodecSelector;ZF)V HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecRenderer;->getCodec()Landroidx/media3/exoplayer/mediacodec/MediaCodecAdapter; -HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecRenderer;->setOutputStreamInfo(Landroidx/media3/exoplayer/mediacodec/MediaCodecRenderer$OutputStreamInfo;)V HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecSelector$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecSelector;->()V HSPLandroidx/media3/exoplayer/mediacodec/MediaCodecUtil$$ExternalSyntheticApiModelOutline0;->m(Landroid/media/MediaCodecInfo;)Z @@ -3984,6 +4002,9 @@ HSPLandroidx/media3/exoplayer/source/DefaultMediaSourceFactory$DelegateFactoryLo HSPLandroidx/media3/exoplayer/source/DefaultMediaSourceFactory;->(Landroidx/media3/datasource/DataSource$Factory;)V HSPLandroidx/media3/exoplayer/source/DefaultMediaSourceFactory;->(Landroidx/media3/datasource/DataSource$Factory;Landroidx/media3/extractor/ExtractorsFactory;)V HSPLandroidx/media3/exoplayer/source/MediaSource$MediaPeriodId;->(Ljava/lang/Object;)V +HSPLandroidx/media3/exoplayer/source/MediaSource$MediaPeriodId;->(Ljava/lang/Object;IIJI)V +HSPLandroidx/media3/exoplayer/source/MediaSource$MediaPeriodId;->(Ljava/lang/Object;J)V +HSPLandroidx/media3/exoplayer/source/MediaSource$MediaPeriodId;->isAd()Z HSPLandroidx/media3/exoplayer/source/ProgressiveMediaSource$Factory$$ExternalSyntheticLambda0;->(Landroidx/media3/extractor/ExtractorsFactory;)V HSPLandroidx/media3/exoplayer/source/ProgressiveMediaSource$Factory;->(Landroidx/media3/datasource/DataSource$Factory;Landroidx/media3/exoplayer/source/ProgressiveMediaExtractor$Factory;)V HSPLandroidx/media3/exoplayer/source/ProgressiveMediaSource$Factory;->(Landroidx/media3/datasource/DataSource$Factory;Landroidx/media3/exoplayer/source/ProgressiveMediaExtractor$Factory;Landroidx/media3/exoplayer/drm/DrmSessionManagerProvider;Landroidx/media3/exoplayer/upstream/LoadErrorHandlingPolicy;I)V @@ -4008,7 +4029,6 @@ HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$$ExternalSynth HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->()V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->(Landroid/content/Context;)V -HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$2100(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$2200(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$2300(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$2400(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z @@ -4022,8 +4042,10 @@ HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Bui HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3200(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3300(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3400(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z -HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3500(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Landroid/util/SparseArray; -HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3600(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Landroid/util/SparseBooleanArray; +HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3500(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z +HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3600(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Z +HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3700(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Landroid/util/SparseArray; +HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->access$3800(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)Landroid/util/SparseBooleanArray; HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->build()Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters; HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->init()V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;->setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(Landroid/content/Context;)Landroidx/media3/common/TrackSelectionParameters$Builder; @@ -4035,10 +4057,8 @@ HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Bui HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->()V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;)V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->(Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters$Builder;Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$1;)V +HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->equals(Ljava/lang/Object;)Z HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->getDefaults(Landroid/content/Context;)Landroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters; -HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->getKeysFromSparseBooleanArray(Landroid/util/SparseBooleanArray;)[I -HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->putSelectionOverridesToBundle(Landroid/os/Bundle;Landroid/util/SparseArray;)V -HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector$Parameters;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector;->()V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector;->(Landroid/content/Context;)V HSPLandroidx/media3/exoplayer/trackselection/DefaultTrackSelector;->(Landroid/content/Context;Landroidx/media3/common/TrackSelectionParameters;Landroidx/media3/exoplayer/trackselection/ExoTrackSelection$Factory;)V @@ -4091,13 +4111,21 @@ HSPLandroidx/media3/exoplayer/upstream/SlidingPercentile$$ExternalSyntheticLambd HSPLandroidx/media3/exoplayer/upstream/SlidingPercentile;->()V HSPLandroidx/media3/exoplayer/upstream/SlidingPercentile;->(I)V HSPLandroidx/media3/exoplayer/upstream/SlidingPercentile;->reset()V +HSPLandroidx/media3/exoplayer/video/CompositingVideoSinkProvider$ReflectivePreviewingSingleInputVideoGraphFactory;->(Landroidx/media3/common/VideoFrameProcessor$Factory;)V +HSPLandroidx/media3/exoplayer/video/CompositingVideoSinkProvider;->(Landroid/content/Context;Landroidx/media3/common/PreviewingVideoGraph$Factory;Landroidx/media3/exoplayer/video/VideoSink$RenderControl;)V +HSPLandroidx/media3/exoplayer/video/CompositingVideoSinkProvider;->(Landroid/content/Context;Landroidx/media3/common/VideoFrameProcessor$Factory;Landroidx/media3/exoplayer/video/VideoSink$RenderControl;)V +HSPLandroidx/media3/exoplayer/video/CompositingVideoSinkProvider;->isInitialized()Z +HSPLandroidx/media3/exoplayer/video/CompositingVideoSinkProvider;->setVideoFrameMetadataListener(Landroidx/media3/exoplayer/video/VideoFrameMetadataListener;)V HSPLandroidx/media3/exoplayer/video/FixedFrameRateEstimator$Matcher;->()V HSPLandroidx/media3/exoplayer/video/FixedFrameRateEstimator;->()V -HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer$VideoFrameProcessorManager;->(Landroidx/media3/exoplayer/video/VideoFrameReleaseHelper;Landroidx/media3/exoplayer/video/MediaCodecVideoRenderer;)V +HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer$ReflectiveDefaultVideoFrameProcessorFactory$$ExternalSyntheticLambda0;->()V +HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer$ReflectiveDefaultVideoFrameProcessorFactory;->()V +HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer$ReflectiveDefaultVideoFrameProcessorFactory;->()V +HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer$ReflectiveDefaultVideoFrameProcessorFactory;->(Landroidx/media3/exoplayer/video/MediaCodecVideoRenderer$1;)V HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->()V HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->(Landroid/content/Context;Landroidx/media3/exoplayer/mediacodec/MediaCodecAdapter$Factory;Landroidx/media3/exoplayer/mediacodec/MediaCodecSelector;JZLandroid/os/Handler;Landroidx/media3/exoplayer/video/VideoRendererEventListener;I)V HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->(Landroid/content/Context;Landroidx/media3/exoplayer/mediacodec/MediaCodecAdapter$Factory;Landroidx/media3/exoplayer/mediacodec/MediaCodecSelector;JZLandroid/os/Handler;Landroidx/media3/exoplayer/video/VideoRendererEventListener;IF)V -HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->clearReportedVideoSize()V +HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->(Landroid/content/Context;Landroidx/media3/exoplayer/mediacodec/MediaCodecAdapter$Factory;Landroidx/media3/exoplayer/mediacodec/MediaCodecSelector;JZLandroid/os/Handler;Landroidx/media3/exoplayer/video/VideoRendererEventListener;IFLandroidx/media3/common/VideoFrameProcessor$Factory;)V HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->deviceNeedsNoPostProcessWorkaround()Z HSPLandroidx/media3/exoplayer/video/MediaCodecVideoRenderer;->handleMessage(ILjava/lang/Object;)V HSPLandroidx/media3/exoplayer/video/VideoFrameReleaseHelper$DisplayHelperV17;->(Landroid/hardware/display/DisplayManager;)V @@ -4120,6 +4148,8 @@ HSPLandroidx/media3/extractor/DefaultExtractorsFactory;->()V HSPLandroidx/media3/extractor/DefaultExtractorsFactory;->()V HSPLandroidx/media3/extractor/DefaultExtractorsFactory;->setConstantBitrateSeekingEnabled(Z)Landroidx/media3/extractor/DefaultExtractorsFactory; HSPLandroidx/media3/extractor/metadata/MetadataInputBuffer;->()V +HSPLandroidx/media3/extractor/text/CueDecoder;->()V +HSPLandroidx/media3/extractor/text/DefaultSubtitleParserFactory;->()V HSPLandroidx/media3/session/CacheBitmapLoader;->(Landroidx/media3/common/util/BitmapLoader;)V HSPLandroidx/media3/session/CommandButton$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/session/CommandButton$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; @@ -4134,12 +4164,12 @@ HSPLandroidx/media3/session/CommandButton;->$r8$lambda$NuCyllBZqMGlcMmw2c9ZW1r2M HSPLandroidx/media3/session/CommandButton;->()V HSPLandroidx/media3/session/CommandButton;->(Landroidx/media3/session/SessionCommand;IILjava/lang/CharSequence;Landroid/os/Bundle;Z)V HSPLandroidx/media3/session/CommandButton;->(Landroidx/media3/session/SessionCommand;IILjava/lang/CharSequence;Landroid/os/Bundle;ZLandroidx/media3/session/CommandButton$1;)V +HSPLandroidx/media3/session/CommandButton;->copyWithIsEnabled(Z)Landroidx/media3/session/CommandButton; HSPLandroidx/media3/session/CommandButton;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/session/CommandButton; +HSPLandroidx/media3/session/CommandButton;->getEnabledCommandButtons(Ljava/util/List;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)Lcom/google/common/collect/ImmutableList; +HSPLandroidx/media3/session/CommandButton;->isEnabled(Landroidx/media3/session/CommandButton;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)Z HSPLandroidx/media3/session/CommandButton;->toBundle()Landroid/os/Bundle; -HSPLandroidx/media3/session/ConnectedControllersManager$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;)V -HSPLandroidx/media3/session/ConnectedControllersManager$$ExternalSyntheticLambda0;->run()V HSPLandroidx/media3/session/ConnectedControllersManager$ConnectedControllerRecord;->(Ljava/lang/Object;Landroidx/media3/session/SequencedFutureManager;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)V -HSPLandroidx/media3/session/ConnectedControllersManager;->$r8$lambda$Vom81RksdvuIVXyQfAu6pd1M7BY(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLandroidx/media3/session/ConnectedControllersManager;->(Landroidx/media3/session/MediaSessionImpl;)V HSPLandroidx/media3/session/ConnectedControllersManager;->addController(Ljava/lang/Object;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)V HSPLandroidx/media3/session/ConnectedControllersManager;->getAvailablePlayerCommands(Landroidx/media3/session/MediaSession$ControllerInfo;)Landroidx/media3/common/Player$Commands; @@ -4149,9 +4179,6 @@ HSPLandroidx/media3/session/ConnectedControllersManager;->getSequencedFutureMana HSPLandroidx/media3/session/ConnectedControllersManager;->getSequencedFutureManager(Ljava/lang/Object;)Landroidx/media3/session/SequencedFutureManager; HSPLandroidx/media3/session/ConnectedControllersManager;->isConnected(Landroidx/media3/session/MediaSession$ControllerInfo;)Z HSPLandroidx/media3/session/ConnectedControllersManager;->isSessionCommandAvailable(Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;)Z -HSPLandroidx/media3/session/ConnectedControllersManager;->lambda$removeController$0(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;)V -HSPLandroidx/media3/session/ConnectedControllersManager;->removeController(Landroidx/media3/session/MediaSession$ControllerInfo;)V -HSPLandroidx/media3/session/ConnectedControllersManager;->removeController(Ljava/lang/Object;)V HSPLandroidx/media3/session/ConnectionRequest$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/session/ConnectionRequest$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/session/ConnectionRequest;->$r8$lambda$2A3KvllqTYxjJdHPpYs14G1Hda8(Landroid/os/Bundle;)Landroidx/media3/session/ConnectionRequest; @@ -4162,11 +4189,14 @@ HSPLandroidx/media3/session/ConnectionRequest;->lambda$static$0(Landroid/os/Bund HSPLandroidx/media3/session/ConnectionRequest;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/session/ConnectionState$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/session/ConnectionState$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; +HSPLandroidx/media3/session/ConnectionState$InProcessBinder;->(Landroidx/media3/session/ConnectionState;)V +HSPLandroidx/media3/session/ConnectionState$InProcessBinder;->(Landroidx/media3/session/ConnectionState;Landroidx/media3/session/ConnectionState$1;)V +HSPLandroidx/media3/session/ConnectionState$InProcessBinder;->getConnectionState()Landroidx/media3/session/ConnectionState; HSPLandroidx/media3/session/ConnectionState;->$r8$lambda$ZjTwf4GufRk5624GRLNfHLYPV2s(Landroid/os/Bundle;)Landroidx/media3/session/ConnectionState; HSPLandroidx/media3/session/ConnectionState;->()V -HSPLandroidx/media3/session/ConnectionState;->(IILandroidx/media3/session/IMediaSession;Landroid/app/PendingIntent;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;Landroidx/media3/common/Player$Commands;Landroid/os/Bundle;Landroidx/media3/session/PlayerInfo;)V +HSPLandroidx/media3/session/ConnectionState;->(IILandroidx/media3/session/IMediaSession;Landroid/app/PendingIntent;Lcom/google/common/collect/ImmutableList;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;Landroidx/media3/common/Player$Commands;Landroid/os/Bundle;Landroid/os/Bundle;Landroidx/media3/session/PlayerInfo;)V HSPLandroidx/media3/session/ConnectionState;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/session/ConnectionState; -HSPLandroidx/media3/session/ConnectionState;->toBundle()Landroid/os/Bundle; +HSPLandroidx/media3/session/ConnectionState;->toBundleInProcess()Landroid/os/Bundle; HSPLandroidx/media3/session/DefaultActionFactory;->(Landroid/app/Service;)V HSPLandroidx/media3/session/DefaultMediaNotificationProvider$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/NotificationManager;Ljava/lang/String;)Landroid/app/NotificationChannel; HSPLandroidx/media3/session/DefaultMediaNotificationProvider$Api26$$ExternalSyntheticApiModelOutline0;->m(Ljava/lang/String;Ljava/lang/CharSequence;I)Landroid/app/NotificationChannel; @@ -4180,22 +4210,27 @@ HSPLandroidx/media3/session/IMediaSession$Stub;->asInterface(Landroid/os/IBinder HSPLandroidx/media3/session/IMediaSessionService$Stub;->()V HSPLandroidx/media3/session/IMediaSessionService$Stub;->asBinder()Landroid/os/IBinder; HSPLandroidx/media3/session/IMediaSessionService$Stub;->asInterface(Landroid/os/IBinder;)Landroidx/media3/session/IMediaSessionService; -HSPLandroidx/media3/session/MediaController$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaController;)V -HSPLandroidx/media3/session/MediaController$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V +HSPLandroidx/media3/session/LegacyConversions;->()V +HSPLandroidx/media3/session/LegacyConversions;->convertToAudioAttributesCompat(Landroidx/media3/common/AudioAttributes;)Landroidx/media/AudioAttributesCompat; +HSPLandroidx/media3/session/LegacyConversions;->convertToPlaybackStateCompatRepeatMode(I)I +HSPLandroidx/media3/session/LegacyConversions;->convertToPlaybackStateCompatShuffleMode(Z)I +HSPLandroidx/media3/session/LegacyConversions;->convertToPlaybackStateCompatState(Landroidx/media3/common/Player;Z)I +HSPLandroidx/media3/session/LegacyConversions;->convertToQueueItemId(I)J +HSPLandroidx/media3/session/LegacyConversions;->getLegacyStreamType(Landroidx/media3/common/AudioAttributes;)I HSPLandroidx/media3/session/MediaController$Builder$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaControllerHolder;Landroidx/media3/session/MediaController;)V HSPLandroidx/media3/session/MediaController$Builder$$ExternalSyntheticLambda0;->run()V HSPLandroidx/media3/session/MediaController$Builder$1;->(Landroidx/media3/session/MediaController$Builder;)V -HSPLandroidx/media3/session/MediaController$Builder$1;->onDisconnected(Landroidx/media3/session/MediaController;)V +HSPLandroidx/media3/session/MediaController$Builder$1;->onCustomLayoutChanged(Landroidx/media3/session/MediaController;Ljava/util/List;)V HSPLandroidx/media3/session/MediaController$Builder$1;->onSetCustomLayout(Landroidx/media3/session/MediaController;Ljava/util/List;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaController$Builder;->$r8$lambda$zyVzcB3Sb8jhbB9a-kIcWAaXt7s(Landroidx/media3/session/MediaControllerHolder;Landroidx/media3/session/MediaController;)V HSPLandroidx/media3/session/MediaController$Builder;->(Landroid/content/Context;Landroidx/media3/session/SessionToken;)V HSPLandroidx/media3/session/MediaController$Builder;->buildAsync()Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaController$Builder;->lambda$buildAsync$0(Landroidx/media3/session/MediaControllerHolder;Landroidx/media3/session/MediaController;)V HSPLandroidx/media3/session/MediaController$Builder;->setApplicationLooper(Landroid/os/Looper;)Landroidx/media3/session/MediaController$Builder; +HSPLandroidx/media3/session/MediaController$Builder;->setConnectionHints(Landroid/os/Bundle;)Landroidx/media3/session/MediaController$Builder; HSPLandroidx/media3/session/MediaController$Builder;->setListener(Landroidx/media3/session/MediaController$Listener;)Landroidx/media3/session/MediaController$Builder; -HSPLandroidx/media3/session/MediaController$Listener$-CC;->$default$onDisconnected(Landroidx/media3/session/MediaController$Listener;Landroidx/media3/session/MediaController;)V +HSPLandroidx/media3/session/MediaController$Listener$-CC;->$default$onCustomLayoutChanged(Landroidx/media3/session/MediaController$Listener;Landroidx/media3/session/MediaController;Ljava/util/List;)V HSPLandroidx/media3/session/MediaController$Listener$-CC;->$default$onSetCustomLayout(Landroidx/media3/session/MediaController$Listener;Landroidx/media3/session/MediaController;Ljava/util/List;)Lcom/google/common/util/concurrent/ListenableFuture; -HSPLandroidx/media3/session/MediaController;->$r8$lambda$7Poy_IVrU20FjlOzoqG4RzKma48(Landroidx/media3/session/MediaController;Landroidx/media3/session/MediaController$Listener;)V HSPLandroidx/media3/session/MediaController;->(Landroid/content/Context;Landroidx/media3/session/SessionToken;Landroid/os/Bundle;Landroidx/media3/session/MediaController$Listener;Landroid/os/Looper;Landroidx/media3/session/MediaController$ConnectionCallback;Landroidx/media3/common/util/BitmapLoader;)V HSPLandroidx/media3/session/MediaController;->addListener(Landroidx/media3/common/Player$Listener;)V HSPLandroidx/media3/session/MediaController;->createImpl(Landroid/content/Context;Landroidx/media3/session/SessionToken;Landroid/os/Bundle;Landroid/os/Looper;Landroidx/media3/common/util/BitmapLoader;)Landroidx/media3/session/MediaController$MediaControllerImpl; @@ -4205,10 +4240,8 @@ HSPLandroidx/media3/session/MediaController;->getCurrentTimeline()Landroidx/medi HSPLandroidx/media3/session/MediaController;->getPlaybackState()I HSPLandroidx/media3/session/MediaController;->isConnected()Z HSPLandroidx/media3/session/MediaController;->isPlaying()Z -HSPLandroidx/media3/session/MediaController;->lambda$release$0(Landroidx/media3/session/MediaController$Listener;)V HSPLandroidx/media3/session/MediaController;->notifyAccepted()V HSPLandroidx/media3/session/MediaController;->notifyControllerListener(Landroidx/media3/common/util/Consumer;)V -HSPLandroidx/media3/session/MediaController;->release()V HSPLandroidx/media3/session/MediaController;->runOnApplicationLooper(Ljava/lang/Runnable;)V HSPLandroidx/media3/session/MediaController;->sendCustomCommand(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaController;->verifyApplicationThread()V @@ -4224,33 +4257,31 @@ HSPLandroidx/media3/session/MediaControllerHolder;->lambda$setController$1(Ljava HSPLandroidx/media3/session/MediaControllerHolder;->maybeSetFutureResult()V HSPLandroidx/media3/session/MediaControllerHolder;->onAccepted()V HSPLandroidx/media3/session/MediaControllerHolder;->setController(Landroidx/media3/session/MediaController;)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda113;->(Landroidx/media3/session/MediaControllerImplBase;Ljava/util/List;I)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda113;->accept(Ljava/lang/Object;)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda118;->(Landroidx/media3/session/MediaControllerImplBase;Lcom/google/common/util/concurrent/ListenableFuture;I)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda118;->run()V +HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda104;->(Landroidx/media3/session/MediaControllerImplBase;I)V +HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda104;->run()V +HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda108;->(Landroidx/media3/session/MediaControllerImplBase;ZI)V +HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda108;->accept(Ljava/lang/Object;)V +HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda114;->(Landroidx/media3/session/MediaControllerImplBase;Lcom/google/common/util/concurrent/ListenableFuture;I)V +HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda114;->run()V HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda38;->(Landroidx/media3/session/MediaControllerImplBase;)V HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda39;->(Landroidx/media3/session/MediaControllerImplBase;)V HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda41;->(Landroidx/media3/session/MediaControllerImplBase;Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;)V HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda41;->run(Landroidx/media3/session/IMediaSession;I)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda81;->(Landroidx/media3/session/MediaControllerImplBase;)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda82;->(Landroidx/media3/session/MediaControllerImplBase;I)V -HSPLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda82;->run()V HSPLandroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler;)V HSPLandroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler;->(Landroidx/media3/session/MediaControllerImplBase;Landroid/os/Looper;)V -HSPLandroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler;->release()V HSPLandroidx/media3/session/MediaControllerImplBase$SessionServiceConnection;->(Landroidx/media3/session/MediaControllerImplBase;Landroid/os/Bundle;)V HSPLandroidx/media3/session/MediaControllerImplBase$SessionServiceConnection;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V HSPLandroidx/media3/session/MediaControllerImplBase$SurfaceCallback;->(Landroidx/media3/session/MediaControllerImplBase;)V HSPLandroidx/media3/session/MediaControllerImplBase$SurfaceCallback;->(Landroidx/media3/session/MediaControllerImplBase;Landroidx/media3/session/MediaControllerImplBase$1;)V -HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$8ePI85Zvn-Y2ZOUzRdQ90F2A8_A(Landroidx/media3/session/MediaControllerImplBase;I)V -HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$h98tQpKckSTD3e3SDer5Lqnajhs(Landroidx/media3/session/MediaControllerImplBase;Lcom/google/common/util/concurrent/ListenableFuture;I)V +HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$9zYDBLO34_xl0JlcPU0_tzaQUTE(Landroidx/media3/session/MediaControllerImplBase;Lcom/google/common/util/concurrent/ListenableFuture;I)V +HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$es4RLb9JXUKd95d4cKofXSS87xM(Landroidx/media3/session/MediaControllerImplBase;I)V HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$mXQX_Ogg1Zjg5n58ylw_9v5Iv2Y(Landroidx/media3/session/MediaControllerImplBase;Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;Landroidx/media3/session/IMediaSession;I)V -HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$vt4LFlOFWDb7FYoJD4Ps6YPbQNk(Landroidx/media3/session/MediaControllerImplBase;Ljava/util/List;ILandroidx/media3/session/MediaController$Listener;)V +HSPLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$oTMV0r3uwAPvI1WXxNvazTtoPXw(Landroidx/media3/session/MediaControllerImplBase;ZILandroidx/media3/session/MediaController$Listener;)V HSPLandroidx/media3/session/MediaControllerImplBase;->(Landroid/content/Context;Landroidx/media3/session/MediaController;Landroidx/media3/session/SessionToken;Landroid/os/Bundle;Landroid/os/Looper;)V HSPLandroidx/media3/session/MediaControllerImplBase;->access$300(Landroidx/media3/session/MediaControllerImplBase;)Landroidx/media3/session/SessionToken; HSPLandroidx/media3/session/MediaControllerImplBase;->addListener(Landroidx/media3/common/Player$Listener;)V HSPLandroidx/media3/session/MediaControllerImplBase;->connect()V -HSPLandroidx/media3/session/MediaControllerImplBase;->createIntersectedCommands(Landroidx/media3/common/Player$Commands;Landroidx/media3/common/Player$Commands;)Landroidx/media3/common/Player$Commands; +HSPLandroidx/media3/session/MediaControllerImplBase;->createIntersectedCommandsEnsuringCommandReleaseAvailable(Landroidx/media3/common/Player$Commands;Landroidx/media3/common/Player$Commands;)Landroidx/media3/common/Player$Commands; HSPLandroidx/media3/session/MediaControllerImplBase;->dispatchRemoteSessionTask(Landroidx/media3/session/IMediaSession;Landroidx/media3/session/MediaControllerImplBase$RemoteSessionTask;Z)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaControllerImplBase;->dispatchRemoteSessionTaskWithSessionCommand(Landroidx/media3/session/SessionCommand;Landroidx/media3/session/MediaControllerImplBase$RemoteSessionTask;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaControllerImplBase;->dispatchRemoteSessionTaskWithSessionCommandInternal(ILandroidx/media3/session/SessionCommand;Landroidx/media3/session/MediaControllerImplBase$RemoteSessionTask;)Lcom/google/common/util/concurrent/ListenableFuture; @@ -4262,14 +4293,14 @@ HSPLandroidx/media3/session/MediaControllerImplBase;->getSessionInterfaceWithSes HSPLandroidx/media3/session/MediaControllerImplBase;->isConnected()Z HSPLandroidx/media3/session/MediaControllerImplBase;->isPlaying()Z HSPLandroidx/media3/session/MediaControllerImplBase;->isReleased()Z -HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$onSetCustomLayout$116(Ljava/util/List;ILandroidx/media3/session/MediaController$Listener;)V -HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$sendControllerResultWhenReady$84(Lcom/google/common/util/concurrent/ListenableFuture;I)V +HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$onSetCustomLayout$112(ZILandroidx/media3/session/MediaController$Listener;)V +HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$sendControllerResultWhenReady$106(Lcom/google/common/util/concurrent/ListenableFuture;I)V HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$sendCustomCommand$21(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;Landroidx/media3/session/IMediaSession;I)V -HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$setFutureResult$83(I)V +HSPLandroidx/media3/session/MediaControllerImplBase;->lambda$setFutureResult$105(I)V +HSPLandroidx/media3/session/MediaControllerImplBase;->notifyPlayerInfoListenersWithReasons(Landroidx/media3/session/PlayerInfo;Landroidx/media3/session/PlayerInfo;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)V HSPLandroidx/media3/session/MediaControllerImplBase;->onConnected(Landroidx/media3/session/ConnectionState;)V HSPLandroidx/media3/session/MediaControllerImplBase;->onPlayerInfoChanged(Landroidx/media3/session/PlayerInfo;Landroidx/media3/session/PlayerInfo$BundlingExclusions;)V HSPLandroidx/media3/session/MediaControllerImplBase;->onSetCustomLayout(ILjava/util/List;)V -HSPLandroidx/media3/session/MediaControllerImplBase;->release()V HSPLandroidx/media3/session/MediaControllerImplBase;->requestConnectToService()Z HSPLandroidx/media3/session/MediaControllerImplBase;->requestConnectToSession(Landroid/os/Bundle;)Z HSPLandroidx/media3/session/MediaControllerImplBase;->sendControllerResult(ILandroidx/media3/session/SessionResult;)V @@ -4299,13 +4330,14 @@ HSPLandroidx/media3/session/MediaControllerStub;->onPlayerInfoChangedWithExclusi HSPLandroidx/media3/session/MediaControllerStub;->onSessionResult(ILandroid/os/Bundle;)V HSPLandroidx/media3/session/MediaControllerStub;->onSetCustomLayout(ILjava/util/List;)V HSPLandroidx/media3/session/MediaControllerStub;->setControllerFutureResult(ILjava/lang/Object;)V -HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda3;->(Landroid/os/Handler;)V -HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda3;->execute(Ljava/lang/Runnable;)V -HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda6;->(Landroidx/media3/session/MediaNotificationManager;Lcom/google/common/util/concurrent/ListenableFuture;Landroidx/media3/session/MediaNotificationManager$MediaControllerListener;Landroidx/media3/session/MediaSession;)V -HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda6;->run()V +HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda2;->(Landroid/os/Handler;)V +HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda2;->execute(Ljava/lang/Runnable;)V +HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda5;->(Landroidx/media3/session/MediaNotificationManager;Lcom/google/common/util/concurrent/ListenableFuture;Landroidx/media3/session/MediaNotificationManager$MediaControllerListener;Landroidx/media3/session/MediaSession;)V +HSPLandroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda5;->run()V HSPLandroidx/media3/session/MediaNotificationManager$Api24;->stopForeground(Landroidx/media3/session/MediaSessionService;Z)V -HSPLandroidx/media3/session/MediaNotificationManager$MediaControllerListener;->(Landroidx/media3/session/MediaSessionService;Landroidx/media3/session/MediaSession;Ljava/util/Map;)V +HSPLandroidx/media3/session/MediaNotificationManager$MediaControllerListener;->(Landroidx/media3/session/MediaSessionService;Landroidx/media3/session/MediaSession;)V HSPLandroidx/media3/session/MediaNotificationManager$MediaControllerListener;->onConnected(Z)V +HSPLandroidx/media3/session/MediaNotificationManager$MediaControllerListener;->onCustomLayoutChanged(Landroidx/media3/session/MediaController;Ljava/util/List;)V HSPLandroidx/media3/session/MediaNotificationManager$MediaControllerListener;->onSetCustomLayout(Landroidx/media3/session/MediaController;Ljava/util/List;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaNotificationManager;->$r8$lambda$1ulvKeHiWSsj_M-1JZwhrZVhpA8(Landroidx/media3/session/MediaNotificationManager;Lcom/google/common/util/concurrent/ListenableFuture;Landroidx/media3/session/MediaNotificationManager$MediaControllerListener;Landroidx/media3/session/MediaSession;)V HSPLandroidx/media3/session/MediaNotificationManager;->$r8$lambda$NYHZ5KZm0zYYXQuqLwbY7Jckyvo(Landroid/os/Handler;Ljava/lang/Runnable;)V @@ -4327,79 +4359,94 @@ HSPLandroidx/media3/session/MediaSession$Builder;->setId(Ljava/lang/String;)Land HSPLandroidx/media3/session/MediaSession$BuilderBase;->(Landroid/content/Context;Landroidx/media3/common/Player;Landroidx/media3/session/MediaSession$Callback;)V HSPLandroidx/media3/session/MediaSession$BuilderBase;->setCallback(Landroidx/media3/session/MediaSession$Callback;)Landroidx/media3/session/MediaSession$BuilderBase; HSPLandroidx/media3/session/MediaSession$BuilderBase;->setId(Ljava/lang/String;)Landroidx/media3/session/MediaSession$BuilderBase; -HSPLandroidx/media3/session/MediaSession$Callback$-CC;->$default$onDisconnected(Landroidx/media3/session/MediaSession$Callback;Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;)V -HSPLandroidx/media3/session/MediaSession$ConnectionResult;->(ZLandroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)V +HSPLandroidx/media3/session/MediaSession$ConnectionResult$AcceptedResultBuilder;->(Landroidx/media3/session/MediaSession;)V +HSPLandroidx/media3/session/MediaSession$ConnectionResult$AcceptedResultBuilder;->build()Landroidx/media3/session/MediaSession$ConnectionResult; +HSPLandroidx/media3/session/MediaSession$ConnectionResult;->()V +HSPLandroidx/media3/session/MediaSession$ConnectionResult;->(ZLandroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;Lcom/google/common/collect/ImmutableList;Landroid/os/Bundle;)V +HSPLandroidx/media3/session/MediaSession$ConnectionResult;->(ZLandroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;Lcom/google/common/collect/ImmutableList;Landroid/os/Bundle;Landroidx/media3/session/MediaSession$1;)V HSPLandroidx/media3/session/MediaSession$ConnectionResult;->accept(Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)Landroidx/media3/session/MediaSession$ConnectionResult; HSPLandroidx/media3/session/MediaSession$ControllerInfo;->(Landroidx/media/MediaSessionManager$RemoteUserInfo;IIZLandroidx/media3/session/MediaSession$ControllerCb;Landroid/os/Bundle;)V HSPLandroidx/media3/session/MediaSession$ControllerInfo;->equals(Ljava/lang/Object;)Z +HSPLandroidx/media3/session/MediaSession$ControllerInfo;->getConnectionHints()Landroid/os/Bundle; HSPLandroidx/media3/session/MediaSession$ControllerInfo;->getControllerCb()Landroidx/media3/session/MediaSession$ControllerCb; HSPLandroidx/media3/session/MediaSession$ControllerInfo;->getControllerVersion()I HSPLandroidx/media3/session/MediaSession$ControllerInfo;->getInterfaceVersion()I +HSPLandroidx/media3/session/MediaSession$ControllerInfo;->getPackageName()Ljava/lang/String; HSPLandroidx/media3/session/MediaSession$ControllerInfo;->hashCode()I HSPLandroidx/media3/session/MediaSession;->()V -HSPLandroidx/media3/session/MediaSession;->(Landroid/content/Context;Ljava/lang/String;Landroidx/media3/common/Player;Landroid/app/PendingIntent;Landroidx/media3/session/MediaSession$Callback;Landroid/os/Bundle;Landroidx/media3/common/util/BitmapLoader;)V -HSPLandroidx/media3/session/MediaSession;->createImpl(Landroid/content/Context;Ljava/lang/String;Landroidx/media3/common/Player;Landroid/app/PendingIntent;Landroidx/media3/session/MediaSession$Callback;Landroid/os/Bundle;Landroidx/media3/common/util/BitmapLoader;)Landroidx/media3/session/MediaSessionImpl; +HSPLandroidx/media3/session/MediaSession;->(Landroid/content/Context;Ljava/lang/String;Landroidx/media3/common/Player;Landroid/app/PendingIntent;Lcom/google/common/collect/ImmutableList;Landroidx/media3/session/MediaSession$Callback;Landroid/os/Bundle;Landroid/os/Bundle;Landroidx/media3/common/util/BitmapLoader;ZZ)V +HSPLandroidx/media3/session/MediaSession;->createImpl(Landroid/content/Context;Ljava/lang/String;Landroidx/media3/common/Player;Landroid/app/PendingIntent;Lcom/google/common/collect/ImmutableList;Landroidx/media3/session/MediaSession$Callback;Landroid/os/Bundle;Landroid/os/Bundle;Landroidx/media3/common/util/BitmapLoader;ZZ)Landroidx/media3/session/MediaSessionImpl; +HSPLandroidx/media3/session/MediaSession;->getCustomLayout()Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/session/MediaSession;->getId()Ljava/lang/String; HSPLandroidx/media3/session/MediaSession;->getToken()Landroidx/media3/session/SessionToken; -HSPLandroidx/media3/session/MediaSession;->handleControllerConnectionFromService(Landroidx/media3/session/IMediaController;IILjava/lang/String;IILandroid/os/Bundle;)V +HSPLandroidx/media3/session/MediaSession;->handleControllerConnectionFromService(Landroidx/media3/session/IMediaController;Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLandroidx/media3/session/MediaSession;->isReleased()Z HSPLandroidx/media3/session/MediaSession;->setCustomLayout(Landroidx/media3/session/MediaSession$ControllerInfo;Ljava/util/List;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSession;->setListener(Landroidx/media3/session/MediaSession$Listener;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda0;->(Ljava/util/List;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda0;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda1;->(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerWrapper;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda1;->run()V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerWrapper;)V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda0;->run()V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda17;->(Landroidx/media3/common/Player$Commands;)V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda17;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda18;->(Landroidx/media3/session/MediaSessionImpl;)V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda18;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda1;->(Landroidx/media3/session/MediaSessionImpl;)V HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda2;->(Landroidx/media3/session/MediaSessionImpl;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda3;->(Landroidx/media3/session/MediaSessionImpl;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda3;->run()V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda2;->run()V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda4;->(Lcom/google/common/collect/ImmutableList;)V +HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda4;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda6;->(Landroidx/media3/session/PlayerWrapper;Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda6;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda7;->(Landroidx/media3/common/Player$Commands;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda7;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda8;->(Landroidx/media3/session/MediaSessionImpl;)V -HSPLandroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda8;->run(Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl$MediaPlayPauseKeyHandler;->(Landroidx/media3/session/MediaSessionImpl;Landroid/os/Looper;)V HSPLandroidx/media3/session/MediaSessionImpl$PlayerInfoChangedHandler;->(Landroidx/media3/session/MediaSessionImpl;Landroid/os/Looper;)V HSPLandroidx/media3/session/MediaSessionImpl$PlayerInfoChangedHandler;->handleMessage(Landroid/os/Message;)V HSPLandroidx/media3/session/MediaSessionImpl$PlayerInfoChangedHandler;->sendPlayerInfoChangedMessage(ZZ)V HSPLandroidx/media3/session/MediaSessionImpl$PlayerListener;->(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$01SsO3LCKUvxOjWIW3Kn8h3-Otg(Landroidx/media3/session/PlayerWrapper;Landroidx/media3/session/PlayerWrapper;Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$1wh78gmVIoNd6SPfHgugwWfFrbo(Landroidx/media3/session/MediaSessionImpl;)V -HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$9aJkPMZtVq5y6kyNL9YBSQjH-VM(Landroidx/media3/common/Player$Commands;Landroidx/media3/session/MediaSession$ControllerCb;I)V -HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$A_X0UrBeoHs5WN_iW5QU7jQJaOs(Ljava/util/List;Landroidx/media3/session/MediaSession$ControllerCb;I)V -HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$NX0UFo3ss33TgI65QLQC7u66CEM(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$NroOxpjPW02vBGUiZXAlHZ1e5NI(Landroidx/media3/common/Player$Commands;Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$b5lgJN0r2mELH0IoiJEFkVL86gg(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerWrapper;)V +HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$dpzBmwiuu4PypD-_kp4T1pSZ1EU(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl;->$r8$lambda$jR9N3TTZxFJ0KbFQHAwTWn_wTpc(Lcom/google/common/collect/ImmutableList;Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl;->()V -HSPLandroidx/media3/session/MediaSessionImpl;->(Landroidx/media3/session/MediaSession;Landroid/content/Context;Ljava/lang/String;Landroidx/media3/common/Player;Landroid/app/PendingIntent;Landroidx/media3/session/MediaSession$Callback;Landroid/os/Bundle;Landroidx/media3/common/util/BitmapLoader;)V -HSPLandroidx/media3/session/MediaSessionImpl;->access$100(Landroidx/media3/session/MediaSessionImpl;)Landroidx/media3/session/PlayerInfo; -HSPLandroidx/media3/session/MediaSessionImpl;->access$102(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerInfo;)Landroidx/media3/session/PlayerInfo; -HSPLandroidx/media3/session/MediaSessionImpl;->access$600(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerInfo;ZZ)V -HSPLandroidx/media3/session/MediaSessionImpl;->connectFromService(Landroidx/media3/session/IMediaController;IILjava/lang/String;IILandroid/os/Bundle;)V +HSPLandroidx/media3/session/MediaSessionImpl;->(Landroidx/media3/session/MediaSession;Landroid/content/Context;Ljava/lang/String;Landroidx/media3/common/Player;Landroid/app/PendingIntent;Lcom/google/common/collect/ImmutableList;Landroidx/media3/session/MediaSession$Callback;Landroid/os/Bundle;Landroid/os/Bundle;Landroidx/media3/common/util/BitmapLoader;ZZ)V +HSPLandroidx/media3/session/MediaSessionImpl;->access$200(Landroidx/media3/session/MediaSessionImpl;)Landroidx/media3/session/PlayerInfo; +HSPLandroidx/media3/session/MediaSessionImpl;->access$202(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerInfo;)Landroidx/media3/session/PlayerInfo; +HSPLandroidx/media3/session/MediaSessionImpl;->access$900(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerInfo;ZZ)V +HSPLandroidx/media3/session/MediaSessionImpl;->connectFromService(Landroidx/media3/session/IMediaController;Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLandroidx/media3/session/MediaSessionImpl;->dispatchOnPlayerInfoChanged(Landroidx/media3/session/PlayerInfo;ZZ)V HSPLandroidx/media3/session/MediaSessionImpl;->dispatchRemoteControllerTask(Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/MediaSessionImpl$RemoteControllerTask;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSessionImpl;->dispatchRemoteControllerTaskToLegacyStub(Landroidx/media3/session/MediaSessionImpl$RemoteControllerTask;)V HSPLandroidx/media3/session/MediaSessionImpl;->dispatchRemoteControllerTaskWithoutReturn(Landroidx/media3/session/MediaSessionImpl$RemoteControllerTask;)V HSPLandroidx/media3/session/MediaSessionImpl;->getApplicationHandler()Landroid/os/Handler; HSPLandroidx/media3/session/MediaSessionImpl;->getContext()Landroid/content/Context; +HSPLandroidx/media3/session/MediaSessionImpl;->getCustomLayout()Lcom/google/common/collect/ImmutableList; HSPLandroidx/media3/session/MediaSessionImpl;->getId()Ljava/lang/String; HSPLandroidx/media3/session/MediaSessionImpl;->getPlayerWrapper()Landroidx/media3/session/PlayerWrapper; HSPLandroidx/media3/session/MediaSessionImpl;->getSessionActivity()Landroid/app/PendingIntent; -HSPLandroidx/media3/session/MediaSessionImpl;->getSessionCompat()Landroid/support/v4/media/session/MediaSessionCompat; +HSPLandroidx/media3/session/MediaSessionImpl;->getSessionExtras()Landroid/os/Bundle; HSPLandroidx/media3/session/MediaSessionImpl;->getToken()Landroidx/media3/session/SessionToken; HSPLandroidx/media3/session/MediaSessionImpl;->handleAvailablePlayerCommandsChanged(Landroidx/media3/common/Player$Commands;)V +HSPLandroidx/media3/session/MediaSessionImpl;->isMediaNotificationController(Landroidx/media3/session/MediaSession$ControllerInfo;)Z HSPLandroidx/media3/session/MediaSessionImpl;->isReleased()Z -HSPLandroidx/media3/session/MediaSessionImpl;->lambda$handleAvailablePlayerCommandsChanged$15(Landroidx/media3/common/Player$Commands;Landroidx/media3/session/MediaSession$ControllerCb;I)V -HSPLandroidx/media3/session/MediaSessionImpl;->lambda$handleAvailablePlayerCommandsChanged$16(Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl;->isSystemUiController(Landroidx/media3/session/MediaSession$ControllerInfo;)Z +HSPLandroidx/media3/session/MediaSessionImpl;->lambda$handleAvailablePlayerCommandsChanged$16(Landroidx/media3/common/Player$Commands;Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl;->lambda$handleAvailablePlayerCommandsChanged$17(Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl;->lambda$new$0(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/PlayerWrapper;)V -HSPLandroidx/media3/session/MediaSessionImpl;->lambda$setCustomLayout$4(Ljava/util/List;Landroidx/media3/session/MediaSession$ControllerCb;I)V +HSPLandroidx/media3/session/MediaSessionImpl;->lambda$setCustomLayout$4(Lcom/google/common/collect/ImmutableList;Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl;->lambda$setPlayerInternal$1(Landroidx/media3/session/PlayerWrapper;Landroidx/media3/session/PlayerWrapper;Landroidx/media3/session/MediaSession$ControllerCb;I)V HSPLandroidx/media3/session/MediaSessionImpl;->onConnectOnHandler(Landroidx/media3/session/MediaSession$ControllerInfo;)Landroidx/media3/session/MediaSession$ConnectionResult; HSPLandroidx/media3/session/MediaSessionImpl;->onCustomCommandOnHandler(Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;)Lcom/google/common/util/concurrent/ListenableFuture; -HSPLandroidx/media3/session/MediaSessionImpl;->onDisconnectedOnHandler(Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLandroidx/media3/session/MediaSessionImpl;->onPostConnectOnHandler(Landroidx/media3/session/MediaSession$ControllerInfo;)V +HSPLandroidx/media3/session/MediaSessionImpl;->resolveControllerInfoForCallback(Landroidx/media3/session/MediaSession$ControllerInfo;)Landroidx/media3/session/MediaSession$ControllerInfo; HSPLandroidx/media3/session/MediaSessionImpl;->schedulePeriodicSessionPositionInfoChanges()V -HSPLandroidx/media3/session/MediaSessionImpl;->setCustomLayout(Landroidx/media3/session/MediaSession$ControllerInfo;Ljava/util/List;)Lcom/google/common/util/concurrent/ListenableFuture; +HSPLandroidx/media3/session/MediaSessionImpl;->setAvailableFrameworkControllerCommands(Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)V +HSPLandroidx/media3/session/MediaSessionImpl;->setCustomLayout(Landroidx/media3/session/MediaSession$ControllerInfo;Lcom/google/common/collect/ImmutableList;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSessionImpl;->setMediaSessionListener(Landroidx/media3/session/MediaSession$Listener;)V HSPLandroidx/media3/session/MediaSessionImpl;->setPlayerInternal(Landroidx/media3/session/PlayerWrapper;Landroidx/media3/session/PlayerWrapper;)V +HSPLandroidx/media3/session/MediaSessionLegacyStub$$ExternalSyntheticLambda3;->(Landroidx/media3/session/MediaSessionLegacyStub;Landroidx/media3/session/PlayerWrapper;)V +HSPLandroidx/media3/session/MediaSessionLegacyStub$$ExternalSyntheticLambda3;->run()V +HSPLandroidx/media3/session/MediaSessionLegacyStub$Api31$$ExternalSyntheticApiModelOutline0;->m(Landroid/media/session/MediaSession;Landroid/content/ComponentName;)V +HSPLandroidx/media3/session/MediaSessionLegacyStub$Api31;->setMediaButtonBroadcastReceiver(Landroid/support/v4/media/session/MediaSessionCompat;Landroid/content/ComponentName;)V HSPLandroidx/media3/session/MediaSessionLegacyStub$ConnectionTimeoutHandler;->(Landroid/os/Looper;Landroidx/media3/session/ConnectedControllersManager;)V HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast;->(Landroidx/media3/session/MediaSessionLegacyStub;)V HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast;->onAvailableCommandsChangedFromPlayer(ILandroidx/media3/common/Player$Commands;)V @@ -4412,31 +4459,35 @@ HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcas HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast;->onShuffleModeEnabledChanged(IZ)V HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast;->onTimelineChanged(ILandroidx/media3/common/Timeline;I)V HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast;->updateMetadataIfChanged()V -HSPLandroidx/media3/session/MediaSessionLegacyStub$MediaPlayPauseKeyHandler;->(Landroidx/media3/session/MediaSessionLegacyStub;Landroid/os/Looper;)V +HSPLandroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast;->updateQueue(Landroidx/media3/common/Timeline;)V +HSPLandroidx/media3/session/MediaSessionLegacyStub;->$r8$lambda$2Zr6irjo-J9zgmVW6WSJ8242FKI(Landroidx/media3/session/MediaSessionLegacyStub;Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionLegacyStub;->()V HSPLandroidx/media3/session/MediaSessionLegacyStub;->(Landroidx/media3/session/MediaSessionImpl;Landroid/net/Uri;Landroid/os/Handler;)V HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$100(Landroidx/media3/session/MediaSessionLegacyStub;)Landroidx/media3/session/MediaSessionImpl; HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$200(Landroidx/media3/session/MediaSessionLegacyStub;Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$300(Landroidx/media3/session/MediaSessionLegacyStub;)Landroid/support/v4/media/session/MediaSessionCompat; -HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$400(Landroid/support/v4/media/session/MediaSessionCompat;Ljava/util/List;)V -HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$600(Landroidx/media3/session/MediaSessionLegacyStub;)Landroidx/media/VolumeProviderCompat; -HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$602(Landroidx/media3/session/MediaSessionLegacyStub;Landroidx/media/VolumeProviderCompat;)Landroidx/media/VolumeProviderCompat; +HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$400(Landroidx/media3/session/MediaSessionLegacyStub;)Z +HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$500(Landroid/support/v4/media/session/MediaSessionCompat;Ljava/util/List;)V +HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$700(Landroidx/media3/session/MediaSessionLegacyStub;)Landroidx/media/VolumeProviderCompat; +HSPLandroidx/media3/session/MediaSessionLegacyStub;->access$702(Landroidx/media3/session/MediaSessionLegacyStub;Landroidx/media/VolumeProviderCompat;)Landroidx/media/VolumeProviderCompat; HSPLandroidx/media3/session/MediaSessionLegacyStub;->getControllerLegacyCbForBroadcast()Landroidx/media3/session/MediaSession$ControllerCb; -HSPLandroidx/media3/session/MediaSessionLegacyStub;->getSessionCompat()Landroid/support/v4/media/session/MediaSessionCompat; +HSPLandroidx/media3/session/MediaSessionLegacyStub;->isQueueEnabled()Z +HSPLandroidx/media3/session/MediaSessionLegacyStub;->lambda$updateLegacySessionPlaybackState$23(Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionLegacyStub;->maybeUpdateFlags(Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionLegacyStub;->queryPackageManagerForMediaButtonReceiver(Landroid/content/Context;)Landroid/content/ComponentName; HSPLandroidx/media3/session/MediaSessionLegacyStub;->setQueue(Landroid/support/v4/media/session/MediaSessionCompat;Ljava/util/List;)V HSPLandroidx/media3/session/MediaSessionLegacyStub;->start()V +HSPLandroidx/media3/session/MediaSessionLegacyStub;->updateLegacySessionPlaybackState(Landroidx/media3/session/PlayerWrapper;)V HSPLandroidx/media3/session/MediaSessionService$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaSessionService;Landroidx/media3/session/MediaNotificationManager;Landroidx/media3/session/MediaSession;)V HSPLandroidx/media3/session/MediaSessionService$$ExternalSyntheticLambda0;->run()V HSPLandroidx/media3/session/MediaSessionService$MediaSessionListener;->(Landroidx/media3/session/MediaSessionService;)V HSPLandroidx/media3/session/MediaSessionService$MediaSessionListener;->(Landroidx/media3/session/MediaSessionService;Landroidx/media3/session/MediaSessionService$1;)V -HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaSessionService$MediaSessionServiceStub;Landroidx/media3/session/IMediaController;Landroidx/media/MediaSessionManager$RemoteUserInfo;Landroidx/media3/session/ConnectionRequest;ZII)V +HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaSessionService$MediaSessionServiceStub;Landroidx/media3/session/IMediaController;Landroidx/media/MediaSessionManager$RemoteUserInfo;Landroidx/media3/session/ConnectionRequest;Z)V HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub$$ExternalSyntheticLambda0;->run()V -HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub;->$r8$lambda$0ZW6V5Gj8iqM9_9QaE2jJdLZyk4(Landroidx/media3/session/MediaSessionService$MediaSessionServiceStub;Landroidx/media3/session/IMediaController;Landroidx/media/MediaSessionManager$RemoteUserInfo;Landroidx/media3/session/ConnectionRequest;ZII)V +HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub;->$r8$lambda$MguNtDaJ33H3oNxSukWPqQObUfY(Landroidx/media3/session/MediaSessionService$MediaSessionServiceStub;Landroidx/media3/session/IMediaController;Landroidx/media/MediaSessionManager$RemoteUserInfo;Landroidx/media3/session/ConnectionRequest;Z)V HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub;->(Landroidx/media3/session/MediaSessionService;)V HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub;->connect(Landroidx/media3/session/IMediaController;Landroid/os/Bundle;)V -HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub;->lambda$connect$0(Landroidx/media3/session/IMediaController;Landroidx/media/MediaSessionManager$RemoteUserInfo;Landroidx/media3/session/ConnectionRequest;ZII)V +HSPLandroidx/media3/session/MediaSessionService$MediaSessionServiceStub;->lambda$connect$0(Landroidx/media3/session/IMediaController;Landroidx/media/MediaSessionManager$RemoteUserInfo;Landroidx/media3/session/ConnectionRequest;Z)V HSPLandroidx/media3/session/MediaSessionService;->$r8$lambda$a2XpJPVIWvV21YOEzzqJkEpwBQI(Landroidx/media3/session/MediaSessionService;Landroidx/media3/session/MediaNotificationManager;Landroidx/media3/session/MediaSession;)V HSPLandroidx/media3/session/MediaSessionService;->()V HSPLandroidx/media3/session/MediaSessionService;->addSession(Landroidx/media3/session/MediaSession;)V @@ -4453,20 +4504,18 @@ HSPLandroidx/media3/session/MediaSessionService;->onUpdateNotification(Landroidx HSPLandroidx/media3/session/MediaSessionService;->onUpdateNotificationInternal(Landroidx/media3/session/MediaSession;Z)Z HSPLandroidx/media3/session/MediaSessionService;->setListener(Landroidx/media3/session/MediaSessionService$Listener;)V HSPLandroidx/media3/session/MediaSessionService;->setMediaNotificationProvider(Landroidx/media3/session/MediaNotification$Provider;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda11;->(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/IMediaController;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda11;->run()V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda19;->(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/IMediaController;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda19;->run()V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda25;->(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda25;->run(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Ljava/lang/Object; -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda68;->(Landroidx/media3/session/MediaSessionStub$SessionTask;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda68;->run(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Ljava/lang/Object; -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda72;->(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;IILandroidx/media3/session/MediaSessionStub$SessionTask;Landroidx/media3/session/MediaSessionImpl;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda72;->run()V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda76;->(Landroidx/media3/session/MediaSession$ControllerInfo;I)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda76;->accept(Ljava/lang/Object;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda81;->(Landroidx/media3/session/MediaSessionImpl;Lcom/google/common/util/concurrent/SettableFuture;Landroidx/media3/common/util/Consumer;Lcom/google/common/util/concurrent/ListenableFuture;)V -HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda81;->run()V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda24;->(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda24;->run(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Ljava/lang/Object; +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda56;->(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/IMediaController;)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda56;->run()V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda70;->(Landroidx/media3/session/MediaSessionStub$SessionTask;)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda70;->run(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Ljava/lang/Object; +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda73;->(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;IILandroidx/media3/session/MediaSessionStub$SessionTask;Landroidx/media3/session/MediaSessionImpl;)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda73;->run()V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda77;->(Landroidx/media3/session/MediaSession$ControllerInfo;I)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda77;->accept(Ljava/lang/Object;)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda82;->(Landroidx/media3/session/MediaSessionImpl;Lcom/google/common/util/concurrent/SettableFuture;Landroidx/media3/common/util/Consumer;Lcom/google/common/util/concurrent/ListenableFuture;)V +HSPLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda82;->run()V HSPLandroidx/media3/session/MediaSessionStub$Controller2Cb;->(Landroidx/media3/session/IMediaController;)V HSPLandroidx/media3/session/MediaSessionStub$Controller2Cb;->getCallbackBinder()Landroid/os/IBinder; HSPLandroidx/media3/session/MediaSessionStub$Controller2Cb;->hashCode()I @@ -4474,15 +4523,14 @@ HSPLandroidx/media3/session/MediaSessionStub$Controller2Cb;->onPlayerInfoChanged HSPLandroidx/media3/session/MediaSessionStub$Controller2Cb;->onSessionResult(ILandroidx/media3/session/SessionResult;)V HSPLandroidx/media3/session/MediaSessionStub$Controller2Cb;->setCustomLayout(ILjava/util/List;)V HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$5u7ZOZu1E3qtXLejtiVCfQspblM(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/IMediaController;)V +HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$KndwrP4QTMahDsglk9eR6NWxXtA(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$RagmTrsP9kOCYea3J9OJn28bc5c(Landroidx/media3/session/MediaSession$ControllerInfo;ILcom/google/common/util/concurrent/ListenableFuture;)V HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$Uz2_vcr_OU9Iuz1uNRDrsZj31fE(Landroidx/media3/session/MediaSessionStub$SessionTask;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$VrGmk0e1imzW80ACT-qbuXd3aCA(Landroidx/media3/session/MediaSessionImpl;Lcom/google/common/util/concurrent/SettableFuture;Landroidx/media3/common/util/Consumer;Lcom/google/common/util/concurrent/ListenableFuture;)V -HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$g1w8aI30ygWD3xJmF-4pacDXEWs(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Lcom/google/common/util/concurrent/ListenableFuture; -HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$p6L8lBmsKUAaiq4jQwn1KSWoNSE(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/IMediaController;)V HSPLandroidx/media3/session/MediaSessionStub;->$r8$lambda$r3ns0uu-mjbAk0TkMAI7ay4cBrI(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;IILandroidx/media3/session/MediaSessionStub$SessionTask;Landroidx/media3/session/MediaSessionImpl;)V HSPLandroidx/media3/session/MediaSessionStub;->(Landroidx/media3/session/MediaSessionImpl;)V -HSPLandroidx/media3/session/MediaSessionStub;->connect(Landroidx/media3/session/IMediaController;IILjava/lang/String;IILandroid/os/Bundle;)V HSPLandroidx/media3/session/MediaSessionStub;->connect(Landroidx/media3/session/IMediaController;ILandroid/os/Bundle;)V +HSPLandroidx/media3/session/MediaSessionStub;->connect(Landroidx/media3/session/IMediaController;Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLandroidx/media3/session/MediaSessionStub;->dispatchSessionTaskWithSessionCommand(Landroidx/media3/session/IMediaController;ILandroidx/media3/session/SessionCommand;ILandroidx/media3/session/MediaSessionStub$SessionTask;)V HSPLandroidx/media3/session/MediaSessionStub;->dispatchSessionTaskWithSessionCommand(Landroidx/media3/session/IMediaController;ILandroidx/media3/session/SessionCommand;Landroidx/media3/session/MediaSessionStub$SessionTask;)V HSPLandroidx/media3/session/MediaSessionStub;->generateAndCacheUniqueTrackGroupIds(Landroidx/media3/session/PlayerInfo;)Landroidx/media3/session/PlayerInfo; @@ -4491,22 +4539,14 @@ HSPLandroidx/media3/session/MediaSessionStub;->handleSessionTaskWhenReady(Landro HSPLandroidx/media3/session/MediaSessionStub;->lambda$connect$17(Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/IMediaController;)V HSPLandroidx/media3/session/MediaSessionStub;->lambda$dispatchSessionTaskWithSessionCommand$15(Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;IILandroidx/media3/session/MediaSessionStub$SessionTask;Landroidx/media3/session/MediaSessionImpl;)V HSPLandroidx/media3/session/MediaSessionStub;->lambda$handleSessionTaskWhenReady$16(Landroidx/media3/session/MediaSessionImpl;Lcom/google/common/util/concurrent/SettableFuture;Landroidx/media3/common/util/Consumer;Lcom/google/common/util/concurrent/ListenableFuture;)V -HSPLandroidx/media3/session/MediaSessionStub;->lambda$onCustomCommand$25(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Lcom/google/common/util/concurrent/ListenableFuture; -HSPLandroidx/media3/session/MediaSessionStub;->lambda$release$19(Landroidx/media3/session/IMediaController;)V +HSPLandroidx/media3/session/MediaSessionStub;->lambda$onCustomCommand$24(Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSessionStub;->lambda$sendSessionResultWhenReady$2(Landroidx/media3/session/MediaSession$ControllerInfo;ILcom/google/common/util/concurrent/ListenableFuture;)V HSPLandroidx/media3/session/MediaSessionStub;->lambda$sendSessionResultWhenReady$3(Landroidx/media3/session/MediaSessionStub$SessionTask;Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;I)Lcom/google/common/util/concurrent/ListenableFuture; HSPLandroidx/media3/session/MediaSessionStub;->onControllerResult(Landroidx/media3/session/IMediaController;ILandroid/os/Bundle;)V HSPLandroidx/media3/session/MediaSessionStub;->onCustomCommand(Landroidx/media3/session/IMediaController;ILandroid/os/Bundle;Landroid/os/Bundle;)V -HSPLandroidx/media3/session/MediaSessionStub;->release(Landroidx/media3/session/IMediaController;I)V HSPLandroidx/media3/session/MediaSessionStub;->sendSessionResult(Landroidx/media3/session/MediaSession$ControllerInfo;ILandroidx/media3/session/SessionResult;)V HSPLandroidx/media3/session/MediaSessionStub;->sendSessionResultWhenReady(Landroidx/media3/session/MediaSessionStub$SessionTask;)Landroidx/media3/session/MediaSessionStub$SessionTask; HSPLandroidx/media3/session/MediaUtils;->()V -HSPLandroidx/media3/session/MediaUtils;->convertToAudioAttributesCompat(Landroidx/media3/common/AudioAttributes;)Landroidx/media/AudioAttributesCompat; -HSPLandroidx/media3/session/MediaUtils;->convertToPlaybackStateCompatRepeatMode(I)I -HSPLandroidx/media3/session/MediaUtils;->convertToPlaybackStateCompatShuffleMode(Z)I -HSPLandroidx/media3/session/MediaUtils;->convertToPlaybackStateCompatState(Landroidx/media3/common/PlaybackException;IZ)I -HSPLandroidx/media3/session/MediaUtils;->convertToQueueItemId(I)J -HSPLandroidx/media3/session/MediaUtils;->getLegacyStreamType(Landroidx/media3/common/AudioAttributes;)I HSPLandroidx/media3/session/MediaUtils;->intersect(Landroidx/media3/common/Player$Commands;Landroidx/media3/common/Player$Commands;)Landroidx/media3/common/Player$Commands; HSPLandroidx/media3/session/MediaUtils;->mergePlayerInfo(Landroidx/media3/session/PlayerInfo;Landroidx/media3/session/PlayerInfo$BundlingExclusions;Landroidx/media3/session/PlayerInfo;Landroidx/media3/session/PlayerInfo$BundlingExclusions;Landroidx/media3/common/Player$Commands;)Landroid/util/Pair; HSPLandroidx/media3/session/PlayerInfo$$ExternalSyntheticLambda0;->()V @@ -4514,8 +4554,14 @@ HSPLandroidx/media3/session/PlayerInfo$$ExternalSyntheticLambda0;->fromBundle(La HSPLandroidx/media3/session/PlayerInfo$Builder;->(Landroidx/media3/session/PlayerInfo;)V HSPLandroidx/media3/session/PlayerInfo$Builder;->build()Landroidx/media3/session/PlayerInfo; HSPLandroidx/media3/session/PlayerInfo$Builder;->setCurrentTracks(Landroidx/media3/common/Tracks;)Landroidx/media3/session/PlayerInfo$Builder; +HSPLandroidx/media3/session/PlayerInfo$Builder;->setDeviceMuted(Z)Landroidx/media3/session/PlayerInfo$Builder; +HSPLandroidx/media3/session/PlayerInfo$Builder;->setDeviceVolume(I)Landroidx/media3/session/PlayerInfo$Builder; +HSPLandroidx/media3/session/PlayerInfo$Builder;->setNewPositionInfo(Landroidx/media3/common/Player$PositionInfo;)Landroidx/media3/session/PlayerInfo$Builder; +HSPLandroidx/media3/session/PlayerInfo$Builder;->setOldPositionInfo(Landroidx/media3/common/Player$PositionInfo;)Landroidx/media3/session/PlayerInfo$Builder; HSPLandroidx/media3/session/PlayerInfo$Builder;->setSessionPositionInfo(Landroidx/media3/session/SessionPositionInfo;)Landroidx/media3/session/PlayerInfo$Builder; HSPLandroidx/media3/session/PlayerInfo$Builder;->setTimeline(Landroidx/media3/common/Timeline;)Landroidx/media3/session/PlayerInfo$Builder; +HSPLandroidx/media3/session/PlayerInfo$Builder;->setTimelineChangeReason(I)Landroidx/media3/session/PlayerInfo$Builder; +HSPLandroidx/media3/session/PlayerInfo$Builder;->setVolume(F)Landroidx/media3/session/PlayerInfo$Builder; HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions;->$r8$lambda$-IF8BPS2-UR_KVmEsmOA_l72_k0(Landroid/os/Bundle;)Landroidx/media3/session/PlayerInfo$BundlingExclusions; @@ -4523,15 +4569,19 @@ HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions;->()V HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions;->(ZZ)V HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/session/PlayerInfo$BundlingExclusions; HSPLandroidx/media3/session/PlayerInfo$BundlingExclusions;->toBundle()Landroid/os/Bundle; +HSPLandroidx/media3/session/PlayerInfo$InProcessBinder;->(Landroidx/media3/session/PlayerInfo;)V +HSPLandroidx/media3/session/PlayerInfo$InProcessBinder;->(Landroidx/media3/session/PlayerInfo;Landroidx/media3/session/PlayerInfo$1;)V +HSPLandroidx/media3/session/PlayerInfo$InProcessBinder;->getPlayerInfo()Landroidx/media3/session/PlayerInfo; HSPLandroidx/media3/session/PlayerInfo;->$r8$lambda$UYUSO7JOpKqYSM-ZlCuW_lSgFks(Landroid/os/Bundle;)Landroidx/media3/session/PlayerInfo; HSPLandroidx/media3/session/PlayerInfo;->()V -HSPLandroidx/media3/session/PlayerInfo;->(Landroidx/media3/common/PlaybackException;ILandroidx/media3/session/SessionPositionInfo;Landroidx/media3/common/Player$PositionInfo;Landroidx/media3/common/Player$PositionInfo;ILandroidx/media3/common/PlaybackParameters;IZLandroidx/media3/common/VideoSize;Landroidx/media3/common/Timeline;Landroidx/media3/common/MediaMetadata;FLandroidx/media3/common/AudioAttributes;Landroidx/media3/common/text/CueGroup;Landroidx/media3/common/DeviceInfo;IZZIIIZZLandroidx/media3/common/MediaMetadata;JJJLandroidx/media3/common/Tracks;Landroidx/media3/common/TrackSelectionParameters;)V +HSPLandroidx/media3/session/PlayerInfo;->(Landroidx/media3/common/PlaybackException;ILandroidx/media3/session/SessionPositionInfo;Landroidx/media3/common/Player$PositionInfo;Landroidx/media3/common/Player$PositionInfo;ILandroidx/media3/common/PlaybackParameters;IZLandroidx/media3/common/VideoSize;Landroidx/media3/common/Timeline;ILandroidx/media3/common/MediaMetadata;FLandroidx/media3/common/AudioAttributes;Landroidx/media3/common/text/CueGroup;Landroidx/media3/common/DeviceInfo;IZZIIIZZLandroidx/media3/common/MediaMetadata;JJJLandroidx/media3/common/Tracks;Landroidx/media3/common/TrackSelectionParameters;)V HSPLandroidx/media3/session/PlayerInfo;->copyWithCurrentTracks(Landroidx/media3/common/Tracks;)Landroidx/media3/session/PlayerInfo; -HSPLandroidx/media3/session/PlayerInfo;->copyWithTimelineAndSessionPositionInfo(Landroidx/media3/common/Timeline;Landroidx/media3/session/SessionPositionInfo;)Landroidx/media3/session/PlayerInfo; +HSPLandroidx/media3/session/PlayerInfo;->copyWithTimelineAndSessionPositionInfo(Landroidx/media3/common/Timeline;Landroidx/media3/session/SessionPositionInfo;I)Landroidx/media3/session/PlayerInfo; +HSPLandroidx/media3/session/PlayerInfo;->filterByAvailableCommands(Landroidx/media3/common/Player$Commands;ZZ)Landroidx/media3/session/PlayerInfo; HSPLandroidx/media3/session/PlayerInfo;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/session/PlayerInfo; HSPLandroidx/media3/session/PlayerInfo;->getCurrentMediaItem()Landroidx/media3/common/MediaItem; -HSPLandroidx/media3/session/PlayerInfo;->toBundle(Landroidx/media3/common/Player$Commands;ZZ)Landroid/os/Bundle; -HSPLandroidx/media3/session/PlayerWrapper;->(Landroidx/media3/common/Player;)V +HSPLandroidx/media3/session/PlayerInfo;->toBundleInProcess()Landroid/os/Bundle; +HSPLandroidx/media3/session/PlayerWrapper;->(Landroidx/media3/common/Player;ZLcom/google/common/collect/ImmutableList;Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)V HSPLandroidx/media3/session/PlayerWrapper;->addListener(Landroidx/media3/common/Player$Listener;)V HSPLandroidx/media3/session/PlayerWrapper;->convertCommandToPlaybackStateActions(I)J HSPLandroidx/media3/session/PlayerWrapper;->createPlaybackStateCompat()Landroid/support/v4/media/session/PlaybackStateCompat; @@ -4542,6 +4592,7 @@ HSPLandroidx/media3/session/PlayerWrapper;->createVolumeProviderCompat()Landroid HSPLandroidx/media3/session/PlayerWrapper;->getAudioAttributes()Landroidx/media3/common/AudioAttributes; HSPLandroidx/media3/session/PlayerWrapper;->getAudioAttributesWithCommandCheck()Landroidx/media3/common/AudioAttributes; HSPLandroidx/media3/session/PlayerWrapper;->getAvailableCommands()Landroidx/media3/common/Player$Commands; +HSPLandroidx/media3/session/PlayerWrapper;->getAvailablePlayerCommands()Landroidx/media3/common/Player$Commands; HSPLandroidx/media3/session/PlayerWrapper;->getBufferedPercentage()I HSPLandroidx/media3/session/PlayerWrapper;->getBufferedPosition()J HSPLandroidx/media3/session/PlayerWrapper;->getContentBufferedPosition()J @@ -4589,6 +4640,8 @@ HSPLandroidx/media3/session/PlayerWrapper;->isDeviceMutedWithCommandCheck()Z HSPLandroidx/media3/session/PlayerWrapper;->isLoading()Z HSPLandroidx/media3/session/PlayerWrapper;->isPlaying()Z HSPLandroidx/media3/session/PlayerWrapper;->isPlayingAd()Z +HSPLandroidx/media3/session/PlayerWrapper;->setAvailableCommands(Landroidx/media3/session/SessionCommands;Landroidx/media3/common/Player$Commands;)V +HSPLandroidx/media3/session/PlayerWrapper;->setCustomLayout(Lcom/google/common/collect/ImmutableList;)V HSPLandroidx/media3/session/PlayerWrapper;->verifyApplicationThread()V HSPLandroidx/media3/session/SequencedFutureManager$SequencedFuture;->(ILjava/lang/Object;)V HSPLandroidx/media3/session/SequencedFutureManager$SequencedFuture;->create(ILjava/lang/Object;)Landroidx/media3/session/SequencedFutureManager$SequencedFuture; @@ -4597,38 +4650,33 @@ HSPLandroidx/media3/session/SequencedFutureManager$SequencedFuture;->getSequence HSPLandroidx/media3/session/SequencedFutureManager$SequencedFuture;->set(Ljava/lang/Object;)Z HSPLandroidx/media3/session/SequencedFutureManager;->()V HSPLandroidx/media3/session/SequencedFutureManager;->createSequencedFuture(Ljava/lang/Object;)Landroidx/media3/session/SequencedFutureManager$SequencedFuture; -HSPLandroidx/media3/session/SequencedFutureManager;->lazyRelease(JLjava/lang/Runnable;)V HSPLandroidx/media3/session/SequencedFutureManager;->obtainNextSequenceNumber()I -HSPLandroidx/media3/session/SequencedFutureManager;->release()V HSPLandroidx/media3/session/SequencedFutureManager;->setFutureResult(ILjava/lang/Object;)V HSPLandroidx/media3/session/SessionCommand$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/session/SessionCommand$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/session/SessionCommand;->$r8$lambda$-vVtmRPGIu-NOoGvOcmGBqPpE2A(Landroid/os/Bundle;)Landroidx/media3/session/SessionCommand; HSPLandroidx/media3/session/SessionCommand;->()V +HSPLandroidx/media3/session/SessionCommand;->(I)V HSPLandroidx/media3/session/SessionCommand;->(Ljava/lang/String;Landroid/os/Bundle;)V HSPLandroidx/media3/session/SessionCommand;->equals(Ljava/lang/Object;)Z HSPLandroidx/media3/session/SessionCommand;->hashCode()I HSPLandroidx/media3/session/SessionCommand;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/session/SessionCommand; HSPLandroidx/media3/session/SessionCommand;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/session/SessionCommands$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/session/SessionCommands$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/session/SessionCommands$Builder;->()V HSPLandroidx/media3/session/SessionCommands$Builder;->add(Landroidx/media3/session/SessionCommand;)Landroidx/media3/session/SessionCommands$Builder; +HSPLandroidx/media3/session/SessionCommands$Builder;->addAllLibraryCommands()Landroidx/media3/session/SessionCommands$Builder; +HSPLandroidx/media3/session/SessionCommands$Builder;->addAllSessionCommands()Landroidx/media3/session/SessionCommands$Builder; +HSPLandroidx/media3/session/SessionCommands$Builder;->addCommandCodes(Ljava/util/List;)V HSPLandroidx/media3/session/SessionCommands$Builder;->build()Landroidx/media3/session/SessionCommands; -HSPLandroidx/media3/session/SessionCommands;->$r8$lambda$QT7G-P2DLDMA1OfVE7mMOAsNnLM(Landroid/os/Bundle;)Landroidx/media3/session/SessionCommands; HSPLandroidx/media3/session/SessionCommands;->()V HSPLandroidx/media3/session/SessionCommands;->(Ljava/util/Collection;)V HSPLandroidx/media3/session/SessionCommands;->(Ljava/util/Collection;Landroidx/media3/session/SessionCommands$1;)V HSPLandroidx/media3/session/SessionCommands;->contains(Landroidx/media3/session/SessionCommand;)Z -HSPLandroidx/media3/session/SessionCommands;->lambda$static$0(Landroid/os/Bundle;)Landroidx/media3/session/SessionCommands; -HSPLandroidx/media3/session/SessionCommands;->toBundle()Landroid/os/Bundle; HSPLandroidx/media3/session/SessionPositionInfo$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/session/SessionPositionInfo$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; -HSPLandroidx/media3/session/SessionPositionInfo;->$r8$lambda$Y5dKAucDohc9tqi4RcAUXuvwkzU(Landroid/os/Bundle;)Landroidx/media3/session/SessionPositionInfo; HSPLandroidx/media3/session/SessionPositionInfo;->()V HSPLandroidx/media3/session/SessionPositionInfo;->(Landroidx/media3/common/Player$PositionInfo;ZJJJIJJJJ)V -HSPLandroidx/media3/session/SessionPositionInfo;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/session/SessionPositionInfo; -HSPLandroidx/media3/session/SessionPositionInfo;->toBundle(ZZ)Landroid/os/Bundle; +HSPLandroidx/media3/session/SessionPositionInfo;->filterByAvailableCommands(ZZ)Landroidx/media3/session/SessionPositionInfo; HSPLandroidx/media3/session/SessionResult$$ExternalSyntheticLambda0;->()V HSPLandroidx/media3/session/SessionResult$$ExternalSyntheticLambda0;->fromBundle(Landroid/os/Bundle;)Landroidx/media3/common/Bundleable; HSPLandroidx/media3/session/SessionResult;->$r8$lambda$x2DqL-v4-Wv0EFW4SM0qwLgSBU4(Landroid/os/Bundle;)Landroidx/media3/session/SessionResult; @@ -4663,13 +4711,6 @@ HSPLandroidx/media3/session/SessionTokenImplBase;->getServiceName()Ljava/lang/St HSPLandroidx/media3/session/SessionTokenImplBase;->getType()I HSPLandroidx/media3/session/SessionTokenImplBase;->getUid()I HSPLandroidx/media3/session/SessionTokenImplBase;->isLegacySession()Z -HSPLandroidx/media3/session/SimpleBitmapLoader$$ExternalSyntheticLambda0;->()V -HSPLandroidx/media3/session/SimpleBitmapLoader$$ExternalSyntheticLambda0;->get()Ljava/lang/Object; -HSPLandroidx/media3/session/SimpleBitmapLoader;->$r8$lambda$7mye94hLFKmF4Jrlc7Qo6EFZmFU()Lcom/google/common/util/concurrent/ListeningExecutorService; -HSPLandroidx/media3/session/SimpleBitmapLoader;->()V -HSPLandroidx/media3/session/SimpleBitmapLoader;->()V -HSPLandroidx/media3/session/SimpleBitmapLoader;->(Ljava/util/concurrent/ExecutorService;)V -HSPLandroidx/media3/session/SimpleBitmapLoader;->lambda$static$0()Lcom/google/common/util/concurrent/ListeningExecutorService; HSPLandroidx/media3/ui/AspectRatioFrameLayout$AspectRatioUpdateDispatcher;->(Landroidx/media3/ui/AspectRatioFrameLayout;)V HSPLandroidx/media3/ui/AspectRatioFrameLayout$AspectRatioUpdateDispatcher;->(Landroidx/media3/ui/AspectRatioFrameLayout;Landroidx/media3/ui/AspectRatioFrameLayout$1;)V HSPLandroidx/media3/ui/AspectRatioFrameLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;)V @@ -4704,7 +4745,6 @@ HSPLandroidx/navigation/NavArgument$Builder;->build()Landroidx/navigation/NavArg HSPLandroidx/navigation/NavArgument$Builder;->setIsNullable(Z)Landroidx/navigation/NavArgument$Builder; HSPLandroidx/navigation/NavArgument$Builder;->setType(Landroidx/navigation/NavType;)Landroidx/navigation/NavArgument$Builder; HSPLandroidx/navigation/NavArgument;->(Landroidx/navigation/NavType;ZLjava/lang/Object;Z)V -HSPLandroidx/navigation/NavArgument;->equals(Ljava/lang/Object;)Z HSPLandroidx/navigation/NavArgument;->hashCode()I HSPLandroidx/navigation/NavBackStackEntry$Companion;->()V HSPLandroidx/navigation/NavBackStackEntry$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -4730,14 +4770,8 @@ HSPLandroidx/navigation/NavBackStackEntry;->getSavedStateRegistry()Landroidx/sav HSPLandroidx/navigation/NavBackStackEntry;->getViewModelStore()Landroidx/lifecycle/ViewModelStore; HSPLandroidx/navigation/NavBackStackEntry;->handleLifecycleEvent(Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/navigation/NavBackStackEntry;->hashCode()I -HSPLandroidx/navigation/NavBackStackEntry;->saveState(Landroid/os/Bundle;)V HSPLandroidx/navigation/NavBackStackEntry;->setMaxLifecycle(Landroidx/lifecycle/Lifecycle$State;)V HSPLandroidx/navigation/NavBackStackEntry;->updateState()V -HSPLandroidx/navigation/NavBackStackEntryState$Companion$CREATOR$1;->()V -HSPLandroidx/navigation/NavBackStackEntryState$Companion;->()V -HSPLandroidx/navigation/NavBackStackEntryState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLandroidx/navigation/NavBackStackEntryState;->()V -HSPLandroidx/navigation/NavBackStackEntryState;->(Landroidx/navigation/NavBackStackEntry;)V HSPLandroidx/navigation/NavController$$ExternalSyntheticLambda0;->(Landroidx/navigation/NavController;)V HSPLandroidx/navigation/NavController$$ExternalSyntheticLambda0;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/navigation/NavController$Companion;->()V @@ -4752,9 +4786,9 @@ HSPLandroidx/navigation/NavController$activity$1;->()V HSPLandroidx/navigation/NavController$navInflater$2;->(Landroidx/navigation/NavController;)V HSPLandroidx/navigation/NavController$navInflater$2;->invoke()Landroidx/navigation/NavInflater; HSPLandroidx/navigation/NavController$navInflater$2;->invoke()Ljava/lang/Object; -HSPLandroidx/navigation/NavController$navigate$4;->(Lkotlin/jvm/internal/Ref$BooleanRef;Landroidx/navigation/NavController;Landroidx/navigation/NavDestination;Landroid/os/Bundle;)V -HSPLandroidx/navigation/NavController$navigate$4;->invoke(Landroidx/navigation/NavBackStackEntry;)V -HSPLandroidx/navigation/NavController$navigate$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLandroidx/navigation/NavController$navigate$5;->(Lkotlin/jvm/internal/Ref$BooleanRef;Landroidx/navigation/NavController;Landroidx/navigation/NavDestination;Landroid/os/Bundle;)V +HSPLandroidx/navigation/NavController$navigate$5;->invoke(Landroidx/navigation/NavBackStackEntry;)V +HSPLandroidx/navigation/NavController$navigate$5;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/navigation/NavController$onBackPressedCallback$1;->(Landroidx/navigation/NavController;)V HSPLandroidx/navigation/NavController;->$r8$lambda$bZL_fnLbLD5ZZthGK_6aY8AQ2pA(Landroidx/navigation/NavController;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/navigation/NavController;->()V @@ -4788,7 +4822,6 @@ HSPLandroidx/navigation/NavController;->navigateInternal(Landroidx/navigation/Na HSPLandroidx/navigation/NavController;->onGraphCreated(Landroid/os/Bundle;)V HSPLandroidx/navigation/NavController;->populateVisibleEntries$navigation_runtime_release()Ljava/util/List; HSPLandroidx/navigation/NavController;->removeOnDestinationChangedListener(Landroidx/navigation/NavController$OnDestinationChangedListener;)V -HSPLandroidx/navigation/NavController;->saveState()Landroid/os/Bundle; HSPLandroidx/navigation/NavController;->setGraph(I)V HSPLandroidx/navigation/NavController;->setGraph(Landroidx/navigation/NavGraph;Landroid/os/Bundle;)V HSPLandroidx/navigation/NavController;->setLifecycleOwner(Landroidx/lifecycle/LifecycleOwner;)V @@ -4815,8 +4848,6 @@ HSPLandroidx/navigation/NavDestination;->(Landroidx/navigation/Navigator;) HSPLandroidx/navigation/NavDestination;->(Ljava/lang/String;)V HSPLandroidx/navigation/NavDestination;->addArgument(Ljava/lang/String;Landroidx/navigation/NavArgument;)V HSPLandroidx/navigation/NavDestination;->addInDefaultArgs(Landroid/os/Bundle;)Landroid/os/Bundle; -HSPLandroidx/navigation/NavDestination;->equals(Ljava/lang/Object;)Z -HSPLandroidx/navigation/NavDestination;->getArguments()Ljava/util/Map; HSPLandroidx/navigation/NavDestination;->getId()I HSPLandroidx/navigation/NavDestination;->getNavigatorName()Ljava/lang/String; HSPLandroidx/navigation/NavDestination;->getParent()Landroidx/navigation/NavGraph; @@ -4921,7 +4952,6 @@ HSPLandroidx/navigation/Navigator;->()V HSPLandroidx/navigation/Navigator;->getState()Landroidx/navigation/NavigatorState; HSPLandroidx/navigation/Navigator;->isAttached()Z HSPLandroidx/navigation/Navigator;->onAttach(Landroidx/navigation/NavigatorState;)V -HSPLandroidx/navigation/Navigator;->onSaveState()Landroid/os/Bundle; HSPLandroidx/navigation/NavigatorProvider$Companion;->()V HSPLandroidx/navigation/NavigatorProvider$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLandroidx/navigation/NavigatorProvider$Companion;->getNameForNavigator$navigation_common_release(Ljava/lang/Class;)Ljava/lang/String; @@ -4949,7 +4979,6 @@ HSPLandroidx/navigation/fragment/DialogFragmentNavigator$$ExternalSyntheticLambd HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Companion;->()V HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Destination;->(Landroidx/navigation/Navigator;)V -HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Destination;->equals(Ljava/lang/Object;)Z HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Destination;->hashCode()I HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Destination;->onInflate(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/navigation/fragment/DialogFragmentNavigator$Destination;->setClassName(Ljava/lang/String;)Landroidx/navigation/fragment/DialogFragmentNavigator$Destination; @@ -4975,7 +5004,7 @@ HSPLandroidx/navigation/fragment/FragmentNavigator$Destination;->getClassName()L HSPLandroidx/navigation/fragment/FragmentNavigator$Destination;->hashCode()I HSPLandroidx/navigation/fragment/FragmentNavigator$Destination;->onInflate(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLandroidx/navigation/fragment/FragmentNavigator$Destination;->setClassName(Ljava/lang/String;)Landroidx/navigation/fragment/FragmentNavigator$Destination; -HSPLandroidx/navigation/fragment/FragmentNavigator$attachClearViewModel$1;->(Landroidx/navigation/NavBackStackEntry;Landroidx/navigation/NavigatorState;)V +HSPLandroidx/navigation/fragment/FragmentNavigator$attachClearViewModel$1;->(Landroidx/navigation/NavBackStackEntry;Landroidx/navigation/NavigatorState;Landroidx/fragment/app/Fragment;)V HSPLandroidx/navigation/fragment/FragmentNavigator$attachClearViewModel$viewModel$1$1;->()V HSPLandroidx/navigation/fragment/FragmentNavigator$attachClearViewModel$viewModel$1$1;->()V HSPLandroidx/navigation/fragment/FragmentNavigator$attachClearViewModel$viewModel$1$1;->invoke(Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/navigation/fragment/FragmentNavigator$ClearEntryStateViewModel; @@ -4993,8 +5022,8 @@ HSPLandroidx/navigation/fragment/FragmentNavigator$fragmentViewObserver$1;->invo HSPLandroidx/navigation/fragment/FragmentNavigator$onAttach$2;->(Landroidx/navigation/NavigatorState;Landroidx/navigation/fragment/FragmentNavigator;)V HSPLandroidx/navigation/fragment/FragmentNavigator$sam$androidx_lifecycle_Observer$0;->(Lkotlin/jvm/functions/Function1;)V HSPLandroidx/navigation/fragment/FragmentNavigator$sam$androidx_lifecycle_Observer$0;->onChanged(Ljava/lang/Object;)V -HSPLandroidx/navigation/fragment/FragmentNavigator;->$r8$lambda$ZTQok9KDpXTagzeByclo4DN6v_M(Landroidx/navigation/NavigatorState;Landroidx/navigation/fragment/FragmentNavigator;Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V -HSPLandroidx/navigation/fragment/FragmentNavigator;->$r8$lambda$l6g2TQ9_Y2DuL3r-DYP3Exi4RF8(Landroidx/navigation/fragment/FragmentNavigator;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V +HSPLandroidx/navigation/fragment/FragmentNavigator;->$r8$lambda$57AG1ONdZyfSFri9zMhNMaEoS04(Landroidx/navigation/NavigatorState;Landroidx/navigation/fragment/FragmentNavigator;Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V +HSPLandroidx/navigation/fragment/FragmentNavigator;->$r8$lambda$UGHviOGo1Bg3DZy7AltD2gCe0Ns(Landroidx/navigation/fragment/FragmentNavigator;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/navigation/fragment/FragmentNavigator;->()V HSPLandroidx/navigation/fragment/FragmentNavigator;->(Landroid/content/Context;Landroidx/fragment/app/FragmentManager;I)V HSPLandroidx/navigation/fragment/FragmentNavigator;->access$getFragmentViewObserver$p(Landroidx/navigation/fragment/FragmentNavigator;)Lkotlin/jvm/functions/Function1; @@ -5004,24 +5033,17 @@ HSPLandroidx/navigation/fragment/FragmentNavigator;->attachObservers(Landroidx/n HSPLandroidx/navigation/fragment/FragmentNavigator;->createDestination()Landroidx/navigation/NavDestination; HSPLandroidx/navigation/fragment/FragmentNavigator;->createDestination()Landroidx/navigation/fragment/FragmentNavigator$Destination; HSPLandroidx/navigation/fragment/FragmentNavigator;->createFragmentTransaction(Landroidx/navigation/NavBackStackEntry;Landroidx/navigation/NavOptions;)Landroidx/fragment/app/FragmentTransaction; -HSPLandroidx/navigation/fragment/FragmentNavigator;->fragmentObserver$lambda$2(Landroidx/navigation/fragment/FragmentNavigator;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V -HSPLandroidx/navigation/fragment/FragmentNavigator;->getEntriesToPop$navigation_fragment_release()Ljava/util/Set; +HSPLandroidx/navigation/fragment/FragmentNavigator;->fragmentObserver$lambda$1(Landroidx/navigation/fragment/FragmentNavigator;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V +HSPLandroidx/navigation/fragment/FragmentNavigator;->getPendingOps$navigation_fragment_release()Ljava/util/List; HSPLandroidx/navigation/fragment/FragmentNavigator;->navigate(Landroidx/navigation/NavBackStackEntry;Landroidx/navigation/NavOptions;Landroidx/navigation/Navigator$Extras;)V HSPLandroidx/navigation/fragment/FragmentNavigator;->navigate(Ljava/util/List;Landroidx/navigation/NavOptions;Landroidx/navigation/Navigator$Extras;)V -HSPLandroidx/navigation/fragment/FragmentNavigator;->onAttach$lambda$4(Landroidx/navigation/NavigatorState;Landroidx/navigation/fragment/FragmentNavigator;Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V +HSPLandroidx/navigation/fragment/FragmentNavigator;->onAttach$lambda$3(Landroidx/navigation/NavigatorState;Landroidx/navigation/fragment/FragmentNavigator;Landroidx/fragment/app/FragmentManager;Landroidx/fragment/app/Fragment;)V HSPLandroidx/navigation/fragment/FragmentNavigator;->onAttach(Landroidx/navigation/NavigatorState;)V -HSPLandroidx/navigation/fragment/FragmentNavigator;->onSaveState()Landroid/os/Bundle; HSPLandroidx/navigation/fragment/NavHostFragment$Companion;->()V HSPLandroidx/navigation/fragment/NavHostFragment$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2$$ExternalSyntheticLambda0;->(Landroidx/navigation/NavHostController;)V -HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2$$ExternalSyntheticLambda0;->saveState()Landroid/os/Bundle; HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2$$ExternalSyntheticLambda1;->(Landroidx/navigation/fragment/NavHostFragment;)V -HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2$$ExternalSyntheticLambda1;->saveState()Landroid/os/Bundle; -HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->$r8$lambda$S8rYz5PdxQ_qmpQw5Wg04g8YyYI(Landroidx/navigation/fragment/NavHostFragment;)Landroid/os/Bundle; -HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->$r8$lambda$yvpdz-7lzmuHOSkQDGqC7TUxHHI(Landroidx/navigation/NavHostController;)Landroid/os/Bundle; HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->(Landroidx/navigation/fragment/NavHostFragment;)V -HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->invoke$lambda$5$lambda$2(Landroidx/navigation/NavHostController;)Landroid/os/Bundle; -HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->invoke$lambda$5$lambda$4(Landroidx/navigation/fragment/NavHostFragment;)Landroid/os/Bundle; HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->invoke()Landroidx/navigation/NavHostController; HSPLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->invoke()Ljava/lang/Object; HSPLandroidx/navigation/fragment/NavHostFragment;->()V @@ -5036,7 +5058,6 @@ HSPLandroidx/navigation/fragment/NavHostFragment;->onCreateNavController(Landroi HSPLandroidx/navigation/fragment/NavHostFragment;->onCreateNavHostController(Landroidx/navigation/NavHostController;)V HSPLandroidx/navigation/fragment/NavHostFragment;->onCreateView(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View; HSPLandroidx/navigation/fragment/NavHostFragment;->onInflate(Landroid/content/Context;Landroid/util/AttributeSet;Landroid/os/Bundle;)V -HSPLandroidx/navigation/fragment/NavHostFragment;->onSaveInstanceState(Landroid/os/Bundle;)V HSPLandroidx/navigation/fragment/NavHostFragment;->onViewCreated(Landroid/view/View;Landroid/os/Bundle;)V HSPLandroidx/navigation/fragment/R$styleable;->()V HSPLandroidx/preference/PreferenceManager;->getDefaultSharedPreferences(Landroid/content/Context;)Landroid/content/SharedPreferences; @@ -5135,14 +5156,9 @@ HSPLandroidx/recyclerview/widget/ConcatAdapter;->(Landroidx/recyclerview/w HSPLandroidx/recyclerview/widget/ConcatAdapter;->(Landroidx/recyclerview/widget/ConcatAdapter$Config;[Landroidx/recyclerview/widget/RecyclerView$Adapter;)V HSPLandroidx/recyclerview/widget/ConcatAdapter;->([Landroidx/recyclerview/widget/RecyclerView$Adapter;)V HSPLandroidx/recyclerview/widget/ConcatAdapter;->addAdapter(Landroidx/recyclerview/widget/RecyclerView$Adapter;)Z -HSPLandroidx/recyclerview/widget/ConcatAdapter;->findRelativeAdapterPositionIn(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)I HSPLandroidx/recyclerview/widget/ConcatAdapter;->getAdapters()Ljava/util/List; HSPLandroidx/recyclerview/widget/ConcatAdapter;->getItemCount()I -HSPLandroidx/recyclerview/widget/ConcatAdapter;->getItemViewType(I)I HSPLandroidx/recyclerview/widget/ConcatAdapter;->onAttachedToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLandroidx/recyclerview/widget/ConcatAdapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V -HSPLandroidx/recyclerview/widget/ConcatAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; -HSPLandroidx/recyclerview/widget/ConcatAdapter;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V HSPLandroidx/recyclerview/widget/ConcatAdapterController$WrapperAndLocalPosition;->()V HSPLandroidx/recyclerview/widget/ConcatAdapterController;->(Landroidx/recyclerview/widget/ConcatAdapter;Landroidx/recyclerview/widget/ConcatAdapter$Config;)V HSPLandroidx/recyclerview/widget/ConcatAdapterController;->addAdapter(ILandroidx/recyclerview/widget/RecyclerView$Adapter;)Z @@ -5150,23 +5166,14 @@ HSPLandroidx/recyclerview/widget/ConcatAdapterController;->addAdapter(Landroidx/ HSPLandroidx/recyclerview/widget/ConcatAdapterController;->calculateAndUpdateStateRestorationPolicy()V HSPLandroidx/recyclerview/widget/ConcatAdapterController;->computeStateRestorationPolicy()Landroidx/recyclerview/widget/RecyclerView$Adapter$StateRestorationPolicy; HSPLandroidx/recyclerview/widget/ConcatAdapterController;->countItemsBefore(Landroidx/recyclerview/widget/NestedAdapterWrapper;)I -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->findWrapperAndLocalPosition(I)Landroidx/recyclerview/widget/ConcatAdapterController$WrapperAndLocalPosition; HSPLandroidx/recyclerview/widget/ConcatAdapterController;->findWrapperFor(Landroidx/recyclerview/widget/RecyclerView$Adapter;)Landroidx/recyclerview/widget/NestedAdapterWrapper; HSPLandroidx/recyclerview/widget/ConcatAdapterController;->getCopyOfAdapters()Ljava/util/List; -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->getItemViewType(I)I -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->getLocalAdapterPosition(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)I HSPLandroidx/recyclerview/widget/ConcatAdapterController;->getTotalCount()I -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->getWrapper(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Landroidx/recyclerview/widget/NestedAdapterWrapper; HSPLandroidx/recyclerview/widget/ConcatAdapterController;->hasStableIds()Z HSPLandroidx/recyclerview/widget/ConcatAdapterController;->indexOfWrapper(Landroidx/recyclerview/widget/RecyclerView$Adapter;)I HSPLandroidx/recyclerview/widget/ConcatAdapterController;->isAttachedTo(Landroidx/recyclerview/widget/RecyclerView;)Z HSPLandroidx/recyclerview/widget/ConcatAdapterController;->onAttachedToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; HSPLandroidx/recyclerview/widget/ConcatAdapterController;->onItemRangeChanged(Landroidx/recyclerview/widget/NestedAdapterWrapper;IILjava/lang/Object;)V -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->onItemRangeInserted(Landroidx/recyclerview/widget/NestedAdapterWrapper;II)V -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V -HSPLandroidx/recyclerview/widget/ConcatAdapterController;->releaseWrapperAndLocalPosition(Landroidx/recyclerview/widget/ConcatAdapterController$WrapperAndLocalPosition;)V HSPLandroidx/recyclerview/widget/ConversationLayoutManager$Companion;->()V HSPLandroidx/recyclerview/widget/ConversationLayoutManager$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLandroidx/recyclerview/widget/ConversationLayoutManager;->()V @@ -5214,6 +5221,7 @@ HSPLandroidx/recyclerview/widget/GapWorker$LayoutPrefetchRegistryImpl;->clearPre HSPLandroidx/recyclerview/widget/GapWorker;->()V HSPLandroidx/recyclerview/widget/GapWorker;->()V HSPLandroidx/recyclerview/widget/GapWorker;->add(Landroidx/recyclerview/widget/RecyclerView;)V +HSPLandroidx/recyclerview/widget/GapWorker;->remove(Landroidx/recyclerview/widget/RecyclerView;)V HSPLandroidx/recyclerview/widget/ItemTouchHelper$1;->(Landroidx/recyclerview/widget/ItemTouchHelper;)V HSPLandroidx/recyclerview/widget/ItemTouchHelper$2;->(Landroidx/recyclerview/widget/ItemTouchHelper;)V HSPLandroidx/recyclerview/widget/ItemTouchHelper$2;->onInterceptTouchEvent(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/MotionEvent;)Z @@ -5246,9 +5254,6 @@ HSPLandroidx/recyclerview/widget/LinearLayoutManager$LayoutChunkResult;->resetIn HSPLandroidx/recyclerview/widget/LinearLayoutManager$LayoutState;->()V HSPLandroidx/recyclerview/widget/LinearLayoutManager$LayoutState;->hasMore(Landroidx/recyclerview/widget/RecyclerView$State;)Z HSPLandroidx/recyclerview/widget/LinearLayoutManager$LayoutState;->next(Landroidx/recyclerview/widget/RecyclerView$Recycler;)Landroid/view/View; -HSPLandroidx/recyclerview/widget/LinearLayoutManager$SavedState$1;->()V -HSPLandroidx/recyclerview/widget/LinearLayoutManager$SavedState;->()V -HSPLandroidx/recyclerview/widget/LinearLayoutManager$SavedState;->()V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->(Landroid/content/Context;)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->(Landroid/content/Context;IZ)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->(Landroid/content/Context;Landroid/util/AttributeSet;II)V @@ -5274,7 +5279,6 @@ HSPLandroidx/recyclerview/widget/LinearLayoutManager;->findOneVisibleChild(IIZZ) HSPLandroidx/recyclerview/widget/LinearLayoutManager;->findReferenceChild(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;ZZ)Landroid/view/View; HSPLandroidx/recyclerview/widget/LinearLayoutManager;->fixLayoutEndGap(ILandroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;Z)I HSPLandroidx/recyclerview/widget/LinearLayoutManager;->fixLayoutStartGap(ILandroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;Z)I -HSPLandroidx/recyclerview/widget/LinearLayoutManager;->getChildClosestToStart()Landroid/view/View; HSPLandroidx/recyclerview/widget/LinearLayoutManager;->getExtraLayoutSpace(Landroidx/recyclerview/widget/RecyclerView$State;)I HSPLandroidx/recyclerview/widget/LinearLayoutManager;->getReverseLayout()Z HSPLandroidx/recyclerview/widget/LinearLayoutManager;->isAutoMeasureEnabled()Z @@ -5282,10 +5286,10 @@ HSPLandroidx/recyclerview/widget/LinearLayoutManager;->isLayoutRTL()Z HSPLandroidx/recyclerview/widget/LinearLayoutManager;->layoutChunk(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;Landroidx/recyclerview/widget/LinearLayoutManager$LayoutState;Landroidx/recyclerview/widget/LinearLayoutManager$LayoutChunkResult;)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->layoutForPredictiveAnimations(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;II)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->onAnchorReady(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;Landroidx/recyclerview/widget/LinearLayoutManager$AnchorInfo;I)V +HSPLandroidx/recyclerview/widget/LinearLayoutManager;->onDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$Recycler;)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->onInitializeAccessibilityEvent(Landroid/view/accessibility/AccessibilityEvent;)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->onLayoutChildren(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->onLayoutCompleted(Landroidx/recyclerview/widget/RecyclerView$State;)V -HSPLandroidx/recyclerview/widget/LinearLayoutManager;->onSaveInstanceState()Landroid/os/Parcelable; HSPLandroidx/recyclerview/widget/LinearLayoutManager;->resolveIsInfinite()Z HSPLandroidx/recyclerview/widget/LinearLayoutManager;->resolveShouldLayoutReverse()V HSPLandroidx/recyclerview/widget/LinearLayoutManager;->scrollToPositionWithOffset(II)V @@ -5304,26 +5308,18 @@ HSPLandroidx/recyclerview/widget/LinearLayoutManager;->updateLayoutStateToFillSt HSPLandroidx/recyclerview/widget/ListAdapter$1;->(Landroidx/recyclerview/widget/ListAdapter;)V HSPLandroidx/recyclerview/widget/ListAdapter$1;->onCurrentListChanged(Ljava/util/List;Ljava/util/List;)V HSPLandroidx/recyclerview/widget/ListAdapter;->(Landroidx/recyclerview/widget/DiffUtil$ItemCallback;)V -HSPLandroidx/recyclerview/widget/ListAdapter;->getCurrentList()Ljava/util/List; HSPLandroidx/recyclerview/widget/ListAdapter;->getItem(I)Ljava/lang/Object; HSPLandroidx/recyclerview/widget/ListAdapter;->getItemCount()I HSPLandroidx/recyclerview/widget/ListAdapter;->onCurrentListChanged(Ljava/util/List;Ljava/util/List;)V HSPLandroidx/recyclerview/widget/ListAdapter;->submitList(Ljava/util/List;Ljava/lang/Runnable;)V HSPLandroidx/recyclerview/widget/NestedAdapterWrapper$1;->(Landroidx/recyclerview/widget/NestedAdapterWrapper;)V HSPLandroidx/recyclerview/widget/NestedAdapterWrapper$1;->onItemRangeChanged(IILjava/lang/Object;)V -HSPLandroidx/recyclerview/widget/NestedAdapterWrapper$1;->onItemRangeInserted(II)V HSPLandroidx/recyclerview/widget/NestedAdapterWrapper;->(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/NestedAdapterWrapper$Callback;Landroidx/recyclerview/widget/ViewTypeStorage;Landroidx/recyclerview/widget/StableIdStorage$StableIdLookup;)V HSPLandroidx/recyclerview/widget/NestedAdapterWrapper;->getCachedItemCount()I -HSPLandroidx/recyclerview/widget/NestedAdapterWrapper;->getItemViewType(I)I -HSPLandroidx/recyclerview/widget/NestedAdapterWrapper;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V -HSPLandroidx/recyclerview/widget/NestedAdapterWrapper;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; HSPLandroidx/recyclerview/widget/OpReorderer;->(Landroidx/recyclerview/widget/OpReorderer$Callback;)V HSPLandroidx/recyclerview/widget/OpReorderer;->getLastMoveOutOfOrder(Ljava/util/List;)I HSPLandroidx/recyclerview/widget/OpReorderer;->reorderOps(Ljava/util/List;)V HSPLandroidx/recyclerview/widget/OrientationHelper$1;->(Landroidx/recyclerview/widget/RecyclerView$LayoutManager;)V -HSPLandroidx/recyclerview/widget/OrientationHelper$1;->getDecoratedMeasurement(Landroid/view/View;)I -HSPLandroidx/recyclerview/widget/OrientationHelper$1;->getDecoratedMeasurementInOther(Landroid/view/View;)I -HSPLandroidx/recyclerview/widget/OrientationHelper$1;->getDecoratedStart(Landroid/view/View;)I HSPLandroidx/recyclerview/widget/OrientationHelper$1;->getEndAfterPadding()I HSPLandroidx/recyclerview/widget/OrientationHelper$1;->getEndPadding()I HSPLandroidx/recyclerview/widget/OrientationHelper$1;->getMode()I @@ -5344,7 +5340,6 @@ HSPLandroidx/recyclerview/widget/OrientationHelper;->(Landroidx/recyclervi HSPLandroidx/recyclerview/widget/OrientationHelper;->createHorizontalHelper(Landroidx/recyclerview/widget/RecyclerView$LayoutManager;)Landroidx/recyclerview/widget/OrientationHelper; HSPLandroidx/recyclerview/widget/OrientationHelper;->createOrientationHelper(Landroidx/recyclerview/widget/RecyclerView$LayoutManager;I)Landroidx/recyclerview/widget/OrientationHelper; HSPLandroidx/recyclerview/widget/OrientationHelper;->createVerticalHelper(Landroidx/recyclerview/widget/RecyclerView$LayoutManager;)Landroidx/recyclerview/widget/OrientationHelper; -HSPLandroidx/recyclerview/widget/OrientationHelper;->getTotalSpaceChange()I HSPLandroidx/recyclerview/widget/OrientationHelper;->onLayoutComplete()V HSPLandroidx/recyclerview/widget/RecyclerView$1;->(Landroidx/recyclerview/widget/RecyclerView;)V HSPLandroidx/recyclerview/widget/RecyclerView$2;->(Landroidx/recyclerview/widget/RecyclerView;)V @@ -5373,18 +5368,15 @@ HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->findRelativeAdapterPosit HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->getStateRestorationPolicy()Landroidx/recyclerview/widget/RecyclerView$Adapter$StateRestorationPolicy; HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->hasObservers()Z HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->hasStableIds()Z -HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->notifyDataSetChanged()V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->notifyItemRangeChanged(IILjava/lang/Object;)V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->notifyItemRangeInserted(II)V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->onAttachedToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;ILjava/util/List;)V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->registerAdapterDataObserver(Landroidx/recyclerview/widget/RecyclerView$AdapterDataObserver;)V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->setHasStableIds(Z)V HSPLandroidx/recyclerview/widget/RecyclerView$Adapter;->unregisterAdapterDataObserver(Landroidx/recyclerview/widget/RecyclerView$AdapterDataObserver;)V HSPLandroidx/recyclerview/widget/RecyclerView$AdapterDataObservable;->()V HSPLandroidx/recyclerview/widget/RecyclerView$AdapterDataObservable;->hasObservers()Z -HSPLandroidx/recyclerview/widget/RecyclerView$AdapterDataObservable;->notifyChanged()V HSPLandroidx/recyclerview/widget/RecyclerView$AdapterDataObservable;->notifyItemRangeChanged(IILjava/lang/Object;)V HSPLandroidx/recyclerview/widget/RecyclerView$AdapterDataObservable;->notifyItemRangeInserted(II)V HSPLandroidx/recyclerview/widget/RecyclerView$AdapterDataObserver;->()V @@ -5432,8 +5424,8 @@ HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->detachAndScrapAtta HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->detachViewAt(I)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->detachViewInternal(ILandroid/view/View;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->dispatchAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView;)V +HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->dispatchDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$Recycler;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->generateLayoutParams(Landroid/content/Context;Landroid/util/AttributeSet;)Landroidx/recyclerview/widget/RecyclerView$LayoutParams; -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->generateLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Landroidx/recyclerview/widget/RecyclerView$LayoutParams; HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getBaseline()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getBottomDecorationHeight(Landroid/view/View;)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getChildAt(I)Landroid/view/View; @@ -5441,19 +5433,13 @@ HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getChildCount()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getChildMeasureSpec(IIIIZ)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getColumnCountForAccessibility(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getDecoratedBottom(Landroid/view/View;)I -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getDecoratedBoundsWithMargins(Landroid/view/View;Landroid/graphics/Rect;)V -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getDecoratedLeft(Landroid/view/View;)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getDecoratedMeasuredHeight(Landroid/view/View;)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getDecoratedMeasuredWidth(Landroid/view/View;)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getDecoratedTop(Landroid/view/View;)I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getFocusedChild()Landroid/view/View; HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getHeight()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getHeightMode()I -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getItemCount()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getLayoutDirection()I -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getLeftDecorationWidth(Landroid/view/View;)I -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getMinimumHeight()I -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getMinimumWidth()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getPaddingBottom()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getPaddingLeft()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getPaddingRight()I @@ -5466,12 +5452,13 @@ HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getTopDecorationHe HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getWidth()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getWidthMode()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->isLayoutHierarchical(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;)Z -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->isMeasurementUpToDate(III)Z HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->layoutDecoratedWithMargins(Landroid/view/View;IIII)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->measureChildWithMargins(Landroid/view/View;II)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onAdapterChanged(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/RecyclerView$Adapter;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onAddFocusables(Landroidx/recyclerview/widget/RecyclerView;Ljava/util/ArrayList;II)Z HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView;)V +HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;)V +HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$Recycler;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onInitializeAccessibilityEvent(Landroid/view/accessibility/AccessibilityEvent;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onInitializeAccessibilityEvent(Landroidx/recyclerview/widget/RecyclerView$Recycler;Landroidx/recyclerview/widget/RecyclerView$State;Landroid/view/accessibility/AccessibilityEvent;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onInitializeAccessibilityNodeInfo(Landroidx/core/view/accessibility/AccessibilityNodeInfoCompat;)V @@ -5487,19 +5474,15 @@ HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->requestLayout()V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->scrapOrRecycleView(Landroidx/recyclerview/widget/RecyclerView$Recycler;ILandroid/view/View;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->setExactMeasureSpecsFrom(Landroidx/recyclerview/widget/RecyclerView;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->setMeasureSpecs(II)V -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->setMeasuredDimension(II)V -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->setMeasuredDimension(Landroid/graphics/Rect;II)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->setMeasuredDimensionFromChildren(II)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->setRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->shouldMeasureChild(Landroid/view/View;IILandroidx/recyclerview/widget/RecyclerView$LayoutParams;)Z HSPLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->stopSmoothScroller()V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutParams;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLandroidx/recyclerview/widget/RecyclerView$LayoutParams;->(Landroid/view/ViewGroup$MarginLayoutParams;)V HSPLandroidx/recyclerview/widget/RecyclerView$LayoutParams;->getViewLayoutPosition()I HSPLandroidx/recyclerview/widget/RecyclerView$LayoutParams;->isItemChanged()Z HSPLandroidx/recyclerview/widget/RecyclerView$LayoutParams;->isItemRemoved()Z HSPLandroidx/recyclerview/widget/RecyclerView$OnScrollListener;->()V -HSPLandroidx/recyclerview/widget/RecyclerView$OnScrollListener;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V HSPLandroidx/recyclerview/widget/RecyclerView$RecycledViewPool$ScrapData;->()V HSPLandroidx/recyclerview/widget/RecyclerView$RecycledViewPool;->()V HSPLandroidx/recyclerview/widget/RecyclerView$RecycledViewPool;->attach()V @@ -5521,7 +5504,6 @@ HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->clearScrap()V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getRecycledViewPool()Landroidx/recyclerview/widget/RecyclerView$RecycledViewPool; HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getScrapCount()I HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getScrapList()Ljava/util/List; -HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getScrapOrCachedViewForId(JIZ)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getScrapOrHiddenOrCachedHolderForPosition(IZ)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getViewForPosition(I)Landroid/view/View; HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->getViewForPosition(IZ)Landroid/view/View; @@ -5531,6 +5513,8 @@ HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->maybeSendPoolingContain HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->offsetPositionRecordsForInsert(II)V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->onAdapterChanged(Landroidx/recyclerview/widget/RecyclerView$Adapter;Landroidx/recyclerview/widget/RecyclerView$Adapter;Z)V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->onAttachedToWindow()V +HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->onDetachedFromWindow()V +HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->poolingContainerDetach(Landroidx/recyclerview/widget/RecyclerView$Adapter;)V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->poolingContainerDetach(Landroidx/recyclerview/widget/RecyclerView$Adapter;Z)V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->recycleAndClearCachedViews()V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->scrapView(Landroid/view/View;)V @@ -5540,14 +5524,9 @@ HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->unscrapView(Landroidx/r HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->updateViewCacheSize()V HSPLandroidx/recyclerview/widget/RecyclerView$Recycler;->validateViewHolderForOffsetPosition(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Z HSPLandroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver;->(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLandroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver;->onChanged()V HSPLandroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver;->onItemRangeChanged(IILjava/lang/Object;)V HSPLandroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver;->onItemRangeInserted(II)V HSPLandroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver;->triggerUpdateProcessor()V -HSPLandroidx/recyclerview/widget/RecyclerView$SavedState$1;->()V -HSPLandroidx/recyclerview/widget/RecyclerView$SavedState;->()V -HSPLandroidx/recyclerview/widget/RecyclerView$SavedState;->(Landroid/os/Parcelable;)V -HSPLandroidx/recyclerview/widget/RecyclerView$SimpleOnItemTouchListener;->()V HSPLandroidx/recyclerview/widget/RecyclerView$State;->()V HSPLandroidx/recyclerview/widget/RecyclerView$State;->assertLayoutStep(I)V HSPLandroidx/recyclerview/widget/RecyclerView$State;->getItemCount()I @@ -5564,10 +5543,8 @@ HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->clearOldPosition()V HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->clearPayload()V HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->clearReturnedFromScrapFlag()V HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->clearTmpDetachFlag()V -HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getAbsoluteAdapterPosition()I HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getAdapterPosition()I HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getBindingAdapterPosition()I -HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getItemId()J HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getItemViewType()I HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getLayoutPosition()I HSPLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getUnmodifiedPayloads()Ljava/util/List; @@ -5591,7 +5568,6 @@ HSPLandroidx/recyclerview/widget/RecyclerView;->(Landroid/content/Context; HSPLandroidx/recyclerview/widget/RecyclerView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLandroidx/recyclerview/widget/RecyclerView;->access$000(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V HSPLandroidx/recyclerview/widget/RecyclerView;->access$100(Landroidx/recyclerview/widget/RecyclerView;I)V -HSPLandroidx/recyclerview/widget/RecyclerView;->access$500(Landroidx/recyclerview/widget/RecyclerView;II)V HSPLandroidx/recyclerview/widget/RecyclerView;->addFocusables(Ljava/util/ArrayList;II)V HSPLandroidx/recyclerview/widget/RecyclerView;->addItemDecoration(Landroidx/recyclerview/widget/RecyclerView$ItemDecoration;)V HSPLandroidx/recyclerview/widget/RecyclerView;->addItemDecoration(Landroidx/recyclerview/widget/RecyclerView$ItemDecoration;I)V @@ -5619,7 +5595,6 @@ HSPLandroidx/recyclerview/widget/RecyclerView;->dispatchLayoutStep2()V HSPLandroidx/recyclerview/widget/RecyclerView;->dispatchLayoutStep3()V HSPLandroidx/recyclerview/widget/RecyclerView;->dispatchOnScrolled(II)V HSPLandroidx/recyclerview/widget/RecyclerView;->dispatchPendingImportantForAccessibilityChanges()V -HSPLandroidx/recyclerview/widget/RecyclerView;->dispatchSaveInstanceState(Landroid/util/SparseArray;)V HSPLandroidx/recyclerview/widget/RecyclerView;->draw(Landroid/graphics/Canvas;)V HSPLandroidx/recyclerview/widget/RecyclerView;->drawChild(Landroid/graphics/Canvas;Landroid/view/View;J)Z HSPLandroidx/recyclerview/widget/RecyclerView;->fillRemainingScrollValues(Landroidx/recyclerview/widget/RecyclerView$State;)V @@ -5627,15 +5602,12 @@ HSPLandroidx/recyclerview/widget/RecyclerView;->findInterceptingOnItemTouchListe HSPLandroidx/recyclerview/widget/RecyclerView;->findMinMaxChildLayoutPositions([I)V HSPLandroidx/recyclerview/widget/RecyclerView;->findNestedRecyclerView(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView; HSPLandroidx/recyclerview/widget/RecyclerView;->generateLayoutParams(Landroid/util/AttributeSet;)Landroid/view/ViewGroup$LayoutParams; -HSPLandroidx/recyclerview/widget/RecyclerView;->generateLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Landroid/view/ViewGroup$LayoutParams; HSPLandroidx/recyclerview/widget/RecyclerView;->getAccessibilityClassName()Ljava/lang/CharSequence; HSPLandroidx/recyclerview/widget/RecyclerView;->getAdapter()Landroidx/recyclerview/widget/RecyclerView$Adapter; HSPLandroidx/recyclerview/widget/RecyclerView;->getAdapterPositionInRecyclerView(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)I HSPLandroidx/recyclerview/widget/RecyclerView;->getBaseline()I HSPLandroidx/recyclerview/widget/RecyclerView;->getChangedHolderKey(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)J -HSPLandroidx/recyclerview/widget/RecyclerView;->getChildViewHolder(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; HSPLandroidx/recyclerview/widget/RecyclerView;->getChildViewHolderInt(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; -HSPLandroidx/recyclerview/widget/RecyclerView;->getDecoratedBoundsWithMarginsInt(Landroid/view/View;Landroid/graphics/Rect;)V HSPLandroidx/recyclerview/widget/RecyclerView;->getFullClassName(Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String; HSPLandroidx/recyclerview/widget/RecyclerView;->getItemAnimator()Landroidx/recyclerview/widget/RecyclerView$ItemAnimator; HSPLandroidx/recyclerview/widget/RecyclerView;->getItemDecorInsetsForChild(Landroid/view/View;)Landroid/graphics/Rect; @@ -5658,6 +5630,7 @@ HSPLandroidx/recyclerview/widget/RecyclerView;->markKnownViewsInvalid()V HSPLandroidx/recyclerview/widget/RecyclerView;->offsetPositionRecordsForInsert(II)V HSPLandroidx/recyclerview/widget/RecyclerView;->onAttachedToWindow()V HSPLandroidx/recyclerview/widget/RecyclerView;->onChildAttachedToWindow(Landroid/view/View;)V +HSPLandroidx/recyclerview/widget/RecyclerView;->onDetachedFromWindow()V HSPLandroidx/recyclerview/widget/RecyclerView;->onDraw(Landroid/graphics/Canvas;)V HSPLandroidx/recyclerview/widget/RecyclerView;->onEnterLayoutOrScroll()V HSPLandroidx/recyclerview/widget/RecyclerView;->onExitLayoutOrScroll()V @@ -5665,7 +5638,6 @@ HSPLandroidx/recyclerview/widget/RecyclerView;->onExitLayoutOrScroll(Z)V HSPLandroidx/recyclerview/widget/RecyclerView;->onInterceptTouchEvent(Landroid/view/MotionEvent;)Z HSPLandroidx/recyclerview/widget/RecyclerView;->onLayout(ZIIII)V HSPLandroidx/recyclerview/widget/RecyclerView;->onMeasure(II)V -HSPLandroidx/recyclerview/widget/RecyclerView;->onSaveInstanceState()Landroid/os/Parcelable; HSPLandroidx/recyclerview/widget/RecyclerView;->onScrolled(II)V HSPLandroidx/recyclerview/widget/RecyclerView;->onSizeChanged(IIII)V HSPLandroidx/recyclerview/widget/RecyclerView;->postAnimationRunner()V @@ -5696,6 +5668,7 @@ HSPLandroidx/recyclerview/widget/RecyclerView;->startInterceptRequestLayout()V HSPLandroidx/recyclerview/widget/RecyclerView;->startNestedScroll(II)Z HSPLandroidx/recyclerview/widget/RecyclerView;->stopGlowAnimations(Landroid/view/MotionEvent;)Z HSPLandroidx/recyclerview/widget/RecyclerView;->stopInterceptRequestLayout(Z)V +HSPLandroidx/recyclerview/widget/RecyclerView;->stopNestedScroll()V HSPLandroidx/recyclerview/widget/RecyclerView;->stopNestedScroll(I)V HSPLandroidx/recyclerview/widget/RecyclerView;->stopScroll()V HSPLandroidx/recyclerview/widget/RecyclerView;->stopScrollersInternal()V @@ -5737,26 +5710,22 @@ HSPLandroidx/recyclerview/widget/ViewBoundsCheck;->(Landroidx/recyclerview HSPLandroidx/recyclerview/widget/ViewBoundsCheck;->findOneViewWithinBoundFlags(IIII)Landroid/view/View; HSPLandroidx/recyclerview/widget/ViewInfoStore$InfoRecord;->()V HSPLandroidx/recyclerview/widget/ViewInfoStore$InfoRecord;->()V +HSPLandroidx/recyclerview/widget/ViewInfoStore$InfoRecord;->drainCache()V HSPLandroidx/recyclerview/widget/ViewInfoStore$InfoRecord;->obtain()Landroidx/recyclerview/widget/ViewInfoStore$InfoRecord; HSPLandroidx/recyclerview/widget/ViewInfoStore$InfoRecord;->recycle(Landroidx/recyclerview/widget/ViewInfoStore$InfoRecord;)V HSPLandroidx/recyclerview/widget/ViewInfoStore;->()V HSPLandroidx/recyclerview/widget/ViewInfoStore;->addToPostLayout(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)V HSPLandroidx/recyclerview/widget/ViewInfoStore;->clear()V HSPLandroidx/recyclerview/widget/ViewInfoStore;->getFromOldChangeHolders(J)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; +HSPLandroidx/recyclerview/widget/ViewInfoStore;->onDetach()V HSPLandroidx/recyclerview/widget/ViewInfoStore;->onViewDetached(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V HSPLandroidx/recyclerview/widget/ViewInfoStore;->process(Landroidx/recyclerview/widget/ViewInfoStore$ProcessCallback;)V HSPLandroidx/recyclerview/widget/ViewInfoStore;->removeFromDisappearedInLayout(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage$WrapperViewTypeLookup;->(Landroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;Landroidx/recyclerview/widget/NestedAdapterWrapper;)V -HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage$WrapperViewTypeLookup;->globalToLocal(I)I -HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage$WrapperViewTypeLookup;->localToGlobal(I)I HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;->()V HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;->createViewTypeWrapper(Landroidx/recyclerview/widget/NestedAdapterWrapper;)Landroidx/recyclerview/widget/ViewTypeStorage$ViewTypeLookup; -HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;->getWrapperForGlobalType(I)Landroidx/recyclerview/widget/NestedAdapterWrapper; -HSPLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;->obtainViewType(Landroidx/recyclerview/widget/NestedAdapterWrapper;)I HSPLandroidx/savedstate/Recreator$Companion;->()V HSPLandroidx/savedstate/Recreator$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLandroidx/savedstate/Recreator$SavedStateProvider;->(Landroidx/savedstate/SavedStateRegistry;)V -HSPLandroidx/savedstate/Recreator$SavedStateProvider;->add(Ljava/lang/String;)V HSPLandroidx/savedstate/Recreator;->()V HSPLandroidx/savedstate/Recreator;->(Landroidx/savedstate/SavedStateRegistryOwner;)V HSPLandroidx/savedstate/Recreator;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V @@ -5772,9 +5741,7 @@ HSPLandroidx/savedstate/SavedStateRegistry;->getSavedStateProvider(Ljava/lang/St HSPLandroidx/savedstate/SavedStateRegistry;->performAttach$lambda$4(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V HSPLandroidx/savedstate/SavedStateRegistry;->performAttach$savedstate_release(Landroidx/lifecycle/Lifecycle;)V HSPLandroidx/savedstate/SavedStateRegistry;->performRestore$savedstate_release(Landroid/os/Bundle;)V -HSPLandroidx/savedstate/SavedStateRegistry;->performSave(Landroid/os/Bundle;)V HSPLandroidx/savedstate/SavedStateRegistry;->registerSavedStateProvider(Ljava/lang/String;Landroidx/savedstate/SavedStateRegistry$SavedStateProvider;)V -HSPLandroidx/savedstate/SavedStateRegistry;->runOnNextRecreation(Ljava/lang/Class;)V HSPLandroidx/savedstate/SavedStateRegistryController$Companion;->()V HSPLandroidx/savedstate/SavedStateRegistryController$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLandroidx/savedstate/SavedStateRegistryController$Companion;->create(Landroidx/savedstate/SavedStateRegistryOwner;)Landroidx/savedstate/SavedStateRegistryController; @@ -5785,7 +5752,6 @@ HSPLandroidx/savedstate/SavedStateRegistryController;->create(Landroidx/savedsta HSPLandroidx/savedstate/SavedStateRegistryController;->getSavedStateRegistry()Landroidx/savedstate/SavedStateRegistry; HSPLandroidx/savedstate/SavedStateRegistryController;->performAttach()V HSPLandroidx/savedstate/SavedStateRegistryController;->performRestore(Landroid/os/Bundle;)V -HSPLandroidx/savedstate/SavedStateRegistryController;->performSave(Landroid/os/Bundle;)V HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner;->set(Landroid/view/View;Landroidx/savedstate/SavedStateRegistryOwner;)V HSPLandroidx/sqlite/db/SimpleSQLiteQuery;->(Ljava/lang/String;[Ljava/lang/Object;)V HSPLandroidx/sqlite/db/SimpleSQLiteQuery;->bind(Landroidx/sqlite/db/SupportSQLiteProgram;ILjava/lang/Object;)V @@ -5829,9 +5795,6 @@ HSPLcom/airbnb/lottie/LottieAnimationView$$ExternalSyntheticLambda1;->onResult(L HSPLcom/airbnb/lottie/LottieAnimationView$$ExternalSyntheticLambda2;->()V HSPLcom/airbnb/lottie/LottieAnimationView$1;->(Lcom/airbnb/lottie/LottieAnimationView;)V HSPLcom/airbnb/lottie/LottieAnimationView$2;->(Lcom/airbnb/lottie/LottieAnimationView;Lcom/airbnb/lottie/value/SimpleLottieValueCallback;)V -HSPLcom/airbnb/lottie/LottieAnimationView$SavedState$1;->()V -HSPLcom/airbnb/lottie/LottieAnimationView$SavedState;->()V -HSPLcom/airbnb/lottie/LottieAnimationView$SavedState;->(Landroid/os/Parcelable;)V HSPLcom/airbnb/lottie/LottieAnimationView$UserActionTaken;->()V HSPLcom/airbnb/lottie/LottieAnimationView$UserActionTaken;->(Ljava/lang/String;I)V HSPLcom/airbnb/lottie/LottieAnimationView;->()V @@ -5846,7 +5809,6 @@ HSPLcom/airbnb/lottie/LottieAnimationView;->init(Landroid/util/AttributeSet;I)V HSPLcom/airbnb/lottie/LottieAnimationView;->invalidate()V HSPLcom/airbnb/lottie/LottieAnimationView;->invalidateDrawable(Landroid/graphics/drawable/Drawable;)V HSPLcom/airbnb/lottie/LottieAnimationView;->onAttachedToWindow()V -HSPLcom/airbnb/lottie/LottieAnimationView;->onSaveInstanceState()Landroid/os/Parcelable; HSPLcom/airbnb/lottie/LottieAnimationView;->pauseAnimation()V HSPLcom/airbnb/lottie/LottieAnimationView;->setAnimation(I)V HSPLcom/airbnb/lottie/LottieAnimationView;->setComposition(Lcom/airbnb/lottie/LottieComposition;)V @@ -5897,13 +5859,11 @@ HSPLcom/airbnb/lottie/LottieCompositionFactory;->rawResCacheKey(Landroid/content HSPLcom/airbnb/lottie/LottieDrawable$$ExternalSyntheticLambda0;->(Lcom/airbnb/lottie/LottieDrawable;F)V HSPLcom/airbnb/lottie/LottieDrawable$$ExternalSyntheticLambda0;->run(Lcom/airbnb/lottie/LottieComposition;)V HSPLcom/airbnb/lottie/LottieDrawable$$ExternalSyntheticLambda9;->(Lcom/airbnb/lottie/LottieDrawable;Lcom/airbnb/lottie/model/KeyPath;Ljava/lang/Object;Lcom/airbnb/lottie/value/LottieValueCallback;)V -HSPLcom/airbnb/lottie/LottieDrawable$$ExternalSyntheticLambda9;->run(Lcom/airbnb/lottie/LottieComposition;)V HSPLcom/airbnb/lottie/LottieDrawable$1;->(Lcom/airbnb/lottie/LottieDrawable;)V HSPLcom/airbnb/lottie/LottieDrawable$1;->onAnimationUpdate(Landroid/animation/ValueAnimator;)V HSPLcom/airbnb/lottie/LottieDrawable$OnVisibleAction;->()V HSPLcom/airbnb/lottie/LottieDrawable$OnVisibleAction;->(Ljava/lang/String;I)V HSPLcom/airbnb/lottie/LottieDrawable;->$r8$lambda$7HgNmvtAytyG5A3axzRshxgGqrI(Lcom/airbnb/lottie/LottieDrawable;FLcom/airbnb/lottie/LottieComposition;)V -HSPLcom/airbnb/lottie/LottieDrawable;->$r8$lambda$riFJCWOqfI5iOFlatZRlwc9qv1U(Lcom/airbnb/lottie/LottieDrawable;Lcom/airbnb/lottie/model/KeyPath;Ljava/lang/Object;Lcom/airbnb/lottie/value/LottieValueCallback;Lcom/airbnb/lottie/LottieComposition;)V HSPLcom/airbnb/lottie/LottieDrawable;->()V HSPLcom/airbnb/lottie/LottieDrawable;->access$000(Lcom/airbnb/lottie/LottieDrawable;)Lcom/airbnb/lottie/model/layer/CompositionLayer; HSPLcom/airbnb/lottie/LottieDrawable;->access$100(Lcom/airbnb/lottie/LottieDrawable;)Lcom/airbnb/lottie/utils/LottieValueAnimator; @@ -5915,18 +5875,12 @@ HSPLcom/airbnb/lottie/LottieDrawable;->draw(Landroid/graphics/Canvas;)V HSPLcom/airbnb/lottie/LottieDrawable;->drawDirectlyToCanvas(Landroid/graphics/Canvas;)V HSPLcom/airbnb/lottie/LottieDrawable;->enableMergePathsForKitKatAndAbove(Z)V HSPLcom/airbnb/lottie/LottieDrawable;->getComposition()Lcom/airbnb/lottie/LottieComposition; -HSPLcom/airbnb/lottie/LottieDrawable;->getImageAssetsFolder()Ljava/lang/String; HSPLcom/airbnb/lottie/LottieDrawable;->getIntrinsicHeight()I HSPLcom/airbnb/lottie/LottieDrawable;->getIntrinsicWidth()I HSPLcom/airbnb/lottie/LottieDrawable;->getOpacity()I -HSPLcom/airbnb/lottie/LottieDrawable;->getProgress()F HSPLcom/airbnb/lottie/LottieDrawable;->getRenderMode()Lcom/airbnb/lottie/RenderMode; -HSPLcom/airbnb/lottie/LottieDrawable;->getRepeatCount()I -HSPLcom/airbnb/lottie/LottieDrawable;->getRepeatMode()I HSPLcom/airbnb/lottie/LottieDrawable;->invalidateSelf()V -HSPLcom/airbnb/lottie/LottieDrawable;->isAnimatingOrWillAnimateOnVisible()Z HSPLcom/airbnb/lottie/LottieDrawable;->isApplyingOpacityToLayersEnabled()Z -HSPLcom/airbnb/lottie/LottieDrawable;->lambda$addValueCallback$14(Lcom/airbnb/lottie/model/KeyPath;Ljava/lang/Object;Lcom/airbnb/lottie/value/LottieValueCallback;Lcom/airbnb/lottie/LottieComposition;)V HSPLcom/airbnb/lottie/LottieDrawable;->lambda$setProgress$13(FLcom/airbnb/lottie/LottieComposition;)V HSPLcom/airbnb/lottie/LottieDrawable;->pauseAnimation()V HSPLcom/airbnb/lottie/LottieDrawable;->resolveKeyPath(Lcom/airbnb/lottie/model/KeyPath;)Ljava/util/List; @@ -6177,7 +6131,6 @@ HSPLcom/airbnb/lottie/model/layer/BaseLayer;->invalidateSelf()V HSPLcom/airbnb/lottie/model/layer/BaseLayer;->lambda$setupInOutAnimations$0()V HSPLcom/airbnb/lottie/model/layer/BaseLayer;->onValueChanged()V HSPLcom/airbnb/lottie/model/layer/BaseLayer;->recordRenderTime(F)V -HSPLcom/airbnb/lottie/model/layer/BaseLayer;->removeAnimation(Lcom/airbnb/lottie/animation/keyframe/BaseKeyframeAnimation;)V HSPLcom/airbnb/lottie/model/layer/BaseLayer;->resolveKeyPath(Lcom/airbnb/lottie/model/KeyPath;ILjava/util/List;Lcom/airbnb/lottie/model/KeyPath;)V HSPLcom/airbnb/lottie/model/layer/BaseLayer;->setMatteLayer(Lcom/airbnb/lottie/model/layer/BaseLayer;)V HSPLcom/airbnb/lottie/model/layer/BaseLayer;->setProgress(F)V @@ -6320,18 +6273,22 @@ HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->(Lokio/BufferedSource; HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->beginArray()V HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->beginObject()V HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->close()V +HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->doPeek()I HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->endArray()V HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->endObject()V HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->findName(Ljava/lang/String;Lcom/airbnb/lottie/parser/moshi/JsonReader$Options;)I HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->hasNext()Z HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->isLiteral(I)Z HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextBoolean()Z +HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextDouble()D HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextInt()I HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextName()Ljava/lang/String; +HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextNonWhitespace(Z)I HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextQuotedValue(Lokio/ByteString;)Ljava/lang/String; HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->nextString()Ljava/lang/String; HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->peek()Lcom/airbnb/lottie/parser/moshi/JsonReader$Token; HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->peekKeyword()I +HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->peekNumber()I HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->selectName(Lcom/airbnb/lottie/parser/moshi/JsonReader$Options;)I HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->skipName()V HSPLcom/airbnb/lottie/parser/moshi/JsonUtf8Reader;->skipQuotedValue(Lokio/ByteString;)V @@ -6449,9 +6406,7 @@ HSPLcom/annimon/stream/Objects;->requireNonNull(Ljava/lang/Object;)Ljava/lang/Ob HSPLcom/annimon/stream/Optional;->()V HSPLcom/annimon/stream/Optional;->()V HSPLcom/annimon/stream/Optional;->(Ljava/lang/Object;)V -HSPLcom/annimon/stream/Optional;->empty()Lcom/annimon/stream/Optional; HSPLcom/annimon/stream/Optional;->of(Ljava/lang/Object;)Lcom/annimon/stream/Optional; -HSPLcom/annimon/stream/Optional;->orElse(Ljava/lang/Object;)Ljava/lang/Object; HSPLcom/annimon/stream/Optional;->orElseThrow(Lcom/annimon/stream/function/Supplier;)Ljava/lang/Object; HSPLcom/annimon/stream/Stream$2;->(Lcom/annimon/stream/Stream;)V HSPLcom/annimon/stream/Stream$2;->apply(ILjava/lang/Object;)Lcom/annimon/stream/IntPair; @@ -6463,7 +6418,6 @@ HSPLcom/annimon/stream/Stream;->(Ljava/util/Iterator;)V HSPLcom/annimon/stream/Stream;->allMatch(Lcom/annimon/stream/function/Predicate;)Z HSPLcom/annimon/stream/Stream;->anyMatch(Lcom/annimon/stream/function/Predicate;)Z HSPLcom/annimon/stream/Stream;->collect(Lcom/annimon/stream/Collector;)Ljava/lang/Object; -HSPLcom/annimon/stream/Stream;->empty()Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->filter(Lcom/annimon/stream/function/Predicate;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->filterNot(Lcom/annimon/stream/function/Predicate;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->findFirst()Lcom/annimon/stream/Optional; @@ -6474,19 +6428,15 @@ HSPLcom/annimon/stream/Stream;->limit(J)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->map(Lcom/annimon/stream/function/Function;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->mapIndexed(IILcom/annimon/stream/function/IndexedFunction;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->match(Lcom/annimon/stream/function/Predicate;I)Z -HSPLcom/annimon/stream/Stream;->max(Ljava/util/Comparator;)Lcom/annimon/stream/Optional; HSPLcom/annimon/stream/Stream;->of(Ljava/lang/Iterable;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->of(Ljava/util/Map;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->of([Ljava/lang/Object;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->rangeClosed(II)Lcom/annimon/stream/Stream; -HSPLcom/annimon/stream/Stream;->reduce(Lcom/annimon/stream/function/BiFunction;)Lcom/annimon/stream/Optional; HSPLcom/annimon/stream/Stream;->reduce(Ljava/lang/Object;Lcom/annimon/stream/function/BiFunction;)Ljava/lang/Object; HSPLcom/annimon/stream/Stream;->sorted()Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->sorted(Ljava/util/Comparator;)Lcom/annimon/stream/Stream; HSPLcom/annimon/stream/Stream;->toList()Ljava/util/List; HSPLcom/annimon/stream/Stream;->withoutNulls()Lcom/annimon/stream/Stream; -HSPLcom/annimon/stream/function/BinaryOperator$Util$2;->(Ljava/util/Comparator;)V -HSPLcom/annimon/stream/function/BinaryOperator$Util;->maxBy(Ljava/util/Comparator;)Lcom/annimon/stream/function/BinaryOperator; HSPLcom/annimon/stream/function/Predicate$Util$4;->(Lcom/annimon/stream/function/Predicate;)V HSPLcom/annimon/stream/function/Predicate$Util$4;->test(Ljava/lang/Object;)Z HSPLcom/annimon/stream/function/Predicate$Util$5;->()V @@ -6513,9 +6463,6 @@ HSPLcom/annimon/stream/iterator/PrimitiveIterator$OfInt;->next()Ljava/lang/Objec HSPLcom/annimon/stream/operator/IntArray;->([I)V HSPLcom/annimon/stream/operator/IntArray;->hasNext()Z HSPLcom/annimon/stream/operator/IntArray;->nextInt()I -HSPLcom/annimon/stream/operator/IntRangeClosed;->(II)V -HSPLcom/annimon/stream/operator/IntRangeClosed;->hasNext()Z -HSPLcom/annimon/stream/operator/IntRangeClosed;->nextInt()I HSPLcom/annimon/stream/operator/ObjArray;->([Ljava/lang/Object;)V HSPLcom/annimon/stream/operator/ObjArray;->hasNext()Z HSPLcom/annimon/stream/operator/ObjArray;->nextIteration()Ljava/lang/Object; @@ -6534,15 +6481,12 @@ HSPLcom/annimon/stream/operator/ObjMapIndexed;->nextIteration()Ljava/lang/Object HSPLcom/annimon/stream/operator/ObjSorted;->(Ljava/util/Iterator;Ljava/util/Comparator;)V HSPLcom/annimon/stream/operator/ObjSorted;->nextIteration()V HSPLcom/bumptech/glide/GeneratedAppGlideModule;->()V +HSPLcom/bumptech/glide/GeneratedAppGlideModule;->getExcludedModuleClasses()Ljava/util/Set; +HSPLcom/bumptech/glide/GeneratedAppGlideModule;->getRequestManagerFactory()Lcom/bumptech/glide/manager/RequestManagerRetriever$RequestManagerFactory; HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->(Landroid/content/Context;)V HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->applyOptions(Landroid/content/Context;Lcom/bumptech/glide/GlideBuilder;)V -HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->getExcludedModuleClasses()Ljava/util/Set; -HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->getRequestManagerFactory()Lcom/bumptech/glide/GeneratedRequestManagerFactory; -HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->getRequestManagerFactory()Lcom/bumptech/glide/manager/RequestManagerRetriever$RequestManagerFactory; HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->isManifestParsingEnabled()Z HSPLcom/bumptech/glide/GeneratedAppGlideModuleImpl;->registerComponents(Landroid/content/Context;Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/Registry;)V -HSPLcom/bumptech/glide/GeneratedRequestManagerFactory;->()V -HSPLcom/bumptech/glide/GeneratedRequestManagerFactory;->build(Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/manager/Lifecycle;Lcom/bumptech/glide/manager/RequestManagerTreeNode;Landroid/content/Context;)Lcom/bumptech/glide/RequestManager; HSPLcom/bumptech/glide/GenericTransitionOptions;->()V HSPLcom/bumptech/glide/Glide;->(Landroid/content/Context;Lcom/bumptech/glide/load/engine/Engine;Lcom/bumptech/glide/load/engine/cache/MemoryCache;Lcom/bumptech/glide/load/engine/bitmap_recycle/BitmapPool;Lcom/bumptech/glide/load/engine/bitmap_recycle/ArrayPool;Lcom/bumptech/glide/manager/RequestManagerRetriever;Lcom/bumptech/glide/manager/ConnectivityMonitorFactory;ILcom/bumptech/glide/Glide$RequestOptionsFactory;Ljava/util/Map;Ljava/util/List;Ljava/util/List;Lcom/bumptech/glide/module/AppGlideModule;Lcom/bumptech/glide/GlideExperiments;)V HSPLcom/bumptech/glide/Glide;->checkAndInitializeGlide(Landroid/content/Context;Lcom/bumptech/glide/GeneratedAppGlideModule;)V @@ -6632,6 +6576,7 @@ HSPLcom/bumptech/glide/RequestManager$RequestManagerConnectivityListener;->()V HSPLcom/bumptech/glide/RequestManager;->(Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/manager/Lifecycle;Lcom/bumptech/glide/manager/RequestManagerTreeNode;Landroid/content/Context;)V HSPLcom/bumptech/glide/RequestManager;->(Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/manager/Lifecycle;Lcom/bumptech/glide/manager/RequestManagerTreeNode;Lcom/bumptech/glide/manager/RequestTracker;Lcom/bumptech/glide/manager/ConnectivityMonitorFactory;Landroid/content/Context;)V +HSPLcom/bumptech/glide/RequestManager;->as(Ljava/lang/Class;)Lcom/bumptech/glide/RequestBuilder; HSPLcom/bumptech/glide/RequestManager;->asDrawable()Lcom/bumptech/glide/RequestBuilder; HSPLcom/bumptech/glide/RequestManager;->clear(Landroid/view/View;)V HSPLcom/bumptech/glide/RequestManager;->clear(Lcom/bumptech/glide/request/target/Target;)V @@ -7155,7 +7100,6 @@ HSPLcom/bumptech/glide/manager/DoNothingFirstFrameWaiter;->registerSelf(Landroid HSPLcom/bumptech/glide/manager/LifecycleLifecycle;->(Landroidx/lifecycle/Lifecycle;)V HSPLcom/bumptech/glide/manager/LifecycleLifecycle;->addListener(Lcom/bumptech/glide/manager/LifecycleListener;)V HSPLcom/bumptech/glide/manager/LifecycleLifecycle;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLcom/bumptech/glide/manager/LifecycleLifecycle;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever$1;->(Lcom/bumptech/glide/manager/LifecycleRequestManagerRetriever;Landroidx/lifecycle/Lifecycle;)V HSPLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever$1;->onStart()V HSPLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever$1;->onStop()V @@ -7164,6 +7108,7 @@ HSPLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever;->(Lcom/bu HSPLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever;->getOnly(Landroidx/lifecycle/Lifecycle;)Lcom/bumptech/glide/RequestManager; HSPLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever;->getOrCreate(Landroid/content/Context;Lcom/bumptech/glide/Glide;Landroidx/lifecycle/Lifecycle;Landroidx/fragment/app/FragmentManager;Z)Lcom/bumptech/glide/RequestManager; HSPLcom/bumptech/glide/manager/RequestManagerRetriever$1;->()V +HSPLcom/bumptech/glide/manager/RequestManagerRetriever$1;->build(Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/manager/Lifecycle;Lcom/bumptech/glide/manager/RequestManagerTreeNode;Landroid/content/Context;)Lcom/bumptech/glide/RequestManager; HSPLcom/bumptech/glide/manager/RequestManagerRetriever;->()V HSPLcom/bumptech/glide/manager/RequestManagerRetriever;->(Lcom/bumptech/glide/manager/RequestManagerRetriever$RequestManagerFactory;Lcom/bumptech/glide/GlideExperiments;)V HSPLcom/bumptech/glide/manager/RequestManagerRetriever;->assertNotDestroyed(Landroid/app/Activity;)V @@ -7289,7 +7234,6 @@ HSPLcom/bumptech/glide/request/SingleRequest;->getErrorDrawable()Landroid/graphi HSPLcom/bumptech/glide/request/SingleRequest;->getLock()Ljava/lang/Object; HSPLcom/bumptech/glide/request/SingleRequest;->getPlaceholderDrawable()Landroid/graphics/drawable/Drawable; HSPLcom/bumptech/glide/request/SingleRequest;->isEquivalentTo(Lcom/bumptech/glide/request/Request;)Z -HSPLcom/bumptech/glide/request/SingleRequest;->isRunning()Z HSPLcom/bumptech/glide/request/SingleRequest;->maybeApplySizeMultiplier(IF)I HSPLcom/bumptech/glide/request/SingleRequest;->notifyRequestCoordinatorLoadFailed()V HSPLcom/bumptech/glide/request/SingleRequest;->obtain(Landroid/content/Context;Lcom/bumptech/glide/GlideContext;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Class;Lcom/bumptech/glide/request/BaseRequestOptions;IILcom/bumptech/glide/Priority;Lcom/bumptech/glide/request/target/Target;Lcom/bumptech/glide/request/RequestListener;Ljava/util/List;Lcom/bumptech/glide/request/RequestCoordinator;Lcom/bumptech/glide/load/engine/Engine;Lcom/bumptech/glide/request/transition/TransitionFactory;Ljava/util/concurrent/Executor;)Lcom/bumptech/glide/request/SingleRequest; @@ -7314,7 +7258,6 @@ HSPLcom/bumptech/glide/request/target/ImageViewTarget;->(Landroid/widget/I HSPLcom/bumptech/glide/request/target/ImageViewTarget;->maybeUpdateAnimatable(Ljava/lang/Object;)V HSPLcom/bumptech/glide/request/target/ImageViewTarget;->onLoadFailed(Landroid/graphics/drawable/Drawable;)V HSPLcom/bumptech/glide/request/target/ImageViewTarget;->onLoadStarted(Landroid/graphics/drawable/Drawable;)V -HSPLcom/bumptech/glide/request/target/ImageViewTarget;->onStop()V HSPLcom/bumptech/glide/request/target/ImageViewTarget;->setDrawable(Landroid/graphics/drawable/Drawable;)V HSPLcom/bumptech/glide/request/target/ImageViewTarget;->setResourceInternal(Ljava/lang/Object;)V HSPLcom/bumptech/glide/request/target/ImageViewTargetFactory;->()V @@ -7435,9 +7378,13 @@ HSPLcom/fasterxml/jackson/annotation/JsonFormat$Value;->hasShape()Z HSPLcom/fasterxml/jackson/annotation/JsonFormat$Value;->withOverrides(Lcom/fasterxml/jackson/annotation/JsonFormat$Value;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value; HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->()V HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->(Ljava/util/Set;ZZZZ)V +HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->_asSet([Ljava/lang/String;)Ljava/util/Set; +HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->_empty(Ljava/util/Set;ZZZZ)Z +HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->construct(Ljava/util/Set;ZZZZ)Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->empty()Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->findIgnoredForDeserialization()Ljava/util/Set; HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->findIgnoredForSerialization()Ljava/util/Set; +HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->from(Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties;)Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->getIgnoreUnknown()Z HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->merge(Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;)Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; HSPLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->withOverrides(Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;)Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; @@ -7478,6 +7425,10 @@ HSPLcom/fasterxml/jackson/core/Base64Variant;->(Lcom/fasterxml/jackson/cor HSPLcom/fasterxml/jackson/core/Base64Variant;->(Lcom/fasterxml/jackson/core/Base64Variant;Ljava/lang/String;ZCI)V HSPLcom/fasterxml/jackson/core/Base64Variant;->(Lcom/fasterxml/jackson/core/Base64Variant;Ljava/lang/String;ZCLcom/fasterxml/jackson/core/Base64Variant$PaddingReadBehaviour;I)V HSPLcom/fasterxml/jackson/core/Base64Variant;->(Ljava/lang/String;Ljava/lang/String;ZCI)V +HSPLcom/fasterxml/jackson/core/Base64Variant;->encodeBase64Chunk(I[CI)I +HSPLcom/fasterxml/jackson/core/Base64Variant;->encodeBase64Partial(II[CI)I +HSPLcom/fasterxml/jackson/core/Base64Variant;->getMaxLineLength()I +HSPLcom/fasterxml/jackson/core/Base64Variant;->usesPadding()Z HSPLcom/fasterxml/jackson/core/Base64Variants;->()V HSPLcom/fasterxml/jackson/core/Base64Variants;->getDefaultVariant()Lcom/fasterxml/jackson/core/Base64Variant; HSPLcom/fasterxml/jackson/core/JsonEncoding;->()V @@ -7568,6 +7519,7 @@ HSPLcom/fasterxml/jackson/core/base/GeneratorBase;->getOutputContext()Lcom/faste HSPLcom/fasterxml/jackson/core/base/GeneratorBase;->isEnabled(Lcom/fasterxml/jackson/core/JsonGenerator$Feature;)Z HSPLcom/fasterxml/jackson/core/base/ParserBase;->()V HSPLcom/fasterxml/jackson/core/base/ParserBase;->(Lcom/fasterxml/jackson/core/io/IOContext;I)V +HSPLcom/fasterxml/jackson/core/base/ParserBase;->_parseIntValue()I HSPLcom/fasterxml/jackson/core/base/ParserBase;->_parseNumericValue(I)V HSPLcom/fasterxml/jackson/core/base/ParserBase;->_releaseBuffers()V HSPLcom/fasterxml/jackson/core/base/ParserBase;->close()V @@ -7621,6 +7573,8 @@ HSPLcom/fasterxml/jackson/core/io/JsonStringEncoder;->quoteAsUTF8(Ljava/lang/Str HSPLcom/fasterxml/jackson/core/io/NumberInput;->()V HSPLcom/fasterxml/jackson/core/io/NumberInput;->parseInt([CII)I HSPLcom/fasterxml/jackson/core/io/NumberOutput;->()V +HSPLcom/fasterxml/jackson/core/io/NumberOutput;->_full3(I[CI)I +HSPLcom/fasterxml/jackson/core/io/NumberOutput;->_leading3(I[BI)I HSPLcom/fasterxml/jackson/core/io/NumberOutput;->_leading3(I[CI)I HSPLcom/fasterxml/jackson/core/io/NumberOutput;->outputInt(I[BI)I HSPLcom/fasterxml/jackson/core/io/NumberOutput;->outputInt(I[CI)I @@ -7667,10 +7621,12 @@ HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->()V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->(Lcom/fasterxml/jackson/core/io/IOContext;ILjava/io/Reader;Lcom/fasterxml/jackson/core/ObjectCodec;Lcom/fasterxml/jackson/core/sym/CharsToNameCanonicalizer;)V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->(Lcom/fasterxml/jackson/core/io/IOContext;ILjava/io/Reader;Lcom/fasterxml/jackson/core/ObjectCodec;Lcom/fasterxml/jackson/core/sym/CharsToNameCanonicalizer;[CIIZ)V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_closeInput()V -HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_finishString()V +HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_closeScope(I)V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_finishString2()V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_loadMore()Z +HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_matchFalse()V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_matchNull()V +HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_matchTrue()V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_nextAfterName()Lcom/fasterxml/jackson/core/JsonToken; HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_parseName()Ljava/lang/String; HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_parseName2(III)Ljava/lang/String; @@ -7682,7 +7638,6 @@ HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_skipColon()I HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_skipColon2(Z)I HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_skipComma(I)I HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_skipString()V -HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_skipWSOrEnd()I HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_skipWSOrEnd2()I HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_updateLocation()V HSPLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_updateNameLocation()V @@ -7702,6 +7657,8 @@ HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->close()V HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeEndArray()V HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeEndObject()V HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeFieldName(Lcom/fasterxml/jackson/core/SerializableString;)V +HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeFieldName(Ljava/lang/String;)V +HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeNumber(I)V HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeNumber(J)V HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeStartArray(Ljava/lang/Object;I)V HSPLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeStartObject(Ljava/lang/Object;)V @@ -7711,6 +7668,7 @@ HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->()V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->(Lcom/fasterxml/jackson/core/io/IOContext;ILjava/io/InputStream;Lcom/fasterxml/jackson/core/ObjectCodec;Lcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;[BIIIZ)V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_closeInput()V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_closeObjectScope()V +HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_finishAndReturnString()Ljava/lang/String; HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_finishString2([CI)V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_loadMore()Z HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_loadMoreGuaranteed()V @@ -7720,10 +7678,8 @@ HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_parseName(I)Ljava/la HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_parsePosNumber(I)Lcom/fasterxml/jackson/core/JsonToken; HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_releaseBuffers()V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_skipColon()I -HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_skipColon2(Z)I HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_skipWS()I HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_skipWS2()I -HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_skipWSOrEnd()I HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_updateLocation()V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_updateNameLocation()V HSPLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->addName([III)Ljava/lang/String; @@ -7744,18 +7700,21 @@ HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->(Lcom/faste HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_flushBuffer()V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_releaseBuffers()V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_verifyValueWrite(Ljava/lang/String;)V +HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeBinary(Lcom/fasterxml/jackson/core/Base64Variant;[BII)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeFieldName(Lcom/fasterxml/jackson/core/SerializableString;Z)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeFieldName(Ljava/lang/String;Z)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeNull()V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeString(Ljava/lang/String;)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeString2(I)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->close()V +HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeBinary(Lcom/fasterxml/jackson/core/Base64Variant;[BII)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeBoolean(Z)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeEndArray()V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeEndObject()V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeFieldName(Lcom/fasterxml/jackson/core/SerializableString;)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeFieldName(Ljava/lang/String;)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeNull()V +HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeNumber(I)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeNumber(J)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeStartArray(Ljava/lang/Object;I)V HSPLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeStartObject(Ljava/lang/Object;)V @@ -7771,6 +7730,7 @@ HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_calcTertiaryShift(I HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_checkNeedForRehash()Z HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_findOffsetForAdd(I)I HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_findSecondary(III)Ljava/lang/String; +HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_findSecondary(IIII)Ljava/lang/String; HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_resizeAndFindOffsetForAdd(I)I HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_spilloverStart()I HSPLcom/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer;->_verifyLongName([III)Z @@ -7891,6 +7851,7 @@ HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findFormat(Lcom/fast HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findImplicitPropertyName(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Ljava/lang/String; HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findInjectableValue(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Lcom/fasterxml/jackson/annotation/JacksonInject$Value; HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findInjectableValueId(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findKeySerializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findMergeInfo(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Boolean; HSPLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findNameForDeserialization(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/databind/PropertyName; @@ -7967,7 +7928,9 @@ HSPLcom/fasterxml/jackson/databind/DeserializationConfig;->without(Lcom/fasterxm HSPLcom/fasterxml/jackson/databind/DeserializationContext;->(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/InjectableValues;)V HSPLcom/fasterxml/jackson/databind/DeserializationContext;->(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/deser/DeserializerFactory;)V HSPLcom/fasterxml/jackson/databind/DeserializationContext;->(Lcom/fasterxml/jackson/databind/deser/DeserializerFactory;Lcom/fasterxml/jackson/databind/deser/DeserializerCache;)V +HSPLcom/fasterxml/jackson/databind/DeserializationContext;->constructType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/DeserializationContext;->findContextualValueDeserializer(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/DeserializationContext;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/KeyDeserializer; HSPLcom/fasterxml/jackson/databind/DeserializationContext;->findNonContextualValueDeserializer(Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/DeserializationContext;->findRootValueDeserializer(Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/DeserializationContext;->getAnnotationIntrospector()Lcom/fasterxml/jackson/databind/AnnotationIntrospector; @@ -8021,6 +7984,7 @@ HSPLcom/fasterxml/jackson/databind/JsonNode;->()V HSPLcom/fasterxml/jackson/databind/JsonNode;->iterator()Ljava/util/Iterator; HSPLcom/fasterxml/jackson/databind/JsonSerializable$Base;->()V HSPLcom/fasterxml/jackson/databind/JsonSerializer;->()V +HSPLcom/fasterxml/jackson/databind/KeyDeserializer;->()V HSPLcom/fasterxml/jackson/databind/MapperFeature;->()V HSPLcom/fasterxml/jackson/databind/MapperFeature;->(Ljava/lang/String;IZ)V HSPLcom/fasterxml/jackson/databind/MapperFeature;->enabledByDefault()Z @@ -8142,6 +8106,7 @@ HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->()V HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->(Lcom/fasterxml/jackson/databind/introspect/ClassIntrospector;Lcom/fasterxml/jackson/databind/AnnotationIntrospector;Lcom/fasterxml/jackson/databind/PropertyNamingStrategy;Lcom/fasterxml/jackson/databind/type/TypeFactory;Lcom/fasterxml/jackson/databind/jsontype/TypeResolverBuilder;Ljava/text/DateFormat;Lcom/fasterxml/jackson/databind/cfg/HandlerInstantiator;Ljava/util/Locale;Ljava/util/TimeZone;Lcom/fasterxml/jackson/core/Base64Variant;Lcom/fasterxml/jackson/databind/jsontype/PolymorphicTypeValidator;Lcom/fasterxml/jackson/databind/introspect/AccessorNamingStrategy$Provider;)V HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getAccessorNaming()Lcom/fasterxml/jackson/databind/introspect/AccessorNamingStrategy$Provider; HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getAnnotationIntrospector()Lcom/fasterxml/jackson/databind/AnnotationIntrospector; +HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getBase64Variant()Lcom/fasterxml/jackson/core/Base64Variant; HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getClassIntrospector()Lcom/fasterxml/jackson/databind/introspect/ClassIntrospector; HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getHandlerInstantiator()Lcom/fasterxml/jackson/databind/cfg/HandlerInstantiator; HSPLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getLocale()Ljava/util/Locale; @@ -8204,7 +8169,9 @@ HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->([Lcom/ HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->deserializers()Ljava/lang/Iterable; HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->hasAbstractTypeResolvers()Z HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->hasDeserializerModifiers()Z +HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->hasKeyDeserializers()Z HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->hasValueInstantiators()Z +HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->keyDeserializers()Ljava/lang/Iterable; HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->valueInstantiators()Ljava/lang/Iterable; HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->withAdditionalDeserializers(Lcom/fasterxml/jackson/databind/deser/Deserializers;)Lcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig; HSPLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->withValueInstantiators(Lcom/fasterxml/jackson/databind/deser/ValueInstantiators;)Lcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig; @@ -8217,6 +8184,7 @@ HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->collectFeatureDefaults(Lja HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->constructType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getAccessorNaming()Lcom/fasterxml/jackson/databind/introspect/AccessorNamingStrategy$Provider; HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getAnnotationIntrospector()Lcom/fasterxml/jackson/databind/AnnotationIntrospector; +HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getBase64Variant()Lcom/fasterxml/jackson/core/Base64Variant; HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getClassIntrospector()Lcom/fasterxml/jackson/databind/introspect/ClassIntrospector; HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getDefaultInclusion(Ljava/lang/Class;Ljava/lang/Class;Lcom/fasterxml/jackson/annotation/JsonInclude$Value;)Lcom/fasterxml/jackson/annotation/JsonInclude$Value; HSPLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getDefaultPropertyInclusion(Ljava/lang/Class;Lcom/fasterxml/jackson/annotation/JsonInclude$Value;)Lcom/fasterxml/jackson/annotation/JsonInclude$Value; @@ -8263,6 +8231,7 @@ HSPLcom/fasterxml/jackson/databind/cfg/SerializerFactoryConfig;->withAdditionalS HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$1;->()V HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$ContainerDefaultMappings;->()V HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$ContainerDefaultMappings;->findCollectionFallback(Lcom/fasterxml/jackson/databind/JavaType;)Ljava/lang/Class; +HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$ContainerDefaultMappings;->findMapFallback(Lcom/fasterxml/jackson/databind/JavaType;)Ljava/lang/Class; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$CreatorCollectionState;->(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/introspect/VisibilityChecker;Lcom/fasterxml/jackson/databind/deser/impl/CreatorCollector;Ljava/util/Map;)V HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$CreatorCollectionState;->addImplicitConstructorCandidate(Lcom/fasterxml/jackson/databind/deser/impl/CreatorCandidate;)V HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$CreatorCollectionState;->addImplicitFactoryCandidate(Lcom/fasterxml/jackson/databind/deser/impl/CreatorCandidate;)V @@ -8288,14 +8257,18 @@ HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCreator HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCustomArrayDeserializer(Lcom/fasterxml/jackson/databind/type/ArrayType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCustomBeanDeserializer(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCustomCollectionDeserializer(Lcom/fasterxml/jackson/databind/type/CollectionType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCustomMapDeserializer(Lcom/fasterxml/jackson/databind/type/MapType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCustomTreeNodeDeserializer(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_getSetterInfo(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;Lcom/fasterxml/jackson/databind/PropertyMetadata;)Lcom/fasterxml/jackson/databind/PropertyMetadata; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_handleSingleArgumentCreator(Lcom/fasterxml/jackson/databind/deser/impl/CreatorCollector;Lcom/fasterxml/jackson/databind/introspect/AnnotatedWithParams;ZZ)Z HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_mapAbstractCollectionType(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/DeserializationConfig;)Lcom/fasterxml/jackson/databind/type/CollectionType; +HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_mapAbstractMapType(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/DeserializationConfig;)Lcom/fasterxml/jackson/databind/type/MapType; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_mapAbstractType2(Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->constructCreatorProperty(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/PropertyName;ILcom/fasterxml/jackson/databind/introspect/AnnotatedParameter;Lcom/fasterxml/jackson/annotation/JacksonInject$Value;)Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createArrayDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/type/ArrayType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createCollectionDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/type/CollectionType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createKeyDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/KeyDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createMapDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/type/MapType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createTreeDeserializer(Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->findDefaultDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->findDeserializerFromAnnotation(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/databind/JsonDeserializer; @@ -8314,6 +8287,7 @@ HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializer;->_deserializeWithErro HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;Ljava/lang/Object;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializer;->deserializeFromObject(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializer;->vanillaDeserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/core/JsonToken;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerBase;->()V HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerBase;->(Lcom/fasterxml/jackson/databind/deser/BeanDeserializerBuilder;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/deser/impl/BeanPropertyMap;Ljava/util/Map;Ljava/util/Set;ZLjava/util/Set;Z)V HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerBase;->_delegateDeserializer()Lcom/fasterxml/jackson/databind/JsonDeserializer; @@ -8350,6 +8324,7 @@ HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerBuilder;->setValueInsta HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->()V HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->(Lcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;)V HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->_findUnsupportedTypeDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->_isSetterlessType(Ljava/lang/Class;)Z HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->_validateSubType(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanDescription;)V HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->addBackReferenceProperties(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/deser/BeanDeserializerBuilder;)V HSPLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->addBeanProps(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/deser/BeanDeserializerBuilder;)V @@ -8385,6 +8360,7 @@ HSPLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->( HSPLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->(Lcom/fasterxml/jackson/databind/deser/DeserializerFactory;Lcom/fasterxml/jackson/databind/deser/DeserializerCache;)V HSPLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->checkUnresolvedObjectId()V HSPLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->deserializerInstance(Lcom/fasterxml/jackson/databind/introspect/Annotated;Ljava/lang/Object;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->keyDeserializerInstance(Lcom/fasterxml/jackson/databind/introspect/Annotated;Ljava/lang/Object;)Lcom/fasterxml/jackson/databind/KeyDeserializer; HSPLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->readRootValue(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JsonDeserializer;Ljava/lang/Object;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->()V HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->(I)V @@ -8395,6 +8371,7 @@ HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->_createDeserializer HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->_findCachedDeserializer(Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->_hasCustomHandlers(Lcom/fasterxml/jackson/databind/JavaType;)Z HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->findDeserializerFromAnnotation(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/deser/DeserializerFactory;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/KeyDeserializer; HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->findValueDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/deser/DeserializerFactory;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/DeserializerCache;->modifyTypeByAnnotation(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/introspect/Annotated;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/deser/DeserializerFactory;->()V @@ -8402,6 +8379,7 @@ HSPLcom/fasterxml/jackson/databind/deser/DeserializerFactory;->()V HSPLcom/fasterxml/jackson/databind/deser/Deserializers$Base;->()V HSPLcom/fasterxml/jackson/databind/deser/Deserializers$Base;->findArrayDeserializer(Lcom/fasterxml/jackson/databind/type/ArrayType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/Deserializers$Base;->findCollectionDeserializer(Lcom/fasterxml/jackson/databind/type/CollectionType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/Deserializers$Base;->findMapDeserializer(Lcom/fasterxml/jackson/databind/type/MapType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/Deserializers$Base;->findTreeNodeDeserializer(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/SettableBeanProperty;->()V HSPLcom/fasterxml/jackson/databind/deser/SettableBeanProperty;->(Lcom/fasterxml/jackson/databind/PropertyName;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/PropertyName;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/util/Annotations;Lcom/fasterxml/jackson/databind/PropertyMetadata;)V @@ -8420,7 +8398,11 @@ HSPLcom/fasterxml/jackson/databind/deser/SettableBeanProperty;->hasViews()Z HSPLcom/fasterxml/jackson/databind/deser/SettableBeanProperty;->setViews([Ljava/lang/Class;)V HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator$Base;->(Ljava/lang/Class;)V HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->()V +HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->canCreateFromObjectWith()Z +HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->canCreateUsingArrayDelegate()Z +HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->canCreateUsingDelegate()Z HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/deser/ValueInstantiator; +HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->createFromObjectWith(Lcom/fasterxml/jackson/databind/DeserializationContext;[Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;Lcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->getArrayDelegateCreator()Lcom/fasterxml/jackson/databind/introspect/AnnotatedWithParams; HSPLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->getDelegateCreator()Lcom/fasterxml/jackson/databind/introspect/AnnotatedWithParams; HSPLcom/fasterxml/jackson/databind/deser/impl/BeanPropertyMap;->(ZLjava/util/Collection;Ljava/util/Map;Ljava/util/Locale;)V @@ -8471,6 +8453,10 @@ HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$ArrayListIns HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$ArrayListInstantiator;->()V HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$ArrayListInstantiator;->canCreateUsingDefault()Z HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$ArrayListInstantiator;->createUsingDefault(Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->()V +HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->()V +HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->canCreateUsingDefault()Z +HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->createUsingDefault(Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators;->findStdValueInstantiator(Lcom/fasterxml/jackson/databind/DeserializationConfig;Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/deser/ValueInstantiator; HSPLcom/fasterxml/jackson/databind/deser/impl/NullsConstantProvider;->()V HSPLcom/fasterxml/jackson/databind/deser/impl/NullsConstantProvider;->(Ljava/lang/Object;)V @@ -8484,6 +8470,7 @@ HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->(Lcom/ HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->assignParameter(Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;Ljava/lang/Object;)Z HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->buffered()Lcom/fasterxml/jackson/databind/deser/impl/PropertyValue; HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->getParameter(Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->getParameters([Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;)[Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->handleIdValue(Lcom/fasterxml/jackson/databind/DeserializationContext;Ljava/lang/Object;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->hasParameter(Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;)Z HSPLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->readIdProperty(Ljava/lang/String;)Z @@ -8507,6 +8494,26 @@ HSPLcom/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer;->deserialize( HSPLcom/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer;->getDeserializer(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer;->isCachable()Z +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/deser/ValueInstantiator;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;)V +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->(Lcom/fasterxml/jackson/databind/deser/std/MapDeserializer;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/util/Set;Ljava/util/Set;)V +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->_isStdKeyDeser(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/KeyDeserializer;)Z +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->_readAndBindStringKeyMap(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;Ljava/util/Map;)V +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/util/Map; +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->isCachable()Z +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->resolve(Lcom/fasterxml/jackson/databind/DeserializationContext;)V +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->setIgnorableProperties(Ljava/util/Set;)V +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->setIncludableProperties(Ljava/util/Set;)V +HSPLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->withResolved(Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/util/Set;Ljava/util/Set;)Lcom/fasterxml/jackson/databind/deser/std/MapDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->(Ljava/lang/Class;Ljava/lang/Boolean;)V +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Boolean; +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$DoubleDeserializer;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$DoubleDeserializer;->(Ljava/lang/Class;Ljava/lang/Double;)V +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$FloatDeserializer;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$FloatDeserializer;->(Ljava/lang/Class;Ljava/lang/Float;)V HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$IntegerDeserializer;->()V HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$IntegerDeserializer;->(Ljava/lang/Class;Ljava/lang/Integer;)V HSPLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$IntegerDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Integer; @@ -8527,6 +8534,16 @@ HSPLcom/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer;->deseriali HSPLcom/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)[Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer;->isCachable()Z HSPLcom/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer;->withResolved(Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/lang/Boolean;)Lcom/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$BooleanDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$DoubleDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$FloatDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$IntDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$IntDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$LongDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$LongDeser;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers;->(Ljava/lang/Class;)V +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; +HSPLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers;->forType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->()V HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->(Lcom/fasterxml/jackson/databind/JavaType;)V HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->(Ljava/lang/Class;)V @@ -8540,7 +8557,15 @@ HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->findFormatOverrid HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->findValueNullProvider(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;Lcom/fasterxml/jackson/databind/PropertyMetadata;)Lcom/fasterxml/jackson/databind/deser/NullValueProvider; HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->handleUnknownProperty(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;Ljava/lang/Object;Ljava/lang/String;)V HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->isDefaultDeserializer(Lcom/fasterxml/jackson/databind/JsonDeserializer;)Z +HSPLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->isDefaultKeyDeserializer(Lcom/fasterxml/jackson/databind/KeyDeserializer;)Z +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD;->(Ljava/lang/Class;)V +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD;->forType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD; +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer;->(ILjava/lang/Class;)V +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer;->(ILjava/lang/Class;Lcom/fasterxml/jackson/databind/deser/std/FromStringDeserializer;)V +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer;->forType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializers;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializers;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/KeyDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/StdScalarDeserializer;->(Ljava/lang/Class;)V HSPLcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;->(Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/JavaType;)V HSPLcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;->(Lcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;)V @@ -8562,10 +8587,16 @@ HSPLcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;->createUsingD HSPLcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;->getArrayDelegateCreator()Lcom/fasterxml/jackson/databind/introspect/AnnotatedWithParams; HSPLcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;->getDelegateCreator()Lcom/fasterxml/jackson/databind/introspect/AnnotatedWithParams; HSPLcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator;->getFromObjectArguments(Lcom/fasterxml/jackson/databind/DeserializationConfig;)[Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty; +HSPLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->()V +HSPLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->(Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/lang/Boolean;)V +HSPLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/ValueInstantiator;)V HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/deser/ValueInstantiator;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/lang/Boolean;)V HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; +HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/util/Collection; +HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;Ljava/util/Collection;)Ljava/util/Collection; HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->isCachable()Z HSPLcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer;->withResolved(Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/lang/Boolean;)Lcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer; HSPLcom/fasterxml/jackson/databind/deser/std/StringDeserializer;->()V @@ -8723,6 +8754,7 @@ HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$EmptyCollector HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NCollector;->(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/annotation/Annotation;Ljava/lang/Class;Ljava/lang/annotation/Annotation;)V HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NCollector;->addOrOverride(Ljava/lang/annotation/Annotation;)Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NCollector;->asAnnotationMap()Lcom/fasterxml/jackson/databind/introspect/AnnotationMap; +HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NCollector;->asAnnotations()Lcom/fasterxml/jackson/databind/util/Annotations; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NoAnnotations;->()V HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NoAnnotations;->get(Ljava/lang/Class;)Ljava/lang/annotation/Annotation; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneAnnotation;->(Ljava/lang/Class;Ljava/lang/annotation/Annotation;)V @@ -8731,6 +8763,9 @@ HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector;- HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector;->addOrOverride(Ljava/lang/annotation/Annotation;)Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector;->asAnnotationMap()Lcom/fasterxml/jackson/databind/introspect/AnnotationMap; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector;->asAnnotations()Lcom/fasterxml/jackson/databind/util/Annotations; +HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector;->isPresent(Ljava/lang/annotation/Annotation;)Z +HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$TwoAnnotations;->(Ljava/lang/Class;Ljava/lang/annotation/Annotation;Ljava/lang/Class;Ljava/lang/annotation/Annotation;)V +HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$TwoAnnotations;->get(Ljava/lang/Class;)Ljava/lang/annotation/Annotation; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector;->()V HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector;->(Ljava/lang/Object;)V HSPLcom/fasterxml/jackson/databind/introspect/AnnotationCollector;->emptyAnnotations()Lcom/fasterxml/jackson/databind/util/Annotations; @@ -8751,6 +8786,7 @@ HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findF HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findFormat(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findImplicitPropertyName(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Ljava/lang/String; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findInjectableValue(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Lcom/fasterxml/jackson/annotation/JacksonInject$Value; +HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findKeySerializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findMergeInfo(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Boolean; HSPLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findNameForDeserialization(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/databind/PropertyName; @@ -8895,6 +8931,7 @@ HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->fi HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findFormat(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value; HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findImplicitPropertyName(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Ljava/lang/String; HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findInjectableValue(Lcom/fasterxml/jackson/databind/introspect/AnnotatedMember;)Lcom/fasterxml/jackson/annotation/JacksonInject$Value; +HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findKeySerializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findMergeInfo(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Boolean; HSPLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findNameForDeserialization(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Lcom/fasterxml/jackson/databind/PropertyName; @@ -9244,12 +9281,15 @@ HSPLcom/fasterxml/jackson/databind/ser/impl/IndexedListSerializer;->serializeCon HSPLcom/fasterxml/jackson/databind/ser/impl/IndexedListSerializer;->serializeContentsUsing(Ljava/util/List;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/JsonSerializer;)V HSPLcom/fasterxml/jackson/databind/ser/impl/IndexedListSerializer;->withResolved(Lcom/fasterxml/jackson/databind/BeanProperty;Lcom/fasterxml/jackson/databind/jsontype/TypeSerializer;Lcom/fasterxml/jackson/databind/JsonSerializer;Ljava/lang/Boolean;)Lcom/fasterxml/jackson/databind/ser/impl/IndexedListSerializer; HSPLcom/fasterxml/jackson/databind/ser/impl/IndexedListSerializer;->withResolved(Lcom/fasterxml/jackson/databind/BeanProperty;Lcom/fasterxml/jackson/databind/jsontype/TypeSerializer;Lcom/fasterxml/jackson/databind/JsonSerializer;Ljava/lang/Boolean;)Lcom/fasterxml/jackson/databind/ser/std/AsArraySerializerBase; +HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Double;->(Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;)V +HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Double;->serializerFor(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonSerializer; HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Empty;->()V HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Empty;->(Z)V HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Empty;->newWith(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;)Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap; HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Empty;->serializerFor(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonSerializer; HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$SerializerAndMapResult;->(Lcom/fasterxml/jackson/databind/JsonSerializer;Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;)V HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Single;->(Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;)V +HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Single;->newWith(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;)Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap; HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Single;->serializerFor(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonSerializer; HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;->(Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;)V HSPLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;->(Z)V @@ -9288,6 +9328,8 @@ HSPLcom/fasterxml/jackson/databind/ser/std/BooleanSerializer;->(Z)V HSPLcom/fasterxml/jackson/databind/ser/std/BooleanSerializer;->createContextual(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonSerializer; HSPLcom/fasterxml/jackson/databind/ser/std/BooleanSerializer;->serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V HSPLcom/fasterxml/jackson/databind/ser/std/ByteArraySerializer;->()V +HSPLcom/fasterxml/jackson/databind/ser/std/ByteArraySerializer;->serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V +HSPLcom/fasterxml/jackson/databind/ser/std/ByteArraySerializer;->serialize([BLcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V HSPLcom/fasterxml/jackson/databind/ser/std/CalendarSerializer;->()V HSPLcom/fasterxml/jackson/databind/ser/std/CalendarSerializer;->()V HSPLcom/fasterxml/jackson/databind/ser/std/CalendarSerializer;->(Ljava/lang/Boolean;Ljava/text/DateFormat;)V @@ -9321,6 +9363,7 @@ HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$FloatSerializer;->< HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$IntLikeSerializer;->()V HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$IntLikeSerializer;->()V HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$IntegerSerializer;->(Ljava/lang/Class;)V +HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$IntegerSerializer;->serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$LongSerializer;->(Ljava/lang/Class;)V HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$LongSerializer;->serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V HSPLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$ShortSerializer;->()V @@ -9413,6 +9456,7 @@ HSPLcom/fasterxml/jackson/databind/type/LogicalType;->()V HSPLcom/fasterxml/jackson/databind/type/LogicalType;->(Ljava/lang/String;I)V HSPLcom/fasterxml/jackson/databind/type/LogicalType;->values()[Lcom/fasterxml/jackson/databind/type/LogicalType; HSPLcom/fasterxml/jackson/databind/type/MapLikeType;->(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;Ljava/lang/Object;Ljava/lang/Object;Z)V +HSPLcom/fasterxml/jackson/databind/type/MapLikeType;->equals(Ljava/lang/Object;)Z HSPLcom/fasterxml/jackson/databind/type/MapLikeType;->getContentType()Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/MapLikeType;->getKeyType()Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/MapLikeType;->hasHandlers()Z @@ -9422,6 +9466,9 @@ HSPLcom/fasterxml/jackson/databind/type/MapLikeType;->withHandlersFrom(Lcom/fast HSPLcom/fasterxml/jackson/databind/type/MapType;->(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;Ljava/lang/Object;Ljava/lang/Object;Z)V HSPLcom/fasterxml/jackson/databind/type/MapType;->construct(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/type/MapType; HSPLcom/fasterxml/jackson/databind/type/MapType;->refine(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; +HSPLcom/fasterxml/jackson/databind/type/PlaceholderForType;->(I)V +HSPLcom/fasterxml/jackson/databind/type/PlaceholderForType;->actualType()Lcom/fasterxml/jackson/databind/JavaType; +HSPLcom/fasterxml/jackson/databind/type/PlaceholderForType;->actualType(Lcom/fasterxml/jackson/databind/JavaType;)V HSPLcom/fasterxml/jackson/databind/type/SimpleType;->(Ljava/lang/Class;)V HSPLcom/fasterxml/jackson/databind/type/SimpleType;->(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;)V HSPLcom/fasterxml/jackson/databind/type/SimpleType;->(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;Ljava/lang/Object;Ljava/lang/Object;Z)V @@ -9434,6 +9481,7 @@ HSPLcom/fasterxml/jackson/databind/type/SimpleType;->refine(Ljava/lang/Class;Lco HSPLcom/fasterxml/jackson/databind/type/SimpleType;->toString()Ljava/lang/String; HSPLcom/fasterxml/jackson/databind/type/TypeBase;->()V HSPLcom/fasterxml/jackson/databind/type/TypeBase;->(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;ILjava/lang/Object;Ljava/lang/Object;Z)V +HSPLcom/fasterxml/jackson/databind/type/TypeBase;->findSuperType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/TypeBase;->getBindings()Lcom/fasterxml/jackson/databind/type/TypeBindings; HSPLcom/fasterxml/jackson/databind/type/TypeBase;->getInterfaces()Ljava/util/List; HSPLcom/fasterxml/jackson/databind/type/TypeBase;->getSuperClass()Lcom/fasterxml/jackson/databind/JavaType; @@ -9461,6 +9509,7 @@ HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->()V HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->()V HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->(Lcom/fasterxml/jackson/databind/util/LookupCache;)V HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_applyModifiers(Ljava/lang/reflect/Type;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; +HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_bindingsForSubtype(Lcom/fasterxml/jackson/databind/JavaType;ILjava/lang/Class;Z)Lcom/fasterxml/jackson/databind/type/TypeBindings; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_collectionType(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_constructSimple(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_findWellKnownSimple(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; @@ -9475,7 +9524,9 @@ HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_mapType(Ljava/lang/Class; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_newSimpleType(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;Lcom/fasterxml/jackson/databind/JavaType;[Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_resolveSuperClass(Lcom/fasterxml/jackson/databind/type/ClassStack;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;)Lcom/fasterxml/jackson/databind/JavaType; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_resolveSuperInterfaces(Lcom/fasterxml/jackson/databind/type/ClassStack;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/type/TypeBindings;)[Lcom/fasterxml/jackson/databind/JavaType; +HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_resolveTypePlaceholders(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;)Ljava/lang/String; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_unknownType()Lcom/fasterxml/jackson/databind/JavaType; +HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->_verifyAndResolvePlaceholders(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;)Z HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->constructCollectionType(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/type/CollectionType; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->constructCollectionType(Ljava/lang/Class;Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/type/CollectionType; HSPLcom/fasterxml/jackson/databind/type/TypeFactory;->constructSpecializedType(Lcom/fasterxml/jackson/databind/JavaType;Ljava/lang/Class;Z)Lcom/fasterxml/jackson/databind/JavaType; @@ -9939,7 +9990,6 @@ HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivityCr HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivityDestroyed(Landroid/app/Activity;)V HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivityPaused(Landroid/app/Activity;)V HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivityResumed(Landroid/app/Activity;)V -HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivityStarted(Landroid/app/Activity;)V HSPLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivityStopped(Landroid/app/Activity;)V HSPLcom/google/android/gms/common/internal/Preconditions;->checkNotEmpty(Ljava/lang/String;)Ljava/lang/String; @@ -9984,7 +10034,6 @@ HSPLcom/google/android/material/animation/AnimationUtils;->()V HSPLcom/google/android/material/animation/AnimationUtils;->lerp(FFF)F HSPLcom/google/android/material/animation/ArgbEvaluatorCompat;->()V HSPLcom/google/android/material/animation/ArgbEvaluatorCompat;->()V -HSPLcom/google/android/material/animation/ArgbEvaluatorCompat;->evaluate(FLjava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; HSPLcom/google/android/material/animation/ArgbEvaluatorCompat;->getInstance()Lcom/google/android/material/animation/ArgbEvaluatorCompat; HSPLcom/google/android/material/animation/MotionSpec;->()V HSPLcom/google/android/material/animation/MotionSpec;->addInfoFromAnimator(Lcom/google/android/material/animation/MotionSpec;Landroid/animation/Animator;)V @@ -10092,7 +10141,6 @@ HSPLcom/google/android/material/appbar/AppBarLayout;->setLiftedState(ZZ)Z HSPLcom/google/android/material/appbar/AppBarLayout;->setOrientation(I)V HSPLcom/google/android/material/appbar/AppBarLayout;->setStatusBarForeground(Landroid/graphics/drawable/Drawable;)V HSPLcom/google/android/material/appbar/AppBarLayout;->shouldDrawStatusBarForeground()Z -HSPLcom/google/android/material/appbar/AppBarLayout;->verifyDrawable(Landroid/graphics/drawable/Drawable;)Z HSPLcom/google/android/material/appbar/CollapsingToolbarLayout$1;->(Lcom/google/android/material/appbar/CollapsingToolbarLayout;)V HSPLcom/google/android/material/appbar/CollapsingToolbarLayout$2;->(Lcom/google/android/material/appbar/CollapsingToolbarLayout;)V HSPLcom/google/android/material/appbar/CollapsingToolbarLayout$2;->onAnimationUpdate(Landroid/animation/ValueAnimator;)V @@ -10195,56 +10243,6 @@ HSPLcom/google/android/material/button/MaterialButtonHelper;->setShapeAppearance HSPLcom/google/android/material/button/MaterialButtonHelper;->updateBackground()V HSPLcom/google/android/material/button/MaterialButtonHelper;->updateButtonShape(Lcom/google/android/material/shape/ShapeAppearanceModel;)V HSPLcom/google/android/material/button/MaterialButtonHelper;->wrapDrawableWithInset(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/InsetDrawable; -HSPLcom/google/android/material/card/MaterialCardView;->()V -HSPLcom/google/android/material/card/MaterialCardView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLcom/google/android/material/card/MaterialCardView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLcom/google/android/material/card/MaterialCardView;->isCheckable()Z -HSPLcom/google/android/material/card/MaterialCardView;->isChecked()Z -HSPLcom/google/android/material/card/MaterialCardView;->isDragged()Z -HSPLcom/google/android/material/card/MaterialCardView;->onAttachedToWindow()V -HSPLcom/google/android/material/card/MaterialCardView;->onCreateDrawableState(I)[I -HSPLcom/google/android/material/card/MaterialCardView;->onMeasure(II)V -HSPLcom/google/android/material/card/MaterialCardView;->setAncestorContentPadding(IIII)V -HSPLcom/google/android/material/card/MaterialCardView;->setBackgroundDrawable(Landroid/graphics/drawable/Drawable;)V -HSPLcom/google/android/material/card/MaterialCardView;->setBackgroundInternal(Landroid/graphics/drawable/Drawable;)V -HSPLcom/google/android/material/card/MaterialCardView;->setCardBackgroundColor(I)V -HSPLcom/google/android/material/card/MaterialCardView;->setClickable(Z)V -HSPLcom/google/android/material/card/MaterialCardViewHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/drawable/InsetDrawable;Landroid/graphics/drawable/Drawable;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper$1;->(Lcom/google/android/material/card/MaterialCardViewHelper;Landroid/graphics/drawable/Drawable;IIII)V -HSPLcom/google/android/material/card/MaterialCardViewHelper$1;->getMinimumHeight()I -HSPLcom/google/android/material/card/MaterialCardViewHelper$1;->getMinimumWidth()I -HSPLcom/google/android/material/card/MaterialCardViewHelper$1;->getPadding(Landroid/graphics/Rect;)Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->()V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->(Lcom/google/android/material/card/MaterialCardView;Landroid/util/AttributeSet;II)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->canClipToOutline()Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->createForegroundRippleDrawable()Landroid/graphics/drawable/Drawable; -HSPLcom/google/android/material/card/MaterialCardViewHelper;->createForegroundShapeDrawable()Lcom/google/android/material/shape/MaterialShapeDrawable; -HSPLcom/google/android/material/card/MaterialCardViewHelper;->getBackground()Lcom/google/android/material/shape/MaterialShapeDrawable; -HSPLcom/google/android/material/card/MaterialCardViewHelper;->getClickableForeground()Landroid/graphics/drawable/Drawable; -HSPLcom/google/android/material/card/MaterialCardViewHelper;->getParentCardViewCalculatedCornerPadding()F -HSPLcom/google/android/material/card/MaterialCardViewHelper;->insetDrawable(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable; -HSPLcom/google/android/material/card/MaterialCardViewHelper;->isCheckable()Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->isCheckedIconBottom()Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->isCheckedIconEnd()Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->loadFromAttributes(Landroid/content/res/TypedArray;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->recalculateCheckedIconPosition(II)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setCardBackgroundColor(Landroid/content/res/ColorStateList;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setCardForegroundColor(Landroid/content/res/ColorStateList;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setChecked(Z)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setChecked(ZZ)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setCheckedIcon(Landroid/graphics/drawable/Drawable;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setCheckedIconMargin(I)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setCheckedIconSize(I)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setShapeAppearanceModel(Lcom/google/android/material/shape/ShapeAppearanceModel;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->setUserContentPadding(IIII)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->shouldAddCornerPaddingInsideCardBackground()Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->shouldAddCornerPaddingOutsideCardBackground()Z -HSPLcom/google/android/material/card/MaterialCardViewHelper;->updateClickable()V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->updateContentPadding()V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->updateElevation()V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->updateInsetForeground(Landroid/graphics/drawable/Drawable;)V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->updateRippleColor()V -HSPLcom/google/android/material/card/MaterialCardViewHelper;->updateStroke()V HSPLcom/google/android/material/chip/Chip$$ExternalSyntheticLambda0;->(Lcom/google/android/material/chip/Chip;)V HSPLcom/google/android/material/chip/Chip$1;->(Lcom/google/android/material/chip/Chip;)V HSPLcom/google/android/material/chip/Chip$1;->onFontRetrieved(Landroid/graphics/Typeface;Z)V @@ -10368,7 +10366,6 @@ HSPLcom/google/android/material/elevation/ElevationOverlayProvider;->(ZIII HSPLcom/google/android/material/elevation/ElevationOverlayProvider;->compositeOverlayIfNeeded(IF)I HSPLcom/google/android/material/elevation/ElevationOverlayProvider;->isThemeElevationOverlayEnabled()Z HSPLcom/google/android/material/expandable/ExpandableWidgetHelper;->(Lcom/google/android/material/expandable/ExpandableWidget;)V -HSPLcom/google/android/material/expandable/ExpandableWidgetHelper;->onSaveInstanceState()Landroid/os/Bundle; HSPLcom/google/android/material/floatingactionbutton/BorderDrawable$BorderState;->(Lcom/google/android/material/floatingactionbutton/BorderDrawable;)V HSPLcom/google/android/material/floatingactionbutton/BorderDrawable$BorderState;->(Lcom/google/android/material/floatingactionbutton/BorderDrawable;Lcom/google/android/material/floatingactionbutton/BorderDrawable$1;)V HSPLcom/google/android/material/floatingactionbutton/BorderDrawable;->(Lcom/google/android/material/shape/ShapeAppearanceModel;)V @@ -10399,7 +10396,6 @@ HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->getS HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->jumpDrawablesToCurrentState()V HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->onAttachedToWindow()V HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->onMeasure(II)V -HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->onSaveInstanceState()Landroid/os/Parcelable; HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->setElevation(F)V HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->setImageDrawable(Landroid/graphics/drawable/Drawable;)V HSPLcom/google/android/material/floatingactionbutton/FloatingActionButton;->setMaxImageSize(I)V @@ -10461,21 +10457,6 @@ HSPLcom/google/android/material/imageview/ShapeableImageView;->access$000(Lcom/g HSPLcom/google/android/material/imageview/ShapeableImageView;->access$100(Lcom/google/android/material/imageview/ShapeableImageView;)Lcom/google/android/material/shape/MaterialShapeDrawable; HSPLcom/google/android/material/imageview/ShapeableImageView;->access$102(Lcom/google/android/material/imageview/ShapeableImageView;Lcom/google/android/material/shape/MaterialShapeDrawable;)Lcom/google/android/material/shape/MaterialShapeDrawable; HSPLcom/google/android/material/imageview/ShapeableImageView;->access$200(Lcom/google/android/material/imageview/ShapeableImageView;)Landroid/graphics/RectF; -HSPLcom/google/android/material/imageview/ShapeableImageView;->drawStroke(Landroid/graphics/Canvas;)V -HSPLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingBottom()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingLeft()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingRight()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingTop()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getPaddingBottom()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getPaddingLeft()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getPaddingRight()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->getPaddingTop()I -HSPLcom/google/android/material/imageview/ShapeableImageView;->isContentPaddingRelative()Z -HSPLcom/google/android/material/imageview/ShapeableImageView;->onDraw(Landroid/graphics/Canvas;)V -HSPLcom/google/android/material/imageview/ShapeableImageView;->onMeasure(II)V -HSPLcom/google/android/material/imageview/ShapeableImageView;->onSizeChanged(IIII)V -HSPLcom/google/android/material/imageview/ShapeableImageView;->setPadding(IIII)V -HSPLcom/google/android/material/imageview/ShapeableImageView;->updateShapeMask(II)V HSPLcom/google/android/material/internal/CollapsingTextHelper$1;->(Lcom/google/android/material/internal/CollapsingTextHelper;)V HSPLcom/google/android/material/internal/CollapsingTextHelper$1;->apply(Landroid/graphics/Typeface;)V HSPLcom/google/android/material/internal/CollapsingTextHelper$2;->(Lcom/google/android/material/internal/CollapsingTextHelper;)V @@ -10655,8 +10636,6 @@ HSPLcom/google/android/material/shape/MaterialShapeDrawable;->requiresCompatShad HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setColorFilter(Landroid/graphics/ColorFilter;)V HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setElevation(F)V HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setFillColor(Landroid/content/res/ColorStateList;)V -HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setShadowBitmapDrawingEnable(Z)V -HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setShadowColor(I)V HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setShapeAppearanceModel(Lcom/google/android/material/shape/ShapeAppearanceModel;)V HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setStroke(FI)V HSPLcom/google/android/material/shape/MaterialShapeDrawable;->setStroke(FLandroid/content/res/ColorStateList;)V @@ -10675,8 +10654,6 @@ HSPLcom/google/android/material/shape/MaterialShapeUtils;->setElevation(Landroid HSPLcom/google/android/material/shape/MaterialShapeUtils;->setParentAbsoluteElevation(Landroid/view/View;)V HSPLcom/google/android/material/shape/MaterialShapeUtils;->setParentAbsoluteElevation(Landroid/view/View;Lcom/google/android/material/shape/MaterialShapeDrawable;)V HSPLcom/google/android/material/shape/RelativeCornerSize;->(F)V -HSPLcom/google/android/material/shape/RelativeCornerSize;->getCornerSize(Landroid/graphics/RectF;)F -HSPLcom/google/android/material/shape/RelativeCornerSize;->getMaxCornerSize(Landroid/graphics/RectF;)F HSPLcom/google/android/material/shape/RoundedCornerTreatment;->()V HSPLcom/google/android/material/shape/RoundedCornerTreatment;->getCornerPath(Lcom/google/android/material/shape/ShapePath;FFF)V HSPLcom/google/android/material/shape/ShapeAppearanceModel$Builder;->()V @@ -10806,9 +10783,6 @@ HSPLcom/google/android/material/shape/ShapePath;->setEndX(F)V HSPLcom/google/android/material/shape/ShapePath;->setEndY(F)V HSPLcom/google/android/material/shape/ShapePath;->setStartX(F)V HSPLcom/google/android/material/shape/ShapePath;->setStartY(F)V -HSPLcom/google/android/material/stateful/ExtendableSavedState$1;->()V -HSPLcom/google/android/material/stateful/ExtendableSavedState;->()V -HSPLcom/google/android/material/stateful/ExtendableSavedState;->(Landroid/os/Parcelable;)V HSPLcom/google/android/material/theme/overlay/MaterialThemeOverlay;->()V HSPLcom/google/android/material/theme/overlay/MaterialThemeOverlay;->obtainAndroidThemeOverlayId(Landroid/content/Context;Landroid/util/AttributeSet;)I HSPLcom/google/android/material/theme/overlay/MaterialThemeOverlay;->obtainMaterialThemeOverlayId(Landroid/content/Context;Landroid/util/AttributeSet;II)I @@ -10816,9 +10790,9 @@ HSPLcom/google/android/material/theme/overlay/MaterialThemeOverlay;->wrap(Landro HSPLcom/google/common/base/Ascii;->isLowerCase(C)Z HSPLcom/google/common/base/Ascii;->toUpperCase(Ljava/lang/String;)Ljava/lang/String; HSPLcom/google/common/base/Charsets;->()V -HSPLcom/google/common/base/MoreObjects;->firstNonNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLcom/google/common/base/Objects;->equal(Ljava/lang/Object;Ljava/lang/Object;)Z HSPLcom/google/common/base/Objects;->hashCode([Ljava/lang/Object;)I +HSPLcom/google/common/base/Preconditions;->checkArgument(ZLjava/lang/Object;)V HSPLcom/google/common/base/Preconditions;->checkElementIndex(II)I HSPLcom/google/common/base/Preconditions;->checkElementIndex(IILjava/lang/String;)I HSPLcom/google/common/base/Preconditions;->checkNotNull(Ljava/lang/Object;)Ljava/lang/Object; @@ -10830,8 +10804,6 @@ HSPLcom/google/common/base/Suppliers$NonSerializableMemoizingSupplier;->(L HSPLcom/google/common/base/Suppliers$NonSerializableMemoizingSupplier;->get()Ljava/lang/Object; HSPLcom/google/common/base/Suppliers;->memoize(Lcom/google/common/base/Supplier;)Lcom/google/common/base/Supplier; HSPLcom/google/common/collect/AbstractIndexedListIterator;->(II)V -HSPLcom/google/common/collect/AbstractIndexedListIterator;->hasNext()Z -HSPLcom/google/common/collect/AbstractIndexedListIterator;->next()Ljava/lang/Object; HSPLcom/google/common/collect/CollectPreconditions;->checkEntryNotNull(Ljava/lang/Object;Ljava/lang/Object;)V HSPLcom/google/common/collect/CollectPreconditions;->checkNonnegative(ILjava/lang/String;)I HSPLcom/google/common/collect/ComparatorOrdering;->(Ljava/util/Comparator;)V @@ -10851,14 +10823,11 @@ HSPLcom/google/common/collect/ImmutableCollection$Builder;->()V HSPLcom/google/common/collect/ImmutableCollection$Builder;->expandedCapacity(II)I HSPLcom/google/common/collect/ImmutableCollection;->()V HSPLcom/google/common/collect/ImmutableCollection;->()V -HSPLcom/google/common/collect/ImmutableCollection;->toArray()[Ljava/lang/Object; -HSPLcom/google/common/collect/ImmutableCollection;->toArray([Ljava/lang/Object;)[Ljava/lang/Object; HSPLcom/google/common/collect/ImmutableList$Builder;->()V HSPLcom/google/common/collect/ImmutableList$Builder;->(I)V HSPLcom/google/common/collect/ImmutableList$Builder;->add(Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList$Builder; HSPLcom/google/common/collect/ImmutableList$Builder;->build()Lcom/google/common/collect/ImmutableList; HSPLcom/google/common/collect/ImmutableList$Itr;->(Lcom/google/common/collect/ImmutableList;I)V -HSPLcom/google/common/collect/ImmutableList$Itr;->get(I)Ljava/lang/Object; HSPLcom/google/common/collect/ImmutableList;->()V HSPLcom/google/common/collect/ImmutableList;->()V HSPLcom/google/common/collect/ImmutableList;->asImmutableList([Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList; @@ -10869,10 +10838,6 @@ HSPLcom/google/common/collect/ImmutableList;->construct([Ljava/lang/Object;)Lcom HSPLcom/google/common/collect/ImmutableList;->copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList; HSPLcom/google/common/collect/ImmutableList;->copyOf([Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList; HSPLcom/google/common/collect/ImmutableList;->equals(Ljava/lang/Object;)Z -HSPLcom/google/common/collect/ImmutableList;->iterator()Lcom/google/common/collect/UnmodifiableIterator; -HSPLcom/google/common/collect/ImmutableList;->iterator()Ljava/util/Iterator; -HSPLcom/google/common/collect/ImmutableList;->listIterator()Lcom/google/common/collect/UnmodifiableListIterator; -HSPLcom/google/common/collect/ImmutableList;->listIterator(I)Lcom/google/common/collect/UnmodifiableListIterator; HSPLcom/google/common/collect/ImmutableList;->of()Lcom/google/common/collect/ImmutableList; HSPLcom/google/common/collect/ImmutableList;->of(Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList; HSPLcom/google/common/collect/ImmutableList;->of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList; @@ -10891,25 +10856,22 @@ HSPLcom/google/common/collect/ImmutableMap;->()V HSPLcom/google/common/collect/ImmutableMap;->()V HSPLcom/google/common/collect/ImmutableMap;->copyOf(Ljava/lang/Iterable;)Lcom/google/common/collect/ImmutableMap; HSPLcom/google/common/collect/ImmutableMap;->copyOf(Ljava/util/Map;)Lcom/google/common/collect/ImmutableMap; -HSPLcom/google/common/collect/ImmutableMap;->equals(Ljava/lang/Object;)Z HSPLcom/google/common/collect/ImmutableMap;->isEmpty()Z HSPLcom/google/common/collect/ImmutableMap;->of()Lcom/google/common/collect/ImmutableMap; -HSPLcom/google/common/collect/ImmutableMap;->values()Lcom/google/common/collect/ImmutableCollection; HSPLcom/google/common/collect/ImmutableSet$Builder;->()V HSPLcom/google/common/collect/ImmutableSet$Builder;->add([Ljava/lang/Object;)Lcom/google/common/collect/ImmutableSet$Builder; HSPLcom/google/common/collect/ImmutableSet$Builder;->build()Lcom/google/common/collect/ImmutableSet; HSPLcom/google/common/collect/ImmutableSet;->()V HSPLcom/google/common/collect/ImmutableSet;->access$100(I[Ljava/lang/Object;)Lcom/google/common/collect/ImmutableSet; -HSPLcom/google/common/collect/ImmutableSet;->asList()Lcom/google/common/collect/ImmutableList; HSPLcom/google/common/collect/ImmutableSet;->chooseTableSize(I)I HSPLcom/google/common/collect/ImmutableSet;->construct(I[Ljava/lang/Object;)Lcom/google/common/collect/ImmutableSet; HSPLcom/google/common/collect/ImmutableSet;->copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableSet; -HSPLcom/google/common/collect/ImmutableSet;->equals(Ljava/lang/Object;)Z HSPLcom/google/common/collect/ImmutableSet;->of()Lcom/google/common/collect/ImmutableSet; +HSPLcom/google/common/collect/ImmutableSet;->of(Ljava/lang/Object;)Lcom/google/common/collect/ImmutableSet; HSPLcom/google/common/collect/ImmutableSet;->of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableSet; +HSPLcom/google/common/collect/ImmutableSet;->of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lcom/google/common/collect/ImmutableSet; HSPLcom/google/common/collect/ImmutableSet;->shouldTrim(II)Z HSPLcom/google/common/collect/Lists;->equalsImpl(Ljava/util/List;Ljava/lang/Object;)Z -HSPLcom/google/common/collect/Maps;->equalsImpl(Ljava/util/Map;Ljava/lang/Object;)Z HSPLcom/google/common/collect/Maps;->newIdentityHashMap()Ljava/util/IdentityHashMap; HSPLcom/google/common/collect/ObjectArrays;->checkElementNotNull(Ljava/lang/Object;I)Ljava/lang/Object; HSPLcom/google/common/collect/ObjectArrays;->checkElementsNotNull([Ljava/lang/Object;)[Ljava/lang/Object; @@ -10920,36 +10882,24 @@ HSPLcom/google/common/collect/RegularImmutableBiMap;->()V HSPLcom/google/common/collect/RegularImmutableBiMap;->()V HSPLcom/google/common/collect/RegularImmutableList;->()V HSPLcom/google/common/collect/RegularImmutableList;->([Ljava/lang/Object;I)V -HSPLcom/google/common/collect/RegularImmutableList;->copyIntoArray([Ljava/lang/Object;I)I HSPLcom/google/common/collect/RegularImmutableList;->get(I)Ljava/lang/Object; HSPLcom/google/common/collect/RegularImmutableList;->isPartialView()Z HSPLcom/google/common/collect/RegularImmutableList;->size()I -HSPLcom/google/common/collect/RegularImmutableMap$KeysOrValuesAsList;->([Ljava/lang/Object;II)V -HSPLcom/google/common/collect/RegularImmutableMap$KeysOrValuesAsList;->size()I HSPLcom/google/common/collect/RegularImmutableMap;->()V HSPLcom/google/common/collect/RegularImmutableMap;->(Ljava/lang/Object;[Ljava/lang/Object;I)V HSPLcom/google/common/collect/RegularImmutableMap;->create(I[Ljava/lang/Object;Lcom/google/common/collect/ImmutableMap$Builder;)Lcom/google/common/collect/RegularImmutableMap; HSPLcom/google/common/collect/RegularImmutableMap;->createHashTable([Ljava/lang/Object;III)Ljava/lang/Object; -HSPLcom/google/common/collect/RegularImmutableMap;->createValues()Lcom/google/common/collect/ImmutableCollection; HSPLcom/google/common/collect/RegularImmutableMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLcom/google/common/collect/RegularImmutableMap;->get(Ljava/lang/Object;[Ljava/lang/Object;IILjava/lang/Object;)Ljava/lang/Object; HSPLcom/google/common/collect/RegularImmutableMap;->size()I HSPLcom/google/common/collect/RegularImmutableSet;->()V HSPLcom/google/common/collect/RegularImmutableSet;->([Ljava/lang/Object;I[Ljava/lang/Object;II)V HSPLcom/google/common/collect/RegularImmutableSet;->contains(Ljava/lang/Object;)Z -HSPLcom/google/common/collect/RegularImmutableSet;->copyIntoArray([Ljava/lang/Object;I)I -HSPLcom/google/common/collect/RegularImmutableSet;->createAsList()Lcom/google/common/collect/ImmutableList; -HSPLcom/google/common/collect/RegularImmutableSet;->iterator()Lcom/google/common/collect/UnmodifiableIterator; HSPLcom/google/common/collect/RegularImmutableSet;->size()I -HSPLcom/google/common/collect/Sets$2;->(Ljava/util/Set;Ljava/util/Set;)V -HSPLcom/google/common/collect/Sets$2;->isEmpty()Z -HSPLcom/google/common/collect/Sets$SetView;->()V -HSPLcom/google/common/collect/Sets$SetView;->(Lcom/google/common/collect/Sets$1;)V -HSPLcom/google/common/collect/Sets;->intersection(Ljava/util/Set;Ljava/util/Set;)Lcom/google/common/collect/Sets$SetView; HSPLcom/google/common/collect/Sets;->newIdentityHashSet()Ljava/util/Set; +HSPLcom/google/common/collect/SingletonImmutableSet;->(Ljava/lang/Object;)V HSPLcom/google/common/collect/UnmodifiableIterator;->()V HSPLcom/google/common/collect/UnmodifiableListIterator;->()V -HSPLcom/google/common/primitives/Ints;->toArray(Ljava/util/Collection;)[I HSPLcom/google/common/util/concurrent/AbstractFuture$AtomicHelper;->()V HSPLcom/google/common/util/concurrent/AbstractFuture$AtomicHelper;->(Lcom/google/common/util/concurrent/AbstractFuture$1;)V HSPLcom/google/common/util/concurrent/AbstractFuture$Listener;->()V @@ -11334,7 +11284,6 @@ HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivityCreated(Land HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivityDestroyed(Landroid/app/Activity;)V HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivityPaused(Landroid/app/Activity;)V HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V -HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V HSPLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V HSPLcom/google/firebase/messaging/FirebaseMessaging$$ExternalSyntheticLambda1;->(Lcom/google/firebase/messaging/FirebaseMessaging;)V @@ -11442,7 +11391,6 @@ HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->()V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->(Lcom/google/i18n/phonenumbers/metadata/source/MetadataSource;Ljava/util/Map;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->buildNationalNumberForParsing(Ljava/lang/String;Ljava/lang/StringBuilder;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->checkRegionForParsing(Ljava/lang/CharSequence;Ljava/lang/String;)Z -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->chooseFormattingPatternForNumber(Ljava/util/List;Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->createExtnPattern(Z)Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->createInstance(Lcom/google/i18n/phonenumbers/MetadataLoader;)Lcom/google/i18n/phonenumbers/PhoneNumberUtil; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->createInstance(Lcom/google/i18n/phonenumbers/metadata/source/MetadataSource;)Lcom/google/i18n/phonenumbers/PhoneNumberUtil; @@ -11451,26 +11399,14 @@ HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->extnDigits(I)Ljava/lang/Strin HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->extractCountryCode(Ljava/lang/StringBuilder;Ljava/lang/StringBuilder;)I HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->extractPhoneContext(Ljava/lang/String;I)Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->extractPossibleNumber(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->format(Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->format(Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;Ljava/lang/StringBuilder;)V -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->formatNsn(Ljava/lang/String;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->formatNsn(Ljava/lang/String;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;Ljava/lang/CharSequence;)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->formatNsnUsingPattern(Ljava/lang/String;Lcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;Ljava/lang/CharSequence;)Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getInstance()Lcom/google/i18n/phonenumbers/PhoneNumberUtil; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getMetadataForRegion(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getMetadataForRegionOrCallingCode(ILjava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getNationalSignificantNumber(Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getNumberDescByType(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getNumberTypeHelper(Ljava/lang/String;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;)Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForCountryCode(I)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForNumber(Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForNumberFromRegionList(Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/util/List;)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->hasValidCountryCallingCode(I)Z -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->isNumberMatchingDesc(Ljava/lang/String;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Z HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->isPhoneContextValid(Ljava/lang/String;)Z HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->isValidRegionCode(Ljava/lang/String;)Z HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->isViablePhoneNumber(Ljava/lang/CharSequence;)Z -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->maybeAppendFormattedExtension(Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;Ljava/lang/StringBuilder;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->maybeExtractCountryCode(Ljava/lang/CharSequence;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;Ljava/lang/StringBuilder;ZLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;)I HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->maybeStripExtension(Ljava/lang/StringBuilder;)Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->maybeStripInternationalPrefixAndNormalize(Ljava/lang/StringBuilder;Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; @@ -11481,52 +11417,30 @@ HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->normalizeDigitsOnly(Ljava/lan HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->parse(Ljava/lang/CharSequence;Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->parse(Ljava/lang/CharSequence;Ljava/lang/String;Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->parseHelper(Ljava/lang/CharSequence;Ljava/lang/String;ZZLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;)V -HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->prefixNumberWithCountryCallingCode(ILcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;Ljava/lang/StringBuilder;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->setInstance(Lcom/google/i18n/phonenumbers/PhoneNumberUtil;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->setItalianLeadingZerosForPhoneNumber(Ljava/lang/CharSequence;Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;)V HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->testNumberLength(Ljava/lang/CharSequence;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;)Lcom/google/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; HSPLcom/google/i18n/phonenumbers/PhoneNumberUtil;->testNumberLength(Ljava/lang/CharSequence;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;Lcom/google/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;)Lcom/google/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->()V -HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->getFormat()Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->getLeadingDigitsPattern(I)Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->getLeadingDigitsPatternCount()I -HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->getNationalPrefixFormattingRule()Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->getPattern()Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->readExternal(Ljava/io/ObjectInput;)V HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->setFormat(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat; HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->setNationalPrefixOptionalWhenFormatting(Z)Lcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat; HSPLcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat;->setPattern(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$NumberFormat; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->()V -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getFixedLine()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getGeneralDesc()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getId()Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getIntlNumberFormatList()Ljava/util/List; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getLeadingDigits()Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixForParsing()Ljava/lang/String; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNumberFormatList()Ljava/util/List; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPager()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPersonalNumber()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPremiumRate()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getSameMobileAndFixedLinePattern()Z -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getSharedCost()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getTollFree()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getUan()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getVoicemail()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getVoip()Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasLeadingDigits()Z HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->readExternal(Ljava/io/ObjectInput;)V HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setCountryCode(I)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setFixedLine(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setGeneralDesc(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setId(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setInternationalPrefix(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setLeadingDigits(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setMainCountryForCode(Z)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setMobile(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setMobileNumberPortableRegion(Z)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setNationalPrefix(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setNationalPrefixForParsing(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setNationalPrefixTransformRule(Ljava/lang/String;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setNoInternationalDialling(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setPager(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->setPersonalNumber(Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;)Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadata; @@ -11541,7 +11455,6 @@ HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->( HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->getMetadataList()Ljava/util/List; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->readExternal(Ljava/io/ObjectInput;)V HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->()V -HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getNationalNumberPattern()Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getPossibleLengthList()Ljava/util/List; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getPossibleLengthLocalOnlyList()Ljava/util/List; HSPLcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->readExternal(Ljava/io/ObjectInput;)V @@ -11553,16 +11466,11 @@ HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->values()[Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->()V HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCode()I -HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->getNationalNumber()J -HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasExtension()Z -HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->isItalianLeadingZero()Z HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->setCountryCode(I)Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber; HSPLcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber;->setNationalNumber(J)Lcom/google/i18n/phonenumbers/Phonenumber$PhoneNumber; HSPLcom/google/i18n/phonenumbers/internal/GeoEntityUtility;->isGeoEntity(Ljava/lang/String;)Z HSPLcom/google/i18n/phonenumbers/internal/RegexBasedMatcher;->()V HSPLcom/google/i18n/phonenumbers/internal/RegexBasedMatcher;->create()Lcom/google/i18n/phonenumbers/internal/MatcherApi; -HSPLcom/google/i18n/phonenumbers/internal/RegexBasedMatcher;->match(Ljava/lang/CharSequence;Ljava/util/regex/Pattern;Z)Z -HSPLcom/google/i18n/phonenumbers/internal/RegexBasedMatcher;->matchNationalNumber(Ljava/lang/CharSequence;Lcom/google/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;Z)Z HSPLcom/google/i18n/phonenumbers/internal/RegexCache$LRUCache$1;->(Lcom/google/i18n/phonenumbers/internal/RegexCache$LRUCache;IFZ)V HSPLcom/google/i18n/phonenumbers/internal/RegexCache$LRUCache$1;->removeEldestEntry(Ljava/util/Map$Entry;)Z HSPLcom/google/i18n/phonenumbers/internal/RegexCache$LRUCache;->(I)V @@ -11612,8 +11520,6 @@ HSPLcom/google/i18n/phonenumbers/metadata/source/MultiFileModeFileNameProvider;- HSPLcom/google/i18n/phonenumbers/metadata/source/MultiFileModeFileNameProvider;->getFor(Ljava/lang/Object;)Ljava/lang/String; HSPLcom/google/i18n/phonenumbers/metadata/source/RegionMetadataSourceImpl;->(Lcom/google/i18n/phonenumbers/metadata/source/PhoneMetadataFileNameProvider;Lcom/google/i18n/phonenumbers/MetadataLoader;Lcom/google/i18n/phonenumbers/metadata/init/MetadataParser;)V HSPLcom/google/i18n/phonenumbers/metadata/source/RegionMetadataSourceImpl;->(Lcom/google/i18n/phonenumbers/metadata/source/PhoneMetadataFileNameProvider;Lcom/google/i18n/phonenumbers/metadata/source/MetadataBootstrappingGuard;)V -HSPLcom/klinker/android/send_message/MmsFileProvider;->()V -HSPLcom/klinker/android/send_message/MmsFileProvider;->onCreate()Z HSPLcom/makeramen/roundedimageview/RoundedDrawable$1;->()V HSPLcom/makeramen/roundedimageview/RoundedDrawable;->(Landroid/graphics/Bitmap;)V HSPLcom/makeramen/roundedimageview/RoundedDrawable;->drawableToBitmap(Landroid/graphics/drawable/Drawable;)Landroid/graphics/Bitmap; @@ -11628,6 +11534,7 @@ HSPLcom/pnikosis/materialishprogress/ProgressWheel;->()V HSPLcom/pnikosis/materialishprogress/ProgressWheel;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLcom/pnikosis/materialishprogress/ProgressWheel;->onVisibilityChanged(Landroid/view/View;I)V HSPLcom/pnikosis/materialishprogress/ProgressWheel;->parseAttributes(Landroid/content/res/TypedArray;)V +HSPLcom/pnikosis/materialishprogress/ProgressWheel;->setAnimationEnabled()V HSPLcom/pnikosis/materialishprogress/ProgressWheel;->setBarColor(I)V HSPLcom/pnikosis/materialishprogress/ProgressWheel;->setupPaints()V HSPLcom/pnikosis/materialishprogress/ProgressWheel;->spin()V @@ -11644,6 +11551,8 @@ HSPLcom/squareup/wire/Message$Companion;->()V HSPLcom/squareup/wire/Message$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLcom/squareup/wire/Message;->()V HSPLcom/squareup/wire/Message;->(Lcom/squareup/wire/ProtoAdapter;Lokio/ByteString;)V +HSPLcom/squareup/wire/Message;->encode()[B +HSPLcom/squareup/wire/Message;->unknownFields()Lokio/ByteString; HSPLcom/squareup/wire/PackedProtoAdapter;->(Lcom/squareup/wire/ProtoAdapter;)V HSPLcom/squareup/wire/ProtoAdapter$Companion;->()V HSPLcom/squareup/wire/ProtoAdapter$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -11651,6 +11560,10 @@ HSPLcom/squareup/wire/ProtoAdapter;->()V HSPLcom/squareup/wire/ProtoAdapter;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Ljava/lang/String;Lcom/squareup/wire/Syntax;)V HSPLcom/squareup/wire/ProtoAdapter;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Ljava/lang/String;Lcom/squareup/wire/Syntax;Ljava/lang/Object;)V HSPLcom/squareup/wire/ProtoAdapter;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Ljava/lang/String;Lcom/squareup/wire/Syntax;Ljava/lang/Object;Ljava/lang/String;)V +HSPLcom/squareup/wire/ProtoAdapter;->decode(Lokio/BufferedSource;)Ljava/lang/Object; +HSPLcom/squareup/wire/ProtoAdapter;->decode([B)Ljava/lang/Object; +HSPLcom/squareup/wire/ProtoAdapter;->encode(Ljava/lang/Object;)[B +HSPLcom/squareup/wire/ProtoAdapter;->encode(Lokio/BufferedSink;Ljava/lang/Object;)V HSPLcom/squareup/wire/ProtoAdapter;->getFieldEncoding$wire_runtime()Lcom/squareup/wire/FieldEncoding; HSPLcom/squareup/wire/ProtoAdapter;->getIdentity()Ljava/lang/Object; HSPLcom/squareup/wire/ProtoAdapter;->getSyntax()Lcom/squareup/wire/Syntax; @@ -11699,7 +11612,24 @@ HSPLcom/squareup/wire/ProtoAdapterKt;->commonStructValue()Lcom/squareup/wire/Pro HSPLcom/squareup/wire/ProtoAdapterKt;->commonUint32()Lcom/squareup/wire/ProtoAdapter; HSPLcom/squareup/wire/ProtoAdapterKt;->commonUint64()Lcom/squareup/wire/ProtoAdapter; HSPLcom/squareup/wire/ProtoAdapterKt;->commonWrapper(Lcom/squareup/wire/ProtoAdapter;Ljava/lang/String;)Lcom/squareup/wire/ProtoAdapter; +HSPLcom/squareup/wire/ProtoReader$Companion;->()V +HSPLcom/squareup/wire/ProtoReader$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLcom/squareup/wire/ProtoReader;->()V +HSPLcom/squareup/wire/ProtoReader;->(Lokio/BufferedSource;)V +HSPLcom/squareup/wire/ProtoReader;->beginMessage()J +HSPLcom/squareup/wire/ProtoReader;->endMessageAndGetUnknownFields(J)Lokio/ByteString; +HSPLcom/squareup/wire/ProtoReader;->nextTag()I HSPLcom/squareup/wire/RepeatedProtoAdapter;->(Lcom/squareup/wire/ProtoAdapter;)V +HSPLcom/squareup/wire/ReverseProtoWriter$Companion;->()V +HSPLcom/squareup/wire/ReverseProtoWriter$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLcom/squareup/wire/ReverseProtoWriter$forwardBuffer$2;->()V +HSPLcom/squareup/wire/ReverseProtoWriter$forwardBuffer$2;->()V +HSPLcom/squareup/wire/ReverseProtoWriter$forwardWriter$2;->(Lcom/squareup/wire/ReverseProtoWriter;)V +HSPLcom/squareup/wire/ReverseProtoWriter;->()V +HSPLcom/squareup/wire/ReverseProtoWriter;->()V +HSPLcom/squareup/wire/ReverseProtoWriter;->emitCurrentSegment()V +HSPLcom/squareup/wire/ReverseProtoWriter;->writeBytes(Lokio/ByteString;)V +HSPLcom/squareup/wire/ReverseProtoWriter;->writeTo(Lokio/BufferedSink;)V HSPLcom/squareup/wire/Syntax$Companion;->()V HSPLcom/squareup/wire/Syntax$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLcom/squareup/wire/Syntax;->$values()[Lcom/squareup/wire/Syntax; @@ -11711,11 +11641,13 @@ HSPLcom/squareup/wire/internal/ImmutableList;->getSize()I HSPLcom/squareup/wire/internal/Internal;->checkElementsNotNull(Ljava/util/List;)V HSPLcom/squareup/wire/internal/Internal;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;)I HSPLcom/squareup/wire/internal/Internal;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I +HSPLcom/squareup/wire/internal/Internal;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)I HSPLcom/squareup/wire/internal/Internal;->immutableCopyOf(Ljava/lang/String;Ljava/util/List;)Ljava/util/List; HSPLcom/squareup/wire/internal/Internal__InternalKt;->checkElementsNotNull(Ljava/util/List;)V HSPLcom/squareup/wire/internal/Internal__InternalKt;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;)I HSPLcom/squareup/wire/internal/Internal__InternalKt;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I HSPLcom/squareup/wire/internal/Internal__InternalKt;->countNonNull(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)I +HSPLcom/squareup/wire/internal/Internal__InternalKt;->immutableCopyOf(Ljava/lang/String;Ljava/util/List;)Ljava/util/List; HSPLio/reactivex/rxjava3/android/plugins/RxAndroidPlugins;->callRequireNonNull(Ljava/util/concurrent/Callable;)Lio/reactivex/rxjava3/core/Scheduler; HSPLio/reactivex/rxjava3/android/plugins/RxAndroidPlugins;->initMainThreadScheduler(Ljava/util/concurrent/Callable;)Lio/reactivex/rxjava3/core/Scheduler; HSPLio/reactivex/rxjava3/android/plugins/RxAndroidPlugins;->onMainThreadScheduler(Lio/reactivex/rxjava3/core/Scheduler;)Lio/reactivex/rxjava3/core/Scheduler; @@ -11745,11 +11677,11 @@ HSPLio/reactivex/rxjava3/core/Flowable;->combineLatest(Lorg/reactivestreams/Publ HSPLio/reactivex/rxjava3/core/Flowable;->combineLatestArray([Lorg/reactivestreams/Publisher;Lio/reactivex/rxjava3/functions/Function;I)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->create(Lio/reactivex/rxjava3/core/FlowableOnSubscribe;Lio/reactivex/rxjava3/core/BackpressureStrategy;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->distinctUntilChanged()Lio/reactivex/rxjava3/core/Flowable; -HSPLio/reactivex/rxjava3/core/Flowable;->distinctUntilChanged(Lio/reactivex/rxjava3/functions/BiPredicate;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->distinctUntilChanged(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->doOnEach(Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Action;Lio/reactivex/rxjava3/functions/Action;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->doOnNext(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->filter(Lio/reactivex/rxjava3/functions/Predicate;)Lio/reactivex/rxjava3/core/Flowable; +HSPLio/reactivex/rxjava3/core/Flowable;->fromFuture(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->interval(JJLjava/util/concurrent/TimeUnit;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->interval(JJLjava/util/concurrent/TimeUnit;Lio/reactivex/rxjava3/core/Scheduler;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->map(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Flowable; @@ -11766,18 +11698,11 @@ HSPLio/reactivex/rxjava3/core/Flowable;->subscribeOn(Lio/reactivex/rxjava3/core/ HSPLio/reactivex/rxjava3/core/Flowable;->switchMap(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->switchMap(Lio/reactivex/rxjava3/functions/Function;I)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->switchMap0(Lio/reactivex/rxjava3/functions/Function;IZ)Lio/reactivex/rxjava3/core/Flowable; -HSPLio/reactivex/rxjava3/core/Flowable;->switchMapSingle(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->throttleLatest(JLjava/util/concurrent/TimeUnit;)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->throttleLatest(JLjava/util/concurrent/TimeUnit;Lio/reactivex/rxjava3/core/Scheduler;Z)Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/core/Flowable;->toObservable()Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Maybe;->()V -HSPLio/reactivex/rxjava3/core/Maybe;->create(Lio/reactivex/rxjava3/core/MaybeOnSubscribe;)Lio/reactivex/rxjava3/core/Maybe; -HSPLio/reactivex/rxjava3/core/Maybe;->doOnSuccess(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/core/Maybe; -HSPLio/reactivex/rxjava3/core/Maybe;->empty()Lio/reactivex/rxjava3/core/Maybe; HSPLio/reactivex/rxjava3/core/Maybe;->filter(Lio/reactivex/rxjava3/functions/Predicate;)Lio/reactivex/rxjava3/core/Maybe; -HSPLio/reactivex/rxjava3/core/Maybe;->flatMap(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Maybe; -HSPLio/reactivex/rxjava3/core/Maybe;->fromCallable(Ljava/util/concurrent/Callable;)Lio/reactivex/rxjava3/core/Maybe; -HSPLio/reactivex/rxjava3/core/Maybe;->observeOn(Lio/reactivex/rxjava3/core/Scheduler;)Lio/reactivex/rxjava3/core/Maybe; HSPLio/reactivex/rxjava3/core/Maybe;->subscribe(Lio/reactivex/rxjava3/core/MaybeObserver;)V HSPLio/reactivex/rxjava3/core/Maybe;->subscribe(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/core/Maybe;->subscribe(Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Action;)Lio/reactivex/rxjava3/disposables/Disposable; @@ -11793,7 +11718,6 @@ HSPLio/reactivex/rxjava3/core/Observable;->combineLatestArray([Lio/reactivex/rxj HSPLio/reactivex/rxjava3/core/Observable;->concatArray([Lio/reactivex/rxjava3/core/ObservableSource;)Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Observable;->create(Lio/reactivex/rxjava3/core/ObservableOnSubscribe;)Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Observable;->distinctUntilChanged()Lio/reactivex/rxjava3/core/Observable; -HSPLio/reactivex/rxjava3/core/Observable;->distinctUntilChanged(Lio/reactivex/rxjava3/functions/BiPredicate;)Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Observable;->distinctUntilChanged(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Observable;->doOnEach(Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Action;Lio/reactivex/rxjava3/functions/Action;)Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Observable;->doOnNext(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/core/Observable; @@ -11847,17 +11771,24 @@ HSPLio/reactivex/rxjava3/core/Scheduler;->schedulePeriodicallyDirect(Ljava/lang/ HSPLio/reactivex/rxjava3/core/Single;->()V HSPLio/reactivex/rxjava3/core/Single;->blockingGet()Ljava/lang/Object; HSPLio/reactivex/rxjava3/core/Single;->doOnSuccess(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/core/Single; +HSPLio/reactivex/rxjava3/core/Single;->error(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Single; +HSPLio/reactivex/rxjava3/core/Single;->error(Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/Single; +HSPLio/reactivex/rxjava3/core/Single;->flatMap(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/core/Single;->flatMapObservable(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Observable; HSPLio/reactivex/rxjava3/core/Single;->fromCallable(Ljava/util/concurrent/Callable;)Lio/reactivex/rxjava3/core/Single; +HSPLio/reactivex/rxjava3/core/Single;->fromFuture(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/core/Single;->just(Ljava/lang/Object;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/core/Single;->map(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/core/Single;->observeOn(Lio/reactivex/rxjava3/core/Scheduler;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/core/Single;->onErrorComplete()Lio/reactivex/rxjava3/core/Maybe; HSPLio/reactivex/rxjava3/core/Single;->onErrorComplete(Lio/reactivex/rxjava3/functions/Predicate;)Lio/reactivex/rxjava3/core/Maybe; +HSPLio/reactivex/rxjava3/core/Single;->onErrorResumeNext(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; +HSPLio/reactivex/rxjava3/core/Single;->onErrorReturn(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/core/Single;->subscribe(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/core/Single;->subscribe(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/core/Single;->subscribe(Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/core/Single;->subscribeOn(Lio/reactivex/rxjava3/core/Scheduler;)Lio/reactivex/rxjava3/core/Single; +HSPLio/reactivex/rxjava3/core/Single;->toSingle(Lio/reactivex/rxjava3/core/Flowable;)Lio/reactivex/rxjava3/core/Single; HSPLio/reactivex/rxjava3/disposables/CompositeDisposable;->()V HSPLio/reactivex/rxjava3/disposables/CompositeDisposable;->add(Lio/reactivex/rxjava3/disposables/Disposable;)Z HSPLio/reactivex/rxjava3/disposables/CompositeDisposable;->delete(Lio/reactivex/rxjava3/disposables/Disposable;)Z @@ -11872,6 +11803,7 @@ HSPLio/reactivex/rxjava3/disposables/ReferenceDisposable;->isDisposed()Z HSPLio/reactivex/rxjava3/disposables/RunnableDisposable;->(Ljava/lang/Runnable;)V HSPLio/reactivex/rxjava3/disposables/RunnableDisposable;->onDisposed(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/disposables/RunnableDisposable;->onDisposed(Ljava/lang/Runnable;)V +HSPLio/reactivex/rxjava3/exceptions/Exceptions;->throwIfFatal(Ljava/lang/Throwable;)V HSPLio/reactivex/rxjava3/flowables/ConnectableFlowable;->()V HSPLio/reactivex/rxjava3/flowables/ConnectableFlowable;->refCount()Lio/reactivex/rxjava3/core/Flowable; HSPLio/reactivex/rxjava3/internal/disposables/CancellableDisposable;->(Lio/reactivex/rxjava3/functions/Cancellable;)V @@ -11885,7 +11817,7 @@ HSPLio/reactivex/rxjava3/internal/disposables/DisposableHelper;->setOnce(Ljava/u HSPLio/reactivex/rxjava3/internal/disposables/DisposableHelper;->validate(Lio/reactivex/rxjava3/disposables/Disposable;Lio/reactivex/rxjava3/disposables/Disposable;)Z HSPLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->()V HSPLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->(Ljava/lang/String;I)V -HSPLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->complete(Lio/reactivex/rxjava3/core/MaybeObserver;)V +HSPLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->error(Ljava/lang/Throwable;Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/disposables/SequentialDisposable;->()V HSPLio/reactivex/rxjava3/internal/disposables/SequentialDisposable;->(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/disposables/SequentialDisposable;->isDisposed()Z @@ -11956,6 +11888,9 @@ HSPLio/reactivex/rxjava3/internal/observers/QueueDrainObserver;->(Lio/reac HSPLio/reactivex/rxjava3/internal/observers/QueueDrainSubscriberPad0;->()V HSPLio/reactivex/rxjava3/internal/observers/QueueDrainSubscriberPad2;->()V HSPLio/reactivex/rxjava3/internal/observers/QueueDrainSubscriberWip;->()V +HSPLio/reactivex/rxjava3/internal/observers/ResumeSingleObserver;->(Ljava/util/concurrent/atomic/AtomicReference;Lio/reactivex/rxjava3/core/SingleObserver;)V +HSPLio/reactivex/rxjava3/internal/observers/ResumeSingleObserver;->onError(Ljava/lang/Throwable;)V +HSPLio/reactivex/rxjava3/internal/observers/ResumeSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber;->(Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber;->checkTerminated(ZZLorg/reactivestreams/Subscriber;Ljava/util/concurrent/atomic/AtomicReference;)Z HSPLio/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber;->drain()V @@ -12002,6 +11937,8 @@ HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFilter$FilterCondit HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFilter$FilterConditionalSubscriber;->tryOnNext(Ljava/lang/Object;)Z HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFilter;->(Lio/reactivex/rxjava3/core/Flowable;Lio/reactivex/rxjava3/functions/Predicate;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFilter;->subscribeActual(Lorg/reactivestreams/Subscriber;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture;->(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture;->subscribeActual(Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable$SubscriberObserver;->(Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable$SubscriberObserver;->onNext(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable$SubscriberObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V @@ -12030,7 +11967,6 @@ HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObser HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->checkTerminated(ZZLorg/reactivestreams/Subscriber;)Z HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->onNext(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->request(J)V -HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->requestFusion(I)I HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->run()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->trySchedule()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnConditionalSubscriber;->(Lio/reactivex/rxjava3/internal/fuseable/ConditionalSubscriber;Lio/reactivex/rxjava3/core/Scheduler$Worker;ZI)V @@ -12038,9 +11974,7 @@ HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOn HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnConditionalSubscriber;->runAsync()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->(Lorg/reactivestreams/Subscriber;Lio/reactivex/rxjava3/core/Scheduler$Worker;ZI)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V -HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->poll()Ljava/lang/Object; HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->runAsync()V -HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->runBackfused()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn;->(Lio/reactivex/rxjava3/core/Flowable;Lio/reactivex/rxjava3/core/Scheduler;ZI)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn;->subscribeActual(Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatest$BackpressureLatestSubscriber;->(Lorg/reactivestreams/Subscriber;)V @@ -12063,7 +11997,9 @@ HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedRepla HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->getHead()Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$Node; HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->leaveTransform(Ljava/lang/Object;)Ljava/lang/Object; HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->next(Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->removeFirst()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->replay(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$InnerSubscription;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->setFirst(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$Node;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$DefaultUnboundedFactory;->()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$InnerSubscription;->(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$ReplaySubscriber;Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$InnerSubscription;->index()Ljava/lang/Object; @@ -12092,6 +12028,11 @@ HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay;->create(Lio HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay;->create(Lio/reactivex/rxjava3/core/Flowable;Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/flowables/ConnectableFlowable; HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay;->subscribeActual(Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMap;->tryScalarXMapSubscribe(Lorg/reactivestreams/Publisher;Lorg/reactivestreams/Subscriber;Lio/reactivex/rxjava3/functions/Function;)Z +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber;->(Lio/reactivex/rxjava3/core/SingleObserver;Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber;->onError(Ljava/lang/Throwable;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle;->(Lio/reactivex/rxjava3/core/Flowable;Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn$SubscribeOnSubscriber$Request;->(Lorg/reactivestreams/Subscription;J)V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn$SubscribeOnSubscriber$Request;->run()V HSPLio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn$SubscribeOnSubscriber;->(Lorg/reactivestreams/Subscriber;Lio/reactivex/rxjava3/core/Scheduler$Worker;Lorg/reactivestreams/Publisher;Z)V @@ -12128,57 +12069,14 @@ HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver;-> HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver;->hasCustomOnError()Z HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver;->onComplete()V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter;->(Lio/reactivex/rxjava3/core/MaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter;->isDisposed()Z -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate;->(Lio/reactivex/rxjava3/core/MaybeOnSubscribe;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty;->()V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty;->()V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter$FilterMaybeObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/functions/Predicate;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter$FilterMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter$FilterMaybeObserver;->onSuccess(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/functions/Predicate;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver;->(Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver;->onComplete()V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/functions/Function;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->isDisposed()Z -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/functions/Function;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable;->(Ljava/util/concurrent/Callable;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/core/Scheduler;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->onComplete()V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->run()V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/core/Scheduler;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete$OnErrorCompleteMultiObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/functions/Predicate;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete$OnErrorCompleteMultiObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete$OnErrorCompleteMultiObserver;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/internal/operators/maybe/MaybePeek;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->onAfterTerminate()V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Action;Lio/reactivex/rxjava3/functions/Action;Lio/reactivex/rxjava3/functions/Action;)V -HSPLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver;->(Lio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->()V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->(Lorg/reactivestreams/Subscriber;Lio/reactivex/rxjava3/functions/Function;Z)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->drain()V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->onNext(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->request(J)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle;->(Lio/reactivex/rxjava3/core/Flowable;Lio/reactivex/rxjava3/functions/Function;Z)V -HSPLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle;->subscribeActual(Lorg/reactivestreams/Subscriber;)V HSPLio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver$SwitchMapSingleObserver;->(Lio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver;)V HSPLio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver$SwitchMapSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver$SwitchMapSingleObserver;->onSuccess(Ljava/lang/Object;)V @@ -12246,15 +12144,7 @@ HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFilter$FilterOb HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFilter$FilterObserver;->onNext(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFilter;->(Lio/reactivex/rxjava3/core/ObservableSource;Lio/reactivex/rxjava3/functions/Predicate;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFilter;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;->(Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;->onSuccess(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->(Lio/reactivex/rxjava3/core/Observer;Lio/reactivex/rxjava3/functions/Function;Z)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->innerSuccess(Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->onNext(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe;->(Lio/reactivex/rxjava3/core/ObservableSource;Lio/reactivex/rxjava3/functions/Function;Z)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver$InnerObserver;->(Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver$InnerObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver$InnerObserver;->onSuccess(Ljava/lang/Object;)V @@ -12271,16 +12161,11 @@ HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromArray;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture;->(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->(Lio/reactivex/rxjava3/core/Observer;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->onNext(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher;->(Lorg/reactivestreams/Publisher;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableJust;->(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableJust;->get()Ljava/lang/Object; HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableMap$MapObserver;->(Lio/reactivex/rxjava3/core/Observer;Lio/reactivex/rxjava3/functions/Function;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableMap$MapObserver;->onNext(Ljava/lang/Object;)V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableMap$MapObserver;->requestFusion(I)I HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableMap;->(Lio/reactivex/rxjava3/core/ObservableSource;Lio/reactivex/rxjava3/functions/Function;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableMap;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->(Lio/reactivex/rxjava3/core/Observer;Lio/reactivex/rxjava3/core/Scheduler$Worker;ZI)V @@ -12288,7 +12173,6 @@ HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$Obser HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->dispose()V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->drainFused()V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->drainNormal()V -HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->isEmpty()Z HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->onComplete()V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->onNext(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V @@ -12395,11 +12279,23 @@ HSPLio/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess$DoOnSuccess HSPLio/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess$DoOnSuccess;->onSuccess(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Consumer;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleError;->(Lio/reactivex/rxjava3/functions/Supplier;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleError;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver;->(Ljava/util/concurrent/atomic/AtomicReference;Lio/reactivex/rxjava3/core/SingleObserver;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver;->onSuccess(Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->(Lio/reactivex/rxjava3/core/SingleObserver;Lio/reactivex/rxjava3/functions/Function;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->isDisposed()Z +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->onSuccess(Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleFromCallable;->(Ljava/util/concurrent/Callable;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleFromCallable;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleJust;->(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleJust;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleMap$MapSingleObserver;->(Lio/reactivex/rxjava3/core/SingleObserver;Lio/reactivex/rxjava3/functions/Function;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleMap$MapSingleObserver;->onError(Ljava/lang/Throwable;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleMap$MapSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleMap$MapSingleObserver;->onSuccess(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleMap;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;)V @@ -12412,6 +12308,17 @@ HSPLio/reactivex/rxjava3/internal/operators/single/SingleObserveOn;->(Lio/ HSPLio/reactivex/rxjava3/internal/operators/single/SingleObserveOn;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorComplete;->(Lio/reactivex/rxjava3/core/Single;Lio/reactivex/rxjava3/functions/Predicate;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorComplete;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->(Lio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn;Lio/reactivex/rxjava3/core/SingleObserver;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->onError(Ljava/lang/Throwable;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->onSuccess(Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;Ljava/lang/Object;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver;->(Lio/reactivex/rxjava3/core/SingleObserver;Lio/reactivex/rxjava3/functions/Function;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver;->onError(Ljava/lang/Throwable;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;)V +HSPLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn$SubscribeOnObserver;->(Lio/reactivex/rxjava3/core/SingleObserver;Lio/reactivex/rxjava3/core/SingleSource;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn$SubscribeOnObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLio/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn$SubscribeOnObserver;->onSuccess(Ljava/lang/Object;)V @@ -12427,7 +12334,9 @@ HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode;->soNext HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode;->spValue(Ljava/lang/Object;)V HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->()V HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->clear()V +HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->isEmpty()Z HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->lpConsumerNode()Lio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode; +HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->lvConsumerNode()Lio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode; HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->lvProducerNode()Lio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode; HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->offer(Ljava/lang/Object;)Z HSPLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->poll()Ljava/lang/Object; @@ -12537,6 +12446,9 @@ HSPLio/reactivex/rxjava3/internal/subscribers/LambdaSubscriber;->onNext(Ljava/la HSPLio/reactivex/rxjava3/internal/subscribers/LambdaSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V HSPLio/reactivex/rxjava3/internal/subscribers/LambdaSubscriber;->request(J)V HSPLio/reactivex/rxjava3/internal/subscriptions/BasicIntQueueSubscription;->()V +HSPLio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription;->(Lorg/reactivestreams/Subscriber;)V +HSPLio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription;->isCancelled()Z +HSPLio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription;->request(J)V HSPLio/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper;->()V HSPLio/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper;->(Ljava/lang/String;I)V HSPLio/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper;->cancel(Ljava/util/concurrent/atomic/AtomicReference;)Z @@ -12576,7 +12488,6 @@ HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->(IF)V HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->add(Ljava/lang/Object;)Z HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->keys()[Ljava/lang/Object; HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->mix(I)I -HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->rehash()V HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->remove(Ljava/lang/Object;)Z HSPLio/reactivex/rxjava3/internal/util/OpenHashSet;->removeEntry(I[Ljava/lang/Object;I)Z HSPLio/reactivex/rxjava3/internal/util/Pow2;->roundToPowerOfTwo(I)I @@ -12596,11 +12507,9 @@ HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->asConsumer(Lkotlin/jvm/functions HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->asOnCompleteAction(Lkotlin/jvm/functions/Function0;)Lio/reactivex/rxjava3/functions/Action; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->asOnErrorConsumer(Lkotlin/jvm/functions/Function1;)Lio/reactivex/rxjava3/functions/Consumer; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy$default(Lio/reactivex/rxjava3/core/Flowable;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/reactivex/rxjava3/disposables/Disposable; -HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy$default(Lio/reactivex/rxjava3/core/Maybe;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy$default(Lio/reactivex/rxjava3/core/Observable;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy$default(Lio/reactivex/rxjava3/core/Single;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy(Lio/reactivex/rxjava3/core/Flowable;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Lio/reactivex/rxjava3/disposables/Disposable; -HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy(Lio/reactivex/rxjava3/core/Maybe;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy(Lio/reactivex/rxjava3/core/Observable;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy(Lio/reactivex/rxjava3/core/Single;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lio/reactivex/rxjava3/disposables/Disposable; HSPLio/reactivex/rxjava3/observables/ConnectableObservable;->()V @@ -12723,14 +12632,13 @@ HSPLj$/time/Duration;->()V HSPLj$/time/Duration;->(JI)V HSPLj$/time/Duration;->d(JI)Lj$/time/Duration; HSPLj$/time/Duration;->f(J)Lj$/time/Duration; -HSPLj$/time/Duration;->g(J)Lj$/time/Duration; HSPLj$/time/Duration;->ofMillis(J)Lj$/time/Duration; +HSPLj$/time/Duration;->ofSeconds(J)Lj$/time/Duration; HSPLj$/time/Duration;->ofSeconds(JJ)Lj$/time/Duration; HSPLj$/time/Duration;->toDays()J HSPLj$/time/Instant;->()V HSPLj$/time/Instant;->(JI)V HSPLj$/time/Instant;->atOffset(Lj$/time/ZoneOffset;)Lj$/time/OffsetDateTime; -HSPLj$/time/Instant;->atZone(Lj$/time/ZoneId;)Lj$/time/ZonedDateTime; HSPLj$/time/Instant;->getEpochSecond()J HSPLj$/time/Instant;->getNano()I HSPLj$/time/Instant;->n(JI)Lj$/time/Instant; @@ -12742,7 +12650,6 @@ HSPLj$/time/LocalDate;->(III)V HSPLj$/time/LocalDate;->getLong(Lj$/time/temporal/TemporalField;)J HSPLj$/time/LocalDate;->o(III)Lj$/time/LocalDate; HSPLj$/time/LocalDate;->q(Lj$/time/temporal/TemporalField;)I -HSPLj$/time/LocalDate;->toEpochDay()J HSPLj$/time/LocalDate;->x(III)Lj$/time/LocalDate; HSPLj$/time/LocalDate;->z(J)Lj$/time/LocalDate; HSPLj$/time/LocalDateTime;->()V @@ -12754,7 +12661,6 @@ HSPLj$/time/LocalDateTime;->j(Lj$/time/temporal/m;)Ljava/lang/Object; HSPLj$/time/LocalDateTime;->ofInstant(Lj$/time/Instant;Lj$/time/ZoneId;)Lj$/time/LocalDateTime; HSPLj$/time/LocalDateTime;->r(Lj$/time/LocalDate;Lj$/time/LocalTime;)Lj$/time/LocalDateTime; HSPLj$/time/LocalDateTime;->s(JILj$/time/ZoneOffset;)Lj$/time/LocalDateTime; -HSPLj$/time/LocalDateTime;->v()Lj$/time/LocalDate; HSPLj$/time/LocalTime;->()V HSPLj$/time/LocalTime;->(IIII)V HSPLj$/time/LocalTime;->n(IIII)Lj$/time/LocalTime; @@ -12773,10 +12679,6 @@ HSPLj$/time/ZoneOffset;->(I)V HSPLj$/time/ZoneOffset;->n()Lj$/time/zone/c; HSPLj$/time/ZoneOffset;->o()I HSPLj$/time/ZoneOffset;->r(I)Lj$/time/ZoneOffset; -HSPLj$/time/ZonedDateTime;->(Lj$/time/LocalDateTime;Lj$/time/ZoneId;Lj$/time/ZoneOffset;)V -HSPLj$/time/ZonedDateTime;->m(JILj$/time/ZoneId;)Lj$/time/ZonedDateTime; -HSPLj$/time/ZonedDateTime;->n(Lj$/time/Instant;Lj$/time/ZoneId;)Lj$/time/ZonedDateTime; -HSPLj$/time/ZonedDateTime;->toLocalDate()Lj$/time/LocalDate; HSPLj$/time/a;->c(JJ)J HSPLj$/time/a;->d(Lsun/misc/Unsafe;Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z HSPLj$/time/a;->e(JJ)J @@ -12925,7 +12827,6 @@ HSPLj$/util/Comparator$-CC;->a()Ljava/util/Comparator; HSPLj$/util/DateRetargetClass;->toInstant(Ljava/util/Date;)Lj$/time/Instant; HSPLj$/util/DesugarArrays;->stream([Ljava/lang/Object;)Lj$/util/stream/Stream; HSPLj$/util/DesugarCollections;->()V -HSPLj$/util/DesugarCollections;->a()Ljava/lang/reflect/Constructor; HSPLj$/util/DesugarCollections;->b()Ljava/lang/reflect/Constructor; HSPLj$/util/DesugarCollections;->synchronizedMap(Ljava/util/Map;)Ljava/util/Map; HSPLj$/util/DesugarTimeZone;->getTimeZone(Ljava/lang/String;)Ljava/util/TimeZone; @@ -12940,7 +12841,6 @@ HSPLj$/util/Optional;->()V HSPLj$/util/Optional;->(Ljava/lang/Object;)V HSPLj$/util/Optional;->empty()Lj$/util/Optional; HSPLj$/util/Optional;->get()Ljava/lang/Object; -HSPLj$/util/Optional;->ifPresent(Lj$/util/function/Consumer;)V HSPLj$/util/Optional;->isPresent()Z HSPLj$/util/Optional;->map(Lj$/util/function/Function;)Lj$/util/Optional; HSPLj$/util/Optional;->of(Ljava/lang/Object;)Lj$/util/Optional; @@ -12951,7 +12851,6 @@ HSPLj$/util/S;->a(Lj$/util/function/Consumer;)V HSPLj$/util/S;->characteristics()I HSPLj$/util/S;->estimateSize()J HSPLj$/util/S;->getExactSizeIfKnown()J -HSPLj$/util/S;->s(Lj$/util/function/Consumer;)Z HSPLj$/util/U;->()V HSPLj$/util/V;->()V HSPLj$/util/W;->()V @@ -12975,6 +12874,7 @@ HSPLj$/util/concurrent/ConcurrentHashMap;->casTabAt([Lj$/util/concurrent/l;ILj$/ HSPLj$/util/concurrent/ConcurrentHashMap;->clear()V HSPLj$/util/concurrent/ConcurrentHashMap;->comparableClassFor(Ljava/lang/Object;)Ljava/lang/Class; HSPLj$/util/concurrent/ConcurrentHashMap;->entrySet()Ljava/util/Set; +HSPLj$/util/concurrent/ConcurrentHashMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLj$/util/concurrent/ConcurrentHashMap;->initTable()[Lj$/util/concurrent/l; HSPLj$/util/concurrent/ConcurrentHashMap;->isEmpty()Z HSPLj$/util/concurrent/ConcurrentHashMap;->keySet()Ljava/util/Set; @@ -13024,17 +12924,13 @@ HSPLj$/util/concurrent/v;->a(Lsun/misc/Unsafe;Ljava/lang/Object;J)I HSPLj$/util/concurrent/v;->b()Ljava/lang/reflect/Field; HSPLj$/util/concurrent/v;->c()Lsun/misc/Unsafe; HSPLj$/util/d;->(Ljava/util/Map;)V -HSPLj$/util/d;->a(Ljava/util/Set;Ljava/lang/Object;)Ljava/util/Set; HSPLj$/util/d;->get(Ljava/lang/Object;)Ljava/lang/Object; -HSPLj$/util/d;->keySet()Ljava/util/Set; HSPLj$/util/d;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +HSPLj$/util/d;->remove(Ljava/lang/Object;)Ljava/lang/Object; HSPLj$/util/d;->values()Ljava/util/Collection; -HSPLj$/util/function/b;->(Ljava/util/Comparator;I)V HSPLj$/util/m;->()V HSPLj$/util/m;->j(Lj$/util/Spliterator;)J HSPLj$/util/m;->y(Ljava/lang/Object;Ljava/lang/Object;)Z -HSPLj$/util/stream/A1;->(Lj$/util/stream/V2;Ljava/lang/Object;I)V -HSPLj$/util/stream/A1;->l1()Lj$/util/stream/P1; HSPLj$/util/stream/B2;->(Lj$/util/stream/c;)V HSPLj$/util/stream/B2;->B1(ILj$/util/stream/g2;)Lj$/util/stream/g2; HSPLj$/util/stream/C2;->(Lj$/util/stream/g2;Ljava/util/Comparator;)V @@ -13046,12 +12942,6 @@ HSPLj$/util/stream/Collector$Characteristics;->values()[Lj$/util/stream/Collecto HSPLj$/util/stream/Collectors;->()V HSPLj$/util/stream/Collectors;->toList()Lj$/util/stream/Collector; HSPLj$/util/stream/Collectors;->toSet()Lj$/util/stream/Collector; -HSPLj$/util/stream/E1;->(Lj$/util/function/BinaryOperator;)V -HSPLj$/util/stream/E1;->accept(Ljava/lang/Object;)V -HSPLj$/util/stream/E1;->get()Ljava/lang/Object; -HSPLj$/util/stream/E1;->m()V -HSPLj$/util/stream/E1;->n(J)V -HSPLj$/util/stream/E1;->q()Z HSPLj$/util/stream/F1;->(Lj$/util/stream/V2;Lj$/util/function/BinaryOperator;Lj$/util/function/BiConsumer;Lj$/util/function/Supplier;Lj$/util/stream/Collector;)V HSPLj$/util/stream/F1;->l1()Lj$/util/stream/P1; HSPLj$/util/stream/F1;->p()I @@ -13117,10 +13007,7 @@ HSPLj$/util/stream/Y1;->collect(Lj$/util/stream/Collector;)Ljava/lang/Object; HSPLj$/util/stream/Y1;->filter(Lj$/util/function/Predicate;)Lj$/util/stream/Stream; HSPLj$/util/stream/Y1;->findFirst()Lj$/util/Optional; HSPLj$/util/stream/Y1;->forEach(Lj$/util/function/Consumer;)V -HSPLj$/util/stream/Y1;->limit(J)Lj$/util/stream/Stream; HSPLj$/util/stream/Y1;->map(Lj$/util/function/Function;)Lj$/util/stream/Stream; -HSPLj$/util/stream/Y1;->max(Ljava/util/Comparator;)Lj$/util/Optional; -HSPLj$/util/stream/Y1;->n(Lj$/util/function/BinaryOperator;)Lj$/util/Optional; HSPLj$/util/stream/Y1;->sorted()Lj$/util/stream/Stream; HSPLj$/util/stream/Y1;->t1(Lj$/util/Spliterator;Lj$/util/stream/g2;)V HSPLj$/util/stream/Z0;->()V @@ -13139,12 +13026,6 @@ HSPLj$/util/stream/c;->isParallel()Z HSPLj$/util/stream/c;->n1(Lj$/util/Spliterator;Lj$/util/stream/g2;)Lj$/util/stream/g2; HSPLj$/util/stream/c;->o1(Lj$/util/stream/g2;)Lj$/util/stream/g2; HSPLj$/util/stream/c;->q1(Lj$/util/stream/F3;)Ljava/lang/Object; -HSPLj$/util/stream/h2;->(Lj$/util/stream/i2;Lj$/util/stream/g2;)V -HSPLj$/util/stream/h2;->accept(Ljava/lang/Object;)V -HSPLj$/util/stream/h2;->n(J)V -HSPLj$/util/stream/h2;->q()Z -HSPLj$/util/stream/i2;->(Lj$/util/stream/c;IJJ)V -HSPLj$/util/stream/i2;->B1(ILj$/util/stream/g2;)Lj$/util/stream/g2; HSPLj$/util/stream/l;->(I)V HSPLj$/util/stream/n;->(Lj$/util/function/Supplier;Lj$/util/function/BiConsumer;Lj$/util/function/BinaryOperator;Lj$/util/function/Function;Ljava/util/Set;)V HSPLj$/util/stream/n;->(Lj$/util/function/Supplier;Lj$/util/function/BiConsumer;Lj$/util/function/BinaryOperator;Ljava/util/Set;)V @@ -13157,12 +13038,8 @@ HSPLj$/util/stream/u2;->q()Z HSPLj$/util/stream/w0;->()V HSPLj$/util/stream/w0;->()V HSPLj$/util/stream/w0;->(Lj$/util/stream/V2;)V -HSPLj$/util/stream/w0;->C0(JJJ)J -HSPLj$/util/stream/w0;->S0(J)I HSPLj$/util/stream/w0;->f0(Lj$/util/stream/w0;Lj$/util/Spliterator;)Ljava/lang/Object; -HSPLj$/util/stream/w0;->k1(Lj$/util/stream/c;JJ)Lj$/util/stream/Stream; HSPLj$/util/stream/w0;->m1(Lj$/util/Spliterator;Z)Lj$/util/stream/Stream; -HSPLj$/util/stream/w0;->p()I HSPLj$/util/stream/w;->(Lj$/util/stream/c;ILjava/lang/Object;I)V HSPLj$/util/stream/w;->B1(ILj$/util/stream/g2;)Lj$/util/stream/g2; HSPLkotlin/InitializedLazyImpl;->(Ljava/lang/Object;)V @@ -13198,10 +13075,13 @@ HSPLkotlin/Result$Companion;->()V HSPLkotlin/Result$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLkotlin/Result$Failure;->(Ljava/lang/Throwable;)V HSPLkotlin/Result;->()V +HSPLkotlin/Result;->(Ljava/lang/Object;)V +HSPLkotlin/Result;->box-impl(Ljava/lang/Object;)Lkotlin/Result; HSPLkotlin/Result;->constructor-impl(Ljava/lang/Object;)Ljava/lang/Object; HSPLkotlin/Result;->exceptionOrNull-impl(Ljava/lang/Object;)Ljava/lang/Throwable; HSPLkotlin/Result;->isFailure-impl(Ljava/lang/Object;)Z HSPLkotlin/Result;->isSuccess-impl(Ljava/lang/Object;)Z +HSPLkotlin/Result;->unbox-impl()Ljava/lang/Object; HSPLkotlin/ResultKt;->createFailure(Ljava/lang/Throwable;)Ljava/lang/Object; HSPLkotlin/ResultKt;->throwOnFailure(Ljava/lang/Object;)V HSPLkotlin/SafePublicationLazyImpl$Companion;->()V @@ -13229,8 +13109,6 @@ HSPLkotlin/UnsafeLazyImpl;->(Lkotlin/jvm/functions/Function0;)V HSPLkotlin/UnsafeLazyImpl;->getValue()Ljava/lang/Object; HSPLkotlin/collections/AbstractCollection$toString$1;->(Lkotlin/collections/AbstractCollection;)V HSPLkotlin/collections/AbstractCollection;->()V -HSPLkotlin/collections/AbstractCollection;->contains(Ljava/lang/Object;)Z -HSPLkotlin/collections/AbstractCollection;->isEmpty()Z HSPLkotlin/collections/AbstractCollection;->size()I HSPLkotlin/collections/AbstractCollection;->toString()Ljava/lang/String; HSPLkotlin/collections/AbstractList$Companion;->()V @@ -13348,7 +13226,6 @@ HSPLkotlin/collections/CollectionsKt;->firstOrNull(Ljava/util/List;)Ljava/lang/O HSPLkotlin/collections/CollectionsKt;->flatten(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt;->getLastIndex(Ljava/util/List;)I HSPLkotlin/collections/CollectionsKt;->getOrNull(Ljava/util/List;I)Ljava/lang/Object; -HSPLkotlin/collections/CollectionsKt;->intersect(Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/Set; HSPLkotlin/collections/CollectionsKt;->joinTo$default(Ljava/lang/Iterable;Ljava/lang/Appendable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Appendable; HSPLkotlin/collections/CollectionsKt;->joinToString$default(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String; HSPLkotlin/collections/CollectionsKt;->last(Ljava/util/List;)Ljava/lang/Object; @@ -13369,6 +13246,7 @@ HSPLkotlin/collections/CollectionsKt;->reverse(Ljava/util/List;)V HSPLkotlin/collections/CollectionsKt;->reversed(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt;->sort(Ljava/util/List;)V HSPLkotlin/collections/CollectionsKt;->sortWith(Ljava/util/List;Ljava/util/Comparator;)V +HSPLkotlin/collections/CollectionsKt;->sorted(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt;->sortedDescending(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt;->sortedWith(Ljava/lang/Iterable;Ljava/util/Comparator;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt;->sumOfFloat(Ljava/lang/Iterable;)F @@ -13392,6 +13270,7 @@ HSPLkotlin/collections/CollectionsKt__CollectionsKt;->listOfNotNull([Ljava/lang/ HSPLkotlin/collections/CollectionsKt__CollectionsKt;->mutableListOf([Ljava/lang/Object;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt__CollectionsKt;->optimizeReadOnlyList(Ljava/util/List;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt__CollectionsKt;->rangeCheck$CollectionsKt__CollectionsKt(III)V +HSPLkotlin/collections/CollectionsKt__IterablesKt;->collectionSizeOrDefault(Ljava/lang/Iterable;I)I HSPLkotlin/collections/CollectionsKt__IterablesKt;->collectionSizeOrNull(Ljava/lang/Iterable;)Ljava/lang/Integer; HSPLkotlin/collections/CollectionsKt__IterablesKt;->flatten(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt__MutableCollectionsJVMKt;->sort(Ljava/util/List;)V @@ -13399,7 +13278,6 @@ HSPLkotlin/collections/CollectionsKt__MutableCollectionsJVMKt;->sortWith(Ljava/u HSPLkotlin/collections/CollectionsKt__MutableCollectionsKt;->addAll(Ljava/util/Collection;Ljava/lang/Iterable;)Z HSPLkotlin/collections/CollectionsKt__MutableCollectionsKt;->addAll(Ljava/util/Collection;[Ljava/lang/Object;)Z HSPLkotlin/collections/CollectionsKt__MutableCollectionsKt;->convertToListIfNotCollection(Ljava/lang/Iterable;)Ljava/util/Collection; -HSPLkotlin/collections/CollectionsKt__MutableCollectionsKt;->retainAll(Ljava/util/Collection;Ljava/lang/Iterable;)Z HSPLkotlin/collections/CollectionsKt___CollectionsJvmKt;->filterIsInstance(Ljava/lang/Iterable;Ljava/lang/Class;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt___CollectionsJvmKt;->filterIsInstanceTo(Ljava/lang/Iterable;Ljava/util/Collection;Ljava/lang/Class;)Ljava/util/Collection; HSPLkotlin/collections/CollectionsKt___CollectionsJvmKt;->reverse(Ljava/util/List;)V @@ -13419,7 +13297,6 @@ HSPLkotlin/collections/CollectionsKt___CollectionsKt;->first(Ljava/util/List;)Lj HSPLkotlin/collections/CollectionsKt___CollectionsKt;->firstOrNull(Ljava/lang/Iterable;)Ljava/lang/Object; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->firstOrNull(Ljava/util/List;)Ljava/lang/Object; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->getOrNull(Ljava/util/List;I)Ljava/lang/Object; -HSPLkotlin/collections/CollectionsKt___CollectionsKt;->intersect(Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/Set; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->joinTo$default(Ljava/lang/Iterable;Ljava/lang/Appendable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Appendable; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->joinTo(Ljava/lang/Iterable;Ljava/lang/Appendable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)Ljava/lang/Appendable; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->joinToString$default(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String; @@ -13433,6 +13310,7 @@ HSPLkotlin/collections/CollectionsKt___CollectionsKt;->plus(Ljava/util/Collectio HSPLkotlin/collections/CollectionsKt___CollectionsKt;->plus(Ljava/util/Collection;Ljava/lang/Object;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->plus(Ljava/util/Collection;[Ljava/lang/Object;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->reversed(Ljava/lang/Iterable;)Ljava/util/List; +HSPLkotlin/collections/CollectionsKt___CollectionsKt;->sorted(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->sortedDescending(Ljava/lang/Iterable;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->sortedWith(Ljava/lang/Iterable;Ljava/util/Comparator;)Ljava/util/List; HSPLkotlin/collections/CollectionsKt___CollectionsKt;->sumOfFloat(Ljava/lang/Iterable;)F @@ -13467,11 +13345,9 @@ HSPLkotlin/collections/EmptyMap;->entrySet()Ljava/util/Set; HSPLkotlin/collections/EmptyMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLkotlin/collections/EmptyMap;->get(Ljava/lang/Object;)Ljava/lang/Void; HSPLkotlin/collections/EmptyMap;->getEntries()Ljava/util/Set; -HSPLkotlin/collections/EmptyMap;->getKeys()Ljava/util/Set; HSPLkotlin/collections/EmptyMap;->getSize()I HSPLkotlin/collections/EmptyMap;->getValues()Ljava/util/Collection; HSPLkotlin/collections/EmptyMap;->isEmpty()Z -HSPLkotlin/collections/EmptyMap;->keySet()Ljava/util/Set; HSPLkotlin/collections/EmptyMap;->size()I HSPLkotlin/collections/EmptyMap;->values()Ljava/util/Collection; HSPLkotlin/collections/EmptySet;->()V @@ -13493,14 +13369,15 @@ HSPLkotlin/collections/IndexingIterator;->next()Ljava/lang/Object; HSPLkotlin/collections/IndexingIterator;->next()Lkotlin/collections/IndexedValue; HSPLkotlin/collections/IntIterator;->()V HSPLkotlin/collections/IntIterator;->next()Ljava/lang/Object; -HSPLkotlin/collections/MapsKt;->asSequence(Ljava/util/Map;)Lkotlin/sequences/Sequence; HSPLkotlin/collections/MapsKt;->build(Ljava/util/Map;)Ljava/util/Map; HSPLkotlin/collections/MapsKt;->createMapBuilder()Ljava/util/Map; HSPLkotlin/collections/MapsKt;->emptyMap()Ljava/util/Map; HSPLkotlin/collections/MapsKt;->linkedMapOf([Lkotlin/Pair;)Ljava/util/LinkedHashMap; HSPLkotlin/collections/MapsKt;->mapCapacity(I)I +HSPLkotlin/collections/MapsKt;->mapOf(Lkotlin/Pair;)Ljava/util/Map; HSPLkotlin/collections/MapsKt;->mapOf([Lkotlin/Pair;)Ljava/util/Map; HSPLkotlin/collections/MapsKt;->plus(Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; +HSPLkotlin/collections/MapsKt;->plus(Ljava/util/Map;Lkotlin/Pair;)Ljava/util/Map; HSPLkotlin/collections/MapsKt;->putAll(Ljava/util/Map;[Lkotlin/Pair;)V HSPLkotlin/collections/MapsKt;->toMap(Ljava/lang/Iterable;)Ljava/util/Map; HSPLkotlin/collections/MapsKt;->toMap(Ljava/util/Map;)Ljava/util/Map; @@ -13508,11 +13385,12 @@ HSPLkotlin/collections/MapsKt;->toMutableMap(Ljava/util/Map;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsJVMKt;->build(Ljava/util/Map;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsJVMKt;->createMapBuilder()Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsJVMKt;->mapCapacity(I)I -HSPLkotlin/collections/MapsKt__MapsJVMKt;->toSingletonMap(Ljava/util/Map;)Ljava/util/Map; +HSPLkotlin/collections/MapsKt__MapsJVMKt;->mapOf(Lkotlin/Pair;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsKt;->emptyMap()Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsKt;->linkedMapOf([Lkotlin/Pair;)Ljava/util/LinkedHashMap; HSPLkotlin/collections/MapsKt__MapsKt;->mapOf([Lkotlin/Pair;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsKt;->plus(Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; +HSPLkotlin/collections/MapsKt__MapsKt;->plus(Ljava/util/Map;Lkotlin/Pair;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsKt;->putAll(Ljava/util/Map;Ljava/lang/Iterable;)V HSPLkotlin/collections/MapsKt__MapsKt;->putAll(Ljava/util/Map;[Lkotlin/Pair;)V HSPLkotlin/collections/MapsKt__MapsKt;->toMap(Ljava/lang/Iterable;)Ljava/util/Map; @@ -13520,7 +13398,6 @@ HSPLkotlin/collections/MapsKt__MapsKt;->toMap(Ljava/lang/Iterable;Ljava/util/Map HSPLkotlin/collections/MapsKt__MapsKt;->toMap(Ljava/util/Map;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsKt;->toMap([Lkotlin/Pair;Ljava/util/Map;)Ljava/util/Map; HSPLkotlin/collections/MapsKt__MapsKt;->toMutableMap(Ljava/util/Map;)Ljava/util/Map; -HSPLkotlin/collections/MapsKt___MapsKt;->asSequence(Ljava/util/Map;)Lkotlin/sequences/Sequence; HSPLkotlin/collections/RingBuffer;->(I)V HSPLkotlin/collections/RingBuffer;->([Ljava/lang/Object;I)V HSPLkotlin/collections/RingBuffer;->access$getCapacity$p(Lkotlin/collections/RingBuffer;)I @@ -13531,7 +13408,6 @@ HSPLkotlin/collections/RingBuffer;->removeFirst(I)V HSPLkotlin/collections/RingBuffer;->toArray()[Ljava/lang/Object; HSPLkotlin/collections/RingBuffer;->toArray([Ljava/lang/Object;)[Ljava/lang/Object; HSPLkotlin/collections/SetsKt;->emptySet()Ljava/util/Set; -HSPLkotlin/collections/SetsKt;->minus(Ljava/util/Set;Ljava/lang/Iterable;)Ljava/util/Set; HSPLkotlin/collections/SetsKt;->minus(Ljava/util/Set;Ljava/lang/Object;)Ljava/util/Set; HSPLkotlin/collections/SetsKt;->plus(Ljava/util/Set;Ljava/lang/Iterable;)Ljava/util/Set; HSPLkotlin/collections/SetsKt;->plus(Ljava/util/Set;Ljava/lang/Object;)Ljava/util/Set; @@ -13540,7 +13416,6 @@ HSPLkotlin/collections/SetsKt;->setOf([Ljava/lang/Object;)Ljava/util/Set; HSPLkotlin/collections/SetsKt__SetsJVMKt;->setOf(Ljava/lang/Object;)Ljava/util/Set; HSPLkotlin/collections/SetsKt__SetsKt;->emptySet()Ljava/util/Set; HSPLkotlin/collections/SetsKt__SetsKt;->setOf([Ljava/lang/Object;)Ljava/util/Set; -HSPLkotlin/collections/SetsKt___SetsKt;->minus(Ljava/util/Set;Ljava/lang/Iterable;)Ljava/util/Set; HSPLkotlin/collections/SetsKt___SetsKt;->minus(Ljava/util/Set;Ljava/lang/Object;)Ljava/util/Set; HSPLkotlin/collections/SetsKt___SetsKt;->plus(Ljava/util/Set;Ljava/lang/Iterable;)Ljava/util/Set; HSPLkotlin/collections/SetsKt___SetsKt;->plus(Ljava/util/Set;Ljava/lang/Object;)Ljava/util/Set; @@ -13593,12 +13468,21 @@ HSPLkotlin/coroutines/jvm/internal/DebugProbesKt;->probeCoroutineResumed(Lkotlin HSPLkotlin/coroutines/jvm/internal/DebugProbesKt;->probeCoroutineSuspended(Lkotlin/coroutines/Continuation;)V HSPLkotlin/coroutines/jvm/internal/RestrictedContinuationImpl;->(Lkotlin/coroutines/Continuation;)V HSPLkotlin/coroutines/jvm/internal/RestrictedSuspendLambda;->(ILkotlin/coroutines/Continuation;)V +HSPLkotlin/internal/PlatformImplementations;->()V +HSPLkotlin/internal/PlatformImplementations;->defaultPlatformRandom()Lkotlin/random/Random; +HSPLkotlin/internal/PlatformImplementationsKt;->()V HSPLkotlin/internal/ProgressionUtilKt;->differenceModulo(III)I HSPLkotlin/internal/ProgressionUtilKt;->differenceModulo(JJJ)J HSPLkotlin/internal/ProgressionUtilKt;->getProgressionLastElement(III)I HSPLkotlin/internal/ProgressionUtilKt;->getProgressionLastElement(JJJ)J HSPLkotlin/internal/ProgressionUtilKt;->mod(II)I HSPLkotlin/internal/ProgressionUtilKt;->mod(JJ)J +HSPLkotlin/internal/jdk7/JDK7PlatformImplementations;->()V +HSPLkotlin/internal/jdk8/JDK8PlatformImplementations$ReflectSdkVersion;->()V +HSPLkotlin/internal/jdk8/JDK8PlatformImplementations$ReflectSdkVersion;->()V +HSPLkotlin/internal/jdk8/JDK8PlatformImplementations;->()V +HSPLkotlin/internal/jdk8/JDK8PlatformImplementations;->defaultPlatformRandom()Lkotlin/random/Random; +HSPLkotlin/internal/jdk8/JDK8PlatformImplementations;->sdkIsNullOrAtLeast(I)Z HSPLkotlin/io/CloseableKt;->closeFinally(Ljava/io/Closeable;Ljava/lang/Throwable;)V HSPLkotlin/jvm/JvmClassMappingKt;->getAnnotationClass(Ljava/lang/annotation/Annotation;)Lkotlin/reflect/KClass; HSPLkotlin/jvm/JvmClassMappingKt;->getJavaClass(Lkotlin/reflect/KClass;)Ljava/lang/Class; @@ -13621,7 +13505,6 @@ HSPLkotlin/jvm/internal/FunctionReference;->(ILjava/lang/Object;)V HSPLkotlin/jvm/internal/FunctionReference;->(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V HSPLkotlin/jvm/internal/FunctionReferenceImpl;->(ILjava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V HSPLkotlin/jvm/internal/FunctionReferenceImpl;->(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V -HSPLkotlin/jvm/internal/Intrinsics;->areEqual(Ljava/lang/Object;Ljava/lang/Object;)Z HSPLkotlin/jvm/internal/Intrinsics;->checkNotNull(Ljava/lang/Object;)V HSPLkotlin/jvm/internal/Intrinsics;->checkNotNull(Ljava/lang/Object;Ljava/lang/String;)V HSPLkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V @@ -13664,6 +13547,19 @@ HSPLkotlin/properties/ObservableProperty;->(Ljava/lang/Object;)V HSPLkotlin/properties/ObservableProperty;->afterChange(Lkotlin/reflect/KProperty;Ljava/lang/Object;Ljava/lang/Object;)V HSPLkotlin/properties/ObservableProperty;->getValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object; HSPLkotlin/properties/ObservableProperty;->setValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;Ljava/lang/Object;)V +HSPLkotlin/random/AbstractPlatformRandom;->()V +HSPLkotlin/random/AbstractPlatformRandom;->nextInt(I)I +HSPLkotlin/random/FallbackThreadLocalRandom$implStorage$1;->()V +HSPLkotlin/random/FallbackThreadLocalRandom$implStorage$1;->initialValue()Ljava/lang/Object; +HSPLkotlin/random/FallbackThreadLocalRandom$implStorage$1;->initialValue()Ljava/util/Random; +HSPLkotlin/random/FallbackThreadLocalRandom;->()V +HSPLkotlin/random/FallbackThreadLocalRandom;->getImpl()Ljava/util/Random; +HSPLkotlin/random/Random$Default;->()V +HSPLkotlin/random/Random$Default;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLkotlin/random/Random$Default;->nextInt(I)I +HSPLkotlin/random/Random;->()V +HSPLkotlin/random/Random;->()V +HSPLkotlin/random/Random;->access$getDefaultRandom$cp()Lkotlin/random/Random; HSPLkotlin/ranges/IntProgression$Companion;->()V HSPLkotlin/ranges/IntProgression$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLkotlin/ranges/IntProgression;->()V @@ -14007,6 +13903,7 @@ HSPLkotlin/reflect/jvm/internal/UtilKt;->()V HSPLkotlin/reflect/jvm/internal/UtilKt;->asKCallableImpl(Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/KCallableImpl; HSPLkotlin/reflect/jvm/internal/UtilKt;->asKFunctionImpl(Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/KFunctionImpl; HSPLkotlin/reflect/jvm/internal/UtilKt;->computeAnnotations(Lkotlin/reflect/jvm/internal/impl/descriptors/annotations/Annotated;)Ljava/util/List; +HSPLkotlin/reflect/jvm/internal/UtilKt;->createArrayType(Ljava/lang/Class;)Ljava/lang/Class; HSPLkotlin/reflect/jvm/internal/UtilKt;->getInstanceReceiverParameter(Lkotlin/reflect/jvm/internal/impl/descriptors/CallableDescriptor;)Lkotlin/reflect/jvm/internal/impl/descriptors/ReceiverParameterDescriptor; HSPLkotlin/reflect/jvm/internal/UtilKt;->toJavaClass(Lkotlin/reflect/jvm/internal/impl/descriptors/ClassDescriptor;)Ljava/lang/Class; HSPLkotlin/reflect/jvm/internal/UtilKt;->unwrapRepeatableAnnotations(Ljava/util/List;)Ljava/util/List; @@ -14614,6 +14511,7 @@ HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/RuntimeSourc HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/SignatureSerializer;->()V HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/SignatureSerializer;->()V HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/SignatureSerializer;->constructorDesc(Ljava/lang/reflect/Constructor;)Ljava/lang/String; +HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/SignatureSerializer;->fieldDesc(Ljava/lang/reflect/Field;)Ljava/lang/String; HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/SignatureSerializer;->methodDesc(Ljava/lang/reflect/Method;)Ljava/lang/String; HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/structure/Java16SealedRecordLoader$Cache;->(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V HSPLkotlin/reflect/jvm/internal/impl/descriptors/runtime/structure/Java16SealedRecordLoader$Cache;->isSealed()Ljava/lang/reflect/Method; @@ -14918,10 +14816,13 @@ HSPLkotlin/reflect/jvm/internal/impl/load/java/typeEnhancement/SignatureEnhancem HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$AnnotationsContainerWithConstants;->(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$AnnotationsContainerWithConstants;->getMemberAnnotations()Ljava/util/Map; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$AnnotationVisitorForMethod;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1;Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$AnnotationVisitorForMethod;->visitParameterAnnotation(ILkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/descriptors/SourceElement;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$AnnotationArgumentVisitor; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$MemberAnnotationVisitor;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1;Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$MemberAnnotationVisitor;->getSignature()Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$MemberAnnotationVisitor;->visitAnnotation(Lkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/descriptors/SourceElement;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$AnnotationArgumentVisitor; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$MemberAnnotationVisitor;->visitEnd()V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader;Ljava/util/HashMap;Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass;Ljava/util/HashMap;Ljava/util/HashMap;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1;->visitField(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/String;Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$AnnotationVisitor; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1;->visitMethod(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/String;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$MethodAnnotationVisitor; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$storage$1;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader;)V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$storage$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; @@ -14947,9 +14848,14 @@ HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationLo HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationLoader;->loadTypeAnnotations(Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Type;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/NameResolver;)Ljava/util/List; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationLoader;->toBinaryClass(Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/ProtoContainer$Class;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$AbstractAnnotationArgumentVisitor;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$AbstractAnnotationArgumentVisitor;->visit(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/Object;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$AbstractAnnotationArgumentVisitor;->visitEnum(Lkotlin/reflect/jvm/internal/impl/name/Name;Lkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/name/Name;)V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$loadAnnotation$1;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;Lkotlin/reflect/jvm/internal/impl/descriptors/ClassDescriptor;Lkotlin/reflect/jvm/internal/impl/name/ClassId;Ljava/util/List;Lkotlin/reflect/jvm/internal/impl/descriptors/SourceElement;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$loadAnnotation$1;->visitConstantValue(Lkotlin/reflect/jvm/internal/impl/name/Name;Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue;)V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$loadAnnotation$1;->visitEnd()V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->(Lkotlin/reflect/jvm/internal/impl/descriptors/ModuleDescriptor;Lkotlin/reflect/jvm/internal/impl/descriptors/NotFoundClasses;Lkotlin/reflect/jvm/internal/impl/storage/StorageManager;Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinClassFinder;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->access$createConstant(Lkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->createConstant(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->loadAnnotation(Lkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/descriptors/SourceElement;Ljava/util/List;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$AnnotationArgumentVisitor; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->resolveClass(Lkotlin/reflect/jvm/internal/impl/name/ClassId;)Lkotlin/reflect/jvm/internal/impl/descriptors/ClassDescriptor; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/DeserializationComponentsForJava$Companion$ModuleData;->(Lkotlin/reflect/jvm/internal/impl/load/kotlin/DeserializationComponentsForJava;Lkotlin/reflect/jvm/internal/impl/load/kotlin/DeserializedDescriptorResolver;)V @@ -14995,12 +14901,15 @@ HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinarySourceElement;-> HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinarySourceElement;->getBinaryClass()Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->()V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->fromFieldNameAndDesc(Ljava/lang/String;Ljava/lang/String;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->fromJvmMemberSignature(Lkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmMemberSignature;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->fromMethodNameAndDesc(Ljava/lang/String;Ljava/lang/String;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->fromMethodSignatureAndParameterIndex(Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;I)Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->()V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->(Ljava/lang/String;)V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->(Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->equals(Ljava/lang/Object;)Z +HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->getSignature()Ljava/lang/String; HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->hashCode()I HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/PackagePartProvider$Empty;->()V HSPLkotlin/reflect/jvm/internal/impl/load/kotlin/PackagePartProvider$Empty;->()V @@ -15148,10 +15057,12 @@ HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->buil HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->buildPartial()Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->create()Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->maybeForceBuilderInitialization()V +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->mergeFrom(Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation;)Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->mergeFrom(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->mergeFrom(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Lkotlin/reflect/jvm/internal/impl/protobuf/MessageLite$Builder; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder;->setId(I)Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation$Builder; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation;->()V +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation;->(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation;->(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$1;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation;->(Lkotlin/reflect/jvm/internal/impl/protobuf/GeneratedMessageLite$Builder;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Annotation;->(Lkotlin/reflect/jvm/internal/impl/protobuf/GeneratedMessageLite$Builder;Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$1;)V @@ -15274,6 +15185,7 @@ HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getOldFlags()I HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getReceiverType()Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Type; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getReturnType()Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Type; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getReturnTypeId()I +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getSerializedSize()I HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getTypeParameter(I)Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$TypeParameter; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getTypeParameterCount()I HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->getTypeParameterList()Ljava/util/List; @@ -15290,6 +15202,8 @@ HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->hasReturnType( HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->hasReturnTypeId()Z HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->hasTypeTable()Z HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->initFields()V +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->isInitialized()Z +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Function;->writeTo(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedOutputStream;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$MemberKind$1;->()V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$MemberKind;->()V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$MemberKind;->(Ljava/lang/String;III)V @@ -15344,6 +15258,7 @@ HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property$1;->()V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property$1;->parsePartialFrom(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Ljava/lang/Object; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property$1;->parsePartialFrom(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property;->()V +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property;->(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property;->(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$1;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property;->(Z)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property;->getContextReceiverTypeCount()I @@ -15502,6 +15417,7 @@ HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter$1;-> HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter$1;->parsePartialFrom(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Ljava/lang/Object; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter$1;->parsePartialFrom(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter; HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter;->()V +HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter;->(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter;->(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$1;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter;->(Z)V HSPLkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter;->getDefaultInstance()Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$ValueParameter; @@ -15755,6 +15671,7 @@ HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolve HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolverBase;->()V HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolverBase;->([Ljava/lang/String;Ljava/util/Set;Ljava/util/List;)V HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolverBase;->getQualifiedClassName(I)Ljava/lang/String; +HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolverBase;->getString(I)Ljava/lang/String; HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolverBase;->isLocalClassName(I)Z HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmNameResolverKt;->toExpandedRecordsList(Ljava/util/List;)Ljava/util/List; HSPLkotlin/reflect/jvm/internal/impl/metadata/jvm/deserialization/JvmProtoBufUtil;->()V @@ -15923,7 +15840,8 @@ HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readBytes()Lkot HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readDouble()D HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readEnum()I HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readFloat()F -HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readInt32()I +HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readMessage(Lkotlin/reflect/jvm/internal/impl/protobuf/MessageLite$Builder;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)V +HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readMessage(Lkotlin/reflect/jvm/internal/impl/protobuf/Parser;Lkotlin/reflect/jvm/internal/impl/protobuf/ExtensionRegistryLite;)Lkotlin/reflect/jvm/internal/impl/protobuf/MessageLite; HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readRawByte()B HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readRawLittleEndian32()I HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readRawLittleEndian64()J @@ -15931,6 +15849,7 @@ HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readRawVarint32 HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readRawVarint64()J HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readRawVarint64SlowPath()J HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readSInt64()J +HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->readTag()I HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->recomputeBufferSizeAfterLimit()V HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;->refillBuffer(I)V HSPLkotlin/reflect/jvm/internal/impl/protobuf/CodedOutputStream;->(Ljava/io/OutputStream;[B)V @@ -15975,6 +15894,7 @@ HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet$1;->()V HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->()V HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->()V HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->(Z)V +HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->addRepeatedField(Lkotlin/reflect/jvm/internal/impl/protobuf/FieldSet$FieldDescriptorLite;Ljava/lang/Object;)V HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->computeElementSize(Lkotlin/reflect/jvm/internal/impl/protobuf/WireFormat$FieldType;ILjava/lang/Object;)I HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->computeElementSizeNoTag(Lkotlin/reflect/jvm/internal/impl/protobuf/WireFormat$FieldType;Ljava/lang/Object;)I HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->computeFieldSize(Lkotlin/reflect/jvm/internal/impl/protobuf/FieldSet$FieldDescriptorLite;Ljava/lang/Object;)I @@ -15982,7 +15902,7 @@ HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->getField(Lkotlin/reflec HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->getSerializedSize()I HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->getWireFormatForFieldType(Lkotlin/reflect/jvm/internal/impl/protobuf/WireFormat$FieldType;Z)I HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->hasField(Lkotlin/reflect/jvm/internal/impl/protobuf/FieldSet$FieldDescriptorLite;)Z -HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->isInitialized(Ljava/util/Map$Entry;)Z +HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->isInitialized()Z HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->iterator()Ljava/util/Iterator; HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->newFieldSet()Lkotlin/reflect/jvm/internal/impl/protobuf/FieldSet; HSPLkotlin/reflect/jvm/internal/impl/protobuf/FieldSet;->readPrimitiveField(Lkotlin/reflect/jvm/internal/impl/protobuf/CodedInputStream;Lkotlin/reflect/jvm/internal/impl/protobuf/WireFormat$FieldType;Z)Ljava/lang/Object; @@ -16073,6 +15993,7 @@ HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->binarySearchInArr HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->checkMutable()V HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->ensureEntryArrayMutable()V HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->entrySet()Ljava/util/Set; +HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->getArrayEntryAt(I)Ljava/util/Map$Entry; HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->getNumArrayEntries()I HSPLkotlin/reflect/jvm/internal/impl/protobuf/SmallSortedMap;->getOverflowEntries()Ljava/lang/Iterable; @@ -16321,6 +16242,15 @@ HSPLkotlin/reflect/jvm/internal/impl/resolve/ResolutionAnchorProviderKt;->getRes HSPLkotlin/reflect/jvm/internal/impl/resolve/calls/inference/CapturedTypeConstructorKt;->createCapturedIfNeeded(Lkotlin/reflect/jvm/internal/impl/types/TypeProjection;Lkotlin/reflect/jvm/internal/impl/descriptors/TypeParameterDescriptor;)Lkotlin/reflect/jvm/internal/impl/types/TypeProjection; HSPLkotlin/reflect/jvm/internal/impl/resolve/calls/inference/CapturedTypeConstructorKt;->wrapWithCapturingSubstitution$default(Lkotlin/reflect/jvm/internal/impl/types/TypeSubstitution;ZILjava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/types/TypeSubstitution; HSPLkotlin/reflect/jvm/internal/impl/resolve/calls/inference/CapturedTypeConstructorKt;->wrapWithCapturingSubstitution(Lkotlin/reflect/jvm/internal/impl/types/TypeSubstitution;Z)Lkotlin/reflect/jvm/internal/impl/types/TypeSubstitution; +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/BooleanValue;->(Z)V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue;->(Ljava/lang/Object;)V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory;->()V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory;->()V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory;->createConstantValue(Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/EnumValue;->(Lkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/name/Name;)V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/IntValue;->(I)V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/IntegerValueConstant;->(Ljava/lang/Object;)V +HSPLkotlin/reflect/jvm/internal/impl/resolve/constants/StringValue;->(Ljava/lang/String;)V HSPLkotlin/reflect/jvm/internal/impl/resolve/descriptorUtil/DescriptorUtilsKt$$Lambda$0;->()V HSPLkotlin/reflect/jvm/internal/impl/resolve/descriptorUtil/DescriptorUtilsKt$$Lambda$0;->()V HSPLkotlin/reflect/jvm/internal/impl/resolve/descriptorUtil/DescriptorUtilsKt$$Lambda$0;->getNeighbors(Ljava/lang/Object;)Ljava/lang/Iterable; @@ -16499,6 +16429,7 @@ HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/Deserializati HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationConfiguration$Default;->getSkipMetadataVersionCheck()Z HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationConfiguration$Default;->getSkipPrereleaseCheck()Z HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationConfiguration$Default;->getTypeAliasesAllowed()Z +HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext;->(Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationComponents;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/NameResolver;Lkotlin/reflect/jvm/internal/impl/descriptors/DeclarationDescriptor;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/TypeTable;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/VersionRequirementTable;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/BinaryVersion;Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/descriptors/DeserializedContainerSource;Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/TypeDeserializer;Ljava/util/List;)V HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext;->childContext$default(Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext;Lkotlin/reflect/jvm/internal/impl/descriptors/DeclarationDescriptor;Ljava/util/List;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/NameResolver;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/TypeTable;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/VersionRequirementTable;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/BinaryVersion;ILjava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext; HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext;->childContext(Lkotlin/reflect/jvm/internal/impl/descriptors/DeclarationDescriptor;Ljava/util/List;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/NameResolver;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/TypeTable;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/VersionRequirementTable;Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/BinaryVersion;)Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext; HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationContext;->getComponents()Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/DeserializationComponents; @@ -16553,6 +16484,7 @@ HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/MemberDeseria HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/MemberDeserializer;->initializeWithCoroutinesExperimentalityStatus(Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/descriptors/DeserializedSimpleFunctionDescriptor;Lkotlin/reflect/jvm/internal/impl/descriptors/ReceiverParameterDescriptor;Lkotlin/reflect/jvm/internal/impl/descriptors/ReceiverParameterDescriptor;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lkotlin/reflect/jvm/internal/impl/types/KotlinType;Lkotlin/reflect/jvm/internal/impl/descriptors/Modality;Lkotlin/reflect/jvm/internal/impl/descriptors/DescriptorVisibility;Ljava/util/Map;)V HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/MemberDeserializer;->loadConstructor(Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Constructor;Z)Lkotlin/reflect/jvm/internal/impl/descriptors/ClassConstructorDescriptor; HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/MemberDeserializer;->loadOldFlags(I)I +HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/MemberDeserializer;->loadProperty(Lkotlin/reflect/jvm/internal/impl/metadata/ProtoBuf$Property;)Lkotlin/reflect/jvm/internal/impl/descriptors/PropertyDescriptor; HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/MemberDeserializer;->valueParameters(Ljava/util/List;Lkotlin/reflect/jvm/internal/impl/protobuf/MessageLite;Lkotlin/reflect/jvm/internal/impl/serialization/deserialization/AnnotatedCallableKind;)Ljava/util/List; HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/NameResolverUtilKt;->getClassId(Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/NameResolver;I)Lkotlin/reflect/jvm/internal/impl/name/ClassId; HSPLkotlin/reflect/jvm/internal/impl/serialization/deserialization/NameResolverUtilKt;->getName(Lkotlin/reflect/jvm/internal/impl/metadata/deserialization/NameResolver;I)Lkotlin/reflect/jvm/internal/impl/name/Name; @@ -16827,7 +16759,6 @@ HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$LockBasedNo HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$LockBasedNotNullLazyValueWithPostCompute;->(Lkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager;Lkotlin/jvm/functions/Function0;)V HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$LockBasedNotNullLazyValueWithPostCompute;->invoke()Ljava/lang/Object; HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$MapBasedMemoizedFunction;->(Lkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager;Ljava/util/concurrent/ConcurrentMap;Lkotlin/jvm/functions/Function1;)V -HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$MapBasedMemoizedFunction;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull;->()V HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull;->(Lkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager;Ljava/util/concurrent/ConcurrentMap;Lkotlin/jvm/functions/Function1;)V HSPLkotlin/reflect/jvm/internal/impl/storage/LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull;->invoke(Ljava/lang/Object;)Ljava/lang/Object; @@ -17193,8 +17124,6 @@ HSPLkotlin/sequences/SequencesKt__SequencesKt;->constrainOnce(Lkotlin/sequences/ HSPLkotlin/sequences/SequencesKt__SequencesKt;->generateSequence(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence; HSPLkotlin/sequences/SequencesKt__SequencesKt;->generateSequence(Lkotlin/jvm/functions/Function0;)Lkotlin/sequences/Sequence; HSPLkotlin/sequences/SequencesKt___SequencesJvmKt$filterIsInstance$1;->(Ljava/lang/Class;)V -HSPLkotlin/sequences/SequencesKt___SequencesJvmKt$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean; -HSPLkotlin/sequences/SequencesKt___SequencesJvmKt$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLkotlin/sequences/SequencesKt___SequencesJvmKt;->filterIsInstance(Lkotlin/sequences/Sequence;Ljava/lang/Class;)Lkotlin/sequences/Sequence; HSPLkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;->()V HSPLkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;->()V @@ -17232,7 +17161,6 @@ HSPLkotlin/text/CharsKt__CharJVMKt;->isWhitespace(C)Z HSPLkotlin/text/Charsets;->()V HSPLkotlin/text/Charsets;->()V HSPLkotlin/text/DelimitedRangesSequence$iterator$1;->(Lkotlin/text/DelimitedRangesSequence;)V -HSPLkotlin/text/DelimitedRangesSequence$iterator$1;->calcNext()V HSPLkotlin/text/DelimitedRangesSequence$iterator$1;->hasNext()Z HSPLkotlin/text/DelimitedRangesSequence$iterator$1;->next()Ljava/lang/Object; HSPLkotlin/text/DelimitedRangesSequence$iterator$1;->next()Lkotlin/ranges/IntRange; @@ -17267,6 +17195,7 @@ HSPLkotlin/text/StringsKt;->contains$default(Ljava/lang/CharSequence;CZILjava/la HSPLkotlin/text/StringsKt;->contains$default(Ljava/lang/CharSequence;Ljava/lang/CharSequence;ZILjava/lang/Object;)Z HSPLkotlin/text/StringsKt;->contains(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Z)Z HSPLkotlin/text/StringsKt;->drop(Ljava/lang/String;I)Ljava/lang/String; +HSPLkotlin/text/StringsKt;->endsWith$default(Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Z HSPLkotlin/text/StringsKt;->getIndices(Ljava/lang/CharSequence;)Lkotlin/ranges/IntRange; HSPLkotlin/text/StringsKt;->getLastIndex(Ljava/lang/CharSequence;)I HSPLkotlin/text/StringsKt;->indexOf$default(Ljava/lang/CharSequence;CIZILjava/lang/Object;)I @@ -17292,10 +17221,11 @@ HSPLkotlin/text/StringsKt__IndentKt$getIndentFunction$1;->invoke(Ljava/lang/Obje HSPLkotlin/text/StringsKt__IndentKt$getIndentFunction$1;->invoke(Ljava/lang/String;)Ljava/lang/String; HSPLkotlin/text/StringsKt__IndentKt;->getIndentFunction$StringsKt__IndentKt(Ljava/lang/String;)Lkotlin/jvm/functions/Function1; HSPLkotlin/text/StringsKt__IndentKt;->indentWidth$StringsKt__IndentKt(Ljava/lang/String;)I -HSPLkotlin/text/StringsKt__IndentKt;->replaceIndent(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; HSPLkotlin/text/StringsKt__IndentKt;->trimIndent(Ljava/lang/String;)Ljava/lang/String; HSPLkotlin/text/StringsKt__StringNumberConversionsKt;->toLongOrNull(Ljava/lang/String;)Ljava/lang/Long; HSPLkotlin/text/StringsKt__StringNumberConversionsKt;->toLongOrNull(Ljava/lang/String;I)Ljava/lang/Long; +HSPLkotlin/text/StringsKt__StringsJVMKt;->endsWith$default(Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Z +HSPLkotlin/text/StringsKt__StringsJVMKt;->endsWith(Ljava/lang/String;Ljava/lang/String;Z)Z HSPLkotlin/text/StringsKt__StringsJVMKt;->isBlank(Ljava/lang/CharSequence;)Z HSPLkotlin/text/StringsKt__StringsJVMKt;->regionMatches(Ljava/lang/String;ILjava/lang/String;IIZ)Z HSPLkotlin/text/StringsKt__StringsJVMKt;->replace$default(Ljava/lang/String;CCZILjava/lang/Object;)Ljava/lang/String; @@ -17315,7 +17245,6 @@ HSPLkotlin/text/StringsKt__StringsKt;->contains$default(Ljava/lang/CharSequence; HSPLkotlin/text/StringsKt__StringsKt;->contains$default(Ljava/lang/CharSequence;Ljava/lang/CharSequence;ZILjava/lang/Object;)Z HSPLkotlin/text/StringsKt__StringsKt;->contains(Ljava/lang/CharSequence;CZ)Z HSPLkotlin/text/StringsKt__StringsKt;->contains(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Z)Z -HSPLkotlin/text/StringsKt__StringsKt;->findAnyOf$StringsKt__StringsKt(Ljava/lang/CharSequence;Ljava/util/Collection;IZZ)Lkotlin/Pair; HSPLkotlin/text/StringsKt__StringsKt;->getIndices(Ljava/lang/CharSequence;)Lkotlin/ranges/IntRange; HSPLkotlin/text/StringsKt__StringsKt;->getLastIndex(Ljava/lang/CharSequence;)I HSPLkotlin/text/StringsKt__StringsKt;->indexOf$default(Ljava/lang/CharSequence;CIZILjava/lang/Object;)I @@ -17444,6 +17373,7 @@ HSPLkotlinx/coroutines/flow/SharedFlowKt;->MutableSharedFlow$default(IILkotlinx/ HSPLkotlinx/coroutines/flow/SharedFlowKt;->MutableSharedFlow(IILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/MutableSharedFlow; HSPLkotlinx/coroutines/flow/SharedFlowKt;->access$setBufferAt([Ljava/lang/Object;JLjava/lang/Object;)V HSPLkotlinx/coroutines/flow/SharedFlowKt;->setBufferAt([Ljava/lang/Object;JLjava/lang/Object;)V +HSPLkotlinx/coroutines/flow/StateFlowImpl;->()V HSPLkotlinx/coroutines/flow/StateFlowImpl;->(Ljava/lang/Object;)V HSPLkotlinx/coroutines/flow/StateFlowImpl;->getValue()Ljava/lang/Object; HSPLkotlinx/coroutines/flow/StateFlowImpl;->setValue(Ljava/lang/Object;)V @@ -17501,6 +17431,7 @@ HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->canonicalizeSyncMode(Ljava HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->detachCancellationSignal(Landroid/os/CancellationSignal;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->execute(Ljava/lang/String;[Ljava/lang/Object;Landroid/os/CancellationSignal;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->executeForChangedRowCount(Ljava/lang/String;[Ljava/lang/Object;Landroid/os/CancellationSignal;)I +HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->executeForCursorWindow(Ljava/lang/String;[Ljava/lang/Object;Landroid/database/CursorWindow;IIZLandroid/os/CancellationSignal;)I HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->executeForLastInsertedRowId(Ljava/lang/String;[Ljava/lang/Object;Landroid/os/CancellationSignal;)J HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->executeForLong(Ljava/lang/String;[Ljava/lang/Object;Landroid/os/CancellationSignal;)J HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->executeForString(Ljava/lang/String;[Ljava/lang/Object;Landroid/os/CancellationSignal;)Ljava/lang/String; @@ -17527,18 +17458,24 @@ HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->setWalModeFromConfiguratio HSPLnet/zetetic/database/sqlcipher/SQLiteConnection;->throwIfStatementForbidden(Lnet/zetetic/database/sqlcipher/SQLiteConnection$PreparedStatement;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool$AcquiredConnectionStatus;->()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool$AcquiredConnectionStatus;->(Ljava/lang/String;I)V +HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool$ConnectionWaiter;->()V +HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool$ConnectionWaiter;->(Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool$1;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->(Lnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->acquireConnection(Ljava/lang/String;ILandroid/os/CancellationSignal;)Lnet/zetetic/database/sqlcipher/SQLiteConnection; HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->closeExcessConnectionsAndLogExceptionsLocked()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->finishAcquireConnectionLocked(Lnet/zetetic/database/sqlcipher/SQLiteConnection;I)V +HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->getPriority(I)I HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->markAcquiredConnectionsLocked(Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool$AcquiredConnectionStatus;)V +HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->obtainConnectionWaiterLocked(Ljava/lang/Thread;JIZLjava/lang/String;I)Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool$ConnectionWaiter; HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->open()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->open(Lnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;)Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool; HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->openConnectionLocked(Lnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;Z)Lnet/zetetic/database/sqlcipher/SQLiteConnection; HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->reconfigure(Lnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->reconfigureAllConnectionsLocked()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->recycleConnectionLocked(Lnet/zetetic/database/sqlcipher/SQLiteConnection;Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool$AcquiredConnectionStatus;)Z +HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->recycleConnectionWaiterLocked(Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool$ConnectionWaiter;)V +HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->releaseConnection(Lnet/zetetic/database/sqlcipher/SQLiteConnection;)V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->setMaxConnectionPoolSizeLocked()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->throwIfClosedLocked()V HSPLnet/zetetic/database/sqlcipher/SQLiteConnectionPool;->tryAcquireNonPrimaryConnectionLocked(Ljava/lang/String;I)Lnet/zetetic/database/sqlcipher/SQLiteConnection; @@ -17576,7 +17513,6 @@ HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->execSQL(Ljava/lang/String;)V HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->execSQL(Ljava/lang/String;[Ljava/lang/Object;)V HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->executeSql(Ljava/lang/String;[Ljava/lang/Object;)I HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->findEditTable(Ljava/lang/String;)Ljava/lang/String; -HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->getPath()Ljava/lang/String; HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->getThreadDefaultConnectionFlags(Z)I HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->getThreadSession()Lnet/zetetic/database/sqlcipher/SQLiteSession; HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->getVersion()I @@ -17609,6 +17545,7 @@ HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->setVersion(I)V HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->throwIfNotOpenLocked()V HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->update(Ljava/lang/String;ILandroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/Object;)I HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->update(Ljava/lang/String;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I +HSPLnet/zetetic/database/sqlcipher/SQLiteDatabase;->updateWithOnConflict(Ljava/lang/String;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;I)I HSPLnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;->()V HSPLnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;->(Ljava/lang/String;I[BLnet/zetetic/database/sqlcipher/SQLiteDatabaseHook;)V HSPLnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;->(Lnet/zetetic/database/sqlcipher/SQLiteDatabaseConfiguration;)V @@ -17639,12 +17576,11 @@ HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->bind(ILjava/lang/Object;)V HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->bindAllArgs([Ljava/lang/Object;)V HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->bindAllArgsAsStrings([Ljava/lang/String;)V HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->bindString(ILjava/lang/String;)V +HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->clearBindings()V HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->getBindArgs()[Ljava/lang/Object; HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->getColumnNames()[Ljava/lang/String; -HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->getConnectionFlags()I HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->getDatabase()Lnet/zetetic/database/sqlcipher/SQLiteDatabase; HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->getSql()Ljava/lang/String; -HSPLnet/zetetic/database/sqlcipher/SQLiteProgram;->onAllReferencesReleased()V HSPLnet/zetetic/database/sqlcipher/SQLiteQuery;->(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;Ljava/lang/String;Landroid/os/CancellationSignal;)V HSPLnet/zetetic/database/sqlcipher/SQLiteQuery;->fillWindow(Landroid/database/CursorWindow;IIZ)I HSPLnet/zetetic/database/sqlcipher/SQLiteQueryBuilder;->()V @@ -17657,12 +17593,10 @@ HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->()V HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->(Lnet/zetetic/database/sqlcipher/SQLiteConnectionPool;)V HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->acquireConnection(Ljava/lang/String;ILandroid/os/CancellationSignal;)V HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->beginTransaction(ILnet/zetetic/database/sqlcipher/SQLiteTransactionListener;ILandroid/os/CancellationSignal;)V -HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->beginTransactionUnchecked(ILnet/zetetic/database/sqlcipher/SQLiteTransactionListener;ILandroid/os/CancellationSignal;)V HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->endTransaction(Landroid/os/CancellationSignal;)V HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->endTransactionUnchecked(Landroid/os/CancellationSignal;Z)V HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->executeForChangedRowCount(Ljava/lang/String;[Ljava/lang/Object;ILandroid/os/CancellationSignal;)I HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->executeForCursorWindow(Ljava/lang/String;[Ljava/lang/Object;Landroid/database/CursorWindow;IIZILandroid/os/CancellationSignal;)I -HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->executeForLastInsertedRowId(Ljava/lang/String;[Ljava/lang/Object;ILandroid/os/CancellationSignal;)J HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->executeForLong(Ljava/lang/String;[Ljava/lang/Object;ILandroid/os/CancellationSignal;)J HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->executeSpecial(Ljava/lang/String;[Ljava/lang/Object;ILandroid/os/CancellationSignal;)Z HSPLnet/zetetic/database/sqlcipher/SQLiteSession;->hasTransaction()Z @@ -17853,9 +17787,11 @@ HSPLokhttp3/HttpUrl;->toString()Ljava/lang/String; HSPLokhttp3/HttpUrl;->uri()Ljava/net/URI; HSPLokhttp3/MediaType;->()V HSPLokhttp3/MediaType;->(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +HSPLokhttp3/MediaType;->charset()Ljava/nio/charset/Charset; HSPLokhttp3/MediaType;->charset(Ljava/nio/charset/Charset;)Ljava/nio/charset/Charset; HSPLokhttp3/MediaType;->get(Ljava/lang/String;)Lokhttp3/MediaType; HSPLokhttp3/MediaType;->parse(Ljava/lang/String;)Lokhttp3/MediaType; +HSPLokhttp3/MediaType;->toString()Ljava/lang/String; HSPLokhttp3/OkHttpClient$1;->()V HSPLokhttp3/OkHttpClient$1;->addLenient(Lokhttp3/Headers$Builder;Ljava/lang/String;)V HSPLokhttp3/OkHttpClient$1;->apply(Lokhttp3/ConnectionSpec;Ljavax/net/ssl/SSLSocket;Z)V @@ -17880,6 +17816,7 @@ HSPLokhttp3/OkHttpClient$Builder;->eventListener(Lokhttp3/EventListener;)Lokhttp HSPLokhttp3/OkHttpClient$Builder;->protocols(Ljava/util/List;)Lokhttp3/OkHttpClient$Builder; HSPLokhttp3/OkHttpClient$Builder;->proxySelector(Ljava/net/ProxySelector;)Lokhttp3/OkHttpClient$Builder; HSPLokhttp3/OkHttpClient$Builder;->readTimeout(JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; +HSPLokhttp3/OkHttpClient$Builder;->retryOnConnectionFailure(Z)Lokhttp3/OkHttpClient$Builder; HSPLokhttp3/OkHttpClient$Builder;->sslSocketFactory(Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder; HSPLokhttp3/OkHttpClient;->()V HSPLokhttp3/OkHttpClient;->(Lokhttp3/OkHttpClient$Builder;)V @@ -17918,6 +17855,8 @@ HSPLokhttp3/RealCall$AsyncCall;->()V HSPLokhttp3/RealCall$AsyncCall;->(Lokhttp3/RealCall;Lokhttp3/Callback;)V HSPLokhttp3/RealCall$AsyncCall;->execute()V HSPLokhttp3/RealCall$AsyncCall;->executeOn(Ljava/util/concurrent/ExecutorService;)V +HSPLokhttp3/RealCall$AsyncCall;->get()Lokhttp3/RealCall; +HSPLokhttp3/RealCall$AsyncCall;->host()Ljava/lang/String; HSPLokhttp3/RealCall;->(Lokhttp3/OkHttpClient;Lokhttp3/Request;Z)V HSPLokhttp3/RealCall;->captureCallStackTrace()V HSPLokhttp3/RealCall;->enqueue(Lokhttp3/Callback;)V @@ -17948,6 +17887,7 @@ HSPLokhttp3/Request;->newBuilder()Lokhttp3/Request$Builder; HSPLokhttp3/Request;->url()Lokhttp3/HttpUrl; HSPLokhttp3/RequestBody$2;->(Lokhttp3/MediaType;I[BI)V HSPLokhttp3/RequestBody;->()V +HSPLokhttp3/RequestBody;->create(Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/RequestBody; HSPLokhttp3/RequestBody;->create(Lokhttp3/MediaType;[B)Lokhttp3/RequestBody; HSPLokhttp3/RequestBody;->create(Lokhttp3/MediaType;[BII)Lokhttp3/RequestBody; HSPLokhttp3/Response$Builder;->()V @@ -17976,6 +17916,7 @@ HSPLokhttp3/Response;->isSuccessful()Z HSPLokhttp3/Response;->message()Ljava/lang/String; HSPLokhttp3/Response;->newBuilder()Lokhttp3/Response$Builder; HSPLokhttp3/Response;->request()Lokhttp3/Request; +HSPLokhttp3/Response;->toString()Ljava/lang/String; HSPLokhttp3/ResponseBody$1;->(Lokhttp3/MediaType;JLokio/BufferedSource;)V HSPLokhttp3/ResponseBody$1;->source()Lokio/BufferedSource; HSPLokhttp3/ResponseBody;->()V @@ -18222,6 +18163,7 @@ HSPLokio/AsyncTimeout;->()V HSPLokio/AsyncTimeout;->()V HSPLokio/AsyncTimeout;->access$getHead$cp()Lokio/AsyncTimeout; HSPLokio/AsyncTimeout;->access$getIDLE_TIMEOUT_MILLIS$cp()J +HSPLokio/AsyncTimeout;->access$getIDLE_TIMEOUT_NANOS$cp()J HSPLokio/AsyncTimeout;->access$getInQueue$p(Lokio/AsyncTimeout;)Z HSPLokio/AsyncTimeout;->access$getNext$p(Lokio/AsyncTimeout;)Lokio/AsyncTimeout; HSPLokio/AsyncTimeout;->access$remainingNanos(Lokio/AsyncTimeout;J)J @@ -18244,11 +18186,12 @@ HSPLokio/Buffer;->close()V HSPLokio/Buffer;->completeSegmentByteCount()J HSPLokio/Buffer;->copyTo(Lokio/Buffer;JJ)Lokio/Buffer; HSPLokio/Buffer;->exhausted()Z -HSPLokio/Buffer;->getByte(J)B HSPLokio/Buffer;->indexOf(BJJ)J HSPLokio/Buffer;->indexOfElement(Lokio/ByteString;J)J HSPLokio/Buffer;->read(Lokio/Buffer;J)J HSPLokio/Buffer;->read([BII)I +HSPLokio/Buffer;->readByte()B +HSPLokio/Buffer;->readByteArray()[B HSPLokio/Buffer;->readByteArray(J)[B HSPLokio/Buffer;->readByteString()Lokio/ByteString; HSPLokio/Buffer;->readByteString(J)Lokio/ByteString; @@ -18257,11 +18200,14 @@ HSPLokio/Buffer;->readHexadecimalUnsignedLong()J HSPLokio/Buffer;->readInt()I HSPLokio/Buffer;->readIntLe()I HSPLokio/Buffer;->readShort()S +HSPLokio/Buffer;->readString(JLjava/nio/charset/Charset;)Ljava/lang/String; HSPLokio/Buffer;->readString(Ljava/nio/charset/Charset;)Ljava/lang/String; HSPLokio/Buffer;->readUtf8(J)Ljava/lang/String; HSPLokio/Buffer;->setSize$okio(J)V HSPLokio/Buffer;->size()J +HSPLokio/Buffer;->skip(J)V HSPLokio/Buffer;->writableSegment$okio(I)Lokio/Segment; +HSPLokio/Buffer;->write(Lokio/Buffer;J)V HSPLokio/Buffer;->write([B)Lokio/Buffer; HSPLokio/Buffer;->write([BII)Lokio/Buffer; HSPLokio/Buffer;->writeAll(Lokio/Source;)J @@ -18388,6 +18334,7 @@ HSPLokio/RealBufferedSource;->readShort()S HSPLokio/RealBufferedSource;->readString(Ljava/nio/charset/Charset;)Ljava/lang/String; HSPLokio/RealBufferedSource;->readUtf8LineStrict()Ljava/lang/String; HSPLokio/RealBufferedSource;->readUtf8LineStrict(J)Ljava/lang/String; +HSPLokio/RealBufferedSource;->request(J)Z HSPLokio/RealBufferedSource;->require(J)V HSPLokio/RealBufferedSource;->select(Lokio/Options;)I HSPLokio/RealBufferedSource;->skip(J)V @@ -18481,6 +18428,7 @@ HSPLorg/conscrypt/ActiveSession;->onPeerCertificateAvailable(Ljava/lang/String;I HSPLorg/conscrypt/ActiveSession;->onPeerCertificatesReceived(Ljava/lang/String;I[Ljava/security/cert/X509Certificate;)V HSPLorg/conscrypt/AddressUtils;->isLiteralIpAddress(Ljava/lang/String;)Z HSPLorg/conscrypt/AddressUtils;->isValidSniHostname(Ljava/lang/String;)Z +HSPLorg/conscrypt/ArrayUtils;->checkOffsetAndCount(III)V HSPLorg/conscrypt/BufferUtils;->checkNotNull([Ljava/nio/ByteBuffer;)V HSPLorg/conscrypt/BufferUtils;->getBufferLargerThan([Ljava/nio/ByteBuffer;I)Ljava/nio/ByteBuffer; HSPLorg/conscrypt/BufferUtils;->remaining([Ljava/nio/ByteBuffer;)J @@ -18564,7 +18512,6 @@ HSPLorg/conscrypt/ConscryptEngine;->singleDstBuffer(Ljava/nio/ByteBuffer;)[Ljava HSPLorg/conscrypt/ConscryptEngine;->singleSrcBuffer(Ljava/nio/ByteBuffer;)[Ljava/nio/ByteBuffer; HSPLorg/conscrypt/ConscryptEngine;->transitionTo(I)V HSPLorg/conscrypt/ConscryptEngine;->unwrap(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult; -HSPLorg/conscrypt/ConscryptEngine;->unwrap([Ljava/nio/ByteBuffer;II[Ljava/nio/ByteBuffer;II)Ljavax/net/ssl/SSLEngineResult; HSPLorg/conscrypt/ConscryptEngine;->unwrap([Ljava/nio/ByteBuffer;[Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult; HSPLorg/conscrypt/ConscryptEngine;->verifyCertificateChain([[BLjava/lang/String;)V HSPLorg/conscrypt/ConscryptEngine;->wrap(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult; @@ -18636,6 +18583,9 @@ HSPLorg/conscrypt/ExternalSession;->getPacketBufferSize()I HSPLorg/conscrypt/ExternalSession;->getPeerCertificates()[Ljava/security/cert/X509Certificate; HSPLorg/conscrypt/ExternalSession;->getPeerHost()Ljava/lang/String; HSPLorg/conscrypt/ExternalSession;->getProtocol()Ljava/lang/String; +HSPLorg/conscrypt/GCMParameters;->(I[B)V +HSPLorg/conscrypt/GCMParameters;->getIV()[B +HSPLorg/conscrypt/GCMParameters;->getTLen()I HSPLorg/conscrypt/HandshakeListener;->()V HSPLorg/conscrypt/Java7ExtendedSSLSession;->()V HSPLorg/conscrypt/Java7ExtendedSSLSession;->(Lorg/conscrypt/ExternalSession;)V @@ -18681,6 +18631,7 @@ HSPLorg/conscrypt/NativeRef$EVP_PKEY;->doFree(J)V HSPLorg/conscrypt/NativeRef$HMAC_CTX;->(J)V HSPLorg/conscrypt/NativeRef$HMAC_CTX;->doFree(J)V HSPLorg/conscrypt/NativeRef$SSL_SESSION;->(J)V +HSPLorg/conscrypt/NativeRef$SSL_SESSION;->doFree(J)V HSPLorg/conscrypt/NativeRef;->(J)V HSPLorg/conscrypt/NativeRef;->finalize()V HSPLorg/conscrypt/NativeSsl$BioWrapper;->(Lorg/conscrypt/NativeSsl;)V @@ -18732,6 +18683,22 @@ HSPLorg/conscrypt/NativeSslSession;->getOcspResponse(Lorg/conscrypt/ConscryptSes HSPLorg/conscrypt/NativeSslSession;->newInstance(Lorg/conscrypt/NativeRef$SSL_SESSION;Lorg/conscrypt/ConscryptSession;)Lorg/conscrypt/NativeSslSession; HSPLorg/conscrypt/OidData;->()V HSPLorg/conscrypt/OidData;->oidToAlgorithmName(Ljava/lang/String;)Ljava/lang/String; +HSPLorg/conscrypt/OpenSSLAeadCipher;->()V +HSPLorg/conscrypt/OpenSSLAeadCipher;->(Lorg/conscrypt/OpenSSLCipher$Mode;)V +HSPLorg/conscrypt/OpenSSLAeadCipher;->allowsNonceReuse()Z +HSPLorg/conscrypt/OpenSSLAeadCipher;->checkInitialization()V +HSPLorg/conscrypt/OpenSSLAeadCipher;->checkSupportedTagLength(I)V +HSPLorg/conscrypt/OpenSSLAeadCipher;->doFinalInternal([BII)I +HSPLorg/conscrypt/OpenSSLAeadCipher;->engineInitInternal([BLjava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)V +HSPLorg/conscrypt/OpenSSLAeadCipher;->expand(I)V +HSPLorg/conscrypt/OpenSSLAeadCipher;->reset()V +HSPLorg/conscrypt/OpenSSLAeadCipher;->updateInternal([BII[BII)I +HSPLorg/conscrypt/OpenSSLAeadCipherAES$GCM;->()V +HSPLorg/conscrypt/OpenSSLAeadCipherAES$GCM;->getEVP_AEAD(I)J +HSPLorg/conscrypt/OpenSSLAeadCipherAES;->(Lorg/conscrypt/OpenSSLCipher$Mode;)V +HSPLorg/conscrypt/OpenSSLAeadCipherAES;->checkSupportedKeySize(I)V +HSPLorg/conscrypt/OpenSSLAeadCipherAES;->getCipherBlockSize()I +HSPLorg/conscrypt/OpenSSLAeadCipherAES;->getOutputSizeForFinal(I)I HSPLorg/conscrypt/OpenSSLBIOInputStream;->(Ljava/io/InputStream;Z)V HSPLorg/conscrypt/OpenSSLBIOInputStream;->getBioContext()J HSPLorg/conscrypt/OpenSSLBIOInputStream;->read([B)I @@ -18883,6 +18850,7 @@ HSPLorg/conscrypt/Platform;->blockGuardOnNetwork()V HSPLorg/conscrypt/Platform;->checkServerTrusted(Ljavax/net/ssl/X509TrustManager;[Ljava/security/cert/X509Certificate;Ljava/lang/String;Lorg/conscrypt/ConscryptEngine;)V HSPLorg/conscrypt/Platform;->checkTrusted(Ljava/lang/String;Ljavax/net/ssl/X509TrustManager;[Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Object;)Z HSPLorg/conscrypt/Platform;->createEngineSocket(Ljava/net/Socket;Ljava/lang/String;IZLorg/conscrypt/SSLParametersImpl;)Lorg/conscrypt/ConscryptEngineSocket; +HSPLorg/conscrypt/Platform;->fromGCMParameterSpec(Ljava/security/spec/AlgorithmParameterSpec;)Lorg/conscrypt/GCMParameters; HSPLorg/conscrypt/Platform;->getDefaultProviderName()Ljava/lang/String; HSPLorg/conscrypt/Platform;->getSSLParameters(Ljavax/net/ssl/SSLParameters;Lorg/conscrypt/SSLParametersImpl;Lorg/conscrypt/ConscryptEngine;)V HSPLorg/conscrypt/Platform;->getSSLParametersFromImpl(Ljavax/net/ssl/SSLParameters;Lorg/conscrypt/SSLParametersImpl;)V @@ -18996,7 +18964,6 @@ HSPLorg/greenrobot/eventbus/SubscriberMethodFinder;->getMethodsAndRelease(Lorg/g HSPLorg/greenrobot/eventbus/SubscriberMethodFinder;->getSubscriberInfo(Lorg/greenrobot/eventbus/SubscriberMethodFinder$FindState;)Lorg/greenrobot/eventbus/meta/SubscriberInfo; HSPLorg/greenrobot/eventbus/SubscriberMethodFinder;->prepareFindState()Lorg/greenrobot/eventbus/SubscriberMethodFinder$FindState; HSPLorg/greenrobot/eventbus/Subscription;->(Ljava/lang/Object;Lorg/greenrobot/eventbus/SubscriberMethod;)V -HSPLorg/greenrobot/eventbus/Subscription;->equals(Ljava/lang/Object;)Z HSPLorg/greenrobot/eventbus/ThreadMode;->()V HSPLorg/greenrobot/eventbus/ThreadMode;->(Ljava/lang/String;I)V HSPLorg/signal/aesgcmprovider/AesGcmProvider;->()V @@ -19073,12 +19040,14 @@ HSPLorg/signal/core/util/CursorExtensionsKt;->optionalLong(Landroid/database/Cur HSPLorg/signal/core/util/CursorExtensionsKt;->optionalString(Landroid/database/Cursor;Ljava/lang/String;)Lj$/util/Optional; HSPLorg/signal/core/util/CursorExtensionsKt;->readToSingleInt$default(Landroid/database/Cursor;IILjava/lang/Object;)I HSPLorg/signal/core/util/CursorExtensionsKt;->readToSingleInt(Landroid/database/Cursor;I)I +HSPLorg/signal/core/util/CursorExtensionsKt;->readToSingleLong$default(Landroid/database/Cursor;JILjava/lang/Object;)J HSPLorg/signal/core/util/CursorExtensionsKt;->readToSingleLong(Landroid/database/Cursor;J)J HSPLorg/signal/core/util/CursorExtensionsKt;->readToSingleObject(Landroid/database/Cursor;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; HSPLorg/signal/core/util/CursorExtensionsKt;->requireBlob(Landroid/database/Cursor;Ljava/lang/String;)[B HSPLorg/signal/core/util/CursorExtensionsKt;->requireBoolean(Landroid/database/Cursor;Ljava/lang/String;)Z HSPLorg/signal/core/util/CursorExtensionsKt;->requireInt(Landroid/database/Cursor;Ljava/lang/String;)I HSPLorg/signal/core/util/CursorExtensionsKt;->requireLong(Landroid/database/Cursor;Ljava/lang/String;)J +HSPLorg/signal/core/util/CursorExtensionsKt;->requireNonNullString(Landroid/database/Cursor;Ljava/lang/String;)Ljava/lang/String; HSPLorg/signal/core/util/CursorExtensionsKt;->requireString(Landroid/database/Cursor;Ljava/lang/String;)Ljava/lang/String; HSPLorg/signal/core/util/CursorExtensionsKt;->toInt(Z)I HSPLorg/signal/core/util/CursorUtil;->getBlob(Landroid/database/Cursor;Ljava/lang/String;)Lj$/util/Optional; @@ -19091,8 +19060,8 @@ HSPLorg/signal/core/util/CursorUtil;->requireBlob(Landroid/database/Cursor;Ljava HSPLorg/signal/core/util/CursorUtil;->requireBoolean(Landroid/database/Cursor;Ljava/lang/String;)Z HSPLorg/signal/core/util/CursorUtil;->requireInt(Landroid/database/Cursor;Ljava/lang/String;)I HSPLorg/signal/core/util/CursorUtil;->requireLong(Landroid/database/Cursor;Ljava/lang/String;)J +HSPLorg/signal/core/util/CursorUtil;->requireString(Landroid/database/Cursor;Ljava/lang/String;)Ljava/lang/String; HSPLorg/signal/core/util/DeleteBuilderPart1;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)V -HSPLorg/signal/core/util/DeleteBuilderPart1;->run()I HSPLorg/signal/core/util/DeleteBuilderPart1;->where(Ljava/lang/String;[Ljava/lang/Object;)Lorg/signal/core/util/DeleteBuilderPart2; HSPLorg/signal/core/util/DeleteBuilderPart2;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V HSPLorg/signal/core/util/DeleteBuilderPart2;->run()I @@ -19135,7 +19104,6 @@ HSPLorg/signal/core/util/MemoryTracker;->getAppJvmHeapUsage()Lorg/signal/core/ut HSPLorg/signal/core/util/MemoryTracker;->start()V HSPLorg/signal/core/util/OptionalExtensionsKt;->or(Lj$/util/Optional;Lj$/util/Optional;)Lj$/util/Optional; HSPLorg/signal/core/util/OptionalExtensionsKt;->orNull(Lj$/util/Optional;)Ljava/lang/Object; -HSPLorg/signal/core/util/OptionalExtensionsKt;->toOptional(Ljava/lang/Object;)Lj$/util/Optional; HSPLorg/signal/core/util/PendingIntentFlags;->()V HSPLorg/signal/core/util/PendingIntentFlags;->()V HSPLorg/signal/core/util/PendingIntentFlags;->immutable()I @@ -19143,10 +19111,12 @@ HSPLorg/signal/core/util/PendingIntentFlags;->mutable()I HSPLorg/signal/core/util/PendingIntentFlags;->updateCurrent()I HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->count(Landroidx/sqlite/db/SupportSQLiteDatabase;)Lorg/signal/core/util/SelectBuilderPart1; HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->delete(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)Lorg/signal/core/util/DeleteBuilderPart1; +HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->deleteAll(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)I HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->exists(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)Lorg/signal/core/util/ExistsBuilderPart1; HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->insertInto(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)Lorg/signal/core/util/InsertBuilderPart1; HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->select(Landroidx/sqlite/db/SupportSQLiteDatabase;[Ljava/lang/String;)Lorg/signal/core/util/SelectBuilderPart1; HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->update(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)Lorg/signal/core/util/UpdateBuilderPart1; +HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->updateAll(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)Lorg/signal/core/util/UpdateAllBuilderPart1; HSPLorg/signal/core/util/SQLiteDatabaseExtensionsKt;->withinTransaction(Landroidx/sqlite/db/SupportSQLiteDatabase;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; HSPLorg/signal/core/util/SelectBuilderPart1;->(Landroidx/sqlite/db/SupportSQLiteDatabase;[Ljava/lang/String;)V HSPLorg/signal/core/util/SelectBuilderPart1;->from(Ljava/lang/String;)Lorg/signal/core/util/SelectBuilderPart2; @@ -19213,14 +19183,15 @@ HSPLorg/signal/core/util/Stopwatch;->access$getDecimalPlaces$p(Lorg/signal/core/ HSPLorg/signal/core/util/Stopwatch;->split(Ljava/lang/String;)V HSPLorg/signal/core/util/Stopwatch;->stop(Ljava/lang/String;)V HSPLorg/signal/core/util/Stopwatch;->stopAndGetLogString()Ljava/lang/String; +HSPLorg/signal/core/util/StreamUtil;->()V +HSPLorg/signal/core/util/StreamUtil;->close(Ljava/io/Closeable;)V +HSPLorg/signal/core/util/StreamUtil;->copy(Ljava/io/InputStream;Ljava/io/OutputStream;)J HSPLorg/signal/core/util/StringExtensionsKt;->nullIfBlank(Ljava/lang/String;)Ljava/lang/String; HSPLorg/signal/core/util/StringExtensionsKt;->toSingleLine(Ljava/lang/String;)Ljava/lang/String; HSPLorg/signal/core/util/StringUtil;->()V -HSPLorg/signal/core/util/StringUtil;->forceLtr(Ljava/lang/CharSequence;)Ljava/lang/String; HSPLorg/signal/core/util/StringUtil;->isEmpty(Ljava/lang/String;)Z HSPLorg/signal/core/util/StringUtil;->isolateBidi(Ljava/lang/String;)Ljava/lang/String; HSPLorg/signal/core/util/StringUtil;->replace(Ljava/lang/CharSequence;CLjava/lang/String;)Ljava/lang/CharSequence; -HSPLorg/signal/core/util/StringUtil;->trim(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; HSPLorg/signal/core/util/StringUtil;->trimToFit(Ljava/lang/String;I)Ljava/lang/String; HSPLorg/signal/core/util/ThreadUtil;->()V HSPLorg/signal/core/util/ThreadUtil;->assertMainThread()V @@ -19231,12 +19202,15 @@ HSPLorg/signal/core/util/ThreadUtil;->postToMain(Ljava/lang/Runnable;)V HSPLorg/signal/core/util/ThreadUtil;->runOnMain(Ljava/lang/Runnable;)V HSPLorg/signal/core/util/ThreadUtil;->sleep(J)V HSPLorg/signal/core/util/ToolbarExtensionsKt;->setActionItemTint(Landroidx/appcompat/widget/Toolbar;I)V +HSPLorg/signal/core/util/UpdateAllBuilderPart1;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)V +HSPLorg/signal/core/util/UpdateAllBuilderPart1;->values([Lkotlin/Pair;)Lorg/signal/core/util/UpdateAllBuilderPart2; +HSPLorg/signal/core/util/UpdateAllBuilderPart2;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;Landroid/content/ContentValues;)V +HSPLorg/signal/core/util/UpdateAllBuilderPart2;->run$default(Lorg/signal/core/util/UpdateAllBuilderPart2;IILjava/lang/Object;)I +HSPLorg/signal/core/util/UpdateAllBuilderPart2;->run(I)I HSPLorg/signal/core/util/UpdateBuilderPart1;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;)V HSPLorg/signal/core/util/UpdateBuilderPart1;->values(Landroid/content/ContentValues;)Lorg/signal/core/util/UpdateBuilderPart2; HSPLorg/signal/core/util/UpdateBuilderPart1;->values([Lkotlin/Pair;)Lorg/signal/core/util/UpdateBuilderPart2; HSPLorg/signal/core/util/UpdateBuilderPart2;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;Landroid/content/ContentValues;)V -HSPLorg/signal/core/util/UpdateBuilderPart2;->run$default(Lorg/signal/core/util/UpdateBuilderPart2;IILjava/lang/Object;)I -HSPLorg/signal/core/util/UpdateBuilderPart2;->run(I)I HSPLorg/signal/core/util/UpdateBuilderPart2;->where(Ljava/lang/String;[Ljava/lang/Object;)Lorg/signal/core/util/UpdateBuilderPart3; HSPLorg/signal/core/util/UpdateBuilderPart3;->(Landroidx/sqlite/db/SupportSQLiteDatabase;Ljava/lang/String;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)V HSPLorg/signal/core/util/UpdateBuilderPart3;->run$default(Lorg/signal/core/util/UpdateBuilderPart3;IILjava/lang/Object;)I @@ -19263,7 +19237,9 @@ HSPLorg/signal/core/util/concurrent/DeadlockDetector$ExecutorInfo;->hashCode()I HSPLorg/signal/core/util/concurrent/DeadlockDetector;->()V HSPLorg/signal/core/util/concurrent/DeadlockDetector;->(Landroid/os/Handler;J)V HSPLorg/signal/core/util/concurrent/DeadlockDetector;->start()V -HSPLorg/signal/core/util/concurrent/LatestPrioritizedSerialExecutor;->(Ljava/util/concurrent/Executor;)V +HSPLorg/signal/core/util/concurrent/FutureMapTransformer;->(Lorg/signal/core/util/concurrent/ListenableFuture;Lorg/signal/core/util/concurrent/FutureTransformers$Transformer;)V +HSPLorg/signal/core/util/concurrent/FutureMapTransformer;->get(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object; +HSPLorg/signal/core/util/concurrent/FutureTransformers;->map(Lorg/signal/core/util/concurrent/ListenableFuture;Lorg/signal/core/util/concurrent/FutureTransformers$Transformer;)Lorg/signal/core/util/concurrent/ListenableFuture; HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->()V HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->add(Lio/reactivex/rxjava3/disposables/Disposable;)Lorg/signal/core/util/concurrent/LifecycleDisposable; HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->bindTo(Landroidx/lifecycle/Lifecycle;)Lorg/signal/core/util/concurrent/LifecycleDisposable; @@ -19272,16 +19248,8 @@ HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->onCreate(Landroidx/lif HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/signal/core/util/concurrent/LifecycleDisposable;->plusAssign(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLorg/signal/core/util/concurrent/LifecycleDisposableKt;->addTo(Lio/reactivex/rxjava3/disposables/Disposable;Lorg/signal/core/util/concurrent/LifecycleDisposable;)Lio/reactivex/rxjava3/disposables/Disposable; -HSPLorg/signal/core/util/concurrent/MaybeCompat$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/signal/core/util/concurrent/MaybeCompat$$ExternalSyntheticLambda0;->subscribe(Lio/reactivex/rxjava3/core/MaybeEmitter;)V -HSPLorg/signal/core/util/concurrent/MaybeCompat;->$r8$lambda$aPKBr0JUhvb1CVWSMT6CNAHU584(Lkotlin/jvm/functions/Function0;Lio/reactivex/rxjava3/core/MaybeEmitter;)V -HSPLorg/signal/core/util/concurrent/MaybeCompat;->()V -HSPLorg/signal/core/util/concurrent/MaybeCompat;->()V -HSPLorg/signal/core/util/concurrent/MaybeCompat;->fromCallable$lambda$0(Lkotlin/jvm/functions/Function0;Lio/reactivex/rxjava3/core/MaybeEmitter;)V -HSPLorg/signal/core/util/concurrent/MaybeCompat;->fromCallable(Lkotlin/jvm/functions/Function0;)Lio/reactivex/rxjava3/core/Maybe; HSPLorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$1;->(Ljava/lang/Object;)V HSPLorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$1;->invoke(Ljava/lang/Object;)V @@ -19289,6 +19257,11 @@ HSPLorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$2;-> HSPLorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$3;->(Ljava/lang/Object;)V HSPLorg/signal/core/util/concurrent/RxExtensions;->safeBlockingGet(Lio/reactivex/rxjava3/core/Single;)Ljava/lang/Object; HSPLorg/signal/core/util/concurrent/RxExtensions;->subscribeWithSubject(Lio/reactivex/rxjava3/core/Observable;Lio/reactivex/rxjava3/subjects/Subject;Lio/reactivex/rxjava3/disposables/CompositeDisposable;)Lio/reactivex/rxjava3/subjects/Subject; +HSPLorg/signal/core/util/concurrent/SettableFuture;->()V +HSPLorg/signal/core/util/concurrent/SettableFuture;->get()Ljava/lang/Object; +HSPLorg/signal/core/util/concurrent/SettableFuture;->get(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object; +HSPLorg/signal/core/util/concurrent/SettableFuture;->notifyAllListeners()V +HSPLorg/signal/core/util/concurrent/SettableFuture;->setException(Ljava/lang/Throwable;)Z HSPLorg/signal/core/util/concurrent/SignalExecutors$$ExternalSyntheticLambda0;->()V HSPLorg/signal/core/util/concurrent/SignalExecutors$$ExternalSyntheticLambda1;->(Ljava/lang/String;I)V HSPLorg/signal/core/util/concurrent/SignalExecutors$$ExternalSyntheticLambda1;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread; @@ -19409,7 +19382,7 @@ HSPLorg/signal/core/util/logging/Scrubber;->scrubPnis(Ljava/lang/CharSequence;)L HSPLorg/signal/core/util/logging/Scrubber;->scrubUuids(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; HSPLorg/signal/core/util/logging/Scrubber;->setIdentifierHmacKeyProvider(Lkotlin/jvm/functions/Function0;)V HSPLorg/signal/core/util/stream/TruncatingInputStream$$ExternalSyntheticBackport0;->m(J)I -HSPLorg/signal/core/util/tracing/DebugAnnotation$Builder;->()V +HSPLorg/signal/core/util/tracing/DebugAnnotation$Builder;->build()Lorg/signal/core/util/tracing/DebugAnnotation; HSPLorg/signal/core/util/tracing/DebugAnnotation$Builder;->name(Ljava/lang/String;)Lorg/signal/core/util/tracing/DebugAnnotation$Builder; HSPLorg/signal/core/util/tracing/DebugAnnotation$Builder;->string_value(Ljava/lang/String;)Lorg/signal/core/util/tracing/DebugAnnotation$Builder; HSPLorg/signal/core/util/tracing/DebugAnnotation$Companion$ADAPTER$1;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Lcom/squareup/wire/Syntax;)V @@ -19419,6 +19392,7 @@ HSPLorg/signal/core/util/tracing/DebugAnnotation;->()V HSPLorg/signal/core/util/tracing/DebugAnnotation;->(Ljava/lang/Long;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Double;Ljava/lang/String;Ljava/lang/Long;Lorg/signal/core/util/tracing/DebugAnnotation$NestedValue;Lokio/ByteString;)V HSPLorg/signal/core/util/tracing/DebugAnnotation;->equals(Ljava/lang/Object;)Z HSPLorg/signal/core/util/tracing/TracePacket$Builder;->()V +HSPLorg/signal/core/util/tracing/TracePacket$Builder;->build()Lorg/signal/core/util/tracing/TracePacket; HSPLorg/signal/core/util/tracing/TracePacket$Builder;->synchronization_marker(Lokio/ByteString;)Lorg/signal/core/util/tracing/TracePacket$Builder; HSPLorg/signal/core/util/tracing/TracePacket$Builder;->timestamp(Ljava/lang/Long;)Lorg/signal/core/util/tracing/TracePacket$Builder; HSPLorg/signal/core/util/tracing/TracePacket$Builder;->track_descriptor(Lorg/signal/core/util/tracing/TrackDescriptor;)Lorg/signal/core/util/tracing/TracePacket$Builder; @@ -19434,15 +19408,13 @@ HSPLorg/signal/core/util/tracing/Tracer$$ExternalSyntheticLambda0;->getTimeNanos HSPLorg/signal/core/util/tracing/Tracer;->()V HSPLorg/signal/core/util/tracing/Tracer;->()V HSPLorg/signal/core/util/tracing/Tracer;->addPacket(Lorg/signal/core/util/tracing/TracePacket;)V -HSPLorg/signal/core/util/tracing/Tracer;->debugAnnotation(Ljava/lang/String;Ljava/lang/String;)Lorg/signal/core/util/tracing/DebugAnnotation; -HSPLorg/signal/core/util/tracing/Tracer;->end(Ljava/lang/String;)V -HSPLorg/signal/core/util/tracing/Tracer;->end(Ljava/lang/String;J)V +HSPLorg/signal/core/util/tracing/Tracer;->forMethodEnd(Ljava/lang/String;JJ)Lorg/signal/core/util/tracing/TracePacket; HSPLorg/signal/core/util/tracing/Tracer;->forSynchronization(J)Lorg/signal/core/util/tracing/TracePacket; HSPLorg/signal/core/util/tracing/Tracer;->forTrack(JLjava/lang/String;)Lorg/signal/core/util/tracing/TracePacket; HSPLorg/signal/core/util/tracing/Tracer;->forTrackId(J)Lorg/signal/core/util/tracing/TracePacket; HSPLorg/signal/core/util/tracing/Tracer;->getInstance()Lorg/signal/core/util/tracing/Tracer; HSPLorg/signal/core/util/tracing/Tracer;->start(Ljava/lang/String;)V -HSPLorg/signal/core/util/tracing/Tracer;->start(Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)V +HSPLorg/signal/core/util/tracing/Tracer;->start(Ljava/lang/String;JLjava/util/Map;)V HSPLorg/signal/core/util/tracing/Tracer;->start(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V HSPLorg/signal/core/util/tracing/Tracer;->start(Ljava/lang/String;Ljava/util/Map;)V HSPLorg/signal/core/util/tracing/Tracer;->toByteArray(Ljava/util/UUID;)[B @@ -19475,20 +19447,13 @@ HSPLorg/signal/glide/Log$Provider$1;->()V HSPLorg/signal/glide/Log$Provider;->()V HSPLorg/signal/glide/SignalGlideCodecs;->()V HSPLorg/signal/glide/SignalGlideCodecs;->setLogProvider(Lorg/signal/glide/Log$Provider;)V -HSPLorg/signal/glide/webp/WebpInputStreamResourceDecoder$Companion;->()V -HSPLorg/signal/glide/webp/WebpInputStreamResourceDecoder$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/signal/glide/webp/WebpInputStreamResourceDecoder;->()V -HSPLorg/signal/glide/webp/WebpInputStreamResourceDecoder;->(Lcom/bumptech/glide/load/engine/bitmap_recycle/BitmapPool;)V -HSPLorg/signal/glide/webp/WebpLibraryGlideModule$Companion;->()V -HSPLorg/signal/glide/webp/WebpLibraryGlideModule$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/signal/glide/webp/WebpLibraryGlideModule;->()V -HSPLorg/signal/glide/webp/WebpLibraryGlideModule;->()V -HSPLorg/signal/glide/webp/WebpLibraryGlideModule;->registerComponents(Landroid/content/Context;Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/Registry;)V HSPLorg/signal/libsignal/internal/Native;->()V HSPLorg/signal/libsignal/internal/Native;->loadLibrary()V HSPLorg/signal/libsignal/internal/NativeHandleGuard;->(Lorg/signal/libsignal/internal/NativeHandleGuard$Owner;)V HSPLorg/signal/libsignal/internal/NativeHandleGuard;->close()V HSPLorg/signal/libsignal/internal/NativeHandleGuard;->nativeHandle()J +HSPLorg/signal/libsignal/net/Network$Environment;->()V +HSPLorg/signal/libsignal/net/Network$Environment;->(Ljava/lang/String;II)V HSPLorg/signal/libsignal/protocol/IdentityKey;->(Lorg/signal/libsignal/protocol/ecc/ECPublicKey;)V HSPLorg/signal/libsignal/protocol/IdentityKey;->([B)V HSPLorg/signal/libsignal/protocol/IdentityKey;->serialize()[B @@ -19506,6 +19471,7 @@ HSPLorg/signal/libsignal/protocol/ServiceId;->getRawUUID()Ljava/util/UUID; HSPLorg/signal/libsignal/protocol/ServiceId;->hashCode()I HSPLorg/signal/libsignal/protocol/ServiceId;->parseFromFixedWidthBinary([B)Lorg/signal/libsignal/protocol/ServiceId; HSPLorg/signal/libsignal/protocol/ServiceId;->parseFromString(Ljava/lang/String;)Lorg/signal/libsignal/protocol/ServiceId; +HSPLorg/signal/libsignal/protocol/ServiceId;->toServiceIdFixedWidthBinary()[B HSPLorg/signal/libsignal/protocol/ServiceId;->toServiceIdString()Ljava/lang/String; HSPLorg/signal/libsignal/protocol/ServiceId;->uuidFromBytes(Ljava/nio/ByteBuffer;)Ljava/util/UUID; HSPLorg/signal/libsignal/protocol/SignalProtocolAddress;->(Ljava/lang/String;I)V @@ -19565,6 +19531,7 @@ HSPLorg/signal/libsignal/protocol/state/SignedPreKeyRecord;->getKeyPair()Lorg/si HSPLorg/signal/libsignal/protocol/state/SignedPreKeyRecord;->getSignature()[B HSPLorg/signal/libsignal/protocol/state/SignedPreKeyRecord;->getTimestamp()J HSPLorg/signal/libsignal/protocol/state/SignedPreKeyRecord;->unsafeNativeHandleWithoutGuard()J +HSPLorg/signal/libsignal/protocol/util/ByteUtil;->trim([BI)[B HSPLorg/signal/libsignal/protocol/util/KeyHelper;->generateRegistrationId(Z)I HSPLorg/signal/libsignal/protocol/util/Medium;->()V HSPLorg/signal/libsignal/protocol/util/Pair;->(Ljava/lang/Object;Ljava/lang/Object;)V @@ -19576,6 +19543,9 @@ HSPLorg/signal/libsignal/zkgroup/internal/ByteArray;->([B)V HSPLorg/signal/libsignal/zkgroup/internal/ByteArray;->serialize()[B HSPLorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;->(Lorg/signal/libsignal/zkgroup/ServerPublicParams;)V HSPLorg/signal/libsignal/zkgroup/profiles/ProfileKey;->([B)V +HSPLorg/signal/libsignal/zkgroup/profiles/ProfileKey;->getProfileKeyVersion(Lorg/signal/libsignal/protocol/ServiceId$Aci;)Lorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion; +HSPLorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion;->([B)V +HSPLorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion;->serialize()Ljava/lang/String; HSPLorg/signal/libsignal/zkgroup/receipts/ClientZkReceiptOperations;->(Lorg/signal/libsignal/zkgroup/ServerPublicParams;)V HSPLorg/signal/paging/BufferedPagingController$$ExternalSyntheticLambda1;->(Lorg/signal/paging/BufferedPagingController;I)V HSPLorg/signal/paging/BufferedPagingController$$ExternalSyntheticLambda1;->run()V @@ -19657,6 +19627,9 @@ HSPLorg/signal/ringrtc/Log;->i(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Th HSPLorg/signal/ringrtc/Log;->initialize(Lorg/signal/ringrtc/Log$Logger;)V HSPLorg/signal/ringrtc/WebRtcLogger;->()V HSPLorg/signal/ringrtc/WebRtcLogger;->()V +HSPLorg/thoughtcrime/securesms/AppCapabilities;->()V +HSPLorg/thoughtcrime/securesms/AppCapabilities;->()V +HSPLorg/thoughtcrime/securesms/AppCapabilities;->getCapabilities(Z)Lorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities; HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda0;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda0;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda10;->()V @@ -19693,7 +19666,7 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda24;->< HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda24;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda25;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda25;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda26;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda26;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda26;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda27;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda27;->run()V @@ -19715,19 +19688,19 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda34;->< HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda34;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda35;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda35;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda36;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda36;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda36;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda37;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda37;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda37;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda38;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda38;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda38;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda39;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda39;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda3;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda40;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda40;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda40;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda41;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda41;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda41;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda42;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda42;->run()V @@ -19739,9 +19712,9 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda45;->< HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda45;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda46;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda46;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda47;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda47;->(Lorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Companion;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda47;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda48;->(Lorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Companion;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda48;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda48;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda49;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda49;->run()V @@ -19753,32 +19726,30 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda51;->< HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda51;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda52;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda52;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda53;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda53;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda53;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda54;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda54;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda54;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda55;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda55;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda55;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda56;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda56;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda56;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda57;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda57;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda57;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda58;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda58;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda59;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda58;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda59;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda59;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda5;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda60;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda60;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda61;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda61;->run()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda62;->()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda63;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda61;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda62;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda63;->()V +HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda63;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda64;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda64;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda65;->()V -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda65;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda66;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda6;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda6;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V @@ -19788,39 +19759,38 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda8;->ru HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda9;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda9;->run()V HSPLorg/thoughtcrime/securesms/ApplicationContext$1;->(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$-Us13jCXTd2iOM0Y6BraEZ1Ael8()V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$-C9Peb3FgJUzS6NSCmy4GbYf_TI(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$-wHBiLBDa8OJf1k67fcIsduxfzw(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$1vBGBwM2yUq7VyFaTDG10uWDuPc(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$3QS0qrAN7nliLfSi63lQeukrNXw(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$66l9coKQ_660ADutlicH4GeEP6I(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$6C1lVL7dG_-wAqmFY6Az_Qc88wU()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$6_YWJVxHZo1viw16tbrU7MDbDJg(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$6huj-CNiUCq08incBeS5_VdKXcY(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$6jOUg8y8V8AjFQVDC73SAPGSCaQ(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$74GuULvxFktNDe6rV-VHuIqPVJg(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$7zPKdwtEmk03-CX6PmLruPNQaJU()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$8LAgI8pE7DigK3aYaz2Nk9lcfrc(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$AGPtfUzlxykaeQb2_And4XR5_cI()V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$AT704sPxWjxGd8P7Knkz-CNN53E(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$BM9zXNQo3VjL7z8V2jLaBOSk3xM(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$C38kbsmhoy45H7BvcAkMdNLosx8(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$CadNTUODZG2Ef63Ub7A1il6CBD0(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$EhXD2bA_njJxvcXV3OctyCch4wQ()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$Euao8MtJ5sFx1Uzh_MqEQ-p_wco()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$GzI-Jr48663DXUZ6ABZXYlOQuSQ(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$Fx-d1Nr9YoqUcyvu6Ylhfae3_S4(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$HAbYs3d3-yBwCTZTjClId9asWMo(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$JFFOXPLm4n83iu1CrQCwt8Rt1vs(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$MEJyjPRiOVBusJTwA48ER4J3M9A(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$QTEjfsRccjaeTw0od8y5UGofLnw()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$QoPhFlm0XNA9Pq0eqhx6SpS3Yf8(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$RIVst1BPIo-PfHpYnrmNZ6n5IC4()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$RhzI01M6WPCcwVqZ9bQRQL3rEFk(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$VPmvaBBdqqvvVsnAcF1XPhfNAwg(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$Wc-lTVXx_Cj3iM16JtR6Ju_gG5s(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$WhOpCGkNoE806tpRKQr4cnlCHgs()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$XEBpgM6g0m715OxGVQde5BV4obs()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$YPJbusS4_A6ryTaa4uhXIPJboWA(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$Ziq45AtHm7EBURq_Andgbc-2PQA(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$avxGAGkfv3Ev4XZkSUGrF0ov8Xw(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$bErCCzC-UcRA-wciaIM0aFj_fYc(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$cQnTp954Na4k9YavnTCgv-5QUVQ()V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$d1IiCBeJCM6wI7G1fz_gXkhXmmY()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$dXZkn_yX1EofCAblV1XQ5RabFZk(Lorg/thoughtcrime/securesms/ApplicationContext;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$gAiTx-utj3eJij4oz9BiVGkOVS4(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$gsuXSdfhwRFZebO53F99f8IHmAg(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$idYYlPtuECvmRBdMPMIWbD5a3kU()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$j9SYVZNI3aEbrOx6jxBWYL046uc()V @@ -19828,17 +19798,17 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$kC2GAeM9RoAdu5aL5 HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$ltM0LNCO0IpxItflkQs1-OW5yWo(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$nCL1qFe_6GUmC6LRVpbNvqPnxzs(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$nYPlff79P2l-muLhW8EMuKgR50w(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$oBwElCRwdRH0K-dD4FNR2zBIlik()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$ot12xp6xNVtSSQ4GK9tV7IySHoM(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$ruqqX1Z0LLWOgajy7Wtjs5N3iks(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$uRzpmm1efLVUhJMEHNtyfP7BiA8(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$vq13xoFA2KFXFtE5Jlx3i42fU-8(Lorg/thoughtcrime/securesms/ApplicationContext;)V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$y2wfEuKgd8zQpNdKJyo7v3d1ZLs(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; +HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$xQ9ZfcE66PEynu9uNL9k6bEaLXs(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$zLJvo83whBob1hm-1YvxiH4EKqg(Lorg/thoughtcrime/securesms/ApplicationContext;)V HSPLorg/thoughtcrime/securesms/ApplicationContext;->$r8$lambda$zNA2sxapNn8tnXiST4flFZyy97A()[B HSPLorg/thoughtcrime/securesms/ApplicationContext;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->attachBaseContext(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->beginJobLoop()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->checkBuildExpiration()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->cleanAvatarStorage()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->ensureProfileUploaded()V @@ -19863,9 +19833,9 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext;->initializeRx()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->initializeScheduledMessageManager()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->initializeSecurityProvider()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->initializeTrimThreadsByDateManager()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$initializeLogging$26()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$initializeRx$27(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; -HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$initializeRx$28(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; +HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$initializeLogging$24()V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$initializeRx$25(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; +HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$initializeRx$26(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Scheduler; HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$0()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$1()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$10()V @@ -19881,8 +19851,6 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$19()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$2()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$20()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$21()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$22()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$23()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$3()[B HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$4()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$5()V @@ -19890,7 +19858,7 @@ HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$6()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$7()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$8()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onCreate$9()V -HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onForeground$24()V +HSPLorg/thoughtcrime/securesms/ApplicationContext;->lambda$onForeground$22()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->onCreate()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->onForeground()V HSPLorg/thoughtcrime/securesms/ApplicationContext;->startAnrDetector()V @@ -19912,7 +19880,6 @@ HSPLorg/thoughtcrime/securesms/LoggingFragment;->(I)V HSPLorg/thoughtcrime/securesms/LoggingFragment;->logEvent(Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/LoggingFragment;->onCreate(Landroid/os/Bundle;)V HSPLorg/thoughtcrime/securesms/LoggingFragment;->onStart()V -HSPLorg/thoughtcrime/securesms/LoggingFragment;->onStop()V HSPLorg/thoughtcrime/securesms/MainActivity$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/MainActivity;)V HSPLorg/thoughtcrime/securesms/MainActivity$$ExternalSyntheticLambda2;->accept(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/MainActivity$1;->(Lorg/thoughtcrime/securesms/MainActivity;Landroid/view/View;)V @@ -19934,7 +19901,6 @@ HSPLorg/thoughtcrime/securesms/MainActivity;->onCreate(Landroid/os/Bundle;Z)V HSPLorg/thoughtcrime/securesms/MainActivity;->onFirstRender()V HSPLorg/thoughtcrime/securesms/MainActivity;->onPreCreate()V HSPLorg/thoughtcrime/securesms/MainActivity;->onResume()V -HSPLorg/thoughtcrime/securesms/MainActivity;->onStop()V HSPLorg/thoughtcrime/securesms/MainActivity;->presentVitalsState(Lorg/thoughtcrime/securesms/notifications/VitalsViewModel$State;)V HSPLorg/thoughtcrime/securesms/MainActivity;->updateTabVisibility()V HSPLorg/thoughtcrime/securesms/MainFragment;->()V @@ -19971,8 +19937,6 @@ HSPLorg/thoughtcrime/securesms/attachments/Attachment$Companion;->()V HSPLorg/thoughtcrime/securesms/attachments/Attachment$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/attachments/Attachment;->()V HSPLorg/thoughtcrime/securesms/attachments/Attachment;->(Ljava/lang/String;IJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;[B[BLjava/lang/String;ZZZIIIZJLjava/lang/String;Lorg/thoughtcrime/securesms/stickers/StickerLocator;Lorg/thoughtcrime/securesms/blurhash/BlurHash;Lorg/thoughtcrime/securesms/audio/AudioHash;Lorg/thoughtcrime/securesms/database/AttachmentTable$TransformProperties;)V -HSPLorg/thoughtcrime/securesms/attachments/Attachment;->isInProgress()Z -HSPLorg/thoughtcrime/securesms/attachments/Attachment;->isPermanentlyFailed()Z HSPLorg/thoughtcrime/securesms/attachments/Attachment;->isSticker()Z HSPLorg/thoughtcrime/securesms/attachments/AttachmentCreator;->()V HSPLorg/thoughtcrime/securesms/attachments/AttachmentCreator;->()V @@ -19986,6 +19950,7 @@ HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment$DisplayOrderCompar HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment$DisplayOrderComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment$DisplayOrderComparator;->compare(Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment;Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment;)I HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment;->()V +HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment;->(Lorg/thoughtcrime/securesms/attachments/AttachmentId;JZZLjava/lang/String;IJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;[B[BILjava/lang/String;ZZZIIZLjava/lang/String;Lorg/thoughtcrime/securesms/stickers/StickerLocator;Lorg/thoughtcrime/securesms/blurhash/BlurHash;Lorg/thoughtcrime/securesms/audio/AudioHash;Lorg/thoughtcrime/securesms/database/AttachmentTable$TransformProperties;IJLjava/lang/String;)V HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment;->getDisplayOrder()I HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment;->getUri()Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/attachments/DatabaseAttachment;->hashCode()I @@ -19998,16 +19963,6 @@ HSPLorg/thoughtcrime/securesms/attachments/PointerAttachment;->()V HSPLorg/thoughtcrime/securesms/attachments/PointerAttachment;->(Ljava/lang/String;IJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;[B[BILjava/lang/String;ZZZIIJLjava/lang/String;Lorg/thoughtcrime/securesms/stickers/StickerLocator;Lorg/thoughtcrime/securesms/blurhash/BlurHash;)V HSPLorg/thoughtcrime/securesms/attachments/PointerAttachment;->(Ljava/lang/String;IJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;[B[BILjava/lang/String;ZZZIIJLjava/lang/String;Lorg/thoughtcrime/securesms/stickers/StickerLocator;Lorg/thoughtcrime/securesms/blurhash/BlurHash;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/attachments/PointerAttachment;->getUri()Landroid/net/Uri; -HSPLorg/thoughtcrime/securesms/audio/AudioRecorder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/audio/AudioRecorder;)V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorder;->()V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorder;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/audio/AudioRecordingHandler;)V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion;->()V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion;->create(Landroid/content/Context;Landroid/media/AudioManager$OnAudioFocusChangeListener;)Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager; -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager26;->(Landroid/content/Context;Landroid/media/AudioManager$OnAudioFocusChangeListener;)V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager;->()V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager;->create(Landroid/content/Context;Landroid/media/AudioManager$OnAudioFocusChangeListener;)Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager; HSPLorg/thoughtcrime/securesms/avatar/Avatar$Companion;->()V HSPLorg/thoughtcrime/securesms/avatar/Avatar$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId$DoNotPersist;->()V @@ -20015,6 +19970,10 @@ HSPLorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId$DoNotPersist;->()V HSPLorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId;->()V HSPLorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId;->()V HSPLorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->()V +HSPLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->(ILorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;)V +HSPLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->getColor()Lorg/thoughtcrime/securesms/avatar/Avatars$ColorPair; +HSPLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->getResourceId()I HSPLorg/thoughtcrime/securesms/avatar/Avatar$Text;->()V HSPLorg/thoughtcrime/securesms/avatar/Avatar$Text;->(Ljava/lang/String;Lorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;Lorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId;)V HSPLorg/thoughtcrime/securesms/avatar/Avatar$Text;->getColor()Lorg/thoughtcrime/securesms/avatar/Avatars$ColorPair; @@ -20025,13 +19984,26 @@ HSPLorg/thoughtcrime/securesms/avatar/Avatar;->(Lorg/thoughtcrime/securesm HSPLorg/thoughtcrime/securesms/avatar/AvatarPickerStorage;->()V HSPLorg/thoughtcrime/securesms/avatar/AvatarPickerStorage;->()V HSPLorg/thoughtcrime/securesms/avatar/AvatarPickerStorage;->cleanOrphans(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer$$ExternalSyntheticLambda0;->run()V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar$Resource;)V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1;->invoke-IoAF18A(Landroid/graphics/Canvas;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->$r8$lambda$LMRb5EH7u5JsF-ZatOYl7HXPvGU(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->()V HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->()V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->createMedia(Landroid/net/Uri;J)Lorg/thoughtcrime/securesms/mediasend/Media; HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->createTextDrawable(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar$Text;ZIZ)Landroid/graphics/drawable/Drawable; +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->getDIMENSIONS()I HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->getTypeface(Landroid/content/Context;)Landroid/graphics/Typeface; +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderAvatar(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderInBackground$lambda$1(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderInBackground(Landroid/content/Context;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V +HSPLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderResource(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar$Resource;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->()V HSPLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->(IILjava/lang/String;)V HSPLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->(Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor;Lorg/thoughtcrime/securesms/avatar/Avatars$ForegroundColor;)V +HSPLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->getBackgroundColor()I HSPLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->getCode()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->getForegroundColor()I HSPLorg/thoughtcrime/securesms/avatar/Avatars$DefaultAvatar;->()V @@ -20057,31 +20029,23 @@ HSPLorg/thoughtcrime/securesms/avatar/TextAvatarDrawable;->getStartX(Landroid/te HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView$WhenMappings;->()V HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView;->()V HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView;->displayChatAvatar(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V +HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView;->displayChatAvatar(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView;->hideStoryRing()V HSPLorg/thoughtcrime/securesms/avatar/view/AvatarView;->setStoryRingFromState(Lorg/thoughtcrime/securesms/database/model/StoryViewState;)V HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->()V HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->clearDrawable()V -HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->getGlideRequests()Lorg/thoughtcrime/securesms/mms/GlideRequests; -HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->setBadge(Lorg/thoughtcrime/securesms/badges/models/Badge;Lorg/thoughtcrime/securesms/mms/GlideRequests;)V +HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->getGlideRequestManager()Lcom/bumptech/glide/RequestManager; +HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->setBadge(Lorg/thoughtcrime/securesms/badges/models/Badge;Lcom/bumptech/glide/RequestManager;)V HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->setBadgeFromRecipient(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->setBadgeFromRecipient(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/mms/GlideRequests;)V +HSPLorg/thoughtcrime/securesms/badges/BadgeImageView;->setBadgeFromRecipient(Lorg/thoughtcrime/securesms/recipients/Recipient;Lcom/bumptech/glide/RequestManager;)V HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$Companion;->()V HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$2;->(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)V -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$2;->invoke(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGift;)Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$4;->(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)V -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$4;->invoke(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGift;)Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$notAnimated$1;->(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)V -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$notAnimated$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration$onDrawOver$notAnimated$1;->invoke(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGift;)Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->()V HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->access$getAnimationState$p(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)Ljava/util/Map; -HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->access$getMessageIdsOpenedThisSession$p(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)Ljava/util/Set; HSPLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->onDrawOver(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLorg/thoughtcrime/securesms/blurhash/Base83;->()V HSPLorg/thoughtcrime/securesms/blurhash/Base83;->isValid(Ljava/lang/String;)Z @@ -20090,35 +20054,13 @@ HSPLorg/thoughtcrime/securesms/blurhash/BlurHash;->()V HSPLorg/thoughtcrime/securesms/blurhash/BlurHash;->parseOrNull(Ljava/lang/String;)Lorg/thoughtcrime/securesms/blurhash/BlurHash; HSPLorg/thoughtcrime/securesms/blurhash/BlurHashModelLoader$Factory;->()V HSPLorg/thoughtcrime/securesms/blurhash/BlurHashResourceDecoder;->()V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->applyCorners()V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->applyCornersForSizeClass2()V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->getCells()[Lorg/thoughtcrime/securesms/components/ThumbnailView; -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->inflateLayout(I)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setCancelTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setCellBackgroundColor(I)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setPlayVideoClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setRadii(IIII)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setRelativeRadii(Lorg/thoughtcrime/securesms/components/ThumbnailView;IIII)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setSlide(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/mms/Slide;IZ)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setSlides(Lorg/thoughtcrime/securesms/mms/GlideRequests;Ljava/util/List;Z)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setStartTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setThumbnailClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->showSlides(Lorg/thoughtcrime/securesms/mms/GlideRequests;Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->sizeClass(I)I HSPLorg/thoughtcrime/securesms/components/AlertView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/AlertView;->initialize()V HSPLorg/thoughtcrime/securesms/components/AlertView;->setNone()V HSPLorg/thoughtcrime/securesms/components/AnimatingToggle;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/AnimatingToggle;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/components/AnimatingToggle;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V -HSPLorg/thoughtcrime/securesms/components/AnimatingToggle;->display(Landroid/view/View;)V HSPLorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/AudioView;)V -HSPLorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda0;->onChanged(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/components/AudioView;)V HSPLorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/components/AudioView;I)V HSPLorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda4;->run()V @@ -20126,21 +20068,12 @@ HSPLorg/thoughtcrime/securesms/components/AudioView$PlayPauseClickedListener;->< HSPLorg/thoughtcrime/securesms/components/AudioView$PlayPauseClickedListener;->(Lorg/thoughtcrime/securesms/components/AudioView;Lorg/thoughtcrime/securesms/components/AudioView$PlayPauseClickedListener-IA;)V HSPLorg/thoughtcrime/securesms/components/AudioView$SeekBarModifiedListener;->(Lorg/thoughtcrime/securesms/components/AudioView;)V HSPLorg/thoughtcrime/securesms/components/AudioView$SeekBarModifiedListener;->(Lorg/thoughtcrime/securesms/components/AudioView;Lorg/thoughtcrime/securesms/components/AudioView$SeekBarModifiedListener-IA;)V -HSPLorg/thoughtcrime/securesms/components/AudioView;->$r8$lambda$70S_ChWvvHg6uKYhRw5m0jX0OG0(Lorg/thoughtcrime/securesms/components/AudioView;Lorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;)V HSPLorg/thoughtcrime/securesms/components/AudioView;->$r8$lambda$ttH02xbblnAnQbQdy9cXzPNafwQ(Lorg/thoughtcrime/securesms/components/AudioView;I)V HSPLorg/thoughtcrime/securesms/components/AudioView;->()V HSPLorg/thoughtcrime/securesms/components/AudioView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/AudioView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/components/AudioView;->getPlaybackStateObserver()Landroidx/lifecycle/Observer; -HSPLorg/thoughtcrime/securesms/components/AudioView;->hasAudioUri()Z -HSPLorg/thoughtcrime/securesms/components/AudioView;->isTarget(Landroid/net/Uri;)Z HSPLorg/thoughtcrime/securesms/components/AudioView;->lambda$setTint$3(I)V HSPLorg/thoughtcrime/securesms/components/AudioView;->onAttachedToWindow()V -HSPLorg/thoughtcrime/securesms/components/AudioView;->onDuration(Landroid/net/Uri;J)V -HSPLorg/thoughtcrime/securesms/components/AudioView;->onPlaybackState(Lorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;)V -HSPLorg/thoughtcrime/securesms/components/AudioView;->onProgress(Landroid/net/Uri;DJ)V -HSPLorg/thoughtcrime/securesms/components/AudioView;->onSpeedChanged(Landroid/net/Uri;F)V -HSPLorg/thoughtcrime/securesms/components/AudioView;->onStart(Landroid/net/Uri;ZZ)V HSPLorg/thoughtcrime/securesms/components/AudioView;->setProgressAndPlayBackgroundTint(I)V HSPLorg/thoughtcrime/securesms/components/AudioView;->setTint(I)V HSPLorg/thoughtcrime/securesms/components/AvatarImageView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/AvatarImageView;Lorg/thoughtcrime/securesms/recipients/Recipient;)V @@ -20166,12 +20099,10 @@ HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->()V HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->disableQuickContact()V HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->initialize(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatar(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/components/AvatarImageView$AvatarOptions;)V -HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatar(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V -HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatar(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/recipients/Recipient;ZZ)V +HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatar(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/components/AvatarImageView$AvatarOptions;)V +HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatar(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V +HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatar(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/recipients/Recipient;ZZ)V HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setAvatarClickHandler(Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V -HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setFallbackPhotoProvider(Lorg/thoughtcrime/securesms/recipients/Recipient$FallbackPhotoProvider;)V -HSPLorg/thoughtcrime/securesms/components/AvatarImageView;->setOnClickListener(Landroid/view/View$OnClickListener;)V HSPLorg/thoughtcrime/securesms/components/ComposeText$1;->(Lorg/thoughtcrime/securesms/components/ComposeText;)V HSPLorg/thoughtcrime/securesms/components/ComposeText$CommitContentListener;->()V HSPLorg/thoughtcrime/securesms/components/ComposeText$CommitContentListener;->(Lorg/thoughtcrime/securesms/components/InputPanel$MediaListener;)V @@ -20192,102 +20123,28 @@ HSPLorg/thoughtcrime/securesms/components/ComposeText;->onCreateInputConnection( HSPLorg/thoughtcrime/securesms/components/ComposeText;->onDraw(Landroid/graphics/Canvas;)V HSPLorg/thoughtcrime/securesms/components/ComposeText;->onMeasure(II)V HSPLorg/thoughtcrime/securesms/components/ComposeText;->onSelectionChanged(II)V -HSPLorg/thoughtcrime/securesms/components/ComposeText;->setCursorPositionChangedListener(Lorg/thoughtcrime/securesms/components/ComposeText$CursorPositionChangedListener;)V HSPLorg/thoughtcrime/securesms/components/ComposeText;->setHint(Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/components/ComposeText;->setHintWithChecks(Ljava/lang/CharSequence;)V -HSPLorg/thoughtcrime/securesms/components/ComposeText;->setInlineQueryChangedListener(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryChangedListener;)V HSPLorg/thoughtcrime/securesms/components/ComposeText;->setMediaListener(Lorg/thoughtcrime/securesms/components/InputPanel$MediaListener;)V -HSPLorg/thoughtcrime/securesms/components/ComposeText;->setMentionValidator(Lorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher$MentionValidator;)V HSPLorg/thoughtcrime/securesms/components/ComposeText;->setMessageSendType(Lorg/thoughtcrime/securesms/conversation/MessageSendType;)V -HSPLorg/thoughtcrime/securesms/components/ComposeText;->setStylingChangedListener(Lorg/thoughtcrime/securesms/components/ComposeText$StylingChangedListener;)V HSPLorg/thoughtcrime/securesms/components/ComposeTextStyleWatcher;->()V HSPLorg/thoughtcrime/securesms/components/ComposeTextStyleWatcher;->()V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter$$ExternalSyntheticLambda0;->(I)V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/components/ConversationItemFooter;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter$$ExternalSyntheticLambda2;->onLayoutChange(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->$r8$lambda$rILpFw6OPAVn7dsgVBus6R0qlZk(Lorg/thoughtcrime/securesms/components/ConversationItemFooter;Landroid/view/View;IIIIIIII)V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->buildMessageId(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)J -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->disableBubbleBackground()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->getDateView()Landroid/view/View; -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->getPlaybackSpeedToggleTouchDelegateRect()Landroid/graphics/Rect; -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->hideAudioDurationViews()V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->init(Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->lambda$init$0(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->notifyTouchDelegateChanged(Landroid/graphics/Rect;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentAudioDuration(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentDate(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/util/Locale;Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentDeliveryStatus(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentInsecureIndicator(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentSimInfo(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentTimer(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setIconColor(I)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setMessageRecord(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/util/Locale;Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;)V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setOnTouchDelegateChangedListener(Lorg/thoughtcrime/securesms/components/ConversationItemFooter$OnTouchDelegateChangedListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setOnlyShowSendingStatus(ZLorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setPlaybackSpeedListener(Lorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView$PlaybackSpeedListener;)V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setRevealDotColor(I)V HSPLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setTextColor(I)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail$Companion;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->dispatchDraw(Landroid/graphics/Canvas;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->getFooter()Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setBorderless(Z)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setCancelTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setClickable(Z)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setConversationColor(I)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setCorners(IIII)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setFocusable(Z)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setImageResource(Lorg/thoughtcrime/securesms/mms/GlideRequests;Ljava/util/List;ZZ)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setMaximumThumbnailHeight(I)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setMinimumThumbnailWidth(I)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setOnLongClickListener(Landroid/view/View$OnLongClickListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setPlayVideoClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setStartTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setThumbnailBounds([I)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setThumbnailClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->showShade(Z)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->showThumbnailView()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState$Creator;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->(ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIII)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->(ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->copy$default(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->copy(ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIII)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$Creator;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState$Creator;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->(FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIII)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->(FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->copy$default(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIIIILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->copy(FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIII)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->()V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;Lorg/thoughtcrime/securesms/util/views/Stub;)V -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->copy$default(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;ILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->copy(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;)Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->getAlbumViewState()Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; -HSPLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->getThumbnailViewState()Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->formatUnreadCount(I)Ljava/lang/CharSequence; -HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setOnClickListener(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setShown(Z)V -HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setUnreadCount(I)V HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setUnreadCountBackgroundTint(I)V HSPLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setWallpaperEnabled(Z)V HSPLorg/thoughtcrime/securesms/components/ConversationSearchBottomBar;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/ConversationSearchBottomBar;->onFinishInflate()V -HSPLorg/thoughtcrime/securesms/components/ConversationSearchBottomBar;->setEventListener(Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar$EventListener;)V HSPLorg/thoughtcrime/securesms/components/CornerMask;->(Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/components/CornerMask;->mask(Landroid/graphics/Canvas;)V HSPLorg/thoughtcrime/securesms/components/CornerMask;->setRadii(IIII)V -HSPLorg/thoughtcrime/securesms/components/CornerMask;->setRadius(I)V HSPLorg/thoughtcrime/securesms/components/CornerMask;->setTopLeftRadius(I)V HSPLorg/thoughtcrime/securesms/components/CornerMask;->setTopRightRadius(I)V HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView$State;->$values()[Lorg/thoughtcrime/securesms/components/DeliveryStatusView$State; @@ -20296,29 +20153,21 @@ HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView$State;->(Ljav HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->clearAnimation()V -HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->isPending()Z HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->setNone()V HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->setTint(I)V HSPLorg/thoughtcrime/securesms/components/DeliveryStatusView;->updateContentDescription()V HSPLorg/thoughtcrime/securesms/components/ExpirationTimerView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/ExpirationTimerView;->stopAnimation()V -HSPLorg/thoughtcrime/securesms/components/FromTextView;->()V HSPLorg/thoughtcrime/securesms/components/FromTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/CharSequence;ZLjava/lang/String;)V -HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/CharSequence;ZLjava/lang/String;Z)V -HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V -HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;ZLjava/lang/String;)V +HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/CharSequence;)V +HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/CharSequence;Ljava/lang/CharSequence;)V +HSPLorg/thoughtcrime/securesms/components/FromTextView;->setText(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Z)V HSPLorg/thoughtcrime/securesms/components/HidingLinearLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/HidingLinearLayout;->hide()V -HSPLorg/thoughtcrime/securesms/components/HidingLinearLayout;->show()V HSPLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->()V HSPLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->addInputListener(Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout$Listener;)V HSPLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->setFragmentManager(Landroidx/fragment/app/FragmentManager;)V -HSPLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/components/InputPanel$Listener;)V -HSPLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/components/InputPanel$Listener;)V HSPLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/components/InputPanel;)V HSPLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/components/InputPanel;)V HSPLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda6;->(Lorg/thoughtcrime/securesms/components/InputPanel;)V @@ -20329,13 +20178,10 @@ HSPLorg/thoughtcrime/securesms/components/InputPanel$RecordTime;->(Landroi HSPLorg/thoughtcrime/securesms/components/InputPanel$SlideToCancel;->(Landroid/view/View;)V HSPLorg/thoughtcrime/securesms/components/InputPanel;->()V HSPLorg/thoughtcrime/securesms/components/InputPanel;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/InputPanel;->getPlaybackStateObserver()Landroidx/lifecycle/Observer; HSPLorg/thoughtcrime/securesms/components/InputPanel;->onFinishInflate()V HSPLorg/thoughtcrime/securesms/components/InputPanel;->setHideForMessageRequestState(Z)V -HSPLorg/thoughtcrime/securesms/components/InputPanel;->setListener(Lorg/thoughtcrime/securesms/components/InputPanel$Listener;)V HSPLorg/thoughtcrime/securesms/components/InputPanel;->setMediaKeyboardToggleMode(Lorg/thoughtcrime/securesms/keyboard/KeyboardPage;)V HSPLorg/thoughtcrime/securesms/components/InputPanel;->setMediaListener(Lorg/thoughtcrime/securesms/components/InputPanel$MediaListener;)V -HSPLorg/thoughtcrime/securesms/components/InputPanel;->setStickerSuggestions(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/components/InputPanel;->setWallpaperEnabled(Z)V HSPLorg/thoughtcrime/securesms/components/InputPanel;->showMediaKeyboardToggle(Z)V HSPLorg/thoughtcrime/securesms/components/InputPanel;->updateVisibility()V @@ -20364,7 +20210,6 @@ HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->$r8$lambd HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->()V HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->_init_$lambda$0(Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;Landroid/view/View;Landroidx/core/view/WindowInsetsCompat;)Landroidx/core/view/WindowInsetsCompat; -HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->addKeyboardStateListener(Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$KeyboardStateListener;)V HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->applyInsets(Landroidx/core/graphics/Insets;Landroidx/core/graphics/Insets;)V HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->getKeyboardGuideline()Landroidx/constraintlayout/widget/Guideline; HSPLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->getNavigationBarGuideline()Landroidx/constraintlayout/widget/Guideline; @@ -20380,9 +20225,6 @@ HSPLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->()V HSPLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->(IIIILorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V HSPLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->(IIIILorg/thoughtcrime/securesms/mms/SlidesClickedListener;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;)V -HSPLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->copy(IIIILorg/thoughtcrime/securesms/mms/SlidesClickedListener;)Lorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState; -HSPLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->getDownloadListener()Lorg/thoughtcrime/securesms/mms/SlidesClickedListener; HSPLorg/thoughtcrime/securesms/components/Material3SearchToolbar$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/Material3SearchToolbar;)V HSPLorg/thoughtcrime/securesms/components/Material3SearchToolbar$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/components/Material3SearchToolbar;)V HSPLorg/thoughtcrime/securesms/components/Material3SearchToolbar$special$$inlined$addTextChangedListener$default$1;->(Landroid/view/View;Lorg/thoughtcrime/securesms/components/Material3SearchToolbar;)V @@ -20394,21 +20236,15 @@ HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView$State;->$values HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView$State;->()V HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView$State;->(Ljava/lang/String;I)V HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView;->isRecordingLocked()Z HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView;->onFinishInflate()V HSPLorg/thoughtcrime/securesms/components/MicrophoneRecorderView;->setHandler(Lorg/thoughtcrime/securesms/audio/AudioRecordingHandler;)V HSPLorg/thoughtcrime/securesms/components/Outliner;->()V -HSPLorg/thoughtcrime/securesms/components/Outliner;->draw(Landroid/graphics/Canvas;IIII)V -HSPLorg/thoughtcrime/securesms/components/Outliner;->setColor(I)V -HSPLorg/thoughtcrime/securesms/components/Outliner;->setRadii(IIII)V -HSPLorg/thoughtcrime/securesms/components/Outliner;->setStrokeWidth(F)V HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;)V HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->()V HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->getCurrentLabel()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->setPlaybackSpeedListener(Lorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView$PlaybackSpeedListener;)V HSPLorg/thoughtcrime/securesms/components/QuoteView$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/components/QuoteView;)V HSPLorg/thoughtcrime/securesms/components/QuoteView$MessageType;->$values()[Lorg/thoughtcrime/securesms/components/QuoteView$MessageType; HSPLorg/thoughtcrime/securesms/components/QuoteView$MessageType;->-$$Nest$smfromCode(I)Lorg/thoughtcrime/securesms/components/QuoteView$MessageType; @@ -20419,24 +20255,15 @@ HSPLorg/thoughtcrime/securesms/components/QuoteView$MessageType;->values()[Lorg/ HSPLorg/thoughtcrime/securesms/components/QuoteView;->()V HSPLorg/thoughtcrime/securesms/components/QuoteView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/QuoteView;->applyColorTheme()V -HSPLorg/thoughtcrime/securesms/components/QuoteView;->dismiss()V HSPLorg/thoughtcrime/securesms/components/QuoteView;->initialize(Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/QuoteView;->isStoryReply()Z HSPLorg/thoughtcrime/securesms/components/QuoteView;->setMessageType(Lorg/thoughtcrime/securesms/components/QuoteView$MessageType;)V HSPLorg/thoughtcrime/securesms/components/QuoteView;->setWallpaperEnabled(Z)V HSPLorg/thoughtcrime/securesms/components/RatingManager;->()V HSPLorg/thoughtcrime/securesms/components/RatingManager;->showRatingDialogIfNecessary(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->()V -HSPLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->(Landroid/view/ViewGroup;Landroid/animation/LayoutTransition;)V -HSPLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->(Landroid/view/ViewGroup;Landroid/animation/LayoutTransition;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->findRecyclerParent()Landroidx/recyclerview/widget/RecyclerView; -HSPLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->onScrollStateChanged(Landroidx/recyclerview/widget/RecyclerView;I)V -HSPLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->onViewAttachedToWindow(Landroid/view/View;)V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$2;->()V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$2;->()V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$3;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$3;->test(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$3;->test(Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;)Z HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$4;->(Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$5;->(Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;)V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$Companion;->()V @@ -20444,54 +20271,14 @@ HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$Companion;->< HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$DefaultScrollStrategy;->()V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$DefaultScrollStrategy;->()V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;->(IZLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollStrategy;)V -HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;->getPosition()I HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1;->()V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1;->()V -HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1;->apply(JLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;)Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest; -HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->()V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->(Landroidx/recyclerview/widget/RecyclerView;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->(Landroidx/recyclerview/widget/RecyclerView;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->(Landroidx/recyclerview/widget/RecyclerView;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lio/reactivex/rxjava3/disposables/CompositeDisposable;)V -HSPLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->notifyListCommitted()V -HSPLorg/thoughtcrime/securesms/components/SearchView;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/components/SearchView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/SearchView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/components/SearchView;->appendEmojiFilter(Landroid/widget/TextView;)[Landroid/text/InputFilter; -HSPLorg/thoughtcrime/securesms/components/SearchView;->initEmojiFilter()V HSPLorg/thoughtcrime/securesms/components/SendButton;->()V HSPLorg/thoughtcrime/securesms/components/SendButton;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/SendButton;->setPopupContainer(Landroid/view/ViewGroup;)V -HSPLorg/thoughtcrime/securesms/components/SendButton;->setScheduledSendListener(Lorg/thoughtcrime/securesms/components/SendButton$ScheduledSendListener;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport0;->m(Ljava/lang/Object;)Ljava/util/List; -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport1;->m(Ljava/lang/Object;)Ljava/util/List; -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport2;->m([Ljava/lang/Object;)Ljava/util/List; -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;Lorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher-IA;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;Lorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher-IA;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;Lorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher-IA;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->()V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->dispatchDraw(Landroid/graphics/Canvas;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->fillTargetDimensions([I[I[I)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->getNonZeroCount([I)I -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->hasSameContents(Lorg/thoughtcrime/securesms/mms/Slide;Lorg/thoughtcrime/securesms/mms/Slide;)Z -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->onMeasure(II)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->onSizeChanged(IIII)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setBounds(IIII)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setCancelTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setClickable(Z)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setFocusable(Z)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setImageResource(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/mms/Slide;ZZ)Lorg/thoughtcrime/securesms/util/concurrent/ListenableFuture; -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setImageResource(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/mms/Slide;ZZII)Lorg/thoughtcrime/securesms/util/concurrent/ListenableFuture; -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setPlayVideoClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setRadii(IIII)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setStartTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->setThumbnailClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V -HSPLorg/thoughtcrime/securesms/components/ThumbnailView;->showSecondaryText(Z)V HSPLorg/thoughtcrime/securesms/components/TypingIndicatorView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/TypingIndicatorView;->initialize(Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/TypingIndicatorView;->setDotTint(I)V @@ -20499,7 +20286,6 @@ HSPLorg/thoughtcrime/securesms/components/TypingIndicatorView;->stopAnimation()V HSPLorg/thoughtcrime/securesms/components/TypingStatusRepository;->()V HSPLorg/thoughtcrime/securesms/components/TypingStatusRepository;->()V HSPLorg/thoughtcrime/securesms/components/TypingStatusRepository;->getTypingThreads()Landroidx/lifecycle/LiveData; -HSPLorg/thoughtcrime/securesms/components/TypingStatusRepository;->getTypists(J)Landroidx/lifecycle/LiveData; HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate$1;->()V HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate$1;->()V HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->()V @@ -20510,7 +20296,6 @@ HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onCreate(Landroid HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/WaveFormSeekBarView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/WaveFormSeekBarView;->getProgressDrawable()Landroid/graphics/drawable/Drawable; HSPLorg/thoughtcrime/securesms/components/WaveFormSeekBarView;->init()V @@ -20526,10 +20311,8 @@ HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText$$ExternalSynthetic HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->$r8$lambda$8pyXdt50o8im33POXP_o4TKoD6U(Lorg/thoughtcrime/securesms/components/emoji/EmojiEditText;Landroid/view/View;Z)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->addOnFocusChangeListener(Landroid/view/View$OnFocusChangeListener;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->appendEmojiFilter([Landroid/text/InputFilter;Z)[Landroid/text/InputFilter; HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->lambda$new$0(Landroid/view/View;Z)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->setOnFocusChangeListener(Landroid/view/View$OnFocusChangeListener;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiFilter;->(Landroid/widget/TextView;Z)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiImageView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiImageView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V @@ -20554,39 +20337,28 @@ HSPLorg/thoughtcrime/securesms/components/emoji/EmojiProvider;->getEmojiDrawable HSPLorg/thoughtcrime/securesms/components/emoji/EmojiSpan;->(Landroid/graphics/drawable/Drawable;Landroid/widget/TextView;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiSpan;->draw(Landroid/graphics/Canvas;Ljava/lang/CharSequence;IIFIIILandroid/graphics/Paint;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiSpan;->getSize(Landroid/graphics/Paint;Ljava/lang/CharSequence;IILandroid/graphics/Paint$FontMetricsInt;)I -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda1;->()V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda2;->run()V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda3;->(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda3;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->$r8$lambda$5IPAQraRDnd37oqJyWeDCIArE8A(Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Ljava/lang/String;)Ljava/lang/Float; HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->$r8$lambda$9VxJG--rce_LMrBbBVi5JkyJelM(Ljava/lang/Runnable;Landroid/view/View;)Lkotlin/Unit; HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->$r8$lambda$PicvuNf_O0Zy5LBsFpj6-AJMdsI(Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->applyWidthMeasureRoundingFix(I)I HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->drawSpecialRenderers(Landroid/graphics/Canvas;Lorg/thoughtcrime/securesms/components/mention/MentionRendererDelegate;Lorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->ellipsizeAnyTextForMaxLength()V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->ellipsizeEmojiTextForMaxLines()V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->getLastLineWidth()I -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->getLongestLineWidth(Ljava/lang/CharSequence;)F HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->hasMetricAffectingSpan(Ljava/lang/CharSequence;)Z HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->invalidateDrawable(Landroid/graphics/drawable/Drawable;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->isEllipsizedAtEnd()Z -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->isJumbomoji()Z HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->isSingleLine()Z HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->lambda$ellipsizeEmojiTextForMaxLines$2()V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->lambda$ellipsizeEmojiTextForMaxLines$3(Ljava/lang/Runnable;Landroid/view/View;)Lkotlin/Unit; -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->lambda$getLongestLineWidth$0(Ljava/lang/String;)Ljava/lang/Float; HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->onDraw(Landroid/graphics/Canvas;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->onMeasure(II)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->onSizeChanged(IIII)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setMentionBackgroundTint(I)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setOverflowText(Ljava/lang/CharSequence;)V +HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setTextColor(I)V -HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setTextSize(IF)V HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->unchanged(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;)Z HSPLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->useSystemEmoji()Z HSPLorg/thoughtcrime/securesms/components/emoji/EmojiToggle$1;->()V @@ -20614,7 +20386,6 @@ HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->$r8$lambd HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->(Lorg/thoughtcrime/securesms/emoji/EmojiCategory;Ljava/util/List;Landroid/net/Uri;)V HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->(Lorg/thoughtcrime/securesms/emoji/EmojiCategory;[Ljava/lang/String;Landroid/net/Uri;)V HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->getDisplayEmoji()Ljava/util/List; -HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->getEmoji()Ljava/util/List; HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->getIconAttr()I HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->getSpriteUri()Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->lambda$new$0(Ljava/lang/String;)Lorg/thoughtcrime/securesms/components/emoji/Emoji; @@ -20654,18 +20425,13 @@ HSPLorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick;->() HSPLorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick;->(Ljava/lang/String;ILjava/lang/String;)V HSPLorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick;->fitzpatrickFromUnicode(Ljava/lang/CharSequence;I)Lorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick; HSPLorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick;->values()[Lorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick; -HSPLorg/thoughtcrime/securesms/components/mention/MentionAnnotation$$ExternalSyntheticLambda1;->()V -HSPLorg/thoughtcrime/securesms/components/mention/MentionAnnotation;->getMentionAnnotations(Landroid/text/Spanned;)Ljava/util/List; -HSPLorg/thoughtcrime/securesms/components/mention/MentionAnnotation;->getMentionAnnotations(Landroid/text/Spanned;II)Ljava/util/List; HSPLorg/thoughtcrime/securesms/components/mention/MentionDeleter;->()V HSPLorg/thoughtcrime/securesms/components/mention/MentionRenderer$MultiLineMentionRenderer;->(IILandroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V HSPLorg/thoughtcrime/securesms/components/mention/MentionRenderer$SingleLineMentionRenderer;->(IILandroid/graphics/drawable/Drawable;)V HSPLorg/thoughtcrime/securesms/components/mention/MentionRenderer;->(II)V HSPLorg/thoughtcrime/securesms/components/mention/MentionRendererDelegate;->(Landroid/content/Context;I)V HSPLorg/thoughtcrime/securesms/components/mention/MentionRendererDelegate;->draw(Landroid/graphics/Canvas;Landroid/text/Spanned;Landroid/text/Layout;)V -HSPLorg/thoughtcrime/securesms/components/mention/MentionRendererDelegate;->setTint(I)V HSPLorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher;->()V -HSPLorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher;->setMentionValidator(Lorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher$MentionValidator;)V HSPLorg/thoughtcrime/securesms/components/menu/ActionItem;->()V HSPLorg/thoughtcrime/securesms/components/menu/ActionItem;->(ILjava/lang/CharSequence;ILjava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/components/menu/ActionItem;->(ILjava/lang/CharSequence;ILjava/lang/Runnable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -20712,6 +20478,7 @@ HSPLorg/thoughtcrime/securesms/components/reminder/OutdatedBuildReminder;->isEli HSPLorg/thoughtcrime/securesms/components/reminder/PushRegistrationReminder;->isEligible()Z HSPLorg/thoughtcrime/securesms/components/reminder/ServiceOutageReminder;->isEligible(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/components/reminder/UnauthorizedReminder;->isEligible(Landroid/content/Context;)Z +HSPLorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder$Companion$WhenMappings;->()V HSPLorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder$Companion;->()V HSPLorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder$Companion;->isEligible()Z @@ -20730,7 +20497,6 @@ HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/Te HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationDelegate;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationDelegate;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationDelegate;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationDelegate;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationRepository;->()V HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationRepository;->(Lorg/whispersystems/signalservice/api/services/DonationsService;)V HSPLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationRepository;->(Lorg/whispersystems/signalservice/api/services/DonationsService;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -20760,7 +20526,6 @@ HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onVi HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1;->(Lorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;)V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1;->onViewAttachedToWindow(Landroid/view/View;)V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;->()V @@ -20774,87 +20539,11 @@ HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;->acce HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;->draw(Landroid/graphics/Canvas;Landroid/text/Spanned;Landroid/text/Layout;)V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;->stopAnimating()V HSPLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate;->updateFromTextColor()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->containsPlayableSlides(Ljava/util/List;)Z -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->getTransferState(Ljava/util/List;)I -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode;->$values()[Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode;->(Ljava/lang/String;I)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress$Companion;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->(JJ)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->toString()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1;->(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1;->(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1;->(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1;->(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2;->(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1;->(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1;->(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->access$isUpdateToExistingSet(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;Ljava/util/List;)Z -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->access$slidesAsListOfTimestamps(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Ljava/util/List;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->access$verboseLog(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->containsPlayableSlides(Ljava/util/List;)Z -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->deriveMode(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->getTransferState(Ljava/util/List;)I -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->isUpdateToExistingSet(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;Ljava/util/List;)Z -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->onAttachedToWindow()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setCancelClickListener(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setClickable(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setFocusable(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setShowSecondaryText(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setSlides(Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setTransferClickListener(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->setVisible(Z)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->slidesAsListOfTimestamps(Ljava/util/List;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->updateState(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->verboseLog(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->(ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZ)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->(ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->copy$default(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZILjava/lang/Object;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->copy(ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZ)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->equals(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->getNetworkProgress()Ljava/util/Map; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->getSlides()Ljava/util/List; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->toString()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$Companion;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State;->$values()[Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State;->(Ljava/lang/String;I)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->()V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->(Landroid/content/Context;Landroid/util/AttributeSet;II)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->(Landroid/content/Context;Landroid/util/AttributeSet;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->progressPaint(I)Landroid/graphics/Paint; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->stopIconPaint(I)Landroid/graphics/Paint; -HSPLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->trackPaint(I)Landroid/graphics/Paint; HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink$Companion;->()V HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->()V -HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->(Landroid/content/Context;ZZZLandroidx/media3/exoplayer/audio/AudioSink;)V -HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->(Landroid/content/Context;ZZZLandroidx/media3/exoplayer/audio/AudioSink;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->(Landroid/content/Context;ZZLandroidx/media3/exoplayer/audio/AudioSink;)V +HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->(Landroid/content/Context;ZZLandroidx/media3/exoplayer/audio/AudioSink;ILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->setAudioAttributes(Landroidx/media3/common/AudioAttributes;)V HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->setAudioSessionId(I)V HSPLorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink;->setListener(Landroidx/media3/exoplayer/audio/AudioSink$Listener;)V @@ -20878,7 +20567,6 @@ HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->acces HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->clearProgressEventHandler()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->createMediaControllerAsync()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->finishPostpone()V -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->getVoiceNotePlaybackState()Landroidx/lifecycle/MutableLiveData; HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->getVoiceNotePlayerViewState()Landroidx/lifecycle/LiveData; HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->initializeMediaController(Landroidx/media3/session/MediaController;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->notifyProgressEventHandler()V @@ -20886,7 +20574,6 @@ HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onCre HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaNotificationProvider$Companion;->()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaNotificationProvider$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaNotificationProvider;->()V @@ -20925,24 +20612,16 @@ HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->compone HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->component5()F HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->component6()Z HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->component7()Lorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState$ClipType; -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getPlayheadPositionMillis()J -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getSpeed()F -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getTrackDuration()J -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getUri()Landroid/net/Uri; -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->isAutoReset()Z -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->isPlaying()Z HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayer;->()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayer;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayer;->(Landroid/content/Context;Landroidx/media3/exoplayer/ExoPlayer;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayer;->(Landroid/content/Context;Landroidx/media3/exoplayer/ExoPlayer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayer;->setAudioAttributes(Landroidx/media3/common/AudioAttributes;Z)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback$Companion;->()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/components/voice/VoiceNotePlayer;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->onConnect(Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;)Landroidx/media3/session/MediaSession$ConnectionResult; HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->onCustomCommand(Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;Landroidx/media3/session/SessionCommand;Landroid/os/Bundle;)Lcom/google/common/util/concurrent/ListenableFuture; -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->onDisconnected(Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->onPostConnect(Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->setAudioStream(Landroid/os/Bundle;)Lcom/google/common/util/concurrent/ListenableFuture; HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager$HardwareSensorEventListener;->(Lorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;)V @@ -20954,14 +20633,13 @@ HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManage HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->sendNewStreamTypeToPlayer(I)V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->unregisterCallbacksAndRelease()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManagerKt;->()V HSPLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManagerKt;->access$getTAG$p()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/components/voice/WorkaroundRenderersFactory;->()V HSPLorg/thoughtcrime/securesms/components/voice/WorkaroundRenderersFactory;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/components/voice/WorkaroundRenderersFactory;->buildAudioSink(Landroid/content/Context;ZZZ)Landroidx/media3/exoplayer/audio/AudioSink; +HSPLorg/thoughtcrime/securesms/components/voice/WorkaroundRenderersFactory;->buildAudioSink(Landroid/content/Context;ZZ)Landroidx/media3/exoplayer/audio/AudioSink; HSPLorg/thoughtcrime/securesms/components/webrtc/SurfaceTextureEglRenderer$$ExternalSyntheticLambda0;->(Ljava/util/concurrent/CountDownLatch;)V HSPLorg/thoughtcrime/securesms/components/webrtc/SurfaceTextureEglRenderer$$ExternalSyntheticLambda0;->run()V HSPLorg/thoughtcrime/securesms/contacts/ContactRepository$1$$ExternalSyntheticLambda0;->()V @@ -21107,17 +20785,19 @@ HSPLorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel;->getSelect HSPLorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel;->setConfiguration(Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchConfiguration;)V HSPLorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel;->setConversationFilterRequest$lambda$1(Lorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationFilterRequest;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchState;)Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchState; HSPLorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel;->setConversationFilterRequest(Lorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationFilterRequest;)V +HSPLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->()V +HSPLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->()V +HSPLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->hasContactsPermissions(Landroid/content/Context;)Z +HSPLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->refreshAll(Landroid/content/Context;Z)V HSPLorg/thoughtcrime/securesms/conversation/BodyBubbleLayoutTransition;->()V HSPLorg/thoughtcrime/securesms/conversation/BodyBubbleLayoutTransition;->()V HSPLorg/thoughtcrime/securesms/conversation/ClipProjectionDrawable;->()V HSPLorg/thoughtcrime/securesms/conversation/ClipProjectionDrawable;->(Landroid/graphics/drawable/Drawable;)V -HSPLorg/thoughtcrime/securesms/conversation/ClipProjectionDrawable;->draw(Landroid/graphics/Canvas;)V HSPLorg/thoughtcrime/securesms/conversation/ClipProjectionDrawable;->setProjections(Ljava/util/Set;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->(ZZ)V HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->(ZZZZ)V HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->(ZZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->includeWarningUpdateMessage()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->isHidden()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData;->isMessageRequestAccepted()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationData;->()V @@ -21130,36 +20810,14 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationData;->getUnreadCount()I HSPLorg/thoughtcrime/securesms/conversation/ConversationData;->shouldJumpToMessage()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationData;->shouldScrollToLastSeen()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationData;->showUniversalExpireTimerMessage()Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider;->(Lorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider-IA;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->hideDecoratorsIfContentIsNotPresent()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->hideDescription()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->prependIcon(Ljava/lang/CharSequence;I)Ljava/lang/CharSequence; -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setAbout(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setAvatar(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setLinkifyDescription(Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setSubtitle(Ljava/lang/CharSequence;I)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setTitle(Lorg/thoughtcrime/securesms/recipients/Recipient;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->showBackgroundBubble(Z)V HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->(Lorg/thoughtcrime/securesms/recipients/RecipientId;JLjava/lang/String;Landroid/net/Uri;Ljava/lang/String;Ljava/util/ArrayList;Lorg/thoughtcrime/securesms/stickers/StickerLocator;ZIIZZLorg/thoughtcrime/securesms/badges/models/Badge;JLorg/thoughtcrime/securesms/conversation/ConversationIntents$ConversationScreenType;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->canInitializeFromDatabase()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->from(Landroid/os/Bundle;)Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args; HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getChatColors()Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getConversationScreenType()Lorg/thoughtcrime/securesms/conversation/ConversationIntents$ConversationScreenType; HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDistributionType()I -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftContentType()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftMedia()Landroid/net/Uri; -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftMediaType()Lorg/thoughtcrime/securesms/mms/SlideFactory$MediaType; -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftText()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getMedia()Ljava/util/ArrayList; -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getShareDataTimestamp()J HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getStartingPosition()I -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getStickerLocator()Lorg/thoughtcrime/securesms/stickers/StickerLocator; HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getThreadId()J HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getWallpaper()Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper; -HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->isBorderless()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->isFirstTimeInSelfCreatedGroup()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->isWithSearchOpen()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents$Builder;->(Landroid/content/Context;Ljava/lang/Class;Lorg/thoughtcrime/securesms/recipients/RecipientId;JLorg/thoughtcrime/securesms/conversation/ConversationIntents$ConversationScreenType;)V @@ -21185,8 +20843,7 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents;->createParentFr HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents;->getIntentData(Landroid/os/Bundle;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents;->getIntentType(Landroid/os/Bundle;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/conversation/ConversationIntents;->isBubbleIntentUri(Landroid/net/Uri;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda6;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda9;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/recipients/RecipientId;)V +HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda4;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$1;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$AttachmentDownloadClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$AttachmentDownloadClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/conversation/ConversationItem$AttachmentDownloadClickListener-IA;)V @@ -21209,8 +20866,6 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$SharedContactEventL HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$SharedContactEventListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/conversation/ConversationItem$SharedContactEventListener-IA;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$SlideClickPassthroughListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$SlideClickPassthroughListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/conversation/ConversationItem$SlideClickPassthroughListener-IA;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener-IA;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$TouchDelegateChangedListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$TouchDelegateChangedListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/conversation/ConversationItem$TouchDelegateChangedListener-IA;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$UrlClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;)V @@ -21219,132 +20874,35 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$ViewOnceMessageClic HSPLorg/thoughtcrime/securesms/conversation/ConversationItem$ViewOnceMessageClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/conversation/ConversationItem$ViewOnceMessageClickListener-IA;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->bind(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Lj$/util/Optional;Lj$/util/Optional;Lorg/thoughtcrime/securesms/mms/GlideRequests;Ljava/util/Locale;Ljava/util/Set;Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/String;ZZZZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->canPlayContent()Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->forceFooter(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getActiveFooter(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Lorg/thoughtcrime/securesms/components/ConversationItemFooter; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getBodyBubbleCorners(IIII)Lorg/thoughtcrime/securesms/util/Projection$Corners; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getColorizerProjections(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/ProjectionList; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getConversationMessage()Lorg/thoughtcrime/securesms/conversation/ConversationMessage; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getDefaultBubbleColor(Z)I -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getDefaultTopMarginForRecord(Lorg/thoughtcrime/securesms/database/model/MessageRecord;II)I -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getGiftId()J -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getOpenableGiftProjection(Z)Lorg/thoughtcrime/securesms/util/Projection; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getRoot()Landroid/view/ViewGroup; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->getSnapshotProjections(Landroid/view/ViewGroup;ZZ)Lorg/thoughtcrime/securesms/util/ProjectionList; -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasAudio(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasDocument(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasExtraText(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasLinkPreview(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasNoBubble(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasOnlyThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasQuote(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasSharedContact(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasSticker(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->initializeAttributes()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isBorderless(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isCaptionlessMms(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isCondensedMode()Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isContentCondensed()Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isEndOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isFooterVisible(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isGiftMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isSingularMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isStartOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isStoryReaction(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isViewOnceMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->isWithinClusteringTime(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->onFinishInflate()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->onMeasure(II)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->onRecipientChanged(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->readDimen(I)I -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->readDimen(Landroid/content/Context;I)I -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setAuthor(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;ZZ)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setBodyText(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/String;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setBubbleState(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;ZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setContactPhoto(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setEventListener(Lorg/thoughtcrime/securesms/BindableConversationItem$EventListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setFooter(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Ljava/util/Locale;ZZ)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setGroupAuthorColor(Lorg/thoughtcrime/securesms/database/model/MessageRecord;ZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setGroupMessageStatus(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setGutterSizes(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setHasBeenQuoted(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setHasBeenScheduled(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setInteractionState(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setMediaAttributes(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;ZZZZ)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setMessageShape(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setMessageSpacing(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setOnClickListener(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setOutlinerRadii(Lorg/thoughtcrime/securesms/components/Outliner;IIII)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setParentScrolling(Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setQuote(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setReactions(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setStatusIcons(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setStoryReactionLabel(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->setThumbnailCorners(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->shouldDrawBodyBubbleOutline(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->shouldInterceptClicks(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->showProjectionArea()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItem;->unbind()V HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$$ExternalSyntheticBackport0;->m(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$$ExternalSyntheticLambda2;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$$ExternalSyntheticLambda2;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->getProjections()Ljava/util/Set; HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->init()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->onDrawForeground(Landroid/graphics/Canvas;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->onSizeChanged(IIII)V HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setBackground(Landroid/graphics/drawable/Drawable;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setOnSizeChangedListener(Lorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$OnSizeChangedListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setOutliners(Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setParentScrolling(Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setQuoteViewProjection(Lorg/thoughtcrime/securesms/util/Projection;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setVideoPlayerProjection(Lorg/thoughtcrime/securesms/util/Projection;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Detailed;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Detailed;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$EditHistory;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$EditHistory;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Standard;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Standard;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->(Z)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->(ZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->(ZLkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;->(Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$SwipeAvailabilityProvider;Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$OnSwipeListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;->attachToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationItemTouchListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItemTouchListener$Callback;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage$ComputedProperties;->(Lorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage$ConversationMessageFactory;->createWithUnresolvedData(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/CharSequence;Ljava/util/List;ZLorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/ConversationMessage; HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/CharSequence;Ljava/util/List;ZLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/conversation/ConversationMessage$ComputedProperties;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/CharSequence;Ljava/util/List;ZLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/conversation/ConversationMessage$ComputedProperties;Lorg/thoughtcrime/securesms/conversation/ConversationMessage-IA;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->equals(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getBottomButton()Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList$BodyRange$Button; -HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getConversationTimestamp()J -HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getDisplayBody(Landroid/content/Context;)Landroid/text/SpannableString; HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getFormattedDate(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Lorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate; HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getMessageRecord()Lorg/thoughtcrime/securesms/database/model/MessageRecord; -HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getMultiselectCollection()Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection; -HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getThreadRecipient()Lorg/thoughtcrime/securesms/recipients/Recipient; HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->hasBeenQuoted()Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->hasStyleLinks()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->hashCode()I HSPLorg/thoughtcrime/securesms/conversation/ConversationMessage;->isTextOnly(Landroid/content/Context;)Z -HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider$onCreateMenu$1;->(Landroid/view/Menu;Z)V HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->(Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Callback;Lorg/signal/core/util/concurrent/LifecycleDisposable;Z)V HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->(Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Callback;Lorg/signal/core/util/concurrent/LifecycleDisposable;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->applyTitleSpan(Landroid/view/MenuItem;Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->hideMenuItem(Landroid/view/Menu;I)V HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->onCreateMenu(Landroid/view/Menu;Landroid/view/MenuInflater;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->setAfterFirstRenderMode(Z)V HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->(Lorg/thoughtcrime/securesms/recipients/Recipient;ZLio/reactivex/rxjava3/core/Observable;ZZZZIJZZ)V +HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->(Lorg/thoughtcrime/securesms/recipients/Recipient;ZLio/reactivex/rxjava3/core/Observable;ZZZZIJLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Z)V HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->component1()Lorg/thoughtcrime/securesms/recipients/Recipient; -HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->component10()Z +HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->component10()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->component11()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->component2()Z HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->component3()Lio/reactivex/rxjava3/core/Observable; @@ -21357,16 +20915,7 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot;->c HSPLorg/thoughtcrime/securesms/conversation/ConversationRepository;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationRepository;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationRepository;->getConversationData(JLorg/thoughtcrime/securesms/recipients/Recipient;I)Lorg/thoughtcrime/securesms/conversation/ConversationData; -HSPLorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel;->(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel;->getSearchResults()Landroidx/lifecycle/LiveData; -HSPLorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter;->(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter$EventListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter;->setStickers(Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator;->(FFF)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator;->(FFFLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator-IA;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$ClampingLinearInterpolator;->(FF)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$ClampingLinearInterpolator;->(FFF)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->dpToPx(I)I +HSPLorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter;->(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter$EventListener;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/conversation/ConversationTitleView;Landroid/view/View$OnClickListener;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->clearExpiring()V @@ -21375,8 +20924,7 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setIndividua HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setOnStoryRingClickListener(Landroid/view/View$OnClickListener;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setRecipientTitle(Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setStoryRingFromState(Lorg/thoughtcrime/securesms/database/model/StoryViewState;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setTitle(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setVerified(Z)V +HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setTitle(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->updateSubtitleVisibility()V HSPLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->updateVerifiedSubtitleVisibility()V HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateItem$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/ConversationUpdateItem;)V @@ -21393,29 +20941,9 @@ HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateItem;->()V HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateItem;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateItem;->onFinishInflate()V HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateItem;->setOnClickListener(Landroid/view/View$OnClickListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$1;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->()V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->(Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$OnTickListener;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onResume(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda0;->()V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda1;->()V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda3;->run()V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->$r8$lambda$gcFI10LhFCaBEmJzQp8t_xBcU8U(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->()V HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->(Lorg/thoughtcrime/securesms/notifications/v2/ConversationId;Landroid/content/Context;Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->getLatestTimestamp(Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge;Landroidx/recyclerview/widget/LinearLayoutManager;)Lj$/util/Optional; HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->ignoreViewReveals()V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->lambda$onViewsRevealed$1(J)V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->onViewsRevealed(J)V -HSPLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->stopIgnoringViewReveals(Ljava/lang/Long;)V HSPLorg/thoughtcrime/securesms/conversation/MessageSendType$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/MessageSendType$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/MessageSendType$SignalMessageSendType$Creator;->()V @@ -21425,9 +20953,8 @@ HSPLorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;->$val HSPLorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;->()V HSPLorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;->(Ljava/lang/String;I)V HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->()V -HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->(IIIIILorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;Lorg/thoughtcrime/securesms/util/CharacterCalculator;Ljava/lang/CharSequence;Ljava/lang/Integer;)V -HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->(IIIIILorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;Lorg/thoughtcrime/securesms/util/CharacterCalculator;Ljava/lang/CharSequence;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->(IIIIILorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;Lorg/thoughtcrime/securesms/util/CharacterCalculator;Ljava/lang/CharSequence;Ljava/lang/Integer;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->(IIIIILorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;Lorg/thoughtcrime/securesms/util/CharacterCalculator;)V +HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->(IIIIILorg/thoughtcrime/securesms/conversation/MessageSendType$TransportType;Lorg/thoughtcrime/securesms/util/CharacterCalculator;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->getButtonDrawableRes()I HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->getComposeHintRes()I HSPLorg/thoughtcrime/securesms/conversation/MessageSendType;->getTitleRes()I @@ -21440,39 +20967,19 @@ HSPLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->(ZLorg/ HSPLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->(ZLorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList$BodyRange$Button;ILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->access$getNO_STYLE$cp()Lorg/thoughtcrime/securesms/conversation/MessageStyler$Result; HSPLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->getBottomButton()Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList$BodyRange$Button; -HSPLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->getHasStyleLinks()Z HSPLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->none()Lorg/thoughtcrime/securesms/conversation/MessageStyler$Result; HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->()V HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->()V -HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->boldStyle()Landroid/text/style/CharacterStyle; -HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->italicStyle()Landroid/text/style/CharacterStyle; -HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->monoStyle()Landroid/text/style/CharacterStyle; -HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->strikethroughStyle()Landroid/text/style/CharacterStyle; HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->style$default(Ljava/lang/Object;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Landroid/text/Spannable;ZILjava/lang/Object;)Lorg/thoughtcrime/securesms/conversation/MessageStyler$Result; HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->style(Ljava/lang/Object;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Landroid/text/Spannable;)Lorg/thoughtcrime/securesms/conversation/MessageStyler$Result; HSPLorg/thoughtcrime/securesms/conversation/MessageStyler;->style(Ljava/lang/Object;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Landroid/text/Spannable;Z)Lorg/thoughtcrime/securesms/conversation/MessageStyler$Result; -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda3;->(Lio/reactivex/rxjava3/core/ObservableEmitter;J)V -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda5;->(J)V -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda5;->subscribe(Lio/reactivex/rxjava3/core/ObservableEmitter;)V -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->$r8$lambda$2XiX_Dh66c_pIVZzuRFfoiDjp1A(JLio/reactivex/rxjava3/core/ObservableEmitter;)V HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->()V HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->()V -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->getScheduledMessageCount$lambda$6(JLio/reactivex/rxjava3/core/ObservableEmitter;)V -HSPLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->getScheduledMessageCount(J)Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;)V HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->()V HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->clearDraft()V -HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->getPlaybackStateObserver()Landroidx/lifecycle/Observer; -HSPLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->setListener(Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView$Listener;)V -HSPLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->()V -HSPLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->(Landroidx/activity/ComponentActivity;)V -HSPLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onResume(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onStart(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/conversation/clicklisteners/AttachmentCancelClickListener$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/clicklisteners/AttachmentCancelClickListener$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/clicklisteners/AttachmentCancelClickListener;->()V @@ -21482,6 +20989,7 @@ HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->(Ljava/lang/String;ILjava/lang/String;I)V HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->colorInt()I HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->deserialize(Ljava/lang/String;)Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor; +HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->random()Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor; HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->serialize()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->values()[Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor; HSPLorg/thoughtcrime/securesms/conversation/colors/AvatarColorHash$$ExternalSyntheticBackport0;->m(II)I @@ -21513,8 +21021,6 @@ HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$BuiltIn;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$NotSet;->()V -HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$NotSet;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id;->(J)V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id;->(JLkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -21526,6 +21032,7 @@ HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id;Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$LinearGradient;Ljava/lang/Integer;)V HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->asSingleColor()I HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->equals(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->getChatBubbleMask()Landroid/graphics/drawable/Drawable; HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->isGradient()Z HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColors;->withId(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id;)Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColorsPalette$Bubbles;->()V @@ -21534,75 +21041,23 @@ HSPLorg/thoughtcrime/securesms/conversation/colors/ChatColorsPalette$Bubbles;->g HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer$onGroupMembershipChanged$$inlined$sortedBy$1;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->()V -HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getDefaultColor(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)I -HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingBodyTextColor(Landroid/content/Context;Z)I -HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingFooterIconColor(Landroid/content/Context;Z)I -HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingFooterTextColor(Landroid/content/Context;Z)I -HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingGroupSenderColor(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)I HSPLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->onGroupMembershipChanged(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$edgeEffectFactory$1;->(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$itemDecoration$1;->(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$itemDecoration$1;->drawShaderMask(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V -HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$itemDecoration$1;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$itemDecoration$1;->onDraw(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$scrollListener$1;->(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)V -HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$scrollListener$1;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->()V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->(Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getChatColors$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; -HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getLayerXfermode$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Landroid/graphics/PorterDuffXfermode; -HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getLayoutManager(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Landroidx/recyclerview/widget/LinearLayoutManager; HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getNoLayerXfermode$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Landroid/graphics/PorterDuffXfermode; HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getUseLayer$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Z -HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$setUseLayer$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;Z)V -HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->getLayoutManager()Landroidx/recyclerview/widget/LinearLayoutManager; HSPLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->setChatColors(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->(Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;Ljava/lang/CharSequence;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->component1()Lorg/thoughtcrime/securesms/database/DraftTable$Drafts; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->component2()Ljava/lang/CharSequence; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1;->(Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1;->invoke()Lkotlin/Pair; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/database/DraftTable;Ljava/util/concurrent/Executor;Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/database/DraftTable;Ljava/util/concurrent/Executor;Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->access$getShareOrDraftDataInternal(Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)Lkotlin/Pair; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->getShareOrDraftData(J)Lio/reactivex/rxjava3/core/Maybe; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->getShareOrDraftDataInternal(J)Lkotlin/Pair; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->loadDraftsInternal(J)Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->(JLorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->(JLorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->getVoiceNoteDraft()Lorg/thoughtcrime/securesms/database/DraftTable$Draft; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1$1;->(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1;->(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1;->accept(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1;->accept(Lkotlin/Pair;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->apply(Lkotlin/Pair;)Lio/reactivex/rxjava3/core/MaybeSource; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->()V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->(JLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;)V -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->access$getStore$p(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;)Lorg/thoughtcrime/securesms/util/rx/RxStore; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->getState()Lio/reactivex/rxjava3/core/Flowable; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->getVoiceNoteDraft()Lorg/thoughtcrime/securesms/database/DraftTable$Draft; -HSPLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->loadShareOrDraftData(J)Lio/reactivex/rxjava3/core/Maybe; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$$ExternalSyntheticLambda1;->(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$$ExternalSyntheticLambda1;->run()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->$r8$lambda$IJ0Uk3eauzGuBkd_D1PotCUrlIQ(Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->animateAppearance(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)Z -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->animateSlide(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)Z HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->isRunning()Z -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->onAnimationFinished$lambda$4(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->onAnimationFinished(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/Multiselect;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/Multiselect;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/Multiselect;->getMmsParts(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Lorg/thoughtcrime/securesms/database/model/MmsMessageRecord;)Ljava/util/Set; @@ -21612,26 +21067,16 @@ HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Com HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Companion;->fromSet(Ljava/util/Set;)Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection; HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Single;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Single;->(Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Single;->toSet()Ljava/util/Set; HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->$values()[Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->()V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->(Ljava/lang/String;I)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->values()[Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$WhenMappings;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->(Landroid/content/Context;Lkotlin/jvm/functions/Function0;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->cleanPulseAnimators()V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->consumePulseRequest(Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->drawFocusShadeOverIfNecessary(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->drawFocusShadeUnderIfNecessary(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->drawPulseShadeOverIfNecessary(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->findAdapterBridge(Landroidx/recyclerview/widget/RecyclerView;)Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->getCurrentSelection(Landroidx/recyclerview/widget/RecyclerView;)Ljava/util/Set; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->getDifferenceForPart(Ljava/util/Set;Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart;)Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->hasRunningPulseRequestAnimators()Z HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->invalidateIfEnterExitAnimatorsAreRunning(Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->invalidateIfPulseRequestAnimatorsAreRunning(Landroidx/recyclerview/widget/RecyclerView;)V @@ -21640,9 +21085,6 @@ HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->onDrawOver(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->resolveMultiselectable(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;)Lorg/thoughtcrime/securesms/conversation/mutiselect/Multiselectable; -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->updateChildOffsets(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->updateMultiselectPartAnimator(Ljava/util/Set;Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart$Attachments;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart$Attachments;->(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart$Attachments;->getConversationMessage()Lorg/thoughtcrime/securesms/conversation/ConversationMessage; @@ -21658,32 +21100,12 @@ HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectRecyclerView$C HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectRecyclerView$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectRecyclerView;->()V HSPLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectRecyclerView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onResume(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$special$$inlined$doOnEachLayout$1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$special$$inlined$doOnEachLayout$1;->onLayoutChange(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->()V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->(Landroidx/fragment/app/Fragment;Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;Landroid/view/View;Landroid/view/ViewGroup;Lorg/thoughtcrime/securesms/components/ComposeText;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->access$getEmojiPopup$p(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsPopup; -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->dismiss()V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->onOrientationChange(Z)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->updateList(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$Results;)V HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;)V HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$None;->()V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$None;->()V HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->()V HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;Lorg/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerRepositoryV2;Lorg/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository;Lorg/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel;)V HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;Lorg/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerRepositoryV2;Lorg/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository;Lorg/thoughtcrime/securesms/components/emoji/RecentEmojiPageModel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->getResults()Lio/reactivex/rxjava3/core/Observable; -HSPLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->getSelection()Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerRepositoryV2;->()V HSPLorg/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerRepositoryV2;->(Lorg/thoughtcrime/securesms/database/RecipientTable;)V HSPLorg/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerRepositoryV2;->(Lorg/thoughtcrime/securesms/database/RecipientTable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -21712,7 +21134,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity$stripeReposi HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->$r8$lambda$rJaCnn2xrQlJTPwnM83GXFMdMzE(Lorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->getVoiceNoteMediaController()Lorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->onCreate$lambda$0(Lorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->onCreate(Landroid/os/Bundle;Z)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->onPreCreate()V @@ -21747,158 +21168,50 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContrac HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts;->(Landroidx/fragment/app/Fragment;Lorg/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts$Callbacks;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda5;->createViewHolder(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda6;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda7;->createViewHolder(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->bindPayloadsIfAvailable()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->canPlayContent()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getBindable()Lorg/thoughtcrime/securesms/BindableConversationItem; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getColorizerProjections(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/ProjectionList; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getDisplayMode()Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getNextMessage()Lj$/util/Optional; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getPreviousMessage()Lj$/util/Optional; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->showProjectionArea()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder;->bind(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder;->bind(Lorg/thoughtcrime/securesms/conversation/v2/data/IncomingMedia;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$OnScrollStateChangedListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$bind$subtitle$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$bind$subtitle$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$bind$subtitle$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$bind$subtitle$2;->invoke(Ljava/lang/String;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->$r8$lambda$RwrnJe2SKX6YQ0B5PDojQRbXNOc(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->bind$lambda$1(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->bind(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->bind(Lorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->$r8$lambda$0GW66dll143qhTHiVUdlBHolclI(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->$r8$lambda$u2AJxgyeBquqI1nF9ok3s6g0b5Q(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/conversation/ConversationAdapter$ItemClickListener;ZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->_init_$lambda$4(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->_init_$lambda$6(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getColorizer$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Lorg/thoughtcrime/securesms/conversation/colors/Colorizer; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getCondensedMode$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getHasWallpaper$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getInlineContent$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Lorg/thoughtcrime/securesms/conversation/ConversationMessage; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getLifecycleOwner$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Landroidx/lifecycle/LifecycleOwner; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$get_selected$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Ljava/util/HashSet; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->consumePulseRequest()Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge$PulseRequest; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getClickListener()Lorg/thoughtcrime/securesms/conversation/ConversationAdapter$ItemClickListener; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getColorizer()Lorg/thoughtcrime/securesms/conversation/colors/Colorizer; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getConversationMessage(I)Lorg/thoughtcrime/securesms/conversation/ConversationMessage; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getDisplayMode()Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getGlideRequests()Lorg/thoughtcrime/securesms/mms/GlideRequests; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getNextMessage(I)Lorg/thoughtcrime/securesms/database/model/MessageRecord; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getPreviousMessage(I)Lorg/thoughtcrime/securesms/database/model/MessageRecord; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getSearchQuery()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->(Landroidx/lifecycle/LifecycleOwner;Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/conversation/ConversationAdapter$ItemClickListener;ZLorg/thoughtcrime/securesms/conversation/colors/Colorizer;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getSelectedItems()Ljava/util/Set; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->hasNoConversationMessages()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->hasWallpaper()Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->isMessageRequestAccepted()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->isParentInScroll()Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->onAttachedToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->onHasWallpaperChanged(Z)Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->setMessageRequestAccepted(Z)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->setMessageRequestIsAccepted(Z)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->setSearchQuery(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->updateSearchQuery(Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reminderStub$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reminderStub$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reminderStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reviewBannerStub$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reviewBannerStub$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reviewBannerStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$unverifiedBannerStub$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$unverifiedBannerStub$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$unverifiedBannerStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$voiceNotePlayerStub$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$voiceNotePlayerStub$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$voiceNotePlayerStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearReminder()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearRequestReview()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearUnverifiedBanner()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearVoiceNotePlayer()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getReminderStub()Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getReviewBannerStub()Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getUnverifiedBannerStub()Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getVoiceNotePlayerStub()Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->hide(Lorg/thoughtcrime/securesms/util/views/Stub;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->setListener(Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$Listener;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda11;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda12;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda13;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda14;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda15;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda16;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda17;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda18;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda8;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda11;->onLayoutChange(Landroid/view/View;IIIIIIII)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda24;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ActionModeCallback;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ActivityResultCallbacks;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$AttachmentKeyboardFragmentListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$AttachmentManagerListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$BackPressedDelegate;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ComposeTextEventsListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationBannerListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationItemClickListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback$onOptionsMenuCreated$1;->(Landroidx/appcompat/widget/SearchView;Landroidx/appcompat/widget/SearchView$OnQueryTextListener;Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroid/view/Menu;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback$onOptionsMenuCreated$queryListener$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback;->clearExpiring()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback;->getSnapshot()Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback;->onOptionsMenuCreated(Landroid/view/Menu;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DataObserver;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DisabledInputListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$InputPanelListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$InputPanelMediaListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$KeyboardEvents;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroidx/recyclerview/widget/LinearLayoutManager;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onResume(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$MotionEventRelayDrain;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollDateHeaderHelper;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollDateHeaderHelper;->bind(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1;->invoke(J)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->$r8$lambda$SqiWUifYWEV36mNfvnPsrkHWoAw(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->onScrolled$lambda$0(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->presentComposeDivider()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SearchEventListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SendButtonListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SwipeAvailabilityProvider;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ThreadHeaderMarginDecoration;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ThreadHeaderMarginDecoration;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ThreadHeaderMarginDecoration;->setToolbarMargin(I)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ToolbarDependentMarginListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroidx/appcompat/widget/Toolbar;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ToolbarDependentMarginListener;->onGlobalLayout()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$VoiceMessageRecordingSessionCallbacks;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$WhenMappings;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$args$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$args$2;->invoke()Ljava/lang/Object; @@ -21914,88 +21227,29 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$conversation HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$conversationRecipientRepository$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$conversationRecipientRepository$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$conversationRecipientRepository$2;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10;->invoke(Lj$/util/Optional;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$14;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16;->accept(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16;->accept(Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17;->invoke(I)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18;->invoke(Lj$/util/Optional;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$4;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$attachListener$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$conversationUpdateTick$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$draftViewModel$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$draftViewModel$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$draftViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$groupCallViewModel$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$groupCallViewModel$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$groupCallViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$1;->(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$2;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$3;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$4;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$4;->invoke()Ljava/lang/Boolean; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$4;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5;->invoke()Ljava/lang/Boolean; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5;->invoke()Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$3;->(Ljava/lang/Object;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$4;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5;->(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$6;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->invoke(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Ljava/lang/Boolean; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeInlineSearch$1$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeInlineSearch$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1;->invoke(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2;->invoke(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1;->invoke(Ljava/util/List;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$8;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$8;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$inlineQueryController$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$inlineQueryController$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$inlineQueryController$2;->invoke()Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$jumpAndPulseScrollStrategy$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2;->invoke(Landroidx/lifecycle/SavedStateHandle;)Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$messageRequestRepository$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$messageRequestRepository$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$messageRequestRepository$2;->invoke()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$messageRequestViewModel$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$motionEventRelay$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$motionEventRelay$2;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$motionEventRelay$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$moveToStartPosition$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$moveToStartPosition$1;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$moveToStartPosition$1;->invoke()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$1;->accept(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$1;->accept(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;)V @@ -22006,17 +21260,7 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConve HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$3;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$3;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$3;->apply(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;)Lio/reactivex/rxjava3/core/ObservableSource; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Ljava/util/List;Lkotlin/jvm/internal/Ref$BooleanRef;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$$ExternalSyntheticLambda0;->run()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1$1;->run()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1;->(Landroid/view/View;Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1;->onLayoutChange(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->$r8$lambda$oOR6vln5-HH0T67uKvvWOaEanvw(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Ljava/util/List;Lkotlin/jvm/internal/Ref$BooleanRef;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->(Lkotlin/jvm/internal/Ref$BooleanRef;Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->invoke$lambda$1(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Ljava/util/List;Lkotlin/jvm/internal/Ref$BooleanRef;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->invoke(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$$inlined$createActivityViewModel$1;->(Lkotlin/jvm/functions/Function0;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$$inlined$createActivityViewModel$1;->invoke()Landroidx/lifecycle/ViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$$inlined$createActivityViewModel$1;->invoke()Ljava/lang/Object; @@ -22028,27 +21272,16 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreate HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$2;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$conversationToolbarOnScrollHelper$1;->(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$conversationToolbarOnScrollHelper$1;->get()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentStoryRing$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentStoryRing$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentStoryRing$1;->invoke(Lorg/thoughtcrime/securesms/database/model/StoryViewState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentTypingIndicator$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentTypingIndicator$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$reactionDelegate$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$recentEmojis$2;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$recentEmojis$2;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$registerForResults$1;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$registerForResults$1;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0;->onChanged(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$scheduledMessagesStub$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$scheduledMessagesStub$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$scheduledMessagesStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$searchViewModel$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$searchViewModel$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$searchViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$1;->(Landroidx/fragment/app/Fragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$1;->invoke()Landroidx/lifecycle/ViewModelStore; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$1;->invoke()Ljava/lang/Object; @@ -22059,14 +21292,8 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inl HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$3;->invoke()Landroidx/lifecycle/ViewModelProvider$Factory; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$3;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$4;->(Landroidx/fragment/app/Fragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$4;->invoke()Landroidx/lifecycle/ViewModelStore; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$4;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$5;->(Lkotlin/jvm/functions/Function0;Landroidx/fragment/app/Fragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$5;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$5;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$6;->(Landroidx/fragment/app/Fragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$6;->invoke()Landroidx/lifecycle/ViewModelProvider$Factory; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$6;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$1;->(Landroidx/fragment/app/Fragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$1;->invoke()Landroidx/fragment/app/Fragment; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$1;->invoke()Ljava/lang/Object; @@ -22080,121 +21307,61 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inl HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$4;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$4;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$6;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$6;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$6;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$7;->(Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$7;->invoke()Landroidx/lifecycle/ViewModelStore; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$7;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$8;->(Lkotlin/jvm/functions/Function0;Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$8;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$8;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$9;->(Landroidx/fragment/app/Fragment;Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$9;->invoke()Landroidx/lifecycle/ViewModelProvider$Factory; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$9;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewModel$2;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewModel$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewModel$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$viewModel$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$viewModel$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$viewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$voiceNotePlayerListener$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->$r8$lambda$YDQLzyHN5FWBrQEkaTYrdZ0__OI(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroid/view/View;IIIIIIII)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$doAfterFirstRender(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getAdapter$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getAnimationsAllowed$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getArgs(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getBinding(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getColorizer$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/colors/Colorizer; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getComposeText(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/components/ComposeText; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getConversationItemDecorations$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getConversationRecipientRepository(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getGroupCallViewModel(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getInlineQueryViewModel$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getInputPanel(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/components/InputPanel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getLayoutManager$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Landroidx/recyclerview/widget/ConversationLayoutManager; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getMarkReadHelper$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/MarkReadHelper; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getMessageRequestRepository(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getScrollToPositionDelegate$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getSearchMenuItem$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Landroid/view/MenuItem; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getThreadHeaderMarginDecoration$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ThreadHeaderMarginDecoration; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getViewModel(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$handleScheduledMessagesCountChange(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;I)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$invalidateOptionsMenu(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$isScrolledToBottom(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$isSearchRequested$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$moveToStartPosition(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/ConversationData;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$onRecipientChanged(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentIdentityRecordsState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentInputReadyState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentRequestReviewState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentScrollButtons(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$setAnimationsAllowed$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Z)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$setSearchMenuItem$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroid/view/MenuItem;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$updateMessageRequestAcceptedState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Z)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$updateToggleButtonState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->doAfterFirstRender()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getArgs()Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getBinding()Lorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getComposeText()Lorg/thoughtcrime/securesms/components/ComposeText; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getContainer()Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getConversationGroupViewModel()Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getConversationRecipientRepository()Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getDraftViewModel()Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getGroupCallViewModel()Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getInlineQueryController()Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getInputPanel()Lorg/thoughtcrime/securesms/components/InputPanel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getKeyboardPagerViewModel()Lorg/thoughtcrime/securesms/keyboard/KeyboardPagerViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getLinkPreviewViewModel()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getMessageRequestRepository()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getMotionEventRelay()Lorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getScheduledMessagesStub()Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSearchNav()Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSearchViewModel()Lorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSendButton()Lorg/thoughtcrime/securesms/components/SendButton; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSendEditButton()Landroid/widget/ImageButton; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getShareDataTimestampViewModel()Lorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getStickerViewModel()Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getViewModel()Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getVoiceNoteMediaController()Lorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->handleScheduledMessagesCountChange(I)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeConversationThreadUi()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeGiphyMp4()Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeInlineSearch()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeLinkPreviews()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeMediaKeyboard()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeSearch()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeStickerSuggestions()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->invalidateOptionsMenu()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->isScrolledToBottom()Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->moveToStartPosition(Lorg/thoughtcrime/securesms/conversation/ConversationData;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->observeConversationThread()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onCreate(Landroid/os/Bundle;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onRecipientChanged(Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onResume()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onViewCreated$lambda$0(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroid/view/View;IIIIIIII)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onViewCreated(Landroid/view/View;Landroid/os/Bundle;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onViewStateRestored(Landroid/os/Bundle;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentActionBarMenu()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentChatColors(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentConversationTitle(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentGroupCallJoinButton()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentIdentityRecordsState(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentInputReadyState(Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentNavigationIconForNormal()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentRequestReviewState(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentScrollButtons(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentStoryRing()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentTypingIndicator()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentWallpaper(Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->registerForResults()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->updateMessageRequestAcceptedState(Z)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->updateToggleButtonState()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->bind(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->getHeight()I -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->getItemView()Landroid/view/View; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->updateForWallpaper()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState$None;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState$None;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState;->()V @@ -22203,19 +21370,9 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$Unrea HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->(ZZ)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->(ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->access$timestamp(Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)J -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->getHasWallpaper()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->getHeader(Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->getItemOffsets(Landroid/graphics/Rect;Landroid/view/View;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->hasHeader(I)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->isFirstUnread(I)Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->onDrawOver(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->setCurrentItems(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->setFirstUnreadCount(I)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->setHasWallpaper(Z)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->timestamp(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)J -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->toEpochDay(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)J -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->updateUnreadState(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository$conversationRecipient$2$$ExternalSyntheticLambda0;->(J)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository$conversationRecipient$2$$ExternalSyntheticLambda0;->call()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository$conversationRecipient$2$1;->()V @@ -22244,10 +21401,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;- HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;->getGroupRecord()Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda11;->(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda11;->call()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda14;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda14;->call()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda19;->(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda19;->call()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda7;->(JLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;I)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda7;->call()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$Companion;->()V @@ -22263,9 +21416,7 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$getMessage HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$getMessageCounts$2;->apply(I)Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$MessageCounts; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$getMessageCounts$2;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$98QfcuQyzMi7mf2qZrmWDK7X98k(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$KdCOHPNqejWN1AhOnsjSsYWIQ1E(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lj$/util/Optional; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$SEmY6z8BVO3vpDRoIUBmm8tqjes(JLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;I)Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$jYghkNuRsI_xLxRgZRxsCeMcFTc(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->(Landroid/content/Context;Z)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->access$getUnreadCount(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;J)I @@ -22275,10 +21426,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getConve HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getIdentityRecords$lambda$11(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getIdentityRecords(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lio/reactivex/rxjava3/core/Single; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getMessageCounts(J)Lio/reactivex/rxjava3/core/Flowable; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getReminder$lambda$10(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lj$/util/Optional; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getReminder(Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lio/reactivex/rxjava3/core/Maybe; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getRequestReviewState$lambda$15(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getRequestReviewState(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;)Lio/reactivex/rxjava3/core/Single; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getUnreadCount(J)I HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getUnreadMentionsCount(J)I HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->()V @@ -22286,10 +21433,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->< HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->(ZZZIZILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->copy$default(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;ZZZIZILjava/lang/Object;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->copy(ZZZIZ)Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->getHasMentions()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->getShowScrollButtons()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->getUnreadCount()I -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->toString()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;->(Lorg/signal/paging/ObservablePagedData;Lorg/thoughtcrime/securesms/conversation/ConversationData;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;->getItems()Lorg/signal/paging/ObservablePagedData; @@ -22314,91 +21457,89 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapte HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter$State;->(Ljava/util/List;ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter$State;->getTypists()Ljava/util/List; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter;->(Lorg/thoughtcrime/securesms/mms/GlideRequests;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter;->(Lcom/bumptech/glide/RequestManager;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter;->getItemCount()I -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->accept(Ljava/lang/Object;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10;->accept(Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11;->apply(Lkotlin/Unit;Lj$/util/Optional;)Lj$/util/Optional; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->apply(Lj$/util/Optional;)Lio/reactivex/rxjava3/core/MaybeSource; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->apply(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->apply(Lkotlin/Unit;Lorg/thoughtcrime/securesms/recipients/Recipient;Lj$/util/Optional;)Lkotlin/Pair; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->apply(Lkotlin/Pair;)Lio/reactivex/rxjava3/core/SingleSource; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15$1;->(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15$1;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->apply(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14;->apply(Lkotlin/Unit;Lorg/thoughtcrime/securesms/recipients/Recipient;Lj$/util/Optional;)Lkotlin/Pair; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15;->apply(Lkotlin/Pair;)Lio/reactivex/rxjava3/core/SingleSource; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16$1;->(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16$1;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$17;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$17;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$1;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda0;->(Lorg/signal/paging/PagingController;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda1;->(Lorg/signal/paging/PagingController;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda2;->(Lorg/signal/paging/PagingController;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda4;->subscribe(Lio/reactivex/rxjava3/core/ObservableEmitter;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->$r8$lambda$6vD-MGLKaMLR-d3fYoBu824GBvs(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;Lio/reactivex/rxjava3/core/ObservableEmitter;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData;Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData;)Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->apply$lambda$4(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;Lio/reactivex/rxjava3/core/ObservableEmitter;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->apply(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;)Lio/reactivex/rxjava3/core/ObservableSource; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->test(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->test(Lorg/thoughtcrime/securesms/recipients/Recipient;)Z +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda0;->subscribe(Lio/reactivex/rxjava3/core/ObservableEmitter;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda1;->(Lorg/signal/paging/PagingController;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda2;->(Lorg/signal/paging/PagingController;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda3;->(Lorg/signal/paging/PagingController;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->$r8$lambda$-cDP_eKfgHXjbVxKWQM3akAxvQw(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;Lio/reactivex/rxjava3/core/ObservableEmitter;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->apply$lambda$4(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;Lio/reactivex/rxjava3/core/ObservableEmitter;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->apply(Lorg/thoughtcrime/securesms/conversation/v2/ConversationThreadState;)Lio/reactivex/rxjava3/core/ObservableSource; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$MessageCounts;Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->(Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;Lj$/util/Optional;)Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9;->accept(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9;->accept(Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5;->test(Lorg/thoughtcrime/securesms/recipients/Recipient;)Z +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$MessageCounts;Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9;->(Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;Lj$/util/Optional;)Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$canShowAsBubble$1;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$canShowAsBubble$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$canShowAsBubble$1;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;)Ljava/lang/Boolean; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1;->apply(Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState;)Lio/reactivex/rxjava3/core/SingleSource; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$1;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$1;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$1;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$2;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$2;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$2;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$2;->apply(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;Landroid/graphics/Rect;)Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1;->test(Lj$/util/Optional;)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$2;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$2;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1;->(ZZ)V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$storyRingState$1;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$storyRingState$1;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$storyRingState$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$storyRingState$1;->apply(Lorg/thoughtcrime/securesms/recipients/Recipient;)Lio/reactivex/rxjava3/core/ObservableSource; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->(JILorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;Lorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->(JILorg/thoughtcrime/securesms/conversation/colors/ChatColors;Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;Lorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->access$getHasMessageRequestStateSubject$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)Lio/reactivex/rxjava3/subjects/BehaviorSubject; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->access$getIdentityRecordsStore$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)Lorg/thoughtcrime/securesms/util/rx/RxStore; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->access$getRepository$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository; @@ -22406,23 +21547,15 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->access$ge HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->access$setRecipientSnapshot$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->canShowAsBubble(Landroid/content/Context;)Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getConversationThreadState()Lio/reactivex/rxjava3/core/Single; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getGroupMemberServiceIds()Lio/reactivex/rxjava3/core/Observable; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getHasMessageRequestState()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getIdentityRecordsObservable()Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getInputReadyState()Lio/reactivex/rxjava3/core/Observable; +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getMessageRequestState()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getPagingController()Lorg/signal/paging/ProxyPagingController; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getRecipient()Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getRecipientSnapshot()Lorg/thoughtcrime/securesms/recipients/Recipient; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getReminder()Lio/reactivex/rxjava3/core/Observable; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getRequestReviewState()Lio/reactivex/rxjava3/core/Observable; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getScheduledMessagesCount()Lio/reactivex/rxjava3/core/Observable; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getScrollButtonState()Lio/reactivex/rxjava3/core/Flowable; -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getSearchQuery()Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getStoryRingState()Lio/reactivex/rxjava3/core/Observable; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getThreadId()J HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getWallpaperSnapshot()Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper; HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->isPushAvailable()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->setShowScrollButtonsForScrollPosition(ZZ)V +HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->onChatBoundsChanged(Landroid/graphics/Rect;)V HSPLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->updateIdentityRecordsInBackground()V HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView$inflater$2;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->()V @@ -22430,18 +21563,13 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->(Landro HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->clear()V -HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->setListener(Lorg/thoughtcrime/securesms/conversation/v2/DisabledInputView$Listener;)V HSPLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->setWallpaperEnabled(Z)V HSPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/GroupRecord;ZLorg/thoughtcrime/securesms/database/identity/IdentityRecordList;Z)V HSPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/database/model/GroupRecord;ZLorg/thoughtcrime/securesms/database/identity/IdentityRecordList;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->isGroup()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->isUnverified()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->isVerified()Z HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/database/model/GroupRecord;ZZ)V +HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/database/model/GroupRecord;ZZZ)V HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->getConversationRecipient()Lorg/thoughtcrime/securesms/recipients/Recipient; -HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->getGroupRecord()Lorg/thoughtcrime/securesms/database/model/GroupRecord; HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->getMessageRequestState()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->isActiveGroup()Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->isAnnouncementGroup()Ljava/lang/Boolean; @@ -22449,31 +21577,8 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->isClientExpired HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->isRequestingMember()Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->isUnauthorized()Z HSPLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->shouldShowInviteToSignal()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay;->setDrain(Lorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay$Drain;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$IndividualReviewState;Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$GroupReviewState;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$IndividualReviewState;Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$GroupReviewState;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->shouldShowReviewBanner()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel;->getTimestamp()J -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1;->(Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1;->apply(Ljava/lang/String;)Lio/reactivex/rxjava3/core/SingleSource; -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->access$getStickerSearchRepository$p(Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;)Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository; -HSPLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->getStickers()Lio/reactivex/rxjava3/core/Flowable; -HSPLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate;->(Landroidx/fragment/app/Fragment;Lorg/thoughtcrime/securesms/audio/AudioRecorder;Lorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$SessionCallback;)V HSPLorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate;->(ZZLjava/lang/String;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate;->getValue()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource$Companion;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource$threadRecipient$2;->(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource;)V @@ -22553,7 +21658,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/data/MessageDataFetcher;->updateM HSPLorg/thoughtcrime/securesms/conversation/v2/data/MessageDataFetcher;->updateWithData(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/conversation/v2/data/MessageDataFetcher$ExtraMessageData;)Lorg/thoughtcrime/securesms/database/model/MessageRecord; HSPLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->(Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->getRecipientInfo()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo; HSPLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeaderKey;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeaderKey;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->()V @@ -22561,7 +21665,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->(Lorg/thoughtcrime/securesms/recipients/RecipientId;ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->copy(Lorg/thoughtcrime/securesms/recipients/RecipientId;ZZZ)Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState; HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->getActiveV2Group()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->getHasCapacity()Z HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->getOngoingCall()Z HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->getRecipientId()Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel$1$1;->(Lorg/thoughtcrime/securesms/recipients/Recipient;)V @@ -22592,7 +21695,6 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewM HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;)V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->access$getStore$p(Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;)Lorg/thoughtcrime/securesms/util/rx/RxStore; HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->getHasOngoingGroupCallSnapshot()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->getState()Lio/reactivex/rxjava3/core/Flowable; HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->peekGroupCall()V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel$1;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel$1;->()V @@ -22619,161 +21721,18 @@ HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel;->(JLorg/thoughtcrime/securesms/groups/v2/GroupManagementRepository;Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;)V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel;->(JLorg/thoughtcrime/securesms/groups/v2/GroupManagementRepository;Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository;ILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel;->updateGroupStateIfNeeded()V +HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData;->(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;Landroid/graphics/drawable/Drawable;)V HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$1;->(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$1;->invoke(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration;->onDraw(Landroid/graphics/Canvas;Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$State;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion$$ExternalSyntheticLambda0;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion$$ExternalSyntheticLambda0;->onLayoutChange(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->$r8$lambda$-arOo52soPOPIS27YgHWzsDQIu8(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->applyBounds(Landroid/graphics/Rect;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->attach$lambda$0(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->attach(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion;->setGlobalChatColors(Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->access$getGlobalChatColors$cp()Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->access$getGlobalMask$cp()Landroid/graphics/drawable/Drawable; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->access$setGlobalChatColors$cp(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->access$setGlobalMask$cp(Landroid/graphics/drawable/Drawable;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->access$setLatestBounds$cp(Landroid/graphics/Rect;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->draw(Landroid/graphics/Canvas;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getChatColors()Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getMask()Landroid/graphics/drawable/Drawable; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getOpacity()I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getOutline(Landroid/graphics/Outline;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->isSolidColor()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->setCorners(Lorg/thoughtcrime/securesms/util/Projection$Corners;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->setCorners([F)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->setLocalChatColors(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V +HSPLorg/thoughtcrime/securesms/conversation/v2/items/ShrinkWrapLinearLayout;->()V +HSPLorg/thoughtcrime/securesms/conversation/v2/items/ShrinkWrapLinearLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->addOnMeasureListener(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnMeasureListener;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->onMeasure(II)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->removeOnMeasureListener(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnMeasureListener;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->setOnDispatchTouchEventListener(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnDispatchTouchEventListener;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->$values()[Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->(Ljava/lang/String;IFF)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->getBottomPadding()F -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->getTopPadding()F -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->isEndingShape()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->isStartingShape()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->access$getCollapsedSpacing$cp()F -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->access$getDefaultSpacing$cp()F -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->getCornersLTR()Lorg/thoughtcrime/securesms/util/Projection$Corners; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isEndOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isSingularMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isStartOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isWithinClusteringTime(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->setBodyBubbleCorners(FFFF)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->setMessageShape(Lorg/thoughtcrime/securesms/database/model/MessageRecord;ZI)Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lorg/thoughtcrime/securesms/components/AvatarImageView;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Landroid/view/ViewGroup;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lcom/google/android/material/imageview/ShapeableImageView;Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView;Lorg/thoughtcrime/securesms/components/DeliveryStatusView;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/ExpirationTimerView;Landroid/view/View;Landroid/widget/Space;Lorg/thoughtcrime/securesms/components/AlertView;Z)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getAlert()Lorg/thoughtcrime/securesms/components/AlertView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getBody()Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getBodyWrapper()Landroid/view/ViewGroup; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getDeliveryStatus()Lorg/thoughtcrime/securesms/components/DeliveryStatusView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterBackground()Landroid/view/View; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterDate()Landroid/widget/TextView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterExpiry()Lorg/thoughtcrime/securesms/components/ExpirationTimerView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterSpace()Landroid/widget/Space; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getReactions()Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getReply()Lcom/google/android/material/imageview/ShapeableImageView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getRoot()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getSenderBadge()Lorg/thoughtcrime/securesms/badges/BadgeImageView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getSenderName()Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getSenderPhoto()Lorg/thoughtcrime/securesms/components/AvatarImageView; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->isIncoming()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridgeKt;->bridge(Lorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;)Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda0;->onLayoutChange(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda4;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda6;->(Lorg/thoughtcrime/securesms/conversation/ConversationAdapter$ItemClickListener;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$PassthroughClickListener;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$ReactionMeasureListener;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$replyDelegate$1;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->$r8$lambda$ocilDMoff9b132TfYhzB6ol1qqk(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->_init_$lambda$0(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->bind(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->bind(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->canPlayContent()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->getColorizerProjections(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/ProjectionList; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->getConversationMessage()Lorg/thoughtcrime/securesms/conversation/ConversationMessage; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->getShape()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->invalidateBodyBubbleDrawable(Landroid/view/ViewGroup;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->invalidateChatColorsDrawable(Landroid/view/ViewGroup;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->invalidateFooterDrawable(Landroid/view/ViewGroup;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->isContentCondensed()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->isForcedFooter()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->linkifyMessageBody(Landroid/text/Spannable;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentAlert()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentBody()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentDate()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentDeliveryStatus()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentFooterBackground()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentFooterEndPadding()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentFooterExpiry()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentReactions()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentSender()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentSenderNameBackground()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentSenderNameColor()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->setConversationMessage(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->setShape(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->showProjectionArea()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$1;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2;->invoke(Landroid/content/Context;Z)Ljava/lang/Integer; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getBodyBubbleColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getBodyTextColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getFooterBubbleColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getReplyIconBackgroundColor()I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils;->linkifyUrlLinks(Landroid/text/Spannable;ZLorg/thoughtcrime/securesms/util/UrlClickHandler;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->getShapeDelegate()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->getThemeDelegate()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState;->$values()[Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState; -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState;->(Ljava/lang/String;I)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Ljava/util/List;Landroid/view/View;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Landroid/widget/Space;Lorg/thoughtcrime/securesms/util/views/Stub;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->displayTuckedIntoBody()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->getFooterWidth()I -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->onPostMeasure()Z -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->onPreMeasure()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$Companion;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener;->()V -HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;)V HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2Payload;->$values()[Lorg/thoughtcrime/securesms/conversation/v2/items/V2Payload; HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2Payload;->()V HSPLorg/thoughtcrime/securesms/conversation/v2/items/V2Payload;->(Ljava/lang/String;I)V @@ -22799,7 +21758,7 @@ HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$Payload; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$Payload;->(Ljava/lang/String;I)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$Payload;->values()[Lorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$Payload; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;->$r8$lambda$2QDH4q4xSHpazU1KhZ4uhNUhhdI(Lorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;Lorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$ConversationViewHolder;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;->(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/mms/GlideRequests;Lorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$OnConversationClickListener;Lorg/thoughtcrime/securesms/conversationlist/ClearFilterViewHolder$OnClearFilterClickListener;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;->(Landroidx/lifecycle/LifecycleOwner;Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$OnConversationClickListener;Lorg/thoughtcrime/securesms/conversationlist/ClearFilterViewHolder$OnClearFilterClickListener;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;->getItem(I)Lorg/thoughtcrime/securesms/conversationlist/model/Conversation; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;->getItemViewType(I)I HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter;->lambda$onCreateViewHolder$1(Lorg/thoughtcrime/securesms/conversationlist/ConversationListAdapter$ConversationViewHolder;Landroid/view/View;)V @@ -22953,12 +21912,12 @@ HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onCre HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onCreateView(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onFirstRender()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onMegaphoneChanged(Lorg/thoughtcrime/securesms/megaphone/Megaphone;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onMegaphoneCompleted(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onPause()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onPostSubmitList(I)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onPrepareOptionsMenu(Landroid/view/Menu;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onResume()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onStart()V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onStop()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onViewCreated(Landroid/view/View;Landroid/os/Bundle;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->requireCallback()Lorg/thoughtcrime/securesms/conversationlist/ConversationListFragment$Callback; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->setAdapter(Landroidx/recyclerview/widget/RecyclerView$Adapter;)V @@ -22966,25 +21925,25 @@ HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->updat HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->updateMultiSelectState()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->updateReminders()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->updateSearchToolbarHint(Lorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationFilterRequest;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda12;->(Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda12;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;Ljava/util/Locale;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda5;->run()V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;Ljava/util/Locale;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda10;->run()V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda13;->(Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda13;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda5;->onChanged(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda6;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda6;->onChanged(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda7;->onChanged(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->$r8$lambda$LAkoq7MeJO-fCezsfjX-mK5pWPo(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;Landroid/text/SpannableString;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->$r8$lambda$dlLpa5X9k6koT8N7PU2hVGd424s(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->$r8$lambda$k1MmUJ3xOtwOkC4HHJE6kKVtClw(Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem;Ljava/util/Locale;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->$r8$lambda$m6UBhFD1iIvqrclbuOW7C8gY-JM(Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Landroid/content/Context;Ljava/lang/CharSequence;)Landroid/text/SpannableString; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->bind(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lorg/thoughtcrime/securesms/mms/GlideRequests;Ljava/util/Locale;Ljava/util/Set;Lorg/thoughtcrime/securesms/conversationlist/model/ConversationSet;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->bindThread(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lorg/thoughtcrime/securesms/mms/GlideRequests;Ljava/util/Locale;Ljava/util/Set;Lorg/thoughtcrime/securesms/conversationlist/model/ConversationSet;Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->createFinalBodyWithMediaIcon(Landroid/content/Context;Ljava/lang/CharSequence;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lorg/thoughtcrime/securesms/mms/GlideRequests;ILorg/thoughtcrime/securesms/glide/GlideLiveDataTarget;)Landroidx/lifecycle/LiveData; -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->getThreadDisplayBody(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lorg/thoughtcrime/securesms/mms/GlideRequests;ILorg/thoughtcrime/securesms/glide/GlideLiveDataTarget;)Landroidx/lifecycle/LiveData; +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->bind(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lcom/bumptech/glide/RequestManager;Ljava/util/Locale;Ljava/util/Set;Lorg/thoughtcrime/securesms/conversationlist/model/ConversationSet;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->bindThread(Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lcom/bumptech/glide/RequestManager;Ljava/util/Locale;Ljava/util/Set;Lorg/thoughtcrime/securesms/conversationlist/model/ConversationSet;Ljava/lang/String;Z)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->createFinalBodyWithMediaIcon(Landroid/content/Context;Ljava/lang/CharSequence;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lcom/bumptech/glide/RequestManager;ILorg/thoughtcrime/securesms/glide/GlideLiveDataTarget;)Landroidx/lifecycle/LiveData; +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->getThreadDisplayBody(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Lcom/bumptech/glide/RequestManager;ILorg/thoughtcrime/securesms/glide/GlideLiveDataTarget;)Landroidx/lifecycle/LiveData; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->lambda$bindThread$1(Ljava/util/Locale;Lorg/thoughtcrime/securesms/database/model/ThreadRecord;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->lambda$getThreadDisplayBody$9(Lorg/thoughtcrime/securesms/database/model/ThreadRecord;Landroid/content/Context;Ljava/lang/CharSequence;)Landroid/text/SpannableString; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->observeDisplayBody(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/LiveData;)V @@ -23003,18 +21962,18 @@ HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItem;->whileLoad HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItemAnimator;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItemAnimator;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListItemAnimator;->disable()V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/mms/GlideRequests;)V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/mms/GlideRequests;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lcom/bumptech/glide/RequestManager;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lcom/bumptech/glide/RequestManager;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda4;->()V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/mms/GlideRequests;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lcom/bumptech/glide/RequestManager;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ChatFilterRepository;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ChatFilterRepository;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$Companion;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter;->()V -HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter;->(Landroid/content/Context;Ljava/util/Set;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$DisplayOptions;Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$LongClickCallbacks;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$StoryContextMenuCallbacks;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$CallButtonClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lorg/thoughtcrime/securesms/mms/GlideRequests;)V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter;->(Landroid/content/Context;Ljava/util/Set;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$DisplayOptions;Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$ConversationListSearchClickCallbacks;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$LongClickCallbacks;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$StoryContextMenuCallbacks;Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchAdapter$CallButtonClickCallbacks;Landroidx/lifecycle/LifecycleOwner;Lcom/bumptech/glide/RequestManager;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$$ExternalSyntheticLambda0;->onResult(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$1;->()V @@ -23071,6 +22030,10 @@ HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$megaph HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$megaphoneState$1;->()V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$megaphoneState$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$megaphoneState$1;->invoke(Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$ConversationListState;)Lorg/thoughtcrime/securesms/megaphone/Megaphone; +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onMegaphoneCompleted$1;->()V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onMegaphoneCompleted$1;->()V +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onMegaphoneCompleted$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onMegaphoneCompleted$1;->invoke(Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$ConversationListState;)Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$ConversationListState; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onVisible$1$1;->(Lorg/thoughtcrime/securesms/megaphone/Megaphone;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onVisible$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onVisible$1$1;->invoke(Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$ConversationListState;)Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$ConversationListState; @@ -23109,6 +22072,7 @@ HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->getN HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->getPinnedCount()I HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->getSelectedState()Lio/reactivex/rxjava3/core/Flowable; HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->getWebSocketState()Lio/reactivex/rxjava3/core/Observable; +HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->onMegaphoneCompleted(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->onMegaphoneVisible(Lorg/thoughtcrime/securesms/megaphone/Megaphone;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->onVisible$lambda$0(Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;Lorg/thoughtcrime/securesms/megaphone/Megaphone;)V HSPLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->onVisible()V @@ -23128,7 +22092,6 @@ HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilte HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->()V HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->access$getBinding$p(Lorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;)Lorg/thoughtcrime/securesms/databinding/ConversationListFilterPullViewBinding; -HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->onSaveInstanceState()Landroid/os/Parcelable; HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->onUserDrag(F)V HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->onUserDragFinished()V HSPLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->setOnCloseClicked(Lorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView$OnCloseClicked;)V @@ -23185,6 +22148,7 @@ HSPLorg/thoughtcrime/securesms/conversationlist/model/Conversation$Type;->(Ljava/lang/String;I)V HSPLorg/thoughtcrime/securesms/conversationlist/model/Conversation$Type;->values()[Lorg/thoughtcrime/securesms/conversationlist/model/Conversation$Type; HSPLorg/thoughtcrime/securesms/conversationlist/model/Conversation;->(Lorg/thoughtcrime/securesms/database/model/ThreadRecord;)V +HSPLorg/thoughtcrime/securesms/conversationlist/model/Conversation;->equals(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/conversationlist/model/Conversation;->getThreadRecord()Lorg/thoughtcrime/securesms/database/model/ThreadRecord; HSPLorg/thoughtcrime/securesms/conversationlist/model/Conversation;->getType()Lorg/thoughtcrime/securesms/conversationlist/model/Conversation$Type; HSPLorg/thoughtcrime/securesms/conversationlist/model/ConversationFilter;->$values()[Lorg/thoughtcrime/securesms/conversationlist/model/ConversationFilter; @@ -23273,12 +22237,15 @@ HSPLorg/thoughtcrime/securesms/crypto/ModernDecryptingPartInputStream;->readFull HSPLorg/thoughtcrime/securesms/crypto/ModernEncryptingPartOutputStream;->createFor(Lorg/thoughtcrime/securesms/crypto/AttachmentSecret;Ljava/io/File;Z)Landroid/util/Pair; HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->()V HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->generateKyberPreKey(ILorg/signal/libsignal/protocol/ecc/ECPrivateKey;)Lorg/signal/libsignal/protocol/state/KyberPreKeyRecord; -HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->generateLastRestortKyberPreKey(ILorg/signal/libsignal/protocol/ecc/ECPrivateKey;)Lorg/signal/libsignal/protocol/state/KyberPreKeyRecord; +HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->generateLastResortKyberPreKey(ILorg/signal/libsignal/protocol/ecc/ECPrivateKey;)Lorg/signal/libsignal/protocol/state/KyberPreKeyRecord; HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->generateSignedPreKey(ILorg/signal/libsignal/protocol/ecc/ECPrivateKey;)Lorg/signal/libsignal/protocol/state/SignedPreKeyRecord; HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->storeLastResortKyberPreKey(Lorg/whispersystems/signalservice/api/SignalServiceAccountDataStore;Lorg/thoughtcrime/securesms/crypto/storage/PreKeyMetadataStore;Lorg/signal/libsignal/protocol/state/KyberPreKeyRecord;)V HSPLorg/thoughtcrime/securesms/crypto/PreKeyUtil;->storeSignedPreKey(Lorg/signal/libsignal/protocol/state/SignalProtocolStore;Lorg/thoughtcrime/securesms/crypto/storage/PreKeyMetadataStore;Lorg/signal/libsignal/protocol/state/SignedPreKeyRecord;)V HSPLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->()V HSPLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->createNew()Lorg/signal/libsignal/zkgroup/profiles/ProfileKey; +HSPLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->getSelfProfileKey()Lorg/signal/libsignal/zkgroup/profiles/ProfileKey; +HSPLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->profileKeyOptional([B)Lj$/util/Optional; +HSPLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->profileKeyOrNull([B)Lorg/signal/libsignal/zkgroup/profiles/ProfileKey; HSPLorg/thoughtcrime/securesms/crypto/ReentrantSessionLock$$ExternalSyntheticLambda0;->(Ljava/util/concurrent/locks/ReentrantLock;)V HSPLorg/thoughtcrime/securesms/crypto/ReentrantSessionLock$$ExternalSyntheticLambda0;->close()V HSPLorg/thoughtcrime/securesms/crypto/ReentrantSessionLock;->$values()[Lorg/thoughtcrime/securesms/crypto/ReentrantSessionLock; @@ -23317,7 +22284,7 @@ HSPLorg/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore;->saveIdent HSPLorg/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore;->saveIdentityWithoutSideEffects(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/whispersystems/signalservice/api/push/ServiceId;Lorg/signal/libsignal/protocol/IdentityKey;Lorg/thoughtcrime/securesms/database/IdentityTable$VerifiedStatus;ZJZ)V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalKyberPreKeyStore;->()V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalKyberPreKeyStore;->(Lorg/whispersystems/signalservice/api/push/ServiceId;)V -HSPLorg/thoughtcrime/securesms/crypto/storage/SignalKyberPreKeyStore;->storeKyberPreKey(ILorg/signal/libsignal/protocol/state/KyberPreKeyRecord;)V +HSPLorg/thoughtcrime/securesms/crypto/storage/SignalKyberPreKeyStore;->storeLastResortKyberPreKey(ILorg/signal/libsignal/protocol/state/KyberPreKeyRecord;)V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore;->deleteAll()V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/crypto/storage/TextSecurePreKeyStore;Lorg/thoughtcrime/securesms/crypto/storage/SignalKyberPreKeyStore;Lorg/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore;Lorg/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore;Lorg/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore;)V @@ -23326,7 +22293,7 @@ HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl; HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->saveIdentity(Lorg/signal/libsignal/protocol/SignalProtocolAddress;Lorg/signal/libsignal/protocol/IdentityKey;)Z HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->senderKeys()Lorg/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore; HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->sessions()Lorg/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore; -HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->storeKyberPreKey(ILorg/signal/libsignal/protocol/state/KyberPreKeyRecord;)V +HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->storeLastResortKyberPreKey(ILorg/signal/libsignal/protocol/state/KyberPreKeyRecord;)V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;->storeSignedPreKey(ILorg/signal/libsignal/protocol/state/SignedPreKeyRecord;)V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceDataStoreImpl;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;Lorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl;)V HSPLorg/thoughtcrime/securesms/crypto/storage/SignalServiceDataStoreImpl;->aci()Lorg/thoughtcrime/securesms/crypto/storage/SignalServiceAccountDataStoreImpl; @@ -23349,12 +22316,13 @@ HSPLorg/thoughtcrime/securesms/database/AttachmentTable$TransformProperties;->access$getDEFAULT_MEDIA_QUALITY$cp()I HSPLorg/thoughtcrime/securesms/database/AttachmentTable$insertAttachment$attachmentId$1;->(Lorg/thoughtcrime/securesms/attachments/Attachment;Lorg/thoughtcrime/securesms/database/AttachmentTable;JZLkotlin/jvm/internal/Ref$BooleanRef;)V HSPLorg/thoughtcrime/securesms/database/AttachmentTable$insertAttachment$attachmentId$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/database/AttachmentTable$insertAttachment$attachmentId$1;->invoke(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;)Lorg/thoughtcrime/securesms/attachments/AttachmentId; HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->()V HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;Lorg/thoughtcrime/securesms/crypto/AttachmentSecret;)V HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->access$getVisualHashStringOrNull(Lorg/thoughtcrime/securesms/database/AttachmentTable;Lorg/thoughtcrime/securesms/attachments/Attachment;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->containsStickerPackId(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->deleteAbandonedPreuploadedAttachments()I HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->getAttachment(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment; +HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->getAttachment(Lorg/thoughtcrime/securesms/attachments/AttachmentId;)Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment; HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->getAttachments(Landroid/database/Cursor;)Ljava/util/List; HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->getAttachmentsForMessage(J)Ljava/util/List; HSPLorg/thoughtcrime/securesms/database/AttachmentTable;->getAttachmentsForMessages(Ljava/util/Collection;)Ljava/util/Map; @@ -23382,10 +22350,20 @@ HSPLorg/thoughtcrime/securesms/database/CallTable$Event;->$values()[Lorg/thought HSPLorg/thoughtcrime/securesms/database/CallTable$Event;->()V HSPLorg/thoughtcrime/securesms/database/CallTable$Event;->(Ljava/lang/String;II)V HSPLorg/thoughtcrime/securesms/database/CallTable$Event;->access$getCode$p(Lorg/thoughtcrime/securesms/database/CallTable$Event;)I +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState$Serializer;->()V +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState$Serializer;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState$Serializer;->serialize(Lorg/thoughtcrime/securesms/database/CallTable$ReadState;)Ljava/lang/Integer; +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState;->$values()[Lorg/thoughtcrime/securesms/database/CallTable$ReadState; +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState;->()V +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState;->(Ljava/lang/String;II)V +HSPLorg/thoughtcrime/securesms/database/CallTable$ReadState;->access$getCode$p(Lorg/thoughtcrime/securesms/database/CallTable$ReadState;)I HSPLorg/thoughtcrime/securesms/database/CallTable;->()V HSPLorg/thoughtcrime/securesms/database/CallTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;)V HSPLorg/thoughtcrime/securesms/database/CallTable;->getCalls(Ljava/util/Collection;)Ljava/util/Map; +HSPLorg/thoughtcrime/securesms/database/CallTable;->getLatestRingingCalls()Ljava/util/List; HSPLorg/thoughtcrime/securesms/database/CallTable;->getOldestDeletionTimestamp()J +HSPLorg/thoughtcrime/securesms/database/CallTable;->getUnreadMissedCallCount()J +HSPLorg/thoughtcrime/securesms/database/CallTable;->markRingingCallsAsMissed()V HSPLorg/thoughtcrime/securesms/database/CdsTable$Companion;->()V HSPLorg/thoughtcrime/securesms/database/CdsTable$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/CdsTable;->()V @@ -23404,7 +22382,6 @@ HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambd HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda10;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda11;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda11;->run()V -HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda13;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda17;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda17;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda20;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V @@ -23419,21 +22396,30 @@ HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambd HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda29;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda30;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda30;->run()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda32;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda32;->run()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda36;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda36;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda37;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda37;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda40;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda40;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda4;->run()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/recipients/RecipientId;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda5;->run()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$6mdIgDDCV4XFVFnyxH8Vj4a6MqU(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$Aq7iz6-OcN5qdEpvMz8WyoOoHtc(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$FLqOSncPM9UHAHmQfH7ITyYgYis(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$P-H8JPj8WgBa8EorlTkjTC0yG1E(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$Q9T3e0x03-9UyovUEacfv32ZkYs(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$XcpL0fyOGdTr1sc4d0z4i8eoe14(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$XpAe1b_YlxfSEkV3hD_v20iDkHw(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$dh6RWMfCAixhY74q-duAcBwIwmU(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$mv9tymw4eNQuLtAMo52Pot0i2c4(Lorg/thoughtcrime/securesms/database/DatabaseObserver;J)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$nM9Xevlg3i5jd4hhWqCSJ8V0APs(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$oXFDlhvhHFY1OBIQHYp3Oanmq-k(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$v9-I7k7VKIptUuQHIpRZcaVjlwY(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$wnm9BEANNc03FZmWKcqOLSgrT_U(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$wtkgxGON7fTcqqEso3BleXuYIA8(Lorg/thoughtcrime/securesms/database/DatabaseObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$zacSulZCbj18KAJ4fsL5guxghT4(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V @@ -23442,6 +22428,9 @@ HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyAttachme HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyConversationListListeners$22()V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyConversationListeners$19(J)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyRecipientChanged$34(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyStickerObservers$26()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyStickerPackObservers$27()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyStoryObservers$35(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$registerConversationListObserver$0(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$registerConversationObserver$1(JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$registerMessageInsertObserver$11(JLorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V @@ -23456,13 +22445,15 @@ HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyConversationLis HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyMapped(Ljava/util/Map;Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyRecipientChanged(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifySet(Ljava/util/Set;)V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyStickerObservers()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyStickerPackObservers()V +HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyStoryObservers(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerConversationListObserver(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerConversationObserver(JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerMapped(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerMessageInsertObserver(JLorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerMessageUpdateObserver(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerNotificationProfileObserver(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V -HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerScheduledMessageObserver(JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerStoryObserver(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerVerboseConversationObserver(JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V HSPLorg/thoughtcrime/securesms/database/DatabaseObserver;->runPostSuccessfulTransaction(Ljava/lang/String;Ljava/lang/Runnable;)V @@ -23473,6 +22464,8 @@ HSPLorg/thoughtcrime/securesms/database/DatabaseTable;->getWritableDatabase()Lor HSPLorg/thoughtcrime/securesms/database/DatabaseTable;->notifyAttachmentListeners()V HSPLorg/thoughtcrime/securesms/database/DatabaseTable;->notifyConversationListListeners()V HSPLorg/thoughtcrime/securesms/database/DatabaseTable;->notifyConversationListeners(J)V +HSPLorg/thoughtcrime/securesms/database/DatabaseTable;->notifyStickerListeners()V +HSPLorg/thoughtcrime/securesms/database/DatabaseTable;->notifyStickerPackListeners()V HSPLorg/thoughtcrime/securesms/database/DistributionListTables$Companion;->()V HSPLorg/thoughtcrime/securesms/database/DistributionListTables$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/DistributionListTables$ListTable;->()V @@ -23491,7 +22484,6 @@ HSPLorg/thoughtcrime/securesms/database/DraftTable$Companion;->()V HSPLorg/thoughtcrime/securesms/database/DraftTable$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->()V HSPLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->(Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->getDraftOfType(Ljava/lang/String;)Lorg/thoughtcrime/securesms/database/DraftTable$Draft; HSPLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->getSize()I HSPLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->size()I HSPLorg/thoughtcrime/securesms/database/DraftTable;->()V @@ -23562,6 +22554,9 @@ HSPLorg/thoughtcrime/securesms/database/JobDatabase$deleteJobs$1;->invoke(Lnet/z HSPLorg/thoughtcrime/securesms/database/JobDatabase$insertJobs$2;->(Ljava/util/List;Lorg/thoughtcrime/securesms/database/JobDatabase;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase$insertJobs$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/database/JobDatabase$insertJobs$2;->invoke(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;)V +HSPLorg/thoughtcrime/securesms/database/JobDatabase$updateJobs$2;->(Ljava/util/List;)V +HSPLorg/thoughtcrime/securesms/database/JobDatabase$updateJobs$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/database/JobDatabase$updateJobs$2;->invoke(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->$r8$lambda$ou_p531IVGikC2LNueT6qnVrWyc(Lorg/thoughtcrime/securesms/database/JobDatabase;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->()V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->(Landroid/app/Application;Lorg/thoughtcrime/securesms/crypto/DatabaseSecret;)V @@ -23570,6 +22565,7 @@ HSPLorg/thoughtcrime/securesms/database/JobDatabase;->access$insertConstraintSpe HSPLorg/thoughtcrime/securesms/database/JobDatabase;->access$insertDependencySpecs(Lorg/thoughtcrime/securesms/database/JobDatabase;Lnet/zetetic/database/sqlcipher/SQLiteDatabase;Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->access$insertJobSpec(Lorg/thoughtcrime/securesms/database/JobDatabase;Lnet/zetetic/database/sqlcipher/SQLiteDatabase;Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->access$setInstance$cp(Lorg/thoughtcrime/securesms/database/JobDatabase;)V +HSPLorg/thoughtcrime/securesms/database/JobDatabase;->constraintSpecFromCursor(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec; HSPLorg/thoughtcrime/securesms/database/JobDatabase;->deleteJobs(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->dropTableIfPresent(Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->getAllConstraintSpecs()Ljava/util/List; @@ -23580,10 +22576,13 @@ HSPLorg/thoughtcrime/securesms/database/JobDatabase;->insertConstraintSpecs(Lnet HSPLorg/thoughtcrime/securesms/database/JobDatabase;->insertDependencySpecs(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->insertJobSpec(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->insertJobs(Ljava/util/List;)V +HSPLorg/thoughtcrime/securesms/database/JobDatabase;->jobSpecFromCursor(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec; HSPLorg/thoughtcrime/securesms/database/JobDatabase;->markJobAsRunning(Ljava/lang/String;J)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->onOpen$lambda$0(Lorg/thoughtcrime/securesms/database/JobDatabase;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->onOpen(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;)V HSPLorg/thoughtcrime/securesms/database/JobDatabase;->updateAllJobsToBePending()V +HSPLorg/thoughtcrime/securesms/database/JobDatabase;->updateJobAfterRetry(Ljava/lang/String;JIJ[B)V +HSPLorg/thoughtcrime/securesms/database/JobDatabase;->updateJobs(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/database/KeyValueDatabase$$ExternalSyntheticLambda0;->()V HSPLorg/thoughtcrime/securesms/database/KeyValueDatabase$$ExternalSyntheticLambda0;->run()V HSPLorg/thoughtcrime/securesms/database/KeyValueDatabase$1;->()V @@ -23606,6 +22605,7 @@ HSPLorg/thoughtcrime/securesms/database/KyberPreKeyTable$Companion;->(Lkot HSPLorg/thoughtcrime/securesms/database/KyberPreKeyTable;->()V HSPLorg/thoughtcrime/securesms/database/KyberPreKeyTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;)V HSPLorg/thoughtcrime/securesms/database/KyberPreKeyTable;->insert(Lorg/whispersystems/signalservice/api/push/ServiceId;ILorg/signal/libsignal/protocol/state/KyberPreKeyRecord;Z)V +HSPLorg/thoughtcrime/securesms/database/KyberPreKeyTable;->toAccountId(Lorg/whispersystems/signalservice/api/push/ServiceId;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/LocalMetricsDatabase$Companion;->()V HSPLorg/thoughtcrime/securesms/database/LocalMetricsDatabase$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/LocalMetricsDatabase$Companion;->getInstance(Landroid/app/Application;)Lorg/thoughtcrime/securesms/database/LocalMetricsDatabase; @@ -23739,7 +22739,7 @@ HSPLorg/thoughtcrime/securesms/database/MessageTable$Companion;->parseQuoteMenti HSPLorg/thoughtcrime/securesms/database/MessageTable$ExpirationInfo;->()V HSPLorg/thoughtcrime/securesms/database/MessageTable$ExpirationInfo;->(JJJZ)V HSPLorg/thoughtcrime/securesms/database/MessageTable$InsertResult;->()V -HSPLorg/thoughtcrime/securesms/database/MessageTable$InsertResult;->(JJLjava/util/Map;)V +HSPLorg/thoughtcrime/securesms/database/MessageTable$InsertResult;->(JJZLjava/util/Map;)V HSPLorg/thoughtcrime/securesms/database/MessageTable$InsertResult;->getMessageId()J HSPLorg/thoughtcrime/securesms/database/MessageTable$MarkedMessageInfo;->()V HSPLorg/thoughtcrime/securesms/database/MessageTable$MarkedMessageInfo;->(JLorg/thoughtcrime/securesms/database/MessageTable$SyncMessageId;Lorg/thoughtcrime/securesms/database/model/MessageId;Lorg/thoughtcrime/securesms/database/MessageTable$ExpirationInfo;Lorg/thoughtcrime/securesms/database/model/StoryType;)V @@ -23787,6 +22787,7 @@ HSPLorg/thoughtcrime/securesms/database/MessageTable;->access$getSerializedLinkP HSPLorg/thoughtcrime/securesms/database/MessageTable;->access$getSerializedSharedContacts(Lorg/thoughtcrime/securesms/database/MessageTable;Ljava/util/Map;Ljava/util/List;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/MessageTable;->buildMeaningfulMessagesQuery(J)Lorg/signal/core/util/SqlUtil$Query; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getAllRateLimitedMessageIds()Ljava/util/Set; +HSPLorg/thoughtcrime/securesms/database/MessageTable;->getAllStoriesFor(Lorg/thoughtcrime/securesms/recipients/RecipientId;I)Lorg/thoughtcrime/securesms/database/MessageTable$Reader; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getConversation(JJJ)Landroid/database/Cursor; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getConversationSnippet(J)Lorg/thoughtcrime/securesms/database/model/MessageRecord; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getConversationSnippetCursor(J)Landroid/database/Cursor; @@ -23797,7 +22798,6 @@ HSPLorg/thoughtcrime/securesms/database/MessageTable;->getNearestExpiringViewOnc HSPLorg/thoughtcrime/securesms/database/MessageTable;->getOldestScheduledSendTimestamp()Lorg/thoughtcrime/securesms/database/model/MessageRecord; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getOldestStorySendTimestamp(Z)Ljava/lang/Long; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getReleaseChannelThreadId(Z)J -HSPLorg/thoughtcrime/securesms/database/MessageTable;->getScheduledMessageCountForThread(J)I HSPLorg/thoughtcrime/securesms/database/MessageTable;->getSerializedLinkPreviews(Ljava/util/Map;Ljava/util/List;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getSerializedSharedContacts(Ljava/util/Map;Ljava/util/List;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/MessageTable;->getStoryViewState(J)Lorg/thoughtcrime/securesms/database/model/StoryViewState; @@ -23805,7 +22805,6 @@ HSPLorg/thoughtcrime/securesms/database/MessageTable;->getStoryViewState(Lorg/th HSPLorg/thoughtcrime/securesms/database/MessageTable;->getThreadIdForMessage(J)J HSPLorg/thoughtcrime/securesms/database/MessageTable;->getUnreadCount(J)I HSPLorg/thoughtcrime/securesms/database/MessageTable;->getUnreadMentionCount(J)I -HSPLorg/thoughtcrime/securesms/database/MessageTable;->getUnreadMisedCallCount()J HSPLorg/thoughtcrime/securesms/database/MessageTable;->getUnreadStoryThreadRecipientIds()Ljava/util/List; HSPLorg/thoughtcrime/securesms/database/MessageTable;->hasFailedOutgoingStory()Z HSPLorg/thoughtcrime/securesms/database/MessageTable;->hasMeaningfulMessage(J)Z @@ -23828,7 +22827,6 @@ HSPLorg/thoughtcrime/securesms/database/MessageType;->values()[Lorg/thoughtcrime HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->()V HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isBadDecryptType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isBoostRequest(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isBundleKeyExchange(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isCallLog(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isChangeNumber(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isChatSessionRefresh(J)Z @@ -23836,7 +22834,6 @@ HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isDraftMessageType(J) HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isDuplicateMessageType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isEndSessionType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isExpirationTimerUpdate(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isFailedMessageType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isForcedSms(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isGiftBadge(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isGroupCall(J)Z @@ -23852,6 +22849,7 @@ HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isIncomingVideoCall(J HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isJoinedType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isKeyExchangeType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isLegacyType(J)Z +HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isMessageRequestAccepted(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isMissedAudioCall(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isMissedVideoCall(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isNoRemoteSessionType(J)Z @@ -23861,13 +22859,9 @@ HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isOutgoingVideoCall(J HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPaymentsActivated(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPaymentsNotification(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPaymentsRequestToActivate(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPendingInsecureSmsFallbackType(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPendingMessageType(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPendingSecureSmsFallbackType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isProfileChange(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPushType(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isRateLimited(J)Z -HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isSecureType(J)Z +HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isReportedSpam(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isSessionSwitchoverType(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isSmsExport(J)Z HSPLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isStoryReaction(J)Z @@ -23951,6 +22945,8 @@ HSPLorg/thoughtcrime/securesms/database/RecipientTable$$ExternalSyntheticLambda1 HSPLorg/thoughtcrime/securesms/database/RecipientTable$Companion;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTable$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable$Companion;->maskCapabilitiesToLong(Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;)J +HSPLorg/thoughtcrime/securesms/database/RecipientTable$GetOrInsertResult;->(Lorg/thoughtcrime/securesms/recipients/RecipientId;Z)V +HSPLorg/thoughtcrime/securesms/database/RecipientTable$GetOrInsertResult;->getRecipientId()Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting$Companion;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting$Companion;->fromId(I)Lorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting; @@ -23959,6 +22955,12 @@ HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;-> HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;->(Ljava/lang/String;II)V HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;->getId()I HSPLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;->values()[Lorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting; +HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState$Companion;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState;->$values()[Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState; +HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState;->(Ljava/lang/String;II)V +HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState;->getId()I HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState$Companion;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState$Companion;->fromId(I)Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState; @@ -24021,7 +23023,7 @@ HSPLorg/thoughtcrime/securesms/database/RecipientTable$getAndPossiblyMerge$3;->i HSPLorg/thoughtcrime/securesms/database/RecipientTable;->$r8$lambda$aWzIz5YHb9jNapMRCuQVry5PhmE()V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;)V -HSPLorg/thoughtcrime/securesms/database/RecipientTable;->buildContentValuesForNewUser(Ljava/lang/String;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;)Landroid/content/ContentValues; +HSPLorg/thoughtcrime/securesms/database/RecipientTable;->buildContentValuesForNewUser(Ljava/lang/String;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Z)Landroid/content/ContentValues; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getAndPossiblyMerge$default(Lorg/thoughtcrime/securesms/database/RecipientTable;Lorg/whispersystems/signalservice/api/push/ServiceId;Ljava/lang/String;ZILjava/lang/Object;)Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getAndPossiblyMerge(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Ljava/lang/String;ZZ)Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getAndPossiblyMerge(Lorg/whispersystems/signalservice/api/push/ServiceId;Ljava/lang/String;)Lorg/thoughtcrime/securesms/recipients/RecipientId; @@ -24036,6 +23038,7 @@ HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getRecipientIdIfAllFiel HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getRecipientsWithNotificationChannels()Lorg/thoughtcrime/securesms/database/RecipientTable$RecipientReader; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getRecord(Lorg/thoughtcrime/securesms/recipients/RecipientId;)Lorg/thoughtcrime/securesms/database/model/RecipientRecord; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->getTAG()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/database/RecipientTable;->insertReleaseChannelRecipient()Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->linkIdsForSelf(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->markNeedsSync(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->markRegistered(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/whispersystems/signalservice/api/push/ServiceId;)Z @@ -24044,6 +23047,8 @@ HSPLorg/thoughtcrime/securesms/database/RecipientTable;->processPnpTuple(Ljava/l HSPLorg/thoughtcrime/securesms/database/RecipientTable;->processPnpTupleToChangeSet(Ljava/lang/String;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;ZZ)Lorg/thoughtcrime/securesms/database/PnpChangeSet; HSPLorg/thoughtcrime/securesms/database/RecipientTable;->rotateStorageId(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setCapabilities(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;)V +HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setMuted(Lorg/thoughtcrime/securesms/recipients/RecipientId;J)V +HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setProfileAvatar(Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setProfileKey$lambda$58()V HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setProfileKey(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/signal/libsignal/zkgroup/profiles/ProfileKey;)Z HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setProfileKeyIfAbsent(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/signal/libsignal/zkgroup/profiles/ProfileKey;)Z @@ -24052,32 +23057,33 @@ HSPLorg/thoughtcrime/securesms/database/RecipientTable;->setProfileSharing(Lorg/ HSPLorg/thoughtcrime/securesms/database/RecipientTable;->update(Lorg/signal/core/util/SqlUtil$Query;Landroid/content/ContentValues;)Z HSPLorg/thoughtcrime/securesms/database/RecipientTable;->update(Lorg/thoughtcrime/securesms/recipients/RecipientId;Landroid/content/ContentValues;)Z HSPLorg/thoughtcrime/securesms/database/RecipientTable;->updatePendingSelfData(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V -HSPLorg/thoughtcrime/securesms/database/RecipientTable;->writePnpChangeSetToDisk(Lorg/thoughtcrime/securesms/database/PnpChangeSet;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;)Lorg/thoughtcrime/securesms/recipients/RecipientId; +HSPLorg/thoughtcrime/securesms/database/RecipientTable;->writePnpChangeSetToDisk(Lorg/thoughtcrime/securesms/database/PnpChangeSet;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Z)Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;)V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda1;->(Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda2;->(Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda3;->(Lkotlin/jvm/functions/Function1;)V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda3;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda4;->(Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getRecipientExtras$1;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getRecipientExtras$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$forcedUnread$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$forcedUnread$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$forcedUnread$1;->invoke(I)Ljava/lang/Boolean; -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$forcedUnread$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$groupMasterKey$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$groupMasterKey$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$identityKey$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$identityKey$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$identityStatus$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$identityStatus$1;->()V -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->$r8$lambda$3gC4IvWj9S7nLeLK-eONY0kYlPA(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/Boolean; +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$2;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$2;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$3;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$3;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$4;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$4;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$5;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$5;->()V +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$5;->invoke(I)Ljava/lang/Boolean; +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$5;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->$r8$lambda$SZDnYaDAB9DrkxazGttwF3vWx5o(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->()V HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->getExtras(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/recipients/Recipient$Extras; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->getRecipientExtras(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/database/model/databaseprotos/RecipientExtras; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->getRecord(Landroid/content/Context;Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/database/model/RecipientRecord; -HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->getSyncExtras$lambda$2(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/Boolean; +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->getSyncExtras$lambda$6(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/Boolean; +HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->getSyncExtras(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/database/model/RecipientRecord$SyncExtras; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->parseBadgeList([B)Ljava/util/List; HSPLorg/thoughtcrime/securesms/database/RecipientTableCursorUtil;->readCapabilities(Landroid/database/Cursor;)Lorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities; HSPLorg/thoughtcrime/securesms/database/RemappedRecordTables$Companion;->()V @@ -24093,6 +23099,7 @@ HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$$ExternalSyntheticLam HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$$ExternalSyntheticLambda0;->subscribe(Lio/reactivex/rxjava3/core/FlowableEmitter;)V HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;)V HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;->(Lio/reactivex/rxjava3/core/Emitter;)V +HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;->onChanged()V HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;->prime()V HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$conversation$1;->(J)V HSPLorg/thoughtcrime/securesms/database/RxDatabaseObserver$conversation$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; @@ -24182,10 +23189,8 @@ HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->-$$Nest$mgetPendingPost HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->-$$Nest$mgetPostSuccessfulTransactionTasks(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;)Ljava/util/Set; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->()V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->(Lnet/zetetic/database/sqlcipher/SQLiteDatabase;)V -HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->beginTransaction()V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->delete(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)I HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->delete(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)I -HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->endTransaction()V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->execSQL(Ljava/lang/String;[Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->getPendingPostSuccessfulTransactionTasks()Ljava/util/Set; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->getPostSuccessfulTransactionTasks()Ljava/util/Set; @@ -24195,7 +23200,6 @@ HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->insertWithOnConflict(Lj HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$beginTransaction$0()V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$delete$14(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/Integer; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$execSQL$19(Ljava/lang/String;[Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$insert$9(Ljava/lang/String;Ljava/lang/String;Landroid/content/ContentValues;)Ljava/lang/Long; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$insertWithOnConflict$13(Ljava/lang/String;Ljava/lang/String;Landroid/content/ContentValues;I)Ljava/lang/Long; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$query$3(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->lambda$query$4(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; @@ -24214,9 +23218,7 @@ HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->replace(Ljava/lang/Stri HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->runPostSuccessfulTransaction(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->runPostSuccessfulTransaction(Ljava/lang/String;Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->setTransactionSuccessful()V -HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->trace(Ljava/lang/String;Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->traceLockEnd()V -HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->traceLockStart()V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->traceSql(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLorg/thoughtcrime/securesms/database/SQLiteDatabase$Returnable;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->traceSql(Ljava/lang/String;Ljava/lang/String;ZLjava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/database/SQLiteDatabase;->traceSql(Ljava/lang/String;Ljava/lang/String;ZLorg/thoughtcrime/securesms/database/SQLiteDatabase$Returnable;)Ljava/lang/Object; @@ -24336,6 +23338,7 @@ HSPLorg/thoughtcrime/securesms/database/SignedPreKeyTable$Companion;->(Lko HSPLorg/thoughtcrime/securesms/database/SignedPreKeyTable;->()V HSPLorg/thoughtcrime/securesms/database/SignedPreKeyTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;)V HSPLorg/thoughtcrime/securesms/database/SignedPreKeyTable;->insert(Lorg/whispersystems/signalservice/api/push/ServiceId;ILorg/signal/libsignal/protocol/state/SignedPreKeyRecord;)V +HSPLorg/thoughtcrime/securesms/database/SignedPreKeyTable;->toAccountId(Lorg/whispersystems/signalservice/api/push/ServiceId;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/SqlCipherDatabaseHook;->()V HSPLorg/thoughtcrime/securesms/database/SqlCipherDatabaseHook;->postKey(Lnet/zetetic/database/sqlcipher/SQLiteConnection;)V HSPLorg/thoughtcrime/securesms/database/SqlCipherDatabaseHook;->preKey(Lnet/zetetic/database/sqlcipher/SQLiteConnection;)V @@ -24348,24 +23351,30 @@ HSPLorg/thoughtcrime/securesms/database/SqlCipherErrorHandler;->(Ljava/lan HSPLorg/thoughtcrime/securesms/database/SqlCipherLibraryLoader;->()V HSPLorg/thoughtcrime/securesms/database/SqlCipherLibraryLoader;->()V HSPLorg/thoughtcrime/securesms/database/SqlCipherLibraryLoader;->load()V +HSPLorg/thoughtcrime/securesms/database/StickerTable$StickerPackRecordReader;->(Landroid/database/Cursor;)V +HSPLorg/thoughtcrime/securesms/database/StickerTable$StickerPackRecordReader;->getNext()Lorg/thoughtcrime/securesms/database/model/StickerPackRecord; HSPLorg/thoughtcrime/securesms/database/StickerTable;->()V HSPLorg/thoughtcrime/securesms/database/StickerTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;Lorg/thoughtcrime/securesms/crypto/AttachmentSecret;)V +HSPLorg/thoughtcrime/securesms/database/StickerTable;->deleteOrphanedPacks()V +HSPLorg/thoughtcrime/securesms/database/StickerTable;->deleteStickersInPackExceptCover(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/database/StickerTable;->getAllStickerPacks(Ljava/lang/String;)Landroid/database/Cursor; +HSPLorg/thoughtcrime/securesms/database/StickerTable;->getStickerPack(Ljava/lang/String;)Lorg/thoughtcrime/securesms/database/model/StickerPackRecord; +HSPLorg/thoughtcrime/securesms/database/StickerTable;->isPackAvailableAsReference(Ljava/lang/String;)Z +HSPLorg/thoughtcrime/securesms/database/StickerTable;->uninstallPack(Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/database/StickerTable;->updatePackInstalled(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;Ljava/lang/String;ZZ)V HSPLorg/thoughtcrime/securesms/database/StorySendTable$Companion;->()V HSPLorg/thoughtcrime/securesms/database/StorySendTable$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/StorySendTable;->()V HSPLorg/thoughtcrime/securesms/database/StorySendTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;)V -HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody;->(Ljava/lang/CharSequence;)V HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody;->(Ljava/lang/CharSequence;I)V HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody;->(Ljava/lang/CharSequence;Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody;->getBody()Ljava/lang/CharSequence; HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->()V -HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->format(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/String;I)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; +HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->format(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/lang/String;ILjava/lang/CharSequence;)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->format(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->getBody(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; -HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->getBodyOrDefault(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;I)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->getFormattedBodyFor(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; -HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->getFormattedBodyForMms(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MmsMessageRecord;)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; +HSPLorg/thoughtcrime/securesms/database/ThreadBodyUtil;->getFormattedBodyForMms(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MmsMessageRecord;Ljava/lang/CharSequence;)Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody; HSPLorg/thoughtcrime/securesms/database/ThreadTable$Companion;->()V HSPLorg/thoughtcrime/securesms/database/ThreadTable$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/ThreadTable$ConversationMetadata;->()V @@ -24404,10 +23413,14 @@ HSPLorg/thoughtcrime/securesms/database/ThreadTable$StaticReader;->close()V HSPLorg/thoughtcrime/securesms/database/ThreadTable$StaticReader;->getCurrent()Lorg/thoughtcrime/securesms/database/model/ThreadRecord; HSPLorg/thoughtcrime/securesms/database/ThreadTable$StaticReader;->getNext()Lorg/thoughtcrime/securesms/database/model/ThreadRecord; HSPLorg/thoughtcrime/securesms/database/ThreadTable$StaticReader;->getSnippetUri(Landroid/database/Cursor;)Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult;->()V +HSPLorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult;->(JZ)V +HSPLorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult;->getNewlyCreated()Z +HSPLorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult;->getThreadId()J HSPLorg/thoughtcrime/securesms/database/ThreadTable$WhenMappings;->()V -HSPLorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdFor$1;->(Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/recipients/RecipientId;ZI)V -HSPLorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdFor$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdFor$1;->invoke(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;)Ljava/lang/Long; +HSPLorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdResultFor$1;->(Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/recipients/RecipientId;ZI)V +HSPLorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdResultFor$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdResultFor$1;->invoke(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;)Lorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult; HSPLorg/thoughtcrime/securesms/database/ThreadTable$update$1$isPinned$2;->(Lorg/thoughtcrime/securesms/database/ThreadTable;J)V HSPLorg/thoughtcrime/securesms/database/ThreadTable$update$1$shouldDelete$2;->(ZJLkotlin/Lazy;)V HSPLorg/thoughtcrime/securesms/database/ThreadTable$update$1;->(JLorg/thoughtcrime/securesms/database/ThreadTable;ZZZ)V @@ -24420,7 +23433,7 @@ HSPLorg/thoughtcrime/securesms/database/ThreadTable;->access$getAttachmentUriFor HSPLorg/thoughtcrime/securesms/database/ThreadTable;->access$getContentTypeFor(Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/ThreadTable;->access$getExtrasFor(Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/ThreadBodyUtil$ThreadBody;)Lorg/thoughtcrime/securesms/database/ThreadTable$Extra; HSPLorg/thoughtcrime/securesms/database/ThreadTable;->access$hasMoreRecentDraft(Lorg/thoughtcrime/securesms/database/ThreadTable;JJ)Z -HSPLorg/thoughtcrime/securesms/database/ThreadTable;->access$updateThread(Lorg/thoughtcrime/securesms/database/ThreadTable;JZLjava/lang/String;Landroid/net/Uri;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/ThreadTable$Extra;JIIJZJIII)V +HSPLorg/thoughtcrime/securesms/database/ThreadTable;->access$updateThread(Lorg/thoughtcrime/securesms/database/ThreadTable;JZLjava/lang/String;Landroid/net/Uri;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/ThreadTable$Extra;JIIJZJIIILorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;)V HSPLorg/thoughtcrime/securesms/database/ThreadTable;->allowedToUnarchive(J)Z HSPLorg/thoughtcrime/securesms/database/ThreadTable;->createQuery(Ljava/lang/String;JJZ)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/ThreadTable;->createQuery(Ljava/lang/String;Ljava/lang/String;JJ)Ljava/lang/String; @@ -24433,6 +23446,7 @@ HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getExtrasFor(Lorg/thoughtc HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getOrCreateThreadIdFor(Lorg/thoughtcrime/securesms/recipients/Recipient;)J HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getOrCreateThreadIdFor(Lorg/thoughtcrime/securesms/recipients/Recipient;I)J HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getOrCreateThreadIdFor(Lorg/thoughtcrime/securesms/recipients/RecipientId;ZI)J +HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getOrCreateThreadIdResultFor(Lorg/thoughtcrime/securesms/recipients/RecipientId;ZI)Lorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult; HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getPinnedConversationListCount(Lorg/thoughtcrime/securesms/conversationlist/model/ConversationFilter;)I HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getRecentConversationList(IZZ)Landroid/database/Cursor; HSPLorg/thoughtcrime/securesms/database/ThreadTable;->getRecentConversationList(IZZZZZZ)Landroid/database/Cursor; @@ -24451,7 +23465,7 @@ HSPLorg/thoughtcrime/securesms/database/ThreadTable;->setLastScrolled(JJ)V HSPLorg/thoughtcrime/securesms/database/ThreadTable;->toQuery(Lorg/thoughtcrime/securesms/conversationlist/model/ConversationFilter;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/ThreadTable;->update(JZ)Z HSPLorg/thoughtcrime/securesms/database/ThreadTable;->update(JZZZ)Z -HSPLorg/thoughtcrime/securesms/database/ThreadTable;->updateThread(JZLjava/lang/String;Landroid/net/Uri;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/ThreadTable$Extra;JIIJZJIII)V +HSPLorg/thoughtcrime/securesms/database/ThreadTable;->updateThread(JZLjava/lang/String;Landroid/net/Uri;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/ThreadTable$Extra;JIIJZJIIILorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;)V HSPLorg/thoughtcrime/securesms/database/UnknownStorageIdTable;->()V HSPLorg/thoughtcrime/securesms/database/UnknownStorageIdTable;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/SignalDatabase;)V HSPLorg/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/NotificationManager;)Ljava/util/List; @@ -24491,7 +23505,6 @@ HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isCallLog()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isChangeNumber()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isEndSession()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isExpirationTimerUpdate()Z -HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isFailed()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isGroupAction()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isGroupCall()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isGroupQuit()Z @@ -24499,7 +23512,7 @@ HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isGroupUpdate()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isIncomingAudioCall()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isIncomingVideoCall()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isJoined()Z -HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isKeyExchange()Z +HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isMessageRequestAccepted()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isMissedAudioCall()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isMissedVideoCall()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isOutgoing()Z @@ -24508,9 +23521,8 @@ HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isOutgoingVideoCal HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPaymentNotification()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPaymentsActivated()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPaymentsRequestToActivate()Z -HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPending()Z -HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPendingInsecureSmsFallback()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isProfileChange()Z +HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isReportedSpam()Z HSPLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isViewed()Z HSPLorg/thoughtcrime/securesms/database/model/DistributionListId$1;->()V HSPLorg/thoughtcrime/securesms/database/model/DistributionListId;->()V @@ -24567,7 +23579,7 @@ HSPLorg/thoughtcrime/securesms/database/model/MessageId$Creator;->()V HSPLorg/thoughtcrime/securesms/database/model/MessageId;->()V HSPLorg/thoughtcrime/securesms/database/model/MessageId;->(J)V HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->()V -HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->(JLjava/lang/String;Lorg/thoughtcrime/securesms/recipients/Recipient;ILorg/thoughtcrime/securesms/recipients/Recipient;JJJJIZJLjava/util/Set;Ljava/util/Set;IJJZZLjava/util/List;ZJZJLorg/thoughtcrime/securesms/database/model/MessageId;I)V +HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->(JLjava/lang/String;Lorg/thoughtcrime/securesms/recipients/Recipient;ILorg/thoughtcrime/securesms/recipients/Recipient;JJJJIZJLjava/util/Set;Ljava/util/Set;IJJZZLjava/util/List;ZJZJLorg/thoughtcrime/securesms/database/model/MessageId;ILorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;)V HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getDisplayBody(Landroid/content/Context;)Landroid/text/SpannableString; HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getDisplayBody(Landroid/content/Context;Lj$/util/function/Consumer;)Landroid/text/SpannableString; HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getExpireStarted()J @@ -24575,6 +23587,7 @@ HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getExpiresIn()J HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getFromDeviceId()I HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getId()J HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getIdentityKeyMismatches()Ljava/util/Set; +HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getMessageExtras()Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras; HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getNetworkFailures()Ljava/util/Set; HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getNotifiedTimestamp()J HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getOriginalMessageId()Lorg/thoughtcrime/securesms/database/model/MessageId; @@ -24588,7 +23601,6 @@ HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getType()J HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->getUpdateDisplayBody(Landroid/content/Context;Lj$/util/function/Consumer;)Lorg/thoughtcrime/securesms/database/model/UpdateDescription; HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->hashCode()I HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isBadDecryptType()Z -HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isBundleKeyExchange()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isChatSessionRefresh()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isDisplayBodyEmpty(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isEditMessage()Z @@ -24596,12 +23608,9 @@ HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isGroupV1Migration HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isIdentityDefault()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isIdentityUpdate()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isIdentityVerified()Z -HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isJumbomoji(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isLegacyMessage()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isPush()Z -HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isRateLimited()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isRemoteDelete()Z -HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isSecure()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isSessionSwitchoverEventType()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isSmsExportType()Z HSPLorg/thoughtcrime/securesms/database/model/MessageRecord;->isThreadMergeEventType()Z @@ -24622,7 +23631,7 @@ HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord$$ExternalSyntheti HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->$r8$lambda$61cfVwuT9NopES3EvrpU58ByOrs(Ljava/util/Set;Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment;)Z HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->$r8$lambda$yFErtnyhgG1o4FUJh3c90u9IkrI(Ljava/util/Set;Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment;)Z HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->()V -HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->(JLorg/thoughtcrime/securesms/recipients/Recipient;ILorg/thoughtcrime/securesms/recipients/Recipient;JJJZJLjava/lang/String;Lorg/thoughtcrime/securesms/mms/SlideDeck;JLjava/util/Set;Ljava/util/Set;IJJZZLorg/thoughtcrime/securesms/database/model/Quote;Ljava/util/List;Ljava/util/List;ZLjava/util/List;ZZJZJLorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Lorg/thoughtcrime/securesms/database/model/StoryType;Lorg/thoughtcrime/securesms/database/model/ParentStoryId;Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge;Lorg/thoughtcrime/securesms/payments/Payment;Lorg/thoughtcrime/securesms/database/CallTable$Call;JLorg/thoughtcrime/securesms/database/model/MessageId;Lorg/thoughtcrime/securesms/database/model/MessageId;IZ)V +HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->(JLorg/thoughtcrime/securesms/recipients/Recipient;ILorg/thoughtcrime/securesms/recipients/Recipient;JJJZJLjava/lang/String;Lorg/thoughtcrime/securesms/mms/SlideDeck;JLjava/util/Set;Ljava/util/Set;IJJZZLorg/thoughtcrime/securesms/database/model/Quote;Ljava/util/List;Ljava/util/List;ZLjava/util/List;ZZJZJLorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Lorg/thoughtcrime/securesms/database/model/StoryType;Lorg/thoughtcrime/securesms/database/model/ParentStoryId;Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge;Lorg/thoughtcrime/securesms/payments/Payment;Lorg/thoughtcrime/securesms/database/CallTable$Call;JLorg/thoughtcrime/securesms/database/model/MessageId;Lorg/thoughtcrime/securesms/database/model/MessageId;IZLorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;)V HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getCall()Lorg/thoughtcrime/securesms/database/CallTable$Call; HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getDisplayBody(Landroid/content/Context;)Landroid/text/SpannableString; HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getGiftBadge()Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge; @@ -24637,7 +23646,6 @@ HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getSharedContac HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getSlideDeck()Lorg/thoughtcrime/securesms/mms/SlideDeck; HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getStoryType()Lorg/thoughtcrime/securesms/database/model/StoryType; HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->getUpdateDisplayBody(Landroid/content/Context;Lj$/util/function/Consumer;)Lorg/thoughtcrime/securesms/database/model/UpdateDescription; -HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->isMediaPending()Z HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->isMms()Z HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->isMmsNotification()Z HSPLorg/thoughtcrime/securesms/database/model/MmsMessageRecord;->isRead()Z @@ -24662,9 +23670,9 @@ HSPLorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails;->toStrin HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities$Companion;->()V HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities;->()V -HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities;->(JLorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;)V +HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities;->(JLorg/thoughtcrime/securesms/recipients/Recipient$Capability;Lorg/thoughtcrime/securesms/recipients/Recipient$Capability;)V HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$SyncExtras;->()V -HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$SyncExtras;->([BLorg/signal/libsignal/zkgroup/groups/GroupMasterKey;[BLorg/thoughtcrime/securesms/database/IdentityTable$VerifiedStatus;ZZJLjava/lang/String;)V +HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord$SyncExtras;->([BLorg/signal/libsignal/zkgroup/groups/GroupMasterKey;[BLorg/thoughtcrime/securesms/database/IdentityTable$VerifiedStatus;ZZJLjava/lang/String;Z)V HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord;->()V HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord;->(Lorg/thoughtcrime/securesms/recipients/RecipientId;Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/database/model/DistributionListId;Lorg/thoughtcrime/securesms/database/RecipientTable$RecipientType;ZJLorg/thoughtcrime/securesms/database/RecipientTable$VibrateState;Lorg/thoughtcrime/securesms/database/RecipientTable$VibrateState;Landroid/net/Uri;Landroid/net/Uri;ILorg/thoughtcrime/securesms/database/RecipientTable$RegisteredState;[BLorg/signal/libsignal/zkgroup/profiles/ExpiringProfileKeyCredential;Lorg/thoughtcrime/securesms/profiles/ProfileName;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/profiles/ProfileName;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails;ZJLjava/lang/String;Lorg/thoughtcrime/securesms/database/RecipientTable$UnidentifiedAccessMode;Lorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities;[BLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper;Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/RecipientRecord$SyncExtras;Lorg/thoughtcrime/securesms/recipients/Recipient$Extras;ZLjava/util/List;ZLorg/thoughtcrime/securesms/recipients/Recipient$HiddenState;Lorg/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId;Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState;)V HSPLorg/thoughtcrime/securesms/database/model/RecipientRecord;->getAbout()Ljava/lang/String; @@ -24756,6 +23764,7 @@ HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fge HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetisPinned(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)Z HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetlastSeen(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)J HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetmeaningfulMessages(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)Z +HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetmessageExtras(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetrecipient(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)Lorg/thoughtcrime/securesms/recipients/Recipient; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetsnippetUri(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->-$$Nest$fgetthreadId(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)J @@ -24779,12 +23788,14 @@ HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setLastSeen HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setMeaningfulMessages(Z)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setPinned(Z)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setRecipient(Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; +HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setSnippetMessageExtras(Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setSnippetUri(Landroid/net/Uri;)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setType(J)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setUnreadCount(I)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;->setUnreadSelfMentionsCount(I)Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;)V HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->(Lorg/thoughtcrime/securesms/database/model/ThreadRecord$Builder;Lorg/thoughtcrime/securesms/database/model/ThreadRecord-IA;)V +HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->equals(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->getBody()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->getBodyRanges()Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList; HSPLorg/thoughtcrime/securesms/database/model/ThreadRecord;->getDate()J @@ -24807,8 +23818,6 @@ HSPLorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonat HSPLorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonation$Companion;->()V HSPLorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonation$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonation;->()V -HSPLorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding;->(Landroid/view/View;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lorg/thoughtcrime/securesms/components/AvatarImageView;Landroid/widget/LinearLayout;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Landroid/view/View;Landroidx/constraintlayout/widget/ConstraintLayout;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V -HSPLorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding; HSPLorg/thoughtcrime/securesms/databinding/ConversationInputPanelBinding;->(Lorg/thoughtcrime/securesms/components/InputPanel;Landroid/widget/ImageButton;Landroidx/constraintlayout/widget/Barrier;Lorg/thoughtcrime/securesms/components/InputPanel;Lorg/thoughtcrime/securesms/components/AnimatingToggle;Landroid/view/View;Landroidx/constraintlayout/widget/Barrier;Lcom/google/android/material/imageview/ShapeableImageView;Landroidx/appcompat/widget/AppCompatTextView;Lorg/thoughtcrime/securesms/components/ComposeText;Lorg/thoughtcrime/securesms/components/emoji/EmojiToggle;Landroid/widget/ImageButton;Lorg/thoughtcrime/securesms/components/HidingLinearLayout;Landroidx/appcompat/widget/AppCompatImageButton;Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/components/LinkPreviewView;Lorg/thoughtcrime/securesms/components/HidingLinearLayout;Landroid/widget/ImageButton;Lorg/thoughtcrime/securesms/components/QuoteView;Lorg/thoughtcrime/securesms/components/MicrophoneRecorderView;Lorg/thoughtcrime/securesms/components/SendButton;Landroid/widget/ImageButton;Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;)V HSPLorg/thoughtcrime/securesms/databinding/ConversationInputPanelBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/ConversationInputPanelBinding; HSPLorg/thoughtcrime/securesms/databinding/ConversationInputPanelBinding;->getRoot()Lorg/thoughtcrime/securesms/components/InputPanel; @@ -24819,22 +23828,11 @@ HSPLorg/thoughtcrime/securesms/databinding/ConversationListTabsBinding;->bind(La HSPLorg/thoughtcrime/securesms/databinding/ConversationListTabsBinding;->getRoot()Landroidx/constraintlayout/widget/ConstraintLayout; HSPLorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding;->(Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar;Landroidx/appcompat/widget/AppCompatImageView;Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar;Landroid/widget/TextView;Lcom/pnikosis/materialishprogress/ProgressWheel;Landroidx/appcompat/widget/AppCompatImageView;)V HSPLorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding; -HSPLorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding;->getRoot()Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar; HSPLorg/thoughtcrime/securesms/databinding/ConversationTitleViewBinding;->(Lorg/thoughtcrime/securesms/conversation/ConversationTitleView;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Landroid/widget/FrameLayout;Lorg/thoughtcrime/securesms/avatar/view/AvatarView;Lorg/thoughtcrime/securesms/conversation/ConversationTitleView;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Landroid/widget/LinearLayout;Lorg/thoughtcrime/securesms/components/FromTextView;Landroidx/appcompat/widget/AppCompatImageView;Landroid/widget/TextView;)V HSPLorg/thoughtcrime/securesms/databinding/ConversationTitleViewBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/ConversationTitleViewBinding; HSPLorg/thoughtcrime/securesms/databinding/ConversationTitleViewBinding;->getRoot()Lorg/thoughtcrime/securesms/conversation/ConversationTitleView; -HSPLorg/thoughtcrime/securesms/databinding/OnboardingMegaphoneCardBinding;->(Lcom/google/android/material/card/MaterialCardView;Landroid/widget/ImageView;Landroid/widget/ImageView;Landroid/widget/TextView;)V -HSPLorg/thoughtcrime/securesms/databinding/OnboardingMegaphoneCardBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/OnboardingMegaphoneCardBinding; -HSPLorg/thoughtcrime/securesms/databinding/OnboardingMegaphoneCardBinding;->getRoot()Lcom/google/android/material/card/MaterialCardView; -HSPLorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding;->(Landroid/view/View;Landroidx/constraintlayout/widget/Guideline;Landroidx/appcompat/widget/AppCompatImageView;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;Landroidx/constraintlayout/widget/Guideline;)V -HSPLorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding; -HSPLorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding;->inflate(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding; HSPLorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding;->(Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;Landroid/view/ViewStub;Landroid/view/View;Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;Landroid/widget/FrameLayout;Lorg/thoughtcrime/securesms/components/menu/SignalBottomActionBar;Landroidx/constraintlayout/widget/Barrier;Lorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;Lcom/google/android/material/button/MaterialButton;Lorg/thoughtcrime/securesms/databinding/ConversationInputPanelBinding;Landroidx/constraintlayout/widget/Barrier;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectRecyclerView;Landroid/widget/FrameLayout;Landroid/view/ViewStub;Lorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding;Lorg/thoughtcrime/securesms/databinding/ConversationTitleViewBinding;Landroid/widget/FrameLayout;Landroid/widget/ImageView;Landroid/view/View;Landroidx/fragment/app/FragmentContainerView;Landroidx/fragment/app/FragmentContainerView;Landroidx/fragment/app/FragmentContainerView;Landroid/widget/FrameLayout;Landroid/view/ViewStub;Landroid/view/ViewStub;Landroid/view/ViewStub;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/ConversationScrollToView;Lorg/thoughtcrime/securesms/components/ConversationScrollToView;Lorg/thoughtcrime/securesms/util/views/DarkOverflowToolbar;Landroid/view/View;Landroid/view/ViewStub;Landroid/view/ViewStub;)V HSPLorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding; -HSPLorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding;->getRoot()Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout; -HSPLorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Lorg/thoughtcrime/securesms/components/AvatarImageView;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Landroid/widget/LinearLayout;Lorg/thoughtcrime/securesms/components/ExpirationTimerView;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView;Lcom/google/android/material/imageview/ShapeableImageView;Landroid/widget/Space;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V -HSPLorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding; -HSPLorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;->getRoot()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies$$ExternalSyntheticLambda0;->()V HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies$$ExternalSyntheticLambda0;->get()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->$r8$lambda$TTNxYGZvGlMOp1oidmVJeKiRxZs()Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration; @@ -24859,12 +23857,14 @@ HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getMessage HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getOkHttpClient()Lokhttp3/OkHttpClient; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getPendingRetryReceiptCache()Lorg/thoughtcrime/securesms/database/PendingRetryReceiptCache; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getPendingRetryReceiptManager()Lorg/thoughtcrime/securesms/service/PendingRetryReceiptManager; +HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getProfileService()Lorg/whispersystems/signalservice/api/services/ProfileService; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getProtocolStore()Lorg/thoughtcrime/securesms/crypto/storage/SignalServiceDataStoreImpl; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getRecipientCache()Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getScheduledMessageManager()Lorg/thoughtcrime/securesms/service/ScheduledMessageManager; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getShakeToReport()Lorg/thoughtcrime/securesms/shakereport/ShakeToReport; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getSignalOkHttpClient()Lokhttp3/OkHttpClient; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getSignalServiceAccountManager()Lorg/whispersystems/signalservice/api/SignalServiceAccountManager; +HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getSignalServiceMessageReceiver()Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getSignalServiceNetworkAccess()Lorg/thoughtcrime/securesms/push/SignalServiceNetworkAccess; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getSignalWebSocket()Lorg/whispersystems/signalservice/api/SignalWebSocket; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getTypingStatusRepository()Lorg/thoughtcrime/securesms/components/TypingStatusRepository; @@ -24905,11 +23905,13 @@ HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->prov HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideMessageNotifier()Lorg/thoughtcrime/securesms/notifications/MessageNotifier; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->providePendingRetryReceiptCache()Lorg/thoughtcrime/securesms/database/PendingRetryReceiptCache; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->providePendingRetryReceiptManager()Lorg/thoughtcrime/securesms/service/PendingRetryReceiptManager; +HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideProfileService(Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;Lorg/whispersystems/signalservice/api/SignalWebSocket;)Lorg/whispersystems/signalservice/api/services/ProfileService; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideProtocolStore()Lorg/thoughtcrime/securesms/crypto/storage/SignalServiceDataStoreImpl; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideRecipientCache()Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideScheduledMessageManager()Lorg/thoughtcrime/securesms/service/ScheduledMessageManager; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideShakeToReport()Lorg/thoughtcrime/securesms/shakereport/ShakeToReport; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideSignalServiceAccountManager(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lorg/whispersystems/signalservice/api/groupsv2/GroupsV2Operations;)Lorg/whispersystems/signalservice/api/SignalServiceAccountManager; +HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideSignalServiceMessageReceiver(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;)Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideSignalServiceNetworkAccess()Lorg/thoughtcrime/securesms/push/SignalServiceNetworkAccess; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideSignalWebSocket(Lj$/util/function/Supplier;)Lorg/whispersystems/signalservice/api/SignalWebSocket; HSPLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideTypingStatusRepository()Lorg/thoughtcrime/securesms/components/TypingStatusRepository; @@ -24974,8 +23976,10 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;->isVersionVal HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;->readVersion$default(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;Landroid/content/Context;ZILjava/lang/Object;)Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;->readVersion(Landroid/content/Context;)Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;->readVersion(Landroid/content/Context;Z)Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version; +HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;->writeVersion(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->(ILjava/util/UUID;Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->access$getObjectMapper$cp()Lcom/fasterxml/jackson/databind/ObjectMapper; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->getDensity()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->getDirectory(Landroid/content/Context;)Ljava/io/File; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->getFile(Landroid/content/Context;Ljava/util/UUID;)Ljava/io/File; @@ -24983,14 +23987,17 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->getUuid()Ljava/util/UU HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->getVersion()I HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->isVersionValid(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)Z HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->readVersion(Landroid/content/Context;)Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version; +HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->writeVersion(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$getLatestEmojiData$1$1;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$getLatestEmojiData$1$1;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$getLatestEmojiData$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles$getLatestEmojiData$1$1;->invoke(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->()V +HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->getBaseDirectory(Landroid/content/Context;)Ljava/io/File; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->getLatestEmojiData(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)Lorg/thoughtcrime/securesms/emoji/ParsedEmojiData; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->getMd5(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;Ljava/util/UUID;)[B +HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->openForReading(Landroid/content/Context;Ljava/lang/String;)Ljava/io/InputStream; HSPLorg/thoughtcrime/securesms/emoji/EmojiFiles;->openForWriting(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;Ljava/util/UUID;)Ljava/io/OutputStream; HSPLorg/thoughtcrime/securesms/emoji/EmojiFilesKt;->access$getEmojiDirectory(Landroid/content/Context;)Ljava/io/File; HSPLorg/thoughtcrime/securesms/emoji/EmojiFilesKt;->access$getFilesUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri; @@ -25055,12 +24062,12 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiMetrics;->(III)V HSPLorg/thoughtcrime/securesms/emoji/EmojiMetrics;->getPerRow()I HSPLorg/thoughtcrime/securesms/emoji/EmojiMetrics;->getRawHeight()I HSPLorg/thoughtcrime/securesms/emoji/EmojiMetrics;->getRawWidth()I -HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Asset;->()V -HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Asset;->(Landroid/net/Uri;)V -HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Asset;->equals(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Asset;->getUri()Landroid/net/Uri; -HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Asset;->hashCode()I -HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Asset;->toString()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->()V +HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->(Landroid/net/Uri;)V +HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->equals(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->getUri()Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->hashCode()I +HSPLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->toString()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/emoji/EmojiPage;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiPage;->(Landroid/net/Uri;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiPage;->(Landroid/net/Uri;Lkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -25087,6 +24094,7 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->$r8$lambda$NLSLe3cZ9aQvIzn HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->$r8$lambda$prHxAb0TF9CtP8w7EJ9vg507J70(Lorg/thoughtcrime/securesms/util/ListenableFutureTask;Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$EmojiPageRequest;Lkotlin/Unit;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->()V +HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->clear()V HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->load$lambda$0(Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$EmojiPageRequest;Landroid/content/Context;)Landroid/graphics/Bitmap; HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->load$lambda$1(Lorg/thoughtcrime/securesms/util/ListenableFutureTask;Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$EmojiPageRequest;Lkotlin/Unit;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->load$run__proxy(Lorg/thoughtcrime/securesms/util/ListenableFutureTask;)Lkotlin/Unit; @@ -25099,12 +24107,14 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiRemote;->getObject(Lorg/thoughtcrime/s HSPLorg/thoughtcrime/securesms/emoji/EmojiRemote;->getVersion()I HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$1;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$1;->()V -HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$1;->invoke(Landroid/net/Uri;)Lorg/thoughtcrime/securesms/emoji/EmojiPage; -HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$parsedData$1;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$parsedData$1;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$parsedData$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$parsedData$1;->invoke(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->()V +HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->()V +HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->invoke(Landroid/net/Uri;)Lorg/thoughtcrime/securesms/emoji/EmojiPage; +HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion;->getEmojiSource()Lorg/thoughtcrime/securesms/emoji/EmojiSource; @@ -25117,8 +24127,6 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$emojiTree$2;->(Lorg/thoug HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$emojiTree$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$emojiTree$2;->invoke()Lorg/thoughtcrime/securesms/components/emoji/parsing/EmojiTree; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$maxEmojiLength$2;->(Lorg/thoughtcrime/securesms/emoji/EmojiSource;)V -HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$maxEmojiLength$2;->invoke()Ljava/lang/Integer; -HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$maxEmojiLength$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource$variationsToCanonical$2;->(Lorg/thoughtcrime/securesms/emoji/EmojiSource;)V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->(FLorg/thoughtcrime/securesms/emoji/EmojiData;Lkotlin/jvm/functions/Function1;)V @@ -25130,21 +24138,22 @@ HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getDecodeScale()F HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getEmojiTree()Lorg/thoughtcrime/securesms/components/emoji/parsing/EmojiTree; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getJumboPages()Ljava/util/Map; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getLatest()Lorg/thoughtcrime/securesms/emoji/EmojiSource; -HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getMaxEmojiLength()I HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getMetrics()Lorg/thoughtcrime/securesms/emoji/EmojiMetrics; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->getObsolete()Ljava/util/List; HSPLorg/thoughtcrime/securesms/emoji/EmojiSource;->refresh()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->()V HSPLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->access$getAssetsUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->access$getPAGE_EMOTICONS$p()Lorg/thoughtcrime/securesms/components/emoji/EmojiPageModel; -HSPLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->access$maxOrZero(Ljava/util/List;)I HSPLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->getAssetsUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri; -HSPLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->maxOrZero(Ljava/util/List;)I +HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V +HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda4;->run()V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda5;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda5;->run()V +HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->$r8$lambda$1MZfAT8L5tWrN2t8lIV1c9aeWgA(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->$r8$lambda$U8tEMIKRjYoTvIByfnS46m01TB0(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->()V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->()V +HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->updateCurrentVersion$lambda$1$lambda$0(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->updateCurrentVersion$lambda$1(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/emoji/JumboEmoji;->updateCurrentVersion(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/emoji/ParsedEmojiData;->()V @@ -25162,8 +24171,14 @@ HSPLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->()V HSPLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->getMap(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;)Lorg/thoughtcrime/securesms/fonts/FontFileMap; HSPLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->getNameOnDisk(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Ljava/lang/String;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->put(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Ljava/lang/String;Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->setMap(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Lorg/thoughtcrime/securesms/fonts/FontFileMap;)V HSPLorg/thoughtcrime/securesms/fonts/FontFileMap;->()V +HSPLorg/thoughtcrime/securesms/fonts/FontFileMap;->(Ljava/util/Map;)V +HSPLorg/thoughtcrime/securesms/fonts/FontFileMap;->access$getObjectMapper$cp()Lcom/fasterxml/jackson/databind/ObjectMapper; HSPLorg/thoughtcrime/securesms/fonts/FontFileMap;->access$getTAG$cp()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/fonts/FontFileMap;->copy(Ljava/util/Map;)Lorg/thoughtcrime/securesms/fonts/FontFileMap; +HSPLorg/thoughtcrime/securesms/fonts/FontFileMap;->getMap()Ljava/util/Map; HSPLorg/thoughtcrime/securesms/fonts/FontManifest$Companion;->()V HSPLorg/thoughtcrime/securesms/fonts/FontManifest$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/fonts/FontManifest$Companion;->fromDisk(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;)Lorg/thoughtcrime/securesms/fonts/FontManifest; @@ -25232,6 +24247,7 @@ HSPLorg/thoughtcrime/securesms/fonts/Fonts;->downloadLatestVersionLong()J HSPLorg/thoughtcrime/securesms/fonts/Fonts;->getDirectory(Landroid/content/Context;)Ljava/io/File; HSPLorg/thoughtcrime/securesms/fonts/Fonts;->getScriptPath(Lorg/thoughtcrime/securesms/fonts/TextFont;Lorg/thoughtcrime/securesms/fonts/FontManifest$FontScript;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/fonts/Fonts;->getSupportedScript(Ljava/util/List;Lorg/thoughtcrime/securesms/fonts/SupportedScript;)Lorg/thoughtcrime/securesms/fonts/SupportedScript; +HSPLorg/thoughtcrime/securesms/fonts/Fonts;->loadFontIntoTypeface(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Ljava/lang/String;)Landroid/graphics/Typeface; HSPLorg/thoughtcrime/securesms/fonts/Fonts;->resolveFont$lambda$2$lambda$1(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/SupportedScript;Lorg/thoughtcrime/securesms/fonts/TextFont;Lorg/thoughtcrime/securesms/fonts/FontVersion;Lorg/thoughtcrime/securesms/fonts/FontManifest;Lorg/thoughtcrime/securesms/fonts/Fonts$FontResult$Immediate;Lorg/thoughtcrime/securesms/fonts/Fonts$FontDownloadKey;)Landroid/graphics/Typeface; HSPLorg/thoughtcrime/securesms/fonts/Fonts;->resolveFont(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/TextFont;Lorg/thoughtcrime/securesms/fonts/SupportedScript;)Lorg/thoughtcrime/securesms/fonts/Fonts$FontResult; HSPLorg/thoughtcrime/securesms/fonts/Fonts;->resolveFontScriptFromScriptName(Lorg/thoughtcrime/securesms/fonts/SupportedScript;Lorg/thoughtcrime/securesms/fonts/FontManifest;)Lorg/thoughtcrime/securesms/fonts/FontManifest$FontScript; @@ -25255,8 +24271,6 @@ HSPLorg/thoughtcrime/securesms/gcm/FcmFetchManager;->()V HSPLorg/thoughtcrime/securesms/gcm/FcmFetchManager;->cancelMayHaveMessagesNotification(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/gcm/FcmFetchManager;->onForeground(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration$onDraw$1;->(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration$onDraw$1;->invoke(Landroid/view/View;)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration$onDraw$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration;->()V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration;->(Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$Callback;Lkotlin/jvm/functions/Function1;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration;->(Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$Callback;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -25265,8 +24279,6 @@ HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ItemDecoration;->setParentRecycl HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$$ExternalSyntheticLambda0;->(Ljava/util/Set;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$RangeComparator;->(II)V -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$RangeComparator;->compare(Ljava/lang/Integer;Ljava/lang/Integer;)I -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$RangeComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->(Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$Callback;I)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->attach(Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$Callback;I)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->findFirstVisibleItemPositions(Landroidx/recyclerview/widget/RecyclerView$LayoutManager;)[I @@ -25274,7 +24286,6 @@ HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->findLastVis HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->getPlaybackSet(Ljava/util/Set;II)Ljava/util/Set; HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->getPlaybackSetForMaximumDistance(Ljava/util/Set;[I[I)Ljava/util/Set; HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->onLayoutChange(Landroid/view/View;IIIIIIII)V -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->performPlaybackUpdate(Landroidx/recyclerview/widget/RecyclerView;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackPolicy;->maxSimultaneousPlaybackInConversation()I HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->()V @@ -25284,10 +24295,8 @@ HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->onCreat HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->onStart(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->(Ljava/util/List;)V -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->getCurrentHolder(I)Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder; HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->stopAndReleaseAssignedVideos(Ljava/util/Set;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->update(Landroidx/recyclerview/widget/RecyclerView;Ljava/util/List;Ljava/util/Set;)V -HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionRecycler;->updateVideoDisplayPositionAndSize(Landroidx/recyclerview/widget/RecyclerView;Lorg/thoughtcrime/securesms/giph/mp4/GiphyMp4Playable;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4VideoPlayer;->()V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4VideoPlayer;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4VideoPlayer;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V @@ -25336,6 +24345,10 @@ HSPLorg/thoughtcrime/securesms/glide/cache/EncryptedCoder;->()V HSPLorg/thoughtcrime/securesms/glide/cache/EncryptedCoder;->()V HSPLorg/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder;->()V HSPLorg/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder;->([B)V +HSPLorg/thoughtcrime/securesms/glide/cache/WebpSanDecoder$Companion;->()V +HSPLorg/thoughtcrime/securesms/glide/cache/WebpSanDecoder$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/glide/cache/WebpSanDecoder;->()V +HSPLorg/thoughtcrime/securesms/glide/cache/WebpSanDecoder;->()V HSPLorg/thoughtcrime/securesms/groups/GroupId;->()V HSPLorg/thoughtcrime/securesms/groups/GroupId;->parseNullableOrThrow(Ljava/lang/String;)Lorg/thoughtcrime/securesms/groups/GroupId; HSPLorg/thoughtcrime/securesms/groups/SelectionLimits$1;->()V @@ -25352,8 +24365,12 @@ HSPLorg/thoughtcrime/securesms/jobmanager/CompositeScheduler;->schedule(JLjava/u HSPLorg/thoughtcrime/securesms/jobmanager/Constraint$-CC;->$default$getJobSchedulerKeyPart(Lorg/thoughtcrime/securesms/jobmanager/Constraint;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobmanager/ConstraintInstantiator;->(Ljava/util/Map;)V HSPLorg/thoughtcrime/securesms/jobmanager/ConstraintInstantiator;->instantiate(Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/Constraint; +HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/jobmanager/InAppScheduler;)V +HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler$$ExternalSyntheticLambda0;->run()V +HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->$r8$lambda$hBEn_48T9NK-BhOmjEIwF4k281g(Lorg/thoughtcrime/securesms/jobmanager/InAppScheduler;)V HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->()V HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V +HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->lambda$schedule$0()V HSPLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->schedule(JLjava/util/List;)V HSPLorg/thoughtcrime/securesms/jobmanager/Job$1;->()V HSPLorg/thoughtcrime/securesms/jobmanager/Job$Parameters$Builder;->()V @@ -25387,11 +24404,14 @@ HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result$ResultType;->(Ljava/l HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result$ResultType;->values()[Lorg/thoughtcrime/securesms/jobmanager/Job$Result$ResultType; HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->()V HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Result$ResultType;Ljava/lang/RuntimeException;[BJ)V +HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->failure()Lorg/thoughtcrime/securesms/jobmanager/Job$Result; +HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->getBackoffInterval()J HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->getException()Ljava/lang/RuntimeException; HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->getOutputData()[B HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->isFailure()Z HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->isRetry()Z HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->isSuccess()Z +HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->retry(J)Lorg/thoughtcrime/securesms/jobmanager/Job$Result; HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->success([B)Lorg/thoughtcrime/securesms/jobmanager/Job$Result; HSPLorg/thoughtcrime/securesms/jobmanager/Job$Result;->toString()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobmanager/Job;->()V @@ -25403,11 +24423,22 @@ HSPLorg/thoughtcrime/securesms/jobmanager/Job;->getParameters()Lorg/thoughtcrime HSPLorg/thoughtcrime/securesms/jobmanager/Job;->getRunAttempt()I HSPLorg/thoughtcrime/securesms/jobmanager/Job;->isCanceled()Z HSPLorg/thoughtcrime/securesms/jobmanager/Job;->onAdded()V +HSPLorg/thoughtcrime/securesms/jobmanager/Job;->onRetry()V HSPLorg/thoughtcrime/securesms/jobmanager/Job;->onSubmit()V HSPLorg/thoughtcrime/securesms/jobmanager/Job;->setContext(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/jobmanager/Job;->setLastRunAttemptTime(J)V HSPLorg/thoughtcrime/securesms/jobmanager/Job;->setNextBackoffInterval(J)V HSPLorg/thoughtcrime/securesms/jobmanager/Job;->setRunAttempt(I)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda0;->()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda13;->()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda13;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda14;->(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobStorage;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda14;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda16;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda16;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda17;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda17;->accept(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda19;->(Lorg/thoughtcrime/securesms/jobmanager/ConstraintInstantiator;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda19;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V @@ -25416,8 +24447,6 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda20;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda22;->(Lorg/thoughtcrime/securesms/jobmanager/JobPredicate;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda22;->test(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda23;->(Lorg/thoughtcrime/securesms/jobmanager/JobController$Callback;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda23;->run()V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda4;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/Job;)V @@ -25428,9 +24457,11 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda7;->accept(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda8;->()V HSPLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda8;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$AFTJhIYz2IJLxa5cdEvspxyDnpk(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)Lorg/thoughtcrime/securesms/jobmanager/Job; HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$FnYUQJ9nqVuTdiLe8l57LDvJzOE(Lorg/thoughtcrime/securesms/jobmanager/JobController;Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$Ka2rmpP3tDCT7kzx5KQlHQUrhA4(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec; HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$YXMN5Ij_rYm1dFbxzMPP4rhbPPI(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/Job;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$_WG2KEwBlGL1eFDhBUpj1kHB45I(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/Job;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$cs0r6RT3Ty9GlYLxMBZkIHg08dM(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/Job;Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/persistence/DependencySpec; HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->()V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->(Landroid/app/Application;Lorg/thoughtcrime/securesms/jobmanager/persistence/JobStorage;Lorg/thoughtcrime/securesms/jobmanager/JobInstantiator;Lorg/thoughtcrime/securesms/jobmanager/ConstraintInstantiator;Lorg/thoughtcrime/securesms/jobmanager/JobTracker;Lorg/thoughtcrime/securesms/jobmanager/Scheduler;Lorg/thoughtcrime/securesms/util/Debouncer;Lorg/thoughtcrime/securesms/jobmanager/JobController$Callback;)V @@ -25444,9 +24475,13 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->init()V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->insertJobChain(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$buildFullSpec$10(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec; HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$buildFullSpec$11(Lorg/thoughtcrime/securesms/jobmanager/Job;Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/persistence/DependencySpec; +HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$onFailure$3(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$onFailure$4(Lorg/thoughtcrime/securesms/jobmanager/Job;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$triggerOnSubmit$8(Lorg/thoughtcrime/securesms/jobmanager/Job;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$triggerOnSubmit$9(Ljava/util/List;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->onFailure(Lorg/thoughtcrime/securesms/jobmanager/Job;)Ljava/util/List; HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->onJobFinished(Lorg/thoughtcrime/securesms/jobmanager/Job;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->onRetry(Lorg/thoughtcrime/securesms/jobmanager/Job;J)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->onSuccess(Lorg/thoughtcrime/securesms/jobmanager/Job;[B)V HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->pullNextEligibleJobForExecution(Lorg/thoughtcrime/securesms/jobmanager/JobPredicate;)Lorg/thoughtcrime/securesms/jobmanager/Job; HSPLorg/thoughtcrime/securesms/jobmanager/JobController;->scheduleJobs(Ljava/util/List;)V @@ -25459,24 +24494,21 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JobLogger;->()V HSPLorg/thoughtcrime/securesms/jobmanager/JobLogger;->()V HSPLorg/thoughtcrime/securesms/jobmanager/JobLogger;->format(Lorg/thoughtcrime/securesms/jobmanager/Job;Ljava/lang/String;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobmanager/JobLogger;->format(Lorg/thoughtcrime/securesms/jobmanager/Job;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda0;->run()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;Landroid/app/Application;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda10;->run()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda14;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda14;->run()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda15;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda15;->run()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda17;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Ljava/lang/Runnable;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda11;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda11;->run()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda17;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda17;->run()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda5;->run()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda7;->()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda7;->shouldRunOnExecutor()Z -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda8;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda8;->onEmpty()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda9;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;Landroid/app/Application;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda9;->run()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda19;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Ljava/lang/Runnable;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda19;->run()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda1;->run()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda6;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda6;->run()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda8;->()V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda8;->shouldRunOnExecutor()Z +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda9;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;->(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;->enqueue()V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;->getJobListChain()Ljava/util/List; @@ -25501,13 +24533,11 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;->getJobStora HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;->getJobThreadCount()I HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;->getJobTracker()Lorg/thoughtcrime/securesms/jobmanager/JobTracker; HSPLorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;->getReservedJobRunners()Ljava/util/List; +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$88wGNi-R9qqqYZRd2q8yENxgty8(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$B0N_1IwVaEFBHupl4Ii7Rtasq5s(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$DYTfX8v0cQlWrG6BZ9230vJDgZM(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$LRMTzBAnZzMhc-JGu7V6yfyQyoc(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$XT2SMZJxrQFMSviwHBjZhWrZ8u4(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;Landroid/app/Application;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$bAbo4Wrv-lAy710xL25n75tW6EQ(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$g0KT-wHqpu8YO4Bvu-23NaTXOYA(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Ljava/lang/Runnable;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$sAhOIfgF3Tsjgqk6ejbaAJGNqJA(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$tbQpu2orId1zOGFwRjHuKH7CxGc(Lorg/thoughtcrime/securesms/jobmanager/JobManager;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->$r8$lambda$n2_WnBTSP7W-v9B5XsgvQbvhaaA(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->-$$Nest$menqueueChain(Lorg/thoughtcrime/securesms/jobmanager/JobManager;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->()V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->(Landroid/app/Application;Lorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;)V @@ -25515,14 +24545,12 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->add(Lorg/thoughtcrime/sec HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->addOnEmptyQueueListener(Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->beginJobLoop()V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->enqueueChain(Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$addOnEmptyQueueListener$10(Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$addOnEmptyQueueListener$11(Lorg/thoughtcrime/securesms/jobmanager/JobManager$EmptyQueueListener;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$beginJobLoop$1()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$enqueueChain$12(Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$enqueueChain$13(Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$new$0(Lorg/thoughtcrime/securesms/jobmanager/JobManager$Configuration;Landroid/app/Application;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$onEmptyQueue$13()V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$runOnExecutor$14(Ljava/lang/Runnable;)V +HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->lambda$runOnExecutor$15(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->onConstraintMet(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->onEmptyQueue()V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->runOnExecutor(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->startChain(Lorg/thoughtcrime/securesms/jobmanager/Job;)Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain; HSPLorg/thoughtcrime/securesms/jobmanager/JobManager;->waitUntilInitialized()V @@ -25582,9 +24610,16 @@ HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->()V HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Lorg/thoughtcrime/securesms/jobmanager/JsonJobData-IA;)V HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->deserialize([B)Lorg/thoughtcrime/securesms/jobmanager/JsonJobData; +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getBoolean(Ljava/lang/String;)Z +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getBooleanOrDefault(Ljava/lang/String;Z)Z +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getLong(Ljava/lang/String;)J +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getString(Ljava/lang/String;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->hasBoolean(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->hasInt(Ljava/lang/String;)Z +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->hasString(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->isEmpty()Z HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->serialize()[B +HSPLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->throwIfAbsent(Ljava/util/Map;Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/jobmanager/impl/AutoDownloadEmojiConstraint$Factory;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/jobmanager/impl/AutoDownloadEmojiConstraint$Factory;->create()Lorg/thoughtcrime/securesms/jobmanager/Constraint; HSPLorg/thoughtcrime/securesms/jobmanager/impl/AutoDownloadEmojiConstraint$Factory;->create()Lorg/thoughtcrime/securesms/jobmanager/impl/AutoDownloadEmojiConstraint; @@ -25730,17 +24765,29 @@ HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Companion;->enqueueIfNecessary()V HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob; HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->()V HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->()V HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V +HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->enqueueIfNecessary()V HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->onRun()V +HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->onShouldRetry(Ljava/lang/Exception;)Z HSPLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/ApkUpdateJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/ApkUpdateJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/AttachmentCompressionJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/AttachmentCopyJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->()V +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->(JLorg/thoughtcrime/securesms/attachments/AttachmentId;Z)V +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;JLorg/thoughtcrime/securesms/attachments/AttachmentId;Z)V +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->constructQueueString(Lorg/thoughtcrime/securesms/attachments/AttachmentId;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->onAdded()V +HSPLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/AttachmentMarkUploadedJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/AttachmentUploadJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/AttachmentUploadJob$Factory;->()V @@ -25749,6 +24796,7 @@ HSPLorg/thoughtcrime/securesms/jobs/AvatarGroupsV1DownloadJob$Factory;->() HSPLorg/thoughtcrime/securesms/jobs/AvatarGroupsV2DownloadJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/BaseJob;->()V HSPLorg/thoughtcrime/securesms/jobs/BaseJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V +HSPLorg/thoughtcrime/securesms/jobs/BaseJob;->getNextRunAttemptBackoff(ILjava/lang/Exception;)J HSPLorg/thoughtcrime/securesms/jobs/BaseJob;->run()Lorg/thoughtcrime/securesms/jobmanager/Job$Result; HSPLorg/thoughtcrime/securesms/jobs/BaseJob;->shouldTrace()Z HSPLorg/thoughtcrime/securesms/jobs/BaseJob;->warn(Ljava/lang/String;Ljava/lang/String;)V @@ -25778,21 +24826,42 @@ HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Companion;->(L HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Companion;->create()Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob; HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob; +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1;->(Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/util/concurrent/CountDownLatch;)V +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1;->invoke(Lorg/thoughtcrime/securesms/mediasend/Media;)V +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$2;->(Ljava/util/concurrent/CountDownLatch;)V HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->()V HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->access$getContext$p$s1046862181(Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;)Landroid/content/Context; HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->onRun()V HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->serialize()[B +HSPLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->setAvatar(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob; HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->()V HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V +HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/recipients/Recipient;ZLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob-IA;)V HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->(Lorg/thoughtcrime/securesms/recipients/Recipient;Z)V HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->(Z)V HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->onRun()V HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->serialize()[B +HSPLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->shouldTrace()Z HSPLorg/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda0;->()V +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda10;->produce()Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda1;->(Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda1;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda2;->(Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda2;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda3;->()V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda4;->(I)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda4;->compare(Ljava/lang/Object;Ljava/lang/Object;)I HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda5;->()V @@ -25807,17 +24876,23 @@ HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheti HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob; +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->$r8$lambda$QoH7dcHnoANVuwa796Z9UVq8P10(Ljava/lang/String;Ljava/io/File;)Z HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->$r8$lambda$dkoZGu-68WkVhszwd5d_cWNZrJU(ILcom/annimon/stream/IntPair;Lcom/annimon/stream/IntPair;)I +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->$r8$lambda$svSYKFZ54wbzF4p08Dr861zOX4Y(Ljava/lang/String;Ljava/io/File;)Z HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->()V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->(Z)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->assertRemoteDownloadConstraints(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->clearOldEmojiData(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->downloadImages(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;Ljava/util/List;Ljava/lang/String;Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$Producer;)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->downloadJson(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)Lorg/thoughtcrime/securesms/emoji/EmojiData; HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->getDesiredRemoteBucketForDensity(Lorg/thoughtcrime/securesms/util/ScreenDensity;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->getFactoryKey()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->getRemoteImageHash(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;Ljava/lang/String;Ljava/lang/String;)[B +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->lambda$clearOldEmojiData$2(Ljava/lang/String;Ljava/io/File;)Z +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->lambda$clearOldEmojiData$3(Ljava/lang/String;Ljava/io/File;)Z HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->lambda$resolveDensity$0(ILcom/annimon/stream/IntPair;Lcom/annimon/stream/IntPair;)I +HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->markComplete(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->onRun()V HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->resolveDensity(Ljava/util/List;Ljava/lang/String;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->scheduleIfNecessary(Landroid/content/Context;)V @@ -25869,16 +24944,18 @@ HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->deleteJobs$lambda$28(Lkotli HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->deleteJobs(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getAllJobSpecs()Ljava/util/List; HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getConstraintSpecs(Ljava/lang/String;)Ljava/util/List; +HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getDependencySpecsThatDependOnJob(Ljava/lang/String;)Ljava/util/List; HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getJobById(Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec; HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getJobCountForFactory(Ljava/lang/String;)I HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getJobCountForFactoryAndQueue(Ljava/lang/String;Ljava/lang/String;)I HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getJobSpec(Ljava/lang/String;)Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec; -HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getMigrationJob()Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec; +HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getSingleLayerOfDependencySpecsThatDependOnJob(Ljava/lang/String;)Ljava/util/List; HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->hasEligibleRunTime(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;J)Z HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->init()V HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->insertJobs(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->markJobAsRunning(Ljava/lang/String;J)V HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->updateAllJobsToBePending()V +HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->updateJobAfterRetry(Ljava/lang/String;JIJ[B)V HSPLorg/thoughtcrime/securesms/jobs/FastJobStorage;->updateJobs(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/jobs/FcmRefreshJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/FetchRemoteMegaphoneImageJob$Factory;->()V @@ -25890,6 +24967,8 @@ HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/FontDownloaderJob; HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$onRun$listener$1;->(Ljava/util/concurrent/CountDownLatch;Ljava/util/concurrent/atomic/AtomicInteger;)V +HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$onRun$listener$1;->onSuccess(Landroid/graphics/Typeface;)V +HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$onRun$listener$1;->onSuccess(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob;->()V HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob;->()V HSPLorg/thoughtcrime/securesms/jobs/FontDownloaderJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V @@ -25911,11 +24990,14 @@ HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Companion;->(Lkotl HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Companion;->enqueue()V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob; HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->()V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->enqueue()V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->onRun()V HSPLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob;->()V @@ -25936,7 +25018,6 @@ HSPLorg/thoughtcrime/securesms/jobs/LocalBackupJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/LocalBackupJobApi29$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MarkerJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MessageFetchJob$Factory;->()V -HSPLorg/thoughtcrime/securesms/jobs/MmsSendJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob$Factory;->()V @@ -25949,10 +25030,14 @@ HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceMessageRequestResponseJob$Factory HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceOutgoingPaymentSyncJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileContentUpdateJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob; HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V +HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob-IA;)V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->onFailure()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceReadUpdateJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/MultiDeviceStickerPackOperationJob$Factory;->()V @@ -25983,7 +25068,8 @@ HSPLorg/thoughtcrime/securesms/jobs/PnpInitializeDevicesJob;->()V HSPLorg/thoughtcrime/securesms/jobs/PnpInitializeDevicesJob;->enqueueIfNecessary()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->create()Lorg/thoughtcrime/securesms/jobs/PreKeysSyncJob; +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->create$default(Lorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;ZILjava/lang/Object;)Lorg/thoughtcrime/securesms/jobs/PreKeysSyncJob; +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->create(Z)Lorg/thoughtcrime/securesms/jobs/PreKeysSyncJob; HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->enqueue()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Companion;->enqueueIfNeeded()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Factory;->()V @@ -25991,21 +25077,29 @@ HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/PreKeysSyncJob; HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->()V -HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->()V -HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V -HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Z)V +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->(Z)V +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->(ZILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->access$getTAG$cp()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->enqueue()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->enqueueIfNeeded()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->onFailure()V HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->onRun()V +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->onShouldRetry(Ljava/lang/Exception;)Z HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->serialize()[B +HSPLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->syncPreKeys(Lorg/whispersystems/signalservice/api/push/ServiceIdType;Lorg/whispersystems/signalservice/api/push/ServiceId;Lorg/whispersystems/signalservice/api/SignalServiceAccountDataStore;Lorg/thoughtcrime/securesms/crypto/storage/PreKeyMetadataStore;Z)V HSPLorg/thoughtcrime/securesms/jobs/ProfileKeySendJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/ProfileUploadJob; HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->()V HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->()V HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V +HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/jobs/ProfileUploadJob-IA;)V HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->onFailure()V HSPLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/PushDistributionListSendJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/PushGroupSendJob$Factory;->()V @@ -26022,11 +25116,17 @@ HSPLorg/thoughtcrime/securesms/jobs/RebuildMessageSearchIndexJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/ReclaimUsernameAndLinkJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/RefreshAttributesJob; HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->()V HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->()V HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Z)V +HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;ZLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob-IA;)V HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->(Z)V HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->onFailure()V +HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->onRun()V +HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->onShouldRetry(Ljava/lang/Exception;)Z HSPLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/RefreshCallLinkDetailsJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/RefreshCallLinkDetailsJob$Factory;->()V @@ -26077,6 +25177,7 @@ HSPLorg/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob;->access$getTAG$cp()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob;->enqueue()V +HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob$1;->()V HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/RotateCertificateJob; @@ -26086,7 +25187,9 @@ HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->(Lorg/thoughtcr HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/jobs/RotateCertificateJob-IA;)V HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->getFactoryKey()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->onAdded()V +HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->onFailure()V HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->onRun()V +HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->onShouldRetry(Ljava/lang/Exception;)Z HSPLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/RotateProfileKeyJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/RotateProfileKeyJob;->()V @@ -26098,10 +25201,16 @@ HSPLorg/thoughtcrime/securesms/jobs/SendRetryReceiptJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/SendViewedReceiptJob$Factory;->(Landroid/app/Application;)V HSPLorg/thoughtcrime/securesms/jobs/SenderKeyDistributionSendJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/ServiceOutageDetectionJob$Factory;->()V -HSPLorg/thoughtcrime/securesms/jobs/SmsSendJob$Factory;->()V -HSPLorg/thoughtcrime/securesms/jobs/SmsSentJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/StickerDownloadJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob; +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob;->()V +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Ljava/lang/String;Ljava/lang/String;ZZ)V +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Ljava/lang/String;Ljava/lang/String;ZZLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob-IA;)V +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob;->onFailure()V +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob;->onRun()V +HSPLorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob;->onShouldRetry(Ljava/lang/Exception;)Z HSPLorg/thoughtcrime/securesms/jobs/StorageAccountRestoreJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/StorageAccountRestoreJob;->()V HSPLorg/thoughtcrime/securesms/jobs/StorageForcePushJob$Factory;->()V @@ -26112,11 +25221,15 @@ HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Companion;->creat HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Companion;->enqueueIfNeeded()V HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob; HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->()V HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->access$getTAG$cp()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->getFactoryKey()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->getLocaleCodes()Ljava/util/List; +HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->onRun()V HSPLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/SubmitRateLimitPushChallengeJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/SubscriptionKeepAliveJob$Factory;->()V @@ -26135,15 +25248,29 @@ HSPLorg/thoughtcrime/securesms/jobs/SyncSystemContactLinksJob$Factory;->() HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$$ExternalSyntheticLambda0;->(J)V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$$ExternalSyntheticLambda0;->run()V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; +HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/ThreadUpdateJob; HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->$r8$lambda$JSigGKNJwOMmimqwpu8xPBnW5UQ(J)V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->(J)V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;J)V +HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;JLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob-IA;)V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->enqueue(J)V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->getFactoryKey()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->lambda$enqueue$0(J)V +HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->onRun()V HSPLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->serialize()[B HSPLorg/thoughtcrime/securesms/jobs/TrimThreadJob$Factory;->()V HSPLorg/thoughtcrime/securesms/jobs/TypingSendJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion$ADAPTER$1;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Lcom/squareup/wire/Syntax;)V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion$ADAPTER$1;->decode(Lcom/squareup/wire/ProtoReader;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion$ADAPTER$1;->decode(Lcom/squareup/wire/ProtoReader;)Lorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData; +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion$ADAPTER$1;->encode(Lcom/squareup/wire/ReverseProtoWriter;Ljava/lang/Object;)V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion$ADAPTER$1;->encode(Lcom/squareup/wire/ReverseProtoWriter;Lorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData;)V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion;->()V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData;->()V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData;->(ZLokio/ByteString;)V +HSPLorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData;->(ZLokio/ByteString;ILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/keyboard/KeyboardPage;->$values()[Lorg/thoughtcrime/securesms/keyboard/KeyboardPage; HSPLorg/thoughtcrime/securesms/keyboard/KeyboardPage;->()V HSPLorg/thoughtcrime/securesms/keyboard/KeyboardPage;->(Ljava/lang/String;I)V @@ -26159,6 +25286,15 @@ HSPLorg/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$Companion;->()V HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState$Companion;->()V +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState$Companion;->deserialize(J)Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState; +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;->$values()[Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState; +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;->()V +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;->(Ljava/lang/String;IJ)V +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;->access$getValue$p(Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;)J +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;->serialize()J +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState;->values()[Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$aciPreKeys$1;->()V HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$aciPreKeys$1;->(Lorg/thoughtcrime/securesms/keyvalue/AccountValues;)V HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues$aciPreKeys$1;->getNextKyberPreKeyId()I @@ -26191,6 +25327,7 @@ HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->generatePniIdentityKeyIf HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getAci()Lorg/whispersystems/signalservice/api/push/ServiceId$ACI; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getAciIdentityKey()Lorg/signal/libsignal/protocol/IdentityKeyPair; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getDeviceId()I +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getDeviceName()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getE164()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getPni()Lorg/whispersystems/signalservice/api/push/ServiceId$PNI; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getPniIdentityKey()Lorg/signal/libsignal/protocol/IdentityKeyPair; @@ -26198,6 +25335,7 @@ HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getPniRegistrationId()I HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getRegistrationId()I HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getServicePassword()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getUsername()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getUsernameSyncState()Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState; HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->hasAciIdentityKey()Z HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->hasPniIdentityKey()Z HSPLorg/thoughtcrime/securesms/keyvalue/AccountValues;->hasStringData(Landroid/content/SharedPreferences;Ljava/lang/String;)Z @@ -26231,6 +25369,7 @@ HSPLorg/thoughtcrime/securesms/keyvalue/BooleanValue;->setValue$Signal_Android_p HSPLorg/thoughtcrime/securesms/keyvalue/CertificateType;->$values()[Lorg/thoughtcrime/securesms/keyvalue/CertificateType; HSPLorg/thoughtcrime/securesms/keyvalue/CertificateType;->()V HSPLorg/thoughtcrime/securesms/keyvalue/CertificateType;->(Ljava/lang/String;I)V +HSPLorg/thoughtcrime/securesms/keyvalue/CertificateType;->values()[Lorg/thoughtcrime/securesms/keyvalue/CertificateType; HSPLorg/thoughtcrime/securesms/keyvalue/CertificateValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/ChatColorsValues$Companion;->()V HSPLorg/thoughtcrime/securesms/keyvalue/ChatColorsValues$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -26260,6 +25399,7 @@ HSPLorg/thoughtcrime/securesms/keyvalue/DonationsValues;->setPending3DSData(Lorg HSPLorg/thoughtcrime/securesms/keyvalue/DonationsValues;->setVerifiedSubscription3DSData(Lorg/thoughtcrime/securesms/components/settings/app/subscription/donate/stripe/Stripe3DSData;)V HSPLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V +HSPLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->getJumboEmojiSheets(I)Ljava/util/HashSet; HSPLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->getLastSearchIndexCheck()J HSPLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->getNextScheduledImageCheck()J HSPLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->getSearchVersion()I @@ -26375,16 +25515,17 @@ HSPLorg/thoughtcrime/securesms/keyvalue/PaymentsValues$liveMobileCoinBalance$2;- HSPLorg/thoughtcrime/securesms/keyvalue/PaymentsValues$liveMobileCoinLedger$2;->(Lorg/thoughtcrime/securesms/keyvalue/PaymentsValues;)V HSPLorg/thoughtcrime/securesms/keyvalue/PaymentsValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/PaymentsValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->$values()[Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode; -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->()V -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->(Ljava/lang/String;II)V -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->deserialize(I)Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode; -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->serialize()I -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->values()[Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode; +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode;->$values()[Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode; +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode;->()V +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode;->(Ljava/lang/String;II)V +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode;->deserialize(I)Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode; +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode;->serialize()I +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode;->values()[Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode; HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->getPhoneNumberListingMode()Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode; -HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->getPhoneNumberListingModeTimestamp()J +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->getAllCertificateTypes()Ljava/util/Collection; +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->getPhoneNumberDiscoverabilityMode()Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode; +HSPLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->getPhoneNumberDiscoverabilityModeTimestamp()J HSPLorg/thoughtcrime/securesms/keyvalue/PinValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/PinValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/PlainTextSharedPrefsDataStore$Companion;->()V @@ -26403,6 +25544,7 @@ HSPLorg/thoughtcrime/securesms/keyvalue/ReleaseChannelValues$Companion;->( HSPLorg/thoughtcrime/securesms/keyvalue/ReleaseChannelValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/ReleaseChannelValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/ReleaseChannelValues;->getReleaseChannelRecipientId()Lorg/thoughtcrime/securesms/recipients/RecipientId; +HSPLorg/thoughtcrime/securesms/keyvalue/ReleaseChannelValues;->setReleaseChannelRecipientId(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/keyvalue/RemoteConfigValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/RemoteConfigValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/RemoteConfigValues;->getCurrentConfig()Ljava/lang/String; @@ -26419,13 +25561,11 @@ HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;->$values()[Lorg/th HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;->()V HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;->(Ljava/lang/String;ILjava/lang/String;)V HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;->deserialize(Ljava/lang/String;)Lorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme; -HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;->values()[Lorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme; HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getCensorshipCircumventionEnabled()Lorg/thoughtcrime/securesms/keyvalue/SettingsValues$CensorshipCircumventionEnabled; HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getKeepMessagesDuration()Lorg/thoughtcrime/securesms/keyvalue/KeepMessagesDuration; HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getLanguage()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getMessageFontSize()I HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getMessageLedColor()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getMessageNotificationSound()Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getMessageNotificationsPrivacy()Lorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference; @@ -26434,12 +25574,10 @@ HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getUniversalExpireTimer HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->getUseCompactNavigationBar()Z HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isBackupEnabled()Z HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isEnterKeySends()Z -HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isLinkPreviewsEnabled()Z HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isMessageNotificationsEnabled()Z HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isMessageVibrateEnabled()Z HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isPreferSystemContactPhotos()Z HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isPreferSystemEmoji()Z -HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->setDefaultSms(Z)V HSPLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->shouldKeepMutedChatsArchived()Z HSPLorg/thoughtcrime/securesms/keyvalue/SignalStore;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/SignalStore;->account()Lorg/thoughtcrime/securesms/keyvalue/AccountValues; @@ -26500,6 +25638,7 @@ HSPLorg/thoughtcrime/securesms/keyvalue/StoryValues;->getLastFontVersionCheck()J HSPLorg/thoughtcrime/securesms/keyvalue/StoryValues;->getLatestActiveStorySendTimestamps(J)Ljava/util/List; HSPLorg/thoughtcrime/securesms/keyvalue/StoryValues;->getUserHasViewedOnboardingStory()Z HSPLorg/thoughtcrime/securesms/keyvalue/StoryValues;->isFeatureDisabled()Z +HSPLorg/thoughtcrime/securesms/keyvalue/StoryValues;->setHasDownloadedOnboardingStory(Z)V HSPLorg/thoughtcrime/securesms/keyvalue/StoryValues;->setLastFontVersionCheck(J)V HSPLorg/thoughtcrime/securesms/keyvalue/StringValue;->(Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/StringValue;->getValue$Signal_Android_playProdBenchmark(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)Ljava/lang/Object; @@ -26507,52 +25646,29 @@ HSPLorg/thoughtcrime/securesms/keyvalue/StringValue;->getValue$Signal_Android_pl HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->clearRegistrationLockAndPin()V HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->getLocalPinHash()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->getMasterKey()Lorg/whispersystems/signalservice/api/kbs/MasterKey; HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->getOrCreateMasterKey()Lorg/whispersystems/signalservice/api/kbs/MasterKey; +HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->getRecoveryPassword()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->hasOptedOut()Z HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->hasPin()Z +HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->isRegistrationLockEnabled()Z HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->lastPinCreateFailed()Z HSPLorg/thoughtcrime/securesms/keyvalue/SvrValues;->optOut()V HSPLorg/thoughtcrime/securesms/keyvalue/TooltipValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/UiHints;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/UiHints;->canDisplayPullToFilterTip()Z HSPLorg/thoughtcrime/securesms/keyvalue/UiHints;->getNeverDisplayPullToFilterTip()I +HSPLorg/thoughtcrime/securesms/keyvalue/UiHints;->hasCompletedUsernameOnboarding()Z HSPLorg/thoughtcrime/securesms/keyvalue/WallpaperValues;->()V HSPLorg/thoughtcrime/securesms/keyvalue/WallpaperValues;->(Lorg/thoughtcrime/securesms/keyvalue/KeyValueStore;)V HSPLorg/thoughtcrime/securesms/keyvalue/WallpaperValues;->getCurrentWallpaper()Lorg/thoughtcrime/securesms/database/model/databaseprotos/Wallpaper; HSPLorg/thoughtcrime/securesms/keyvalue/WallpaperValues;->getWallpaper()Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper; -HSPLorg/thoughtcrime/securesms/keyvalue/WallpaperValues;->hasWallpaperSet()Z -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion;->forNoLinks()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Creator;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->(Ljava/lang/String;ZZLorg/thoughtcrime/securesms/linkpreview/LinkPreview;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository$Error;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->(Ljava/lang/String;ZZLorg/thoughtcrime/securesms/linkpreview/LinkPreview;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository$Error;Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->hasContent()Z -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->hasLinks()Z -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$Companion;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->invoke()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1;->(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1;->invoke(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->()V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->(Landroidx/lifecycle/SavedStateHandle;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;Z)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->(Landroidx/lifecycle/SavedStateHandle;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->access$setSavedLinkPreviewState(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->getLinkPreviewState()Lio/reactivex/rxjava3/core/Flowable; -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->getSavedLinkPreviewState()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; -HSPLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->setSavedLinkPreviewState(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V HSPLorg/thoughtcrime/securesms/logging/CustomSignalProtocolLogger;->()V HSPLorg/thoughtcrime/securesms/logging/CustomSignalProtocolLogger;->log(ILjava/lang/String;Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$Companion;->()V HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest;->(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/Throwable;Z)V +HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest;->getCreateTime()J HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest;->getKeepLonger()Z HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest;->getLevel()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest;->getMessage()Ljava/lang/String; @@ -26576,7 +25692,6 @@ HSPLorg/thoughtcrime/securesms/logging/PersistentLogger;->getThreadString()Ljava HSPLorg/thoughtcrime/securesms/logging/PersistentLogger;->i(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Z)V HSPLorg/thoughtcrime/securesms/logging/PersistentLogger;->w(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Z)V HSPLorg/thoughtcrime/securesms/logging/PersistentLogger;->write(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Z)V -HSPLorg/thoughtcrime/securesms/logsubmit/LogSectionNotifications$$ExternalSyntheticApiModelOutline2;->m(Landroid/app/NotificationChannel;)Z HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment$$ExternalSyntheticLambda0;->()V HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment$$ExternalSyntheticLambda0;->run()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/main/MainActivityListHostFragment;)V @@ -26628,6 +25743,10 @@ HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment;->presentToolba HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment;->presentToolbarForDestination(Landroidx/navigation/NavDestination;)V HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment;->updateNotificationProfileStatus(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/main/MainActivityListHostFragment;->updateProxyStatus(Lorg/whispersystems/signalservice/api/websocket/WebSocketConnectionState;)V +HSPLorg/thoughtcrime/securesms/mediasend/Media$1;->()V +HSPLorg/thoughtcrime/securesms/mediasend/Media;->()V +HSPLorg/thoughtcrime/securesms/mediasend/Media;->(Landroid/net/Uri;Ljava/lang/String;JIIJJZZLj$/util/Optional;Lj$/util/Optional;Lj$/util/Optional;)V +HSPLorg/thoughtcrime/securesms/mediasend/Media;->getUri()Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/megaphone/ForeverSchedule;->(Z)V HSPLorg/thoughtcrime/securesms/megaphone/ForeverSchedule;->shouldDisplay(IJJJ)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetbodyText(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; @@ -26635,10 +25754,10 @@ HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetbuttonL HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetbuttonText(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetcanSnooze(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetevent(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetimageRequest(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/mms/GlideRequest; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetimageRes(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)I HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetlottieRes(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)I HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetonVisibleListener(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetrequestBuilder(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lcom/bumptech/glide/RequestBuilder; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetsecondaryButtonListener(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetsecondaryButtonText(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetsnoozeListener(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener; @@ -26646,6 +25765,11 @@ HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgetstyle(L HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->-$$Nest$fgettitleText(Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;)Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;Lorg/thoughtcrime/securesms/megaphone/Megaphone$Style;)V HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->build()Lorg/thoughtcrime/securesms/megaphone/Megaphone; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->setActionButton(ILorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener;)Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->setBody(I)Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->setImage(I)Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->setSecondaryButton(ILorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener;)Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Builder;->setTitle(I)Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Style;->$values()[Lorg/thoughtcrime/securesms/megaphone/Megaphone$Style; HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Style;->()V HSPLorg/thoughtcrime/securesms/megaphone/Megaphone$Style;->(Ljava/lang/String;I)V @@ -26691,27 +25815,36 @@ HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneRepository;->markFinished(Lorg HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneRepository;->markVisible(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;)V HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneRepository;->onAppForegrounded()V HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneRepository;->resetDatabaseCache()V +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText$Companion;->()V +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText$Companion;->from(I)Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText;->()V +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText;->(ILjava/lang/String;)V +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText;->(ILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneText;->from(I)Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneViewBuilder$1;->()V HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneViewBuilder;->build(Landroid/content/Context;Lorg/thoughtcrime/securesms/megaphone/Megaphone;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)Landroid/view/View; HSPLorg/thoughtcrime/securesms/megaphone/MegaphoneViewBuilder;->buildOnboardingMegaphone(Landroid/content/Context;Lorg/thoughtcrime/securesms/megaphone/Megaphone;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)Landroid/view/View; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda18;->(Ljava/util/Map;J)V -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda18;->test(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda19;->()V -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda19;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda20;->(Ljava/util/Map;)V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda0;->()V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda19;->(Ljava/util/Map;J)V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda19;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda1;->()V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda20;->()V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda20;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda21;->(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda21;->(Ljava/util/Map;)V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda21;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda2;->()V -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda2;->test(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;)V -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda3;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda22;->(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda22;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda4;->()V -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda4;->apply(Ljava/lang/Object;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda5;->()V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda4;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;)V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda5;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda6;->()V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda6;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda7;->()V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda7;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda8;->()V +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda8;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$1;->(Landroid/content/Context;Ljava/util/Map;)V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$3;->()V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$Event;->$values()[Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event; @@ -26721,10 +25854,10 @@ HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$Event;->fromKey(Ljava/lang/S HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$Event;->getKey()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$Event;->hasKey(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones$Event;->values()[Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$57Iylt9yWAB65XCua6kCFNHv3Ho(Ljava/util/Map$Entry;)Ljava/lang/Long; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$Jd3YY1Tctc615OoR-BunWBsX5AM(Ljava/lang/Long;)Z -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$StkmuqSPG82Z8-YWKFWZC31YUUs(Ljava/util/Map$Entry;)Z -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$bfAOsFTMV105nBLDPhyo5-_RYW0(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;Ljava/util/Map$Entry;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$PIMhmmzwnmuRXoXqQmaSjV_KAVA(Ljava/util/Map$Entry;)Ljava/lang/Long; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$YpoSl2MBeUbMiv4CB5UIXMEi5Dk(Ljava/lang/Long;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$iF2prwdoNwztORLiNF2IU1hb4Xg(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;Ljava/util/Map$Entry;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$iZmqBQeABnviaUaUIqqXo5ljPj8(Ljava/util/Map$Entry;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$jKOYs4kAlzGKOSd0Gb2wil_axMM(Ljava/util/Map;JLjava/util/Map$Entry;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->$r8$lambda$ya9b6y2SFOc06_b4NHtqa2lYZ44(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MegaphoneRecord;)Lorg/thoughtcrime/securesms/megaphone/Megaphone; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$sfgetALWAYS()Lorg/thoughtcrime/securesms/megaphone/MegaphoneSchedule; @@ -26734,54 +25867,36 @@ HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowBackup HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowGrantFullScreenIntentPermission(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowNotificationsMegaphone(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowOnboardingMegaphone(Landroid/content/Context;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowPnpLaunchMegaphone()Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowRemoteMegaphone(Ljava/util/Map;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowSetUpYourUsernameMegaphone(Ljava/util/Map;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->-$$Nest$smshouldShowTurnOffCircumventionMegaphone()Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->()V HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->buildDisplayOrder(Landroid/content/Context;Ljava/util/Map;)Ljava/util/Map; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->buildOnboardingMegaphone()Lorg/thoughtcrime/securesms/megaphone/Megaphone; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->buildPnpLaunchMegaphone()Lorg/thoughtcrime/securesms/megaphone/Megaphone; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->forRecord(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MegaphoneRecord;)Lorg/thoughtcrime/securesms/megaphone/Megaphone; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->getNextMegaphone(Landroid/content/Context;Ljava/util/Map;)Lorg/thoughtcrime/securesms/megaphone/Megaphone; HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$getNextMegaphone$0(Ljava/util/Map;JLjava/util/Map$Entry;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$getNextMegaphone$1(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/MegaphoneRecord;)Lorg/thoughtcrime/securesms/megaphone/Megaphone; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$22(Ljava/util/Map$Entry;)Z -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$23(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;Ljava/util/Map$Entry;)Z -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$24(Ljava/util/Map$Entry;)Ljava/lang/Long; -HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$25(Ljava/lang/Long;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$23(Ljava/util/Map$Entry;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$24(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;Ljava/util/Map$Entry;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$25(Ljava/util/Map$Entry;)Ljava/lang/Long; +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->lambda$timeSinceLastDonatePrompt$26(Ljava/lang/Long;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowAddAProfilePhotoMegaphone(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowBackupSchedulePermissionMegaphone(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowGrantFullScreenIntentPermission(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowNotificationsMegaphone(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowOnboardingMegaphone(Landroid/content/Context;)Z +HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowPnpLaunchMegaphone()Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowRemoteMegaphone(Ljava/util/Map;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowSetUpYourUsernameMegaphone(Ljava/util/Map;)Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->shouldShowTurnOffCircumventionMegaphone()Z HSPLorg/thoughtcrime/securesms/megaphone/Megaphones;->timeSinceLastDonatePrompt(Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event;Ljava/util/Map;)J -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$AddPhotoCardViewHolder;->(Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$AddPhotoCardViewHolder;->getBackgroundColor()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$AddPhotoCardViewHolder;->getButtonStringRes()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$AddPhotoCardViewHolder;->getImageRes()I HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)V HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->buildData()Ljava/util/List; HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->getItemCount()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->getItemId(I)J -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->getItemViewType(I)I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->onBindViewHolder(Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder;I)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder; -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$ActionClickListener;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder;Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$ActionClickListener;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder;->(Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder;->bind(Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$ActionClickListener;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$GroupCardViewHolder;->(Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$GroupCardViewHolder;->getBackgroundColor()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$GroupCardViewHolder;->getButtonStringRes()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$GroupCardViewHolder;->getImageRes()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$InviteCardViewHolder;->(Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$InviteCardViewHolder;->getBackgroundColor()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$InviteCardViewHolder;->getButtonStringRes()I -HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$InviteCardViewHolder;->getImageRes()I +HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView;->-$$Nest$sfgetTAG()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView;->()V HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView;->initialize(Landroid/content/Context;)V @@ -26813,29 +25928,28 @@ HSPLorg/thoughtcrime/securesms/megaphone/RemoteMegaphoneRepository;->getRemoteMe HSPLorg/thoughtcrime/securesms/megaphone/RemoteMegaphoneRepository;->hasRemoteMegaphoneToShow(Z)Z HSPLorg/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule;->()V HSPLorg/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule;->shouldDisplay(IJJJ)Z -HSPLorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule$Companion;->()V -HSPLorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule;->()V -HSPLorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule;->shouldDisplay(IJJJ)Z HSPLorg/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver;->()V HSPLorg/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver;->startOrUpdateAlarm(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo$Companion;->()V +HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo;->()V -HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo;->(IILjava/lang/String;)V -HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo;->getDescription()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo;->(IILjava/lang/String;Z)V +HSPLorg/thoughtcrime/securesms/messagerequests/GroupInfo;->(IILjava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->()V HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/messagerequests/GroupInfo;Ljava/util/List;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;)V -HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component1()Lorg/thoughtcrime/securesms/recipients/Recipient; -HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component2()Lorg/thoughtcrime/securesms/messagerequests/GroupInfo; -HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component3()Ljava/util/List; -HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component4()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;->()V HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;->getMessageRequestState(Lorg/thoughtcrime/securesms/recipients/Recipient;J)Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository;->getRecipientInfo(Lorg/thoughtcrime/securesms/recipients/RecipientId;J)Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo; -HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->$values()[Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState$Companion;->()V +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State;->$values()[Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State; +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State;->()V +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State;->(Ljava/lang/String;I)V HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->()V -HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->(Ljava/lang/String;I)V +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->(Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State;Z)V +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->(Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->isAccepted()Z HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/messages/IncomingMessageObserver;)V HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver$$ExternalSyntheticLambda0;->run()V HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver$2;->(Lorg/thoughtcrime/securesms/messages/IncomingMessageObserver;)V @@ -26878,6 +25992,7 @@ HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->access$setDecr HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->access$waitForConnectionNecessary(Lorg/thoughtcrime/securesms/messages/IncomingMessageObserver;)V HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->addDecryptionDrainedListener(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->disconnect()V +HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->getDecryptionDrained()Z HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->isConnectionNecessary()Z HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->notifyRegistrationChanged()V HSPLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->onAppForegrounded()V @@ -26944,6 +26059,8 @@ HSPLorg/thoughtcrime/securesms/migrations/PinOptOutMigration$Factory;->()V HSPLorg/thoughtcrime/securesms/migrations/PinReminderMigrationJob$Factory;->()V HSPLorg/thoughtcrime/securesms/migrations/PniAccountInitializationMigrationJob$Factory;->()V HSPLorg/thoughtcrime/securesms/migrations/PniMigrationJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/migrations/PnpLaunchMigrationJob$Factory;->()V +HSPLorg/thoughtcrime/securesms/migrations/PnpLaunchMigrationJob$Factory;->()V HSPLorg/thoughtcrime/securesms/migrations/PreKeysSyncMigrationJob$Factory;->()V HSPLorg/thoughtcrime/securesms/migrations/PreKeysSyncMigrationJob$Factory;->()V HSPLorg/thoughtcrime/securesms/migrations/ProfileMigrationJob$Factory;->()V @@ -26978,46 +26095,16 @@ HSPLorg/thoughtcrime/securesms/migrations/UserNotificationMigrationJob$Factory;- HSPLorg/thoughtcrime/securesms/migrations/UuidMigrationJob$Factory;->()V HSPLorg/thoughtcrime/securesms/mms/AttachmentManager;->()V HSPLorg/thoughtcrime/securesms/mms/AttachmentManager;->(Landroid/content/Context;Landroid/view/View;Lorg/thoughtcrime/securesms/mms/AttachmentManager$AttachmentListener;)V -HSPLorg/thoughtcrime/securesms/mms/AttachmentManager;->isAttachmentPresent()Z HSPLorg/thoughtcrime/securesms/mms/AttachmentStreamUriLoader$Factory;->()V HSPLorg/thoughtcrime/securesms/mms/DecryptableStreamUriLoader$Factory;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/mms/GlideApp;->get(Landroid/content/Context;)Lcom/bumptech/glide/Glide; -HSPLorg/thoughtcrime/securesms/mms/GlideApp;->with(Landroid/content/Context;)Lorg/thoughtcrime/securesms/mms/GlideRequests; -HSPLorg/thoughtcrime/securesms/mms/GlideApp;->with(Landroid/view/View;)Lorg/thoughtcrime/securesms/mms/GlideRequests; -HSPLorg/thoughtcrime/securesms/mms/GlideApp;->with(Landroidx/fragment/app/Fragment;)Lorg/thoughtcrime/securesms/mms/GlideRequests; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->()V -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->apply(Lcom/bumptech/glide/request/BaseRequestOptions;)Lorg/thoughtcrime/securesms/mms/GlideOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->autoClone()Lcom/bumptech/glide/request/BaseRequestOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->autoClone()Lorg/thoughtcrime/securesms/mms/GlideOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->clone()Lcom/bumptech/glide/request/BaseRequestOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->clone()Lorg/thoughtcrime/securesms/mms/GlideOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->lock()Lcom/bumptech/glide/request/BaseRequestOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideOptions;->lock()Lorg/thoughtcrime/securesms/mms/GlideOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->(Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/RequestManager;Ljava/lang/Class;Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->apply(Lcom/bumptech/glide/request/BaseRequestOptions;)Lcom/bumptech/glide/RequestBuilder; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->apply(Lcom/bumptech/glide/request/BaseRequestOptions;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->diskCacheStrategy(Lcom/bumptech/glide/load/engine/DiskCacheStrategy;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->error(Landroid/graphics/drawable/Drawable;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->load(Ljava/lang/Object;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->override(I)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->override(II)Lcom/bumptech/glide/request/BaseRequestOptions; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->override(II)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequest;->transform(Lcom/bumptech/glide/load/Transformation;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequests;->(Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/manager/Lifecycle;Lcom/bumptech/glide/manager/RequestManagerTreeNode;Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/mms/GlideRequests;->as(Ljava/lang/Class;)Lcom/bumptech/glide/RequestBuilder; -HSPLorg/thoughtcrime/securesms/mms/GlideRequests;->as(Ljava/lang/Class;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequests;->asDrawable()Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/mms/GlideRequests;->setRequestOptions(Lcom/bumptech/glide/request/RequestOptions;)V HSPLorg/thoughtcrime/securesms/mms/ImageSlide;->()V HSPLorg/thoughtcrime/securesms/mms/ImageSlide;->(Lorg/thoughtcrime/securesms/attachments/Attachment;)V HSPLorg/thoughtcrime/securesms/mms/ImageSlide;->hasImage()Z -HSPLorg/thoughtcrime/securesms/mms/ImageSlide;->hasPlaceholder()Z -HSPLorg/thoughtcrime/securesms/mms/ImageSlide;->isBorderless()Z HSPLorg/thoughtcrime/securesms/mms/IncomingMessage$Companion;->()V HSPLorg/thoughtcrime/securesms/mms/IncomingMessage$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->()V -HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->(Lorg/thoughtcrime/securesms/database/MessageType;Lorg/thoughtcrime/securesms/recipients/RecipientId;JJJLorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/mms/MessageGroupContext;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/StoryType;Lorg/thoughtcrime/securesms/database/model/ParentStoryId;ZIJLorg/thoughtcrime/securesms/mms/QuoteModel;ZZLjava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge;)V -HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->(Lorg/thoughtcrime/securesms/database/MessageType;Lorg/thoughtcrime/securesms/recipients/RecipientId;JJJLorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/mms/MessageGroupContext;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/StoryType;Lorg/thoughtcrime/securesms/database/model/ParentStoryId;ZIJLorg/thoughtcrime/securesms/mms/QuoteModel;ZZLjava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->(Lorg/thoughtcrime/securesms/database/MessageType;Lorg/thoughtcrime/securesms/recipients/RecipientId;JJJLorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/mms/MessageGroupContext;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/StoryType;Lorg/thoughtcrime/securesms/database/model/ParentStoryId;ZIJLorg/thoughtcrime/securesms/mms/QuoteModel;ZZLjava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge;Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;)V +HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->(Lorg/thoughtcrime/securesms/database/MessageType;Lorg/thoughtcrime/securesms/recipients/RecipientId;JJJLorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/mms/MessageGroupContext;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/StoryType;Lorg/thoughtcrime/securesms/database/model/ParentStoryId;ZIJLorg/thoughtcrime/securesms/mms/QuoteModel;ZZLjava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge;Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras;ILkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getAttachments()Ljava/util/List; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getBody()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getExpiresIn()J @@ -27025,6 +26112,7 @@ HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getFrom()Lorg/thoughtcrime/ HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getGiftBadge()Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getLinkPreviews()Ljava/util/List; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getMentions()Ljava/util/List; +HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getMessageExtras()Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getMessageRanges()Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getParentStoryId()Lorg/thoughtcrime/securesms/database/model/ParentStoryId; HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->getQuote()Lorg/thoughtcrime/securesms/mms/QuoteModel; @@ -27040,6 +26128,7 @@ HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->isGroupMessage()Z HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->isUnidentified()Z HSPLorg/thoughtcrime/securesms/mms/IncomingMessage;->isViewOnce()Z HSPLorg/thoughtcrime/securesms/mms/PartAuthority;->()V +HSPLorg/thoughtcrime/securesms/mms/PartAuthority;->getEmojiFilename(Landroid/net/Uri;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/mms/PartAuthority;->getEmojiUri(Ljava/lang/String;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/mms/SentMediaQuality;->$values()[Lorg/thoughtcrime/securesms/mms/SentMediaQuality; HSPLorg/thoughtcrime/securesms/mms/SentMediaQuality;->()V @@ -27054,28 +26143,17 @@ HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule$Companion;->setRegisterGlid HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule;->()V HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule;->()V HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule;->applyOptions(Landroid/content/Context;Lcom/bumptech/glide/GlideBuilder;)V -HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule;->isManifestParsingEnabled()Z HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule;->registerComponents(Landroid/content/Context;Lcom/bumptech/glide/Glide;Lcom/bumptech/glide/Registry;)V HSPLorg/thoughtcrime/securesms/mms/SignalGlideModule;->setRegisterGlideComponents(Lorg/thoughtcrime/securesms/mms/RegisterGlideComponents;)V HSPLorg/thoughtcrime/securesms/mms/Slide;->(Lorg/thoughtcrime/securesms/attachments/Attachment;)V -HSPLorg/thoughtcrime/securesms/mms/Slide;->asAttachment()Lorg/thoughtcrime/securesms/attachments/Attachment; HSPLorg/thoughtcrime/securesms/mms/Slide;->getBody()Lj$/util/Optional; -HSPLorg/thoughtcrime/securesms/mms/Slide;->getCaption()Lj$/util/Optional; HSPLorg/thoughtcrime/securesms/mms/Slide;->getContentType()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/mms/Slide;->getFileSize()J -HSPLorg/thoughtcrime/securesms/mms/Slide;->getPlaceholderBlur()Lorg/thoughtcrime/securesms/blurhash/BlurHash; -HSPLorg/thoughtcrime/securesms/mms/Slide;->getTransferState()I HSPLorg/thoughtcrime/securesms/mms/Slide;->getUri()Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/mms/Slide;->hasAudio()Z HSPLorg/thoughtcrime/securesms/mms/Slide;->hasDocument()Z HSPLorg/thoughtcrime/securesms/mms/Slide;->hasSticker()Z HSPLorg/thoughtcrime/securesms/mms/Slide;->hasVideo()Z -HSPLorg/thoughtcrime/securesms/mms/Slide;->hashCode()I -HSPLorg/thoughtcrime/securesms/mms/Slide;->isInProgress()Z -HSPLorg/thoughtcrime/securesms/mms/Slide;->isPendingDownload()Z HSPLorg/thoughtcrime/securesms/mms/Slide;->isVideoGif()Z -HSPLorg/thoughtcrime/securesms/mms/SlideDeck$$ExternalSyntheticLambda0;->()V -HSPLorg/thoughtcrime/securesms/mms/SlideDeck$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getAudioSlide()Lorg/thoughtcrime/securesms/mms/AudioSlide; HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getBody()Ljava/lang/String; @@ -27084,7 +26162,6 @@ HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getSlides()Ljava/util/List; HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getStickerSlide()Lorg/thoughtcrime/securesms/mms/StickerSlide; HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getTextSlide()Lorg/thoughtcrime/securesms/mms/TextSlide; HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getThumbnailSlide()Lorg/thoughtcrime/securesms/mms/Slide; -HSPLorg/thoughtcrime/securesms/mms/SlideDeck;->getThumbnailSlides()Ljava/util/List; HSPLorg/thoughtcrime/securesms/mms/SlideFactory$MediaType;->$values()[Lorg/thoughtcrime/securesms/mms/SlideFactory$MediaType; HSPLorg/thoughtcrime/securesms/mms/SlideFactory$MediaType;->()V HSPLorg/thoughtcrime/securesms/mms/SlideFactory$MediaType;->(Ljava/lang/String;ILjava/lang/String;)V @@ -27144,9 +26221,8 @@ HSPLorg/thoughtcrime/securesms/net/StaticDns;->(Ljava/util/Map;)V HSPLorg/thoughtcrime/securesms/net/UserAgentInterceptor;->(Ljava/lang/String;)V HSPLorg/thoughtcrime/securesms/net/UserAgentInterceptor;->intercept(Lokhttp3/Interceptor$Chain;)Lokhttp3/Response; HSPLorg/thoughtcrime/securesms/notifications/Configuration;->()V -HSPLorg/thoughtcrime/securesms/notifications/Configuration;->(JIFIIJI)V -HSPLorg/thoughtcrime/securesms/notifications/Configuration;->getMessageLatencyPercentage()I -HSPLorg/thoughtcrime/securesms/notifications/Configuration;->getMessageLatencyThreshold()J +HSPLorg/thoughtcrime/securesms/notifications/Configuration;->(JIFIILjava/util/Map;)V +HSPLorg/thoughtcrime/securesms/notifications/Configuration;->getMessageLatencyPercentiles()Ljava/util/Map; HSPLorg/thoughtcrime/securesms/notifications/Configuration;->getMinimumEventAgeMs()J HSPLorg/thoughtcrime/securesms/notifications/Configuration;->getMinimumMessageLatencyEvents()I HSPLorg/thoughtcrime/securesms/notifications/Configuration;->getMinimumServiceEventCount()I @@ -27186,7 +26262,7 @@ HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->()V HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->getConfiguration()Lorg/thoughtcrime/securesms/notifications/Configuration; HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->getDefaultConfiguration()Lorg/thoughtcrime/securesms/notifications/Configuration; -HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->hasLongMessageLatency(Ljava/util/List;JIIJ)Z +HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->hasLongMessageLatency(Ljava/util/List;JILjava/util/Map;)Z HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->hasRepeatedFailedServiceStarts(Ljava/util/List;JIF)Z HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->haveEnoughData(Ljava/lang/String;J)Z HSPLorg/thoughtcrime/securesms/notifications/SlowNotificationHeuristics;->isFailingToDrainQueue(Ljava/util/List;JI)Z @@ -27234,28 +26310,26 @@ HSPLorg/thoughtcrime/securesms/notifications/v2/NotificationState$notificationIt HSPLorg/thoughtcrime/securesms/notifications/v2/NotificationState;->()V HSPLorg/thoughtcrime/securesms/notifications/v2/NotificationState;->(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/notifications/v2/NotificationState;->access$getEMPTY$cp()Lorg/thoughtcrime/securesms/notifications/v2/NotificationState; -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter$PhoneNumber;->-$$Nest$fgetcountryCode(Lorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter$PhoneNumber;)I -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter$PhoneNumber;->(Ljava/lang/String;ILjava/lang/String;)V -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter$PhoneNumber;->getCountryCode()I -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter;->()V -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter;->(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter;->get(Landroid/content/Context;)Lorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter; -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter;->parseAreaCode(Ljava/lang/String;I)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter;->prettyPrint(Ljava/lang/String;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter;->prettyPrintFormat(Ljava/lang/String;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/permissions/Permissions$$ExternalSyntheticLambda0;->(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/permissions/Permissions$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z +HSPLorg/thoughtcrime/securesms/permissions/Permissions;->$r8$lambda$Q0AcdMcPXUgr1QQ_HDTcoSx0sHo(Landroid/content/Context;Ljava/lang/String;)Z +HSPLorg/thoughtcrime/securesms/permissions/Permissions;->()V +HSPLorg/thoughtcrime/securesms/permissions/Permissions;->hasAll(Landroid/content/Context;[Ljava/lang/String;)Z +HSPLorg/thoughtcrime/securesms/permissions/Permissions;->isRuntimePermissionsRequired()Z +HSPLorg/thoughtcrime/securesms/permissions/Permissions;->lambda$hasAll$2(Landroid/content/Context;Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/pin/SvrRepository;->()V HSPLorg/thoughtcrime/securesms/pin/SvrRepository;->()V HSPLorg/thoughtcrime/securesms/pin/SvrRepository;->onRegistrationComplete(Lorg/whispersystems/signalservice/api/kbs/MasterKey;Ljava/lang/String;ZZ)V HSPLorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference;->(Ljava/lang/String;)V -HSPLorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference;->isDisplayContact()Z HSPLorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference;->toString()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->()V HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getAvatar(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;)Ljava/io/InputStream; HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getAvatarDirectory(Landroid/content/Context;)Ljava/io/File; HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getAvatarFile(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;)Ljava/io/File; -HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getAvatarFile(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;Z)Ljava/io/File; HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getAvatarFileDetails(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;)Lorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails; +HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getOutputStream(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;Z)Ljava/io/OutputStream; HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->hasAvatar(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;)Z +HSPLorg/thoughtcrime/securesms/profiles/AvatarHelper;->setAvatar(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/io/InputStream;)V HSPLorg/thoughtcrime/securesms/profiles/ProfileName$$ExternalSyntheticLambda0;->()V HSPLorg/thoughtcrime/securesms/profiles/ProfileName$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/profiles/ProfileName$$ExternalSyntheticLambda1;->()V @@ -27264,6 +26338,8 @@ HSPLorg/thoughtcrime/securesms/profiles/ProfileName$1;->()V HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->$r8$lambda$pNHvm3E5R2_hKbty_0luXfn7Cik(Ljava/lang/Boolean;Ljava/lang/String;)Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->()V HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->(Ljava/lang/String;Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->asGiven(Ljava/lang/String;)Lorg/thoughtcrime/securesms/profiles/ProfileName; +HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->equals(Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->fromParts(Ljava/lang/String;Ljava/lang/String;)Lorg/thoughtcrime/securesms/profiles/ProfileName; HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->getFamilyName()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/profiles/ProfileName;->getGivenName()Ljava/lang/String; @@ -27283,20 +26359,69 @@ HSPLorg/thoughtcrime/securesms/providers/BaseContentProvider;->attachInfo(Landro HSPLorg/thoughtcrime/securesms/providers/BlobContentProvider;->()V HSPLorg/thoughtcrime/securesms/providers/BlobContentProvider;->()V HSPLorg/thoughtcrime/securesms/providers/BlobContentProvider;->onCreate()Z +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;J)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda10;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda11;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda11;->run()V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;Ljava/io/OutputStream;Landroid/net/Uri;Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda1;->call()Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda9;->(JLandroid/net/Uri;)V HSPLorg/thoughtcrime/securesms/providers/BlobProvider$1;->(I)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$2;->()V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Ljava/io/InputStream;J)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Ljava/io/InputStream;JLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder-IA;)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->buildBlobSpec(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->createForSingleSessionOnDisk(Landroid/content/Context;)Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$fgetid(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetData(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/io/InputStream; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetFileName(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetFileSize(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)J +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetId(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetMimeType(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetStorageType(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->(Ljava/io/InputStream;Ljava/lang/String;Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;Ljava/lang/String;Ljava/lang/String;J)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->(Ljava/io/InputStream;Ljava/lang/String;Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;Ljava/lang/String;Ljava/lang/String;JLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec-IA;)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getData()Ljava/io/InputStream; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getFileName()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getFileSize()J +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getId()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getMimeType()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getStorageType()Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->$values()[Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->-$$Nest$mencode(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->-$$Nest$misMemory(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Z +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->-$$Nest$smdecode(Ljava/lang/String;)Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->()V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->(Ljava/lang/String;ILjava/lang/String;Z)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->decode(Ljava/lang/String;)Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->encode()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->isMemory()Z +HSPLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->values()[Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->$r8$lambda$ODJ5xh2VOR1mLM-AV1r-HG7pEAk(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->$r8$lambda$hszeKLE-J5rLAuyYe0jTaWcOLg4(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;JLjava/io/File;)Ljava/io/InputStream; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->$r8$lambda$vEFatZFK1evY8Xp8zObuRkcU_8Q(Lorg/thoughtcrime/securesms/providers/BlobProvider;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;Ljava/io/OutputStream;Landroid/net/Uri;Landroid/content/Context;)Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->-$$Nest$mwriteBlobSpecToDisk(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->()V HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->()V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->buildFileName(Ljava/lang/String;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->buildUri(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->deleteOrphanedDraftFiles(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->forData(Ljava/io/InputStream;J)Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getAttachmentSecret(Landroid/content/Context;)Lorg/thoughtcrime/securesms/crypto/AttachmentSecret; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getBlobRepresentation(Landroid/content/Context;Landroid/net/Uri;Lorg/thoughtcrime/securesms/util/IOFunction;Lorg/thoughtcrime/securesms/util/IOFunction;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getDirectory(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getInstance()Lorg/thoughtcrime/securesms/providers/BlobProvider; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getOrCreateDirectory(Landroid/content/Context;Ljava/lang/String;)Ljava/io/File; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getStream(Landroid/content/Context;Landroid/net/Uri;)Ljava/io/InputStream; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->getStream(Landroid/content/Context;Landroid/net/Uri;J)Ljava/io/InputStream; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->initialize(Landroid/content/Context;)V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->isAuthority(Landroid/net/Uri;)Z +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->lambda$getStream$1(Landroid/content/Context;JLjava/io/File;)Ljava/io/InputStream; HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->lambda$initialize$3(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/providers/MmsBodyProvider;->()V -HSPLorg/thoughtcrime/securesms/providers/MmsBodyProvider;->()V -HSPLorg/thoughtcrime/securesms/providers/MmsBodyProvider;->onCreate()Z +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->lambda$writeBlobSpecToDiskAsync$4(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;Ljava/io/OutputStream;Landroid/net/Uri;Landroid/content/Context;)Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->waitUntilInitialized()V +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->writeBlobSpecToDisk(Landroid/content/Context;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Landroid/net/Uri; +HSPLorg/thoughtcrime/securesms/providers/BlobProvider;->writeBlobSpecToDiskAsync(Landroid/content/Context;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/util/concurrent/Future; HSPLorg/thoughtcrime/securesms/providers/PartProvider;->()V HSPLorg/thoughtcrime/securesms/providers/PartProvider;->()V HSPLorg/thoughtcrime/securesms/providers/PartProvider;->onCreate()Z @@ -27327,34 +26452,22 @@ HSPLorg/thoughtcrime/securesms/ratelimit/RateLimitUtil;->()V HSPLorg/thoughtcrime/securesms/ratelimit/RateLimitUtil;->retryAllRateLimitedMessages(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/reactions/ReactionsConversationView;->()V HSPLorg/thoughtcrime/securesms/reactions/ReactionsConversationView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/reactions/ReactionsConversationView;->clear()V HSPLorg/thoughtcrime/securesms/reactions/ReactionsConversationView;->init(Landroid/util/AttributeSet;)V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda0;->run()V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;)V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda3;->onChanged(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda4;->()V +HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda4;->contentsMatch(Ljava/lang/Object;Ljava/lang/Object;)Z HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda5;->()V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda5;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda6;->()V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda9;->(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda9;->run()V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$4o-q--s8xb4fbde9teliyQxlyww(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$CYcq6dHxZW6RfEGMe0s6kvofKaE(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$bhowCzW_4HRIO1hvMslBpl08AJE(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/Object;)Lorg/thoughtcrime/securesms/recipients/Recipient; -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$pGM0bNiB06y_fkMUloVDwF8BcLs(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->()V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->fetchAndCacheRecipientFromDisk(Lorg/thoughtcrime/securesms/recipients/RecipientId;)Lorg/thoughtcrime/securesms/recipients/Recipient; HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->get()Lorg/thoughtcrime/securesms/recipients/Recipient; HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->getId()Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->getLiveData()Landroidx/lifecycle/LiveData; -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$new$0(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$new$1(Lorg/thoughtcrime/securesms/recipients/Recipient;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$new$2(Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/Object;)Lorg/thoughtcrime/securesms/recipients/Recipient; -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$observeForever$6(Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->observable()Lio/reactivex/rxjava3/core/Observable; -HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->observeForever(Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->refresh()Lorg/thoughtcrime/securesms/recipients/LiveRecipient; HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->refresh(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipient;->resolve()Lorg/thoughtcrime/securesms/recipients/Recipient; @@ -27385,6 +26498,7 @@ HSPLorg/thoughtcrime/securesms/recipients/LiveRecipientCache;->lambda$addToCache HSPLorg/thoughtcrime/securesms/recipients/LiveRecipientCache;->lambda$new$0()Z HSPLorg/thoughtcrime/securesms/recipients/LiveRecipientCache;->lambda$warmUp$3(Lorg/signal/core/util/Stopwatch;)V HSPLorg/thoughtcrime/securesms/recipients/LiveRecipientCache;->warmUp()V +HSPLorg/thoughtcrime/securesms/recipients/Recipient$$ExternalSyntheticLambda3;->()V HSPLorg/thoughtcrime/securesms/recipients/Recipient$Capability;->$values()[Lorg/thoughtcrime/securesms/recipients/Recipient$Capability; HSPLorg/thoughtcrime/securesms/recipients/Recipient$Capability;->()V HSPLorg/thoughtcrime/securesms/recipients/Recipient$Capability;->(Ljava/lang/String;II)V @@ -27406,11 +26520,8 @@ HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getAutoChatColor()Lorg/tho HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getAvatarColor()Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getBadges()Ljava/util/List; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getChatColors()Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getCombinedAboutAndEmoji()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getContactPhoto()Lorg/thoughtcrime/securesms/contacts/avatars/ContactPhoto; -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getContactUri()Landroid/net/Uri; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getDisplayName(Landroid/content/Context;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getDisplayNameOrUsername(Landroid/content/Context;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getE164()Lj$/util/Optional; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getExpiresInSeconds()I HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getFallbackContactPhoto(Lorg/thoughtcrime/securesms/recipients/Recipient$FallbackPhotoProvider;I)Lorg/thoughtcrime/securesms/contacts/avatars/FallbackContactPhoto; @@ -27418,18 +26529,17 @@ HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getFallbackContactPhotoDra HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getGroupName(Landroid/content/Context;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getId()Lorg/thoughtcrime/securesms/recipients/RecipientId; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getNameFromLocalData(Landroid/content/Context;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getNotificationChannel()Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getPhoneNumberSharing()Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getProfileAvatar()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getProfileAvatarFileDetails()Lorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails; +HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getProfileKey()[B HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getProfileName()Lorg/thoughtcrime/securesms/profiles/ProfileName; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getRegistered()Lorg/thoughtcrime/securesms/database/RecipientTable$RegisteredState; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getServiceId()Lj$/util/Optional; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getSmallFallbackContactPhotoDrawable(Landroid/content/Context;ZLorg/thoughtcrime/securesms/recipients/Recipient$FallbackPhotoProvider;I)Landroid/graphics/drawable/Drawable; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->getWallpaper()Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->hasE164()Z +HSPLorg/thoughtcrime/securesms/recipients/Recipient;->hasSameContent(Lorg/thoughtcrime/securesms/recipients/Recipient;)Z HSPLorg/thoughtcrime/securesms/recipients/Recipient;->hasServiceId()Z -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->hasWallpaper()Z HSPLorg/thoughtcrime/securesms/recipients/Recipient;->hashCode()I HSPLorg/thoughtcrime/securesms/recipients/Recipient;->isActiveGroup()Z HSPLorg/thoughtcrime/securesms/recipients/Recipient;->isBlocked()Z @@ -27460,7 +26570,7 @@ HSPLorg/thoughtcrime/securesms/recipients/Recipient;->resolved(Lorg/thoughtcrime HSPLorg/thoughtcrime/securesms/recipients/Recipient;->resolvedList(Ljava/util/Collection;)Ljava/util/List; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->self()Lorg/thoughtcrime/securesms/recipients/Recipient; HSPLorg/thoughtcrime/securesms/recipients/Recipient;->shouldBlurAvatar()Z -HSPLorg/thoughtcrime/securesms/recipients/Recipient;->shouldShowE164()Z +HSPLorg/thoughtcrime/securesms/recipients/Recipient;->shouldHideStory()Z HSPLorg/thoughtcrime/securesms/recipients/Recipient;->showVerified()Z HSPLorg/thoughtcrime/securesms/recipients/Recipient;->trustedPush(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Ljava/lang/String;)Lorg/thoughtcrime/securesms/recipients/Recipient; HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;)V @@ -27474,6 +26584,7 @@ HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails$Companion;->(Lk HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails$Companion;->forIndividual(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/RecipientRecord;)Lorg/thoughtcrime/securesms/recipients/RecipientDetails; HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails$Companion;->forUnknown()Lorg/thoughtcrime/securesms/recipients/RecipientDetails; HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails;->()V +HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails;->(Ljava/lang/String;Ljava/lang/String;ZLorg/thoughtcrime/securesms/database/RecipientTable$RegisteredState;Lorg/thoughtcrime/securesms/database/model/RecipientRecord;Ljava/util/List;ZLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;Lj$/util/Optional;)V HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails;->(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/database/model/DistributionListId;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/net/Uri;Landroid/net/Uri;Lj$/util/Optional;Landroid/net/Uri;Landroid/net/Uri;JLorg/thoughtcrime/securesms/database/RecipientTable$VibrateState;Lorg/thoughtcrime/securesms/database/RecipientTable$VibrateState;ZILjava/util/List;Lorg/thoughtcrime/securesms/profiles/ProfileName;Lorg/thoughtcrime/securesms/database/RecipientTable$RegisteredState;[BLorg/signal/libsignal/zkgroup/profiles/ExpiringProfileKeyCredential;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails;ZLorg/thoughtcrime/securesms/recipients/Recipient$HiddenState;ZJZLjava/lang/String;Lorg/thoughtcrime/securesms/database/RecipientTable$UnidentifiedAccessMode;Lorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities;[BLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper;Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/profiles/ProfileName;Lj$/util/Optional;ZLjava/util/List;ZZLorg/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId;Lj$/util/Optional;Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState;)V HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails;->(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/whispersystems/signalservice/api/push/ServiceId$PNI;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/groups/GroupId;Lorg/thoughtcrime/securesms/database/model/DistributionListId;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/net/Uri;Landroid/net/Uri;Lj$/util/Optional;Landroid/net/Uri;Landroid/net/Uri;JLorg/thoughtcrime/securesms/database/RecipientTable$VibrateState;Lorg/thoughtcrime/securesms/database/RecipientTable$VibrateState;ZILjava/util/List;Lorg/thoughtcrime/securesms/profiles/ProfileName;Lorg/thoughtcrime/securesms/database/RecipientTable$RegisteredState;[BLorg/signal/libsignal/zkgroup/profiles/ExpiringProfileKeyCredential;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails;ZLorg/thoughtcrime/securesms/recipients/Recipient$HiddenState;ZJZLjava/lang/String;Lorg/thoughtcrime/securesms/database/RecipientTable$UnidentifiedAccessMode;Lorg/thoughtcrime/securesms/database/model/RecipientRecord$Capabilities;[BLorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting;Lorg/thoughtcrime/securesms/wallpaper/ChatWallpaper;Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor;Ljava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/profiles/ProfileName;Lj$/util/Optional;ZLjava/util/List;ZZLorg/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId;Lj$/util/Optional;Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState;Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/recipients/RecipientDetails;->forIndividual(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/model/RecipientRecord;)Lorg/thoughtcrime/securesms/recipients/RecipientDetails; @@ -27506,6 +26617,7 @@ HSPLorg/thoughtcrime/securesms/recipients/RecipientUtil;->isLegacyProfileSharing HSPLorg/thoughtcrime/securesms/recipients/RecipientUtil;->isMessageRequestAccepted(Landroid/content/Context;J)Z HSPLorg/thoughtcrime/securesms/recipients/RecipientUtil;->isMessageRequestAccepted(Ljava/lang/Long;Lorg/thoughtcrime/securesms/recipients/Recipient;)Z HSPLorg/thoughtcrime/securesms/recipients/RecipientUtil;->isRecipientHidden(J)Z +HSPLorg/thoughtcrime/securesms/recipients/RecipientUtil;->toSignalServiceAddress(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; HSPLorg/thoughtcrime/securesms/registration/RegistrationData;->()V HSPLorg/thoughtcrime/securesms/registration/RegistrationData;->(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILorg/signal/libsignal/zkgroup/profiles/ProfileKey;Ljava/lang/String;ILjava/lang/String;)V HSPLorg/thoughtcrime/securesms/registration/RegistrationData;->getE164()Ljava/lang/String; @@ -27539,6 +26651,12 @@ HSPLorg/thoughtcrime/securesms/registration/VerifyResponse;->getMasterKey()Lorg/ HSPLorg/thoughtcrime/securesms/registration/VerifyResponse;->getPin()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/registration/VerifyResponse;->getPniPreKeyCollection()Lorg/whispersystems/signalservice/api/account/PreKeyCollection; HSPLorg/thoughtcrime/securesms/registration/VerifyResponse;->getVerifyAccountResponse()Lorg/whispersystems/signalservice/internal/push/VerifyAccountResponse; +HSPLorg/thoughtcrime/securesms/registration/viewmodel/RegistrationViewModel$$ExternalSyntheticLambda3;->()V +HSPLorg/thoughtcrime/securesms/registration/viewmodel/RegistrationViewModel$$ExternalSyntheticLambda3;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->()V +HSPLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->()V +HSPLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->insertReleaseChannelMessage$default(Lorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/lang/String;JLjava/lang/String;IILjava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Lorg/thoughtcrime/securesms/database/model/StoryType;ILjava/lang/Object;)Lorg/thoughtcrime/securesms/database/MessageTable$InsertResult; +HSPLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->insertReleaseChannelMessage(Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/lang/String;JLjava/lang/String;IILjava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Lorg/thoughtcrime/securesms/database/model/StoryType;)Lorg/thoughtcrime/securesms/database/MessageTable$InsertResult; HSPLorg/thoughtcrime/securesms/revealable/ViewOnceMessageManager;->()V HSPLorg/thoughtcrime/securesms/revealable/ViewOnceMessageManager;->(Landroid/app/Application;)V HSPLorg/thoughtcrime/securesms/revealable/ViewOnceMessageManager;->getNextClosestEvent()Ljava/lang/Object; @@ -27639,6 +26757,11 @@ HSPLorg/thoughtcrime/securesms/shakereport/ShakeToReport;->()V HSPLorg/thoughtcrime/securesms/shakereport/ShakeToReport;->(Landroid/app/Application;)V HSPLorg/thoughtcrime/securesms/shakereport/ShakeToReport;->enable()V HSPLorg/thoughtcrime/securesms/shakereport/ShakeToReport;->registerActivity(Landroidx/appcompat/app/AppCompatActivity;)V +HSPLorg/thoughtcrime/securesms/stickers/BlessedPacks$1;->()V +HSPLorg/thoughtcrime/securesms/stickers/BlessedPacks$Pack;->(Ljava/lang/String;Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/stickers/BlessedPacks$Pack;->getPackId()Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/stickers/BlessedPacks;->()V +HSPLorg/thoughtcrime/securesms/stickers/BlessedPacks;->contains(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/stickers/StickerRemoteUriLoader$Factory;->()V HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository;Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository$Callback;)V HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository$$ExternalSyntheticLambda0;->run()V @@ -27647,7 +26770,6 @@ HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository;->()V HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository;->getStickerFeatureAvailability(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository$Callback;)V HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository;->getStickerFeatureAvailabilitySync()Ljava/lang/Boolean; HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository;->lambda$getStickerFeatureAvailability$2(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository$Callback;)V -HSPLorg/thoughtcrime/securesms/stickers/StickerSearchRepository;->searchByEmoji(Ljava/lang/String;)Lio/reactivex/rxjava3/core/Single; HSPLorg/thoughtcrime/securesms/storage/StorageSyncHelper$$ExternalSyntheticLambda0;->()V HSPLorg/thoughtcrime/securesms/storage/StorageSyncHelper$$ExternalSyntheticLambda0;->generate()[B HSPLorg/thoughtcrime/securesms/storage/StorageSyncHelper;->$r8$lambda$Qu9GyOxIHYeSe2KLWGmWWrZGbxY()[B @@ -27803,7 +26925,6 @@ HSPLorg/thoughtcrime/securesms/util/AppForegroundObserver;->()V HSPLorg/thoughtcrime/securesms/util/AppForegroundObserver;->addListener(Lorg/thoughtcrime/securesms/util/AppForegroundObserver$Listener;)V HSPLorg/thoughtcrime/securesms/util/AppForegroundObserver;->begin()V HSPLorg/thoughtcrime/securesms/util/AppForegroundObserver;->onForeground()V -HSPLorg/thoughtcrime/securesms/util/AppForegroundObserver;->removeListener(Lorg/thoughtcrime/securesms/util/AppForegroundObserver$Listener;)V HSPLorg/thoughtcrime/securesms/util/AppStartup$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/util/AppStartup;)V HSPLorg/thoughtcrime/securesms/util/AppStartup$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/util/AppStartup;)V HSPLorg/thoughtcrime/securesms/util/AppStartup$Task;->(Lorg/thoughtcrime/securesms/util/AppStartup;Ljava/lang/String;Ljava/lang/Runnable;)V @@ -27823,15 +26944,9 @@ HSPLorg/thoughtcrime/securesms/util/AppStartup;->onCriticalRenderEventStart()V HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->()V HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->getFallback(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;I)Landroid/graphics/drawable/Drawable; HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->loadIconIntoImageView(Lorg/thoughtcrime/securesms/recipients/Recipient;Landroid/widget/ImageView;I)V -HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->request(Lorg/thoughtcrime/securesms/mms/GlideRequest;Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;ILcom/bumptech/glide/load/resource/bitmap/BitmapTransformation;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->request(Lorg/thoughtcrime/securesms/mms/GlideRequest;Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;ZILcom/bumptech/glide/load/resource/bitmap/BitmapTransformation;)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->requestCircle(Lorg/thoughtcrime/securesms/mms/GlideRequest;Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;I)Lorg/thoughtcrime/securesms/mms/GlideRequest; -HSPLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/NotificationManager;Ljava/lang/String;Ljava/lang/String;)Landroid/app/NotificationChannel; -HSPLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline1;->m(Landroid/app/NotificationManager;)Z -HSPLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline2;->m(Landroid/app/NotificationManager;)I -HSPLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline3;->m(Landroid/app/NotificationManager;)Z -HSPLorg/thoughtcrime/securesms/util/BubbleUtil;->()V -HSPLorg/thoughtcrime/securesms/util/BubbleUtil;->canBubble(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;Ljava/lang/Long;)Z +HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->request(Lcom/bumptech/glide/RequestBuilder;Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;ILcom/bumptech/glide/load/resource/bitmap/BitmapTransformation;)Lcom/bumptech/glide/RequestBuilder; +HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->request(Lcom/bumptech/glide/RequestBuilder;Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;ZILcom/bumptech/glide/load/resource/bitmap/BitmapTransformation;)Lcom/bumptech/glide/RequestBuilder; +HSPLorg/thoughtcrime/securesms/util/AvatarUtil;->requestCircle(Lcom/bumptech/glide/RequestBuilder;Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;I)Lcom/bumptech/glide/RequestBuilder; HSPLorg/thoughtcrime/securesms/util/ByteUnit$1;->(Ljava/lang/String;I)V HSPLorg/thoughtcrime/securesms/util/ByteUnit$1;->(Ljava/lang/String;ILorg/thoughtcrime/securesms/util/ByteUnit$1-IA;)V HSPLorg/thoughtcrime/securesms/util/ByteUnit$2;->(Ljava/lang/String;I)V @@ -27866,41 +26981,23 @@ HSPLorg/thoughtcrime/securesms/util/CachedInflater;->cacheUntilLimit(ILandroid/v HSPLorg/thoughtcrime/securesms/util/CachedInflater;->clear()V HSPLorg/thoughtcrime/securesms/util/CachedInflater;->from(Landroid/content/Context;)Lorg/thoughtcrime/securesms/util/CachedInflater; HSPLorg/thoughtcrime/securesms/util/CachedInflater;->inflate(ILandroid/view/ViewGroup;Z)Landroid/view/View; -HSPLorg/thoughtcrime/securesms/util/CenteredImageSpan;->(Landroid/graphics/drawable/Drawable;)V -HSPLorg/thoughtcrime/securesms/util/CenteredImageSpan;->draw(Landroid/graphics/Canvas;Ljava/lang/CharSequence;IIFIIILandroid/graphics/Paint;)V -HSPLorg/thoughtcrime/securesms/util/CenteredImageSpan;->getSize(Landroid/graphics/Paint;Ljava/lang/CharSequence;IILandroid/graphics/Paint$FontMetricsInt;)I HSPLorg/thoughtcrime/securesms/util/CharacterCalculator;->()V HSPLorg/thoughtcrime/securesms/util/ConfigurationUtil;->getFontScale(Landroid/content/res/Configuration;)F HSPLorg/thoughtcrime/securesms/util/ConfigurationUtil;->getNightModeConfiguration(Landroid/content/Context;)I HSPLorg/thoughtcrime/securesms/util/ConfigurationUtil;->getNightModeConfiguration(Landroid/content/res/Configuration;)I HSPLorg/thoughtcrime/securesms/util/ContextUtil;->requireDrawable(Landroid/content/Context;I)Landroid/graphics/drawable/Drawable; HSPLorg/thoughtcrime/securesms/util/ConversationShortcutPhoto$Loader$Factory;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/util/ConversationUtil;->()V -HSPLorg/thoughtcrime/securesms/util/ConversationUtil;->getChannelId(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/util/ConversationUtil;->getShortcutId(Lorg/thoughtcrime/securesms/recipients/RecipientId;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2;->()V HSPLorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2;->()V -HSPLorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2;->invoke()Ljava/text/SimpleDateFormat; HSPLorg/thoughtcrime/securesms/util/DateUtils;->()V HSPLorg/thoughtcrime/securesms/util/DateUtils;->()V HSPLorg/thoughtcrime/securesms/util/DateUtils;->getBriefRelativeTimeSpanString(Landroid/content/Context;Ljava/util/Locale;J)Ljava/lang/String; -HSPLorg/thoughtcrime/securesms/util/DateUtils;->getConversationDateHeaderString(Landroid/content/Context;Ljava/util/Locale;J)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/DateUtils;->getDatelessRelativeTimeSpanFormattedDate(Landroid/content/Context;Ljava/util/Locale;J)Lorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate; -HSPLorg/thoughtcrime/securesms/util/DateUtils;->getSameDayDateFormat()Ljava/text/SimpleDateFormat; HSPLorg/thoughtcrime/securesms/util/DateUtils;->isNow(J)Z -HSPLorg/thoughtcrime/securesms/util/DateUtils;->isSameDay(JJ)Z -HSPLorg/thoughtcrime/securesms/util/DateUtils;->isSameExtendedRelativeTimestamp(JJ)Z HSPLorg/thoughtcrime/securesms/util/DateUtils;->isWithin-HG0u8IE(JJ)Z HSPLorg/thoughtcrime/securesms/util/Debouncer;->(J)V HSPLorg/thoughtcrime/securesms/util/Debouncer;->(JLjava/util/concurrent/TimeUnit;)V HSPLorg/thoughtcrime/securesms/util/Debouncer;->publish(Ljava/lang/Runnable;)V -HSPLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate$lazyDefault$2;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate$lazyDefault$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->getLazyDefault()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->getValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->setValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/util/DefaultValueLiveData;->(Ljava/lang/Object;)V HSPLorg/thoughtcrime/securesms/util/DefaultValueLiveData;->getValue()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/DefaultValueLiveData;->postValue(Ljava/lang/Object;)V @@ -27937,9 +27034,11 @@ HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->crashPromptConfig()Ljava/lang HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->delayedNotificationsPromptConfig()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->getBackgroundMessageProcessInterval()J HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->getBoolean(Ljava/lang/String;Z)Z +HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->getDefaultMaxBackoff()J HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->getInteger(Ljava/lang/String;I)I HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->getLong(Ljava/lang/String;J)J HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->gifSearchAvailable()Z HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->groupLimits()Lorg/thoughtcrime/securesms/groups/SelectionLimits; HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->init()V HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->instantVideoPlayback()Z @@ -27947,12 +27046,10 @@ HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->internalUser()Z HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->mapToJson(Ljava/util/Map;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->okHttpAutomaticRetry()Z HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->parseStoredConfig(Ljava/lang/String;)Ljava/util/Map; -HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->phoneNumberPrivacy()Z HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->refreshIfNecessary()V HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->retryReceipts()Z HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->retryRespondMaxAge()J HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->triggerFlagChangeListeners(Ljava/util/Map;)V -HSPLorg/thoughtcrime/securesms/util/FeatureFlags;->usernames()Z HSPLorg/thoughtcrime/securesms/util/FrameRateTracker$1;->(Lorg/thoughtcrime/securesms/util/FrameRateTracker;)V HSPLorg/thoughtcrime/securesms/util/FrameRateTracker$1;->doFrame(J)V HSPLorg/thoughtcrime/securesms/util/FrameRateTracker;->-$$Nest$fgetbadFrameThresholdNanos(Lorg/thoughtcrime/securesms/util/FrameRateTracker;)J @@ -27972,8 +27069,6 @@ HSPLorg/thoughtcrime/securesms/util/FullscreenHelper;->(Landroid/app/Activ HSPLorg/thoughtcrime/securesms/util/FullscreenHelper;->(Landroid/app/Activity;Z)V HSPLorg/thoughtcrime/securesms/util/FullscreenHelper;->showSystemUI()V HSPLorg/thoughtcrime/securesms/util/FullscreenHelper;->showSystemUI(Landroid/view/Window;)V -HSPLorg/thoughtcrime/securesms/util/JavaTimeExtensionsKt;->toLocalDate$default(JLj$/time/ZoneId;ILjava/lang/Object;)Lj$/time/LocalDate; -HSPLorg/thoughtcrime/securesms/util/JavaTimeExtensionsKt;->toLocalDate(JLj$/time/ZoneId;)Lj$/time/LocalDate; HSPLorg/thoughtcrime/securesms/util/JavaTimeExtensionsKt;->toLocalDateTime(JLj$/time/ZoneId;)Lj$/time/LocalDateTime; HSPLorg/thoughtcrime/securesms/util/JsonUtils$SaneJSONObject;->(Lorg/json/JSONObject;)V HSPLorg/thoughtcrime/securesms/util/JsonUtils$SaneJSONObject;->getInt(Ljava/lang/String;)I @@ -27982,6 +27077,7 @@ HSPLorg/thoughtcrime/securesms/util/JsonUtils$SaneJSONObject;->getString(Ljava/l HSPLorg/thoughtcrime/securesms/util/JsonUtils$SaneJSONObject;->isNull(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/util/JsonUtils;->()V HSPLorg/thoughtcrime/securesms/util/JsonUtils;->fromJson(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/util/JsonUtils;->fromJson([BLjava/lang/Class;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/JsonUtils;->getMapper()Lcom/fasterxml/jackson/databind/ObjectMapper; HSPLorg/thoughtcrime/securesms/util/JsonUtils;->toJson(Ljava/lang/Object;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/LRUCache;->(I)V @@ -28032,11 +27128,6 @@ HSPLorg/thoughtcrime/securesms/util/LocalMetrics;->start(Ljava/lang/String;Ljava HSPLorg/thoughtcrime/securesms/util/LocaleUtil;->()V HSPLorg/thoughtcrime/securesms/util/LocaleUtil;->()V HSPLorg/thoughtcrime/securesms/util/LocaleUtil;->getLocaleDefaults()Ljava/util/List; -HSPLorg/thoughtcrime/securesms/util/LongClickMovementMethod$1;->(Lorg/thoughtcrime/securesms/util/LongClickMovementMethod;)V -HSPLorg/thoughtcrime/securesms/util/LongClickMovementMethod;->(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/util/LongClickMovementMethod;->getInstance(Landroid/content/Context;)Lorg/thoughtcrime/securesms/util/LongClickMovementMethod; -HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;IIII)V -HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$$ExternalSyntheticLambda0;->onAnimationUpdate(Landroid/animation/ValueAnimator;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$1;->(Landroid/app/Activity;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$1;->invoke(I)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; @@ -28048,7 +27139,6 @@ HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onCreate(Landroi HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onPause(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onResume(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onStart(Landroidx/lifecycle/LifecycleOwner;)V -HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onStop(Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$ColorSet;->()V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$ColorSet;->(I)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$ColorSet;->(II)V @@ -28056,7 +27146,6 @@ HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$ColorSet;->getStatus HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$ColorSet;->getToolbarColorRes()I HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$OnScrollListener;->(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$OnScrollListener;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V -HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->$r8$lambda$T0JnL_tDtAWK4RNMpbrK8xUunio(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;IIIILandroid/animation/ValueAnimator;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->()V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->(Landroid/app/Activity;Ljava/util/List;Ljava/util/List;Landroidx/lifecycle/LifecycleOwner;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->(Landroid/app/Activity;Ljava/util/List;Ljava/util/List;Landroidx/lifecycle/LifecycleOwner;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -28067,7 +27156,6 @@ HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->getActiveColorSet( HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->getInactiveColorSet()Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper$ColorSet; HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->setColorImmediate()V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->setToolbarColor(I)V -HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->updateActiveState$lambda$7$lambda$6(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;IIIILandroid/animation/ValueAnimator;)V HSPLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->updateActiveState(Z)V HSPLorg/thoughtcrime/securesms/util/MediaUtil$1;->()V HSPLorg/thoughtcrime/securesms/util/MediaUtil$SlideType;->$values()[Lorg/thoughtcrime/securesms/util/MediaUtil$SlideType; @@ -28080,23 +27168,19 @@ HSPLorg/thoughtcrime/securesms/util/MediaUtil;->getSlideTypeFromContentType(Ljav HSPLorg/thoughtcrime/securesms/util/MediaUtil;->isAudioType(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/util/MediaUtil;->isGif(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/util/MediaUtil;->isImageType(Ljava/lang/String;)Z -HSPLorg/thoughtcrime/securesms/util/MediaUtil;->isInstantVideoSupported(Lorg/thoughtcrime/securesms/mms/Slide;)Z HSPLorg/thoughtcrime/securesms/util/MediaUtil;->isLongTextType(Ljava/lang/String;)Z +HSPLorg/thoughtcrime/securesms/util/MediaUtil;->isVideo(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasAudio(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasDocument(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasExtraText(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasGiftBadge(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasLinkPreview(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasLocation(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasNoBubble(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z -HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasOnlyThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasQuote(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasSharedContact(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasSticker(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->hasThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z -HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isBorderless(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isCaptionlessMms(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z -HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isEditMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isScheduled(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isStoryReaction(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z HSPLorg/thoughtcrime/securesms/util/MessageRecordUtil;->isTextOnly(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Landroid/content/Context;)Z @@ -28109,42 +27193,40 @@ HSPLorg/thoughtcrime/securesms/util/NetworkUtil;->getNetworkInfo(Landroid/conten HSPLorg/thoughtcrime/securesms/util/NetworkUtil;->isConnected(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/NetworkUtil;->isConnectedWifi(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/NoCrossfadeChangeDefaultAnimator;->()V -HSPLorg/thoughtcrime/securesms/util/NullableSavedStateHandleDelegate;->(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;)V +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda2;->()V +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda3;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda3;->call()Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda4;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda4;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->$r8$lambda$64DRPwLhDKidiYVBrJ1oGsaeSVY(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/internal/ServiceResponse;)Lorg/signal/libsignal/protocol/util/Pair; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->$r8$lambda$cqO5Ws54dRBOxkD_sPlVLlSYwIg(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->$r8$lambda$dDuBqdOM1yCYB_18NZWtjJd7BlA(Lorg/whispersystems/signalservice/api/services/ProfileService;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;)Lio/reactivex/rxjava3/core/SingleSource; HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->()V HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->handleSelfProfileKeyChange()V -HSPLorg/thoughtcrime/securesms/util/Projection$Corners;->()V -HSPLorg/thoughtcrime/securesms/util/Projection$Corners;->(F)V -HSPLorg/thoughtcrime/securesms/util/Projection$Corners;->(FFFF)V -HSPLorg/thoughtcrime/securesms/util/Projection$Corners;->([F)V -HSPLorg/thoughtcrime/securesms/util/Projection$Corners;->toRadii()[F -HSPLorg/thoughtcrime/securesms/util/Projection$Corners;->toRelativeRadii(Z)[F +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->lambda$retrieveProfile$0(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->lambda$retrieveProfile$1(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/internal/ServiceResponse;)Lorg/signal/libsignal/protocol/util/Pair; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->lambda$retrieveProfile$2(Lorg/whispersystems/signalservice/api/services/ProfileService;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;)Lio/reactivex/rxjava3/core/SingleSource; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->retrieveProfile(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Z)Lio/reactivex/rxjava3/core/Single; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->retrieveProfileSync(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Z)Lorg/whispersystems/signalservice/api/profiles/ProfileAndCredential; +HSPLorg/thoughtcrime/securesms/util/ProfileUtil;->toSignalServiceAddress(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; HSPLorg/thoughtcrime/securesms/util/ProjectionList;->()V HSPLorg/thoughtcrime/securesms/util/ProjectionList;->()V HSPLorg/thoughtcrime/securesms/util/ProjectionList;->(I)V HSPLorg/thoughtcrime/securesms/util/ProjectionList;->(IILkotlin/jvm/internal/DefaultConstructorMarker;)V -HSPLorg/thoughtcrime/securesms/util/ProjectionList;->close()V -HSPLorg/thoughtcrime/securesms/util/ProjectionList;->getSize()I -HSPLorg/thoughtcrime/securesms/util/ProjectionList;->size()I HSPLorg/thoughtcrime/securesms/util/PushCharacterCalculator$1;->()V HSPLorg/thoughtcrime/securesms/util/PushCharacterCalculator;->()V HSPLorg/thoughtcrime/securesms/util/PushCharacterCalculator;->()V HSPLorg/thoughtcrime/securesms/util/RemoteDeprecation;->()V HSPLorg/thoughtcrime/securesms/util/RemoteDeprecation;->getTimeUntilDeprecation()J HSPLorg/thoughtcrime/securesms/util/RemoteDeprecation;->getTimeUntilDeprecation(Ljava/lang/String;JLjava/lang/String;)J -HSPLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt$delegate$1;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt;->delegate(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;)Lkotlin/properties/ReadWriteProperty; -HSPLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt;->delegate(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;Ljava/lang/Object;)Lkotlin/properties/ReadWriteProperty; -HSPLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt;->delegate(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion$factoryProducer$1;->(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion$factoryProducer$1;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion$factoryProducer$1;->invoke()Lorg/thoughtcrime/securesms/util/SavedStateViewModelFactory; HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion;->()V HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion;->factoryProducer(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lkotlin/jvm/functions/Function0; HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory;->()V -HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory;->(Lkotlin/jvm/functions/Function1;Landroidx/savedstate/SavedStateRegistryOwner;)V -HSPLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory;->create(Ljava/lang/String;Ljava/lang/Class;Landroidx/lifecycle/SavedStateHandle;)Landroidx/lifecycle/ViewModel; HSPLorg/thoughtcrime/securesms/util/ScreenDensity$1;->()V HSPLorg/thoughtcrime/securesms/util/ScreenDensity;->()V HSPLorg/thoughtcrime/securesms/util/ScreenDensity;->(Ljava/lang/String;I)V @@ -28152,10 +27234,8 @@ HSPLorg/thoughtcrime/securesms/util/ScreenDensity;->get(Landroid/content/Context HSPLorg/thoughtcrime/securesms/util/ScreenDensity;->getBucket()Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/ScreenDensity;->isKnownDensity()Z HSPLorg/thoughtcrime/securesms/util/ScreenDensity;->xhdpiRelativeDensityScaleFactor(Ljava/lang/String;)F -HSPLorg/thoughtcrime/securesms/util/SearchUtil;->getHighlightedSpan(Ljava/util/Locale;Lorg/thoughtcrime/securesms/util/SearchUtil$StyleFactory;Landroid/text/Spannable;Ljava/lang/String;I)Landroid/text/Spannable; HSPLorg/thoughtcrime/securesms/util/ServiceUtil;->getActivityManager(Landroid/content/Context;)Landroid/app/ActivityManager; HSPLorg/thoughtcrime/securesms/util/ServiceUtil;->getAlarmManager(Landroid/content/Context;)Landroid/app/AlarmManager; -HSPLorg/thoughtcrime/securesms/util/ServiceUtil;->getAudioManager(Landroid/content/Context;)Landroid/media/AudioManager; HSPLorg/thoughtcrime/securesms/util/ServiceUtil;->getConnectivityManager(Landroid/content/Context;)Landroid/net/ConnectivityManager; HSPLorg/thoughtcrime/securesms/util/ServiceUtil;->getNotificationManager(Landroid/content/Context;)Landroid/app/NotificationManager; HSPLorg/thoughtcrime/securesms/util/ServiceUtil;->getPowerManager(Landroid/content/Context;)Landroid/os/PowerManager; @@ -28168,10 +27248,8 @@ HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ColdStart;->onRenderFinis HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ColdStart;->onRenderStart()V HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ColdStart;->start()V HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onDataLoaded()V -HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onDataPostedToMain()V HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onMetadataLoadStarted()V HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onMetadataLoaded()V -HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onRenderFinished()V HSPLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->start()V HSPLorg/thoughtcrime/securesms/util/SignalProxyUtil;->()V HSPLorg/thoughtcrime/securesms/util/SignalProxyUtil;->startListeningToWebsocket()V @@ -28207,17 +27285,11 @@ HSPLorg/thoughtcrime/securesms/util/SoftHashMap$SoftValue;->(Ljava/lang/Ob HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->()V HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->(I)V HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->addToStrongReferences(Ljava/lang/Object;)V +HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->clear()V HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->processQueue()V HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/SoftHashMap;->trimStrongReferencesIfNecessary()V -HSPLorg/thoughtcrime/securesms/util/SpanUtil;->()V -HSPLorg/thoughtcrime/securesms/util/SpanUtil;->buildCenteredImageSpan(Landroid/graphics/drawable/Drawable;)Ljava/lang/CharSequence; -HSPLorg/thoughtcrime/securesms/util/SpanUtil;->space(ILorg/signal/core/util/DimensionUnit;)Ljava/lang/CharSequence; -HSPLorg/thoughtcrime/securesms/util/SplashScreenUtil$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/Activity;)Landroid/window/SplashScreen; -HSPLorg/thoughtcrime/securesms/util/SplashScreenUtil$$ExternalSyntheticApiModelOutline1;->m(Landroid/window/SplashScreen;I)V -HSPLorg/thoughtcrime/securesms/util/SplashScreenUtil$1;->()V -HSPLorg/thoughtcrime/securesms/util/SplashScreenUtil;->setSplashScreenThemeIfNecessary(Landroid/app/Activity;Lorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;)V HSPLorg/thoughtcrime/securesms/util/StorageUtil;->getCleanFileName(Ljava/lang/String;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences$MediaKeyboardMode;->$values()[Lorg/thoughtcrime/securesms/util/TextSecurePreferences$MediaKeyboardMode; HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences$MediaKeyboardMode;->()V @@ -28240,7 +27312,6 @@ HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getLastVersionCode(L HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getLongPreference(Landroid/content/Context;Ljava/lang/String;J)J HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getMediaDownloadAllowed(Landroid/content/Context;Ljava/lang/String;I)Ljava/util/Set; HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getMediaKeyboardMode(Landroid/content/Context;)Lorg/thoughtcrime/securesms/util/TextSecurePreferences$MediaKeyboardMode; -HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getMessageBodyTextSize(Landroid/content/Context;)I HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getMobileMediaDownloadAllowed(Landroid/content/Context;)Ljava/util/Set; HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getNotificationChannelVersion(Landroid/content/Context;)I HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->getNotificationLedColor(Landroid/content/Context;)Ljava/lang/String; @@ -28270,6 +27341,7 @@ HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->isScreenLockEnabled( HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->isScreenSecurityEnabled(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->isSystemEmojiPreferred(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->isUnauthorizedReceived(Landroid/content/Context;)Z +HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->isUniversalUnidentifiedAccess(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->needsFullContactSync(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->setBooleanPreference(Landroid/content/Context;Ljava/lang/String;Z)V HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->setDirectoryRefreshTime(Landroid/content/Context;J)V @@ -28283,9 +27355,7 @@ HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->setPromptedPushRegis HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->setSignedPreKeyRotationTime(Landroid/content/Context;J)V HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->setUnauthorizedReceived(Landroid/content/Context;Z)V HSPLorg/thoughtcrime/securesms/util/TextSecurePreferences;->setUnidentifiedAccessCertificateRotationTime(Landroid/content/Context;J)V -HSPLorg/thoughtcrime/securesms/util/ThemeUtil;->getAttribute(Landroid/content/Context;ILjava/lang/String;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/ThemeUtil;->getThemedBoolean(Landroid/content/Context;I)Z -HSPLorg/thoughtcrime/securesms/util/ThemeUtil;->isDarkTheme(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/ThrottledDebouncer$OverflowHandler;->-$$Nest$fgetlastRun(Lorg/thoughtcrime/securesms/util/ThrottledDebouncer$OverflowHandler;)J HSPLorg/thoughtcrime/securesms/util/ThrottledDebouncer$OverflowHandler;->()V HSPLorg/thoughtcrime/securesms/util/ThrottledDebouncer$OverflowHandler;->handleMessage(Landroid/os/Message;)V @@ -28303,10 +27373,7 @@ HSPLorg/thoughtcrime/securesms/util/Util;->getSecretBytes(I)[B HSPLorg/thoughtcrime/securesms/util/Util;->getSecretBytes(Ljava/security/SecureRandom;I)[B HSPLorg/thoughtcrime/securesms/util/Util;->getTimeUntilBuildExpiry()J HSPLorg/thoughtcrime/securesms/util/Util;->hasItems(Ljava/util/Collection;)Z -HSPLorg/thoughtcrime/securesms/util/Util;->hashCode([Ljava/lang/Object;)I -HSPLorg/thoughtcrime/securesms/util/Util;->isDefaultSmsProvider(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/Util;->isEmpty(Ljava/lang/CharSequence;)Z -HSPLorg/thoughtcrime/securesms/util/Util;->isEmpty(Ljava/util/Collection;)Z HSPLorg/thoughtcrime/securesms/util/Util;->join(Ljava/util/Collection;Ljava/lang/String;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/Util;->join([Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; HSPLorg/thoughtcrime/securesms/util/Util;->uri(Ljava/lang/String;)Landroid/net/Uri; @@ -28315,12 +27382,7 @@ HSPLorg/thoughtcrime/securesms/util/VersionTracker;->()V HSPLorg/thoughtcrime/securesms/util/VersionTracker;->getDaysSinceFirstInstalled(Landroid/content/Context;)J HSPLorg/thoughtcrime/securesms/util/VersionTracker;->getLastSeenVersion(Landroid/content/Context;)I HSPLorg/thoughtcrime/securesms/util/VersionTracker;->updateLastSeenVersion(Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->drawAsTopItemDecoration(Landroid/view/View;Landroid/graphics/Canvas;Landroid/view/View;Landroid/view/View;I)V HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->getLifecycle(Landroid/view/View;)Landroidx/lifecycle/Lifecycle; -HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->getVisible(Landroid/view/View;)Z -HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->layoutIn(Landroid/view/View;Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->padding$default(Landroid/view/View;IIIIILjava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->padding(Landroid/view/View;IIII)V HSPLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->setVisible(Landroid/view/View;Z)V HSPLorg/thoughtcrime/securesms/util/ViewModelFactory$Companion$factoryProducer$1;->(Lkotlin/jvm/functions/Function0;)V HSPLorg/thoughtcrime/securesms/util/ViewModelFactory$Companion$factoryProducer$1;->invoke()Ljava/lang/Object; @@ -28333,57 +27395,30 @@ HSPLorg/thoughtcrime/securesms/util/ViewModelFactory;->(Lkotlin/jvm/functi HSPLorg/thoughtcrime/securesms/util/ViewModelFactory;->create(Ljava/lang/Class;)Landroidx/lifecycle/ViewModel; HSPLorg/thoughtcrime/securesms/util/ViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel; HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$1;->(Landroidx/fragment/app/Fragment;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$1;->invoke()Landroidx/fragment/app/Fragment; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$1;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$2;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$2;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$2;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$3;->(Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$3;->invoke()Landroidx/lifecycle/ViewModelStore; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$3;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$4;->(Lkotlin/jvm/functions/Function0;Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$4;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$4;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$1;->(Landroidx/fragment/app/Fragment;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$1;->invoke()Landroidx/savedstate/SavedStateRegistryOwner; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$1;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$1;->(Landroidx/fragment/app/Fragment;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$1;->invoke()Landroidx/fragment/app/Fragment; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$1;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$2;->(Lkotlin/jvm/functions/Function0;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$2;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$2;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$3;->(Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$3;->invoke()Landroidx/lifecycle/ViewModelStore; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$3;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$4;->(Lkotlin/jvm/functions/Function0;Lkotlin/Lazy;)V -HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$4;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$4;->(Landroidx/fragment/app/Fragment;)V +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$4;->invoke()Landroidx/fragment/app/Fragment; HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$4;->invoke()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->animateOut(Landroid/view/View;Landroid/view/animation/Animation;I)Lorg/thoughtcrime/securesms/util/concurrent/ListenableFuture; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$5;->(Lkotlin/jvm/functions/Function0;)V +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$5;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$5;->invoke()Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$6;->(Lkotlin/Lazy;)V +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$6;->invoke()Landroidx/lifecycle/ViewModelStore; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$6;->invoke()Ljava/lang/Object; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$7;->(Lkotlin/jvm/functions/Function0;Lkotlin/Lazy;)V +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$7;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; +HSPLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$7;->invoke()Ljava/lang/Object; HSPLorg/thoughtcrime/securesms/util/ViewUtil;->dpToPx(I)I -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->fadeOut(Landroid/view/View;I)Lorg/thoughtcrime/securesms/util/concurrent/ListenableFuture; -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->fadeOut(Landroid/view/View;II)Lorg/thoughtcrime/securesms/util/concurrent/ListenableFuture; HSPLorg/thoughtcrime/securesms/util/ViewUtil;->findStubById(Landroid/view/View;I)Lorg/thoughtcrime/securesms/util/views/Stub; -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->getAlphaAnimation(FFI)Landroid/view/animation/Animation; -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->getLeftMargin(Landroid/view/View;)I -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->getRightMargin(Landroid/view/View;)I -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->getTopMargin(Landroid/view/View;)I HSPLorg/thoughtcrime/securesms/util/ViewUtil;->getWidth(Landroid/view/View;)I HSPLorg/thoughtcrime/securesms/util/ViewUtil;->isLtr(Landroid/content/Context;)Z HSPLorg/thoughtcrime/securesms/util/ViewUtil;->isLtr(Landroid/view/View;)Z HSPLorg/thoughtcrime/securesms/util/ViewUtil;->isRtl(Landroid/content/Context;)Z -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->isRtl(Landroid/view/View;)Z HSPLorg/thoughtcrime/securesms/util/ViewUtil;->mirrorIfRtl(Landroid/view/View;Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingBottom(Landroid/view/View;I)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingEnd(Landroid/view/View;I)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingStart(Landroid/view/View;I)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setPaddingTop(Landroid/view/View;I)V HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setTextViewGravityStart(Landroid/widget/TextView;Landroid/content/Context;)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setTopMargin(Landroid/view/View;I)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setTopMargin(Landroid/view/View;IZ)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->setVisibilityIfNonNull(Landroid/view/View;I)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->updateLayoutParams(Landroid/view/View;II)V -HSPLorg/thoughtcrime/securesms/util/ViewUtil;->updateLayoutParamsIfNonNull(Landroid/view/View;II)V HSPLorg/thoughtcrime/securesms/util/WakeLockUtil;->()V HSPLorg/thoughtcrime/securesms/util/WakeLockUtil;->acquire(Landroid/content/Context;IJLjava/lang/String;)Landroid/os/PowerManager$WakeLock; HSPLorg/thoughtcrime/securesms/util/WakeLockUtil;->prefixTag(Ljava/lang/String;)Ljava/lang/String; @@ -28399,31 +27434,17 @@ HSPLorg/thoughtcrime/securesms/util/WindowUtil;->setNavigationBarColor(Landroid/ HSPLorg/thoughtcrime/securesms/util/WindowUtil;->setStatusBarColor(Landroid/view/Window;I)V HSPLorg/thoughtcrime/securesms/util/WindowUtil;->setSystemUiFlags(Landroid/view/Window;I)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/LayoutFactory;->(Lj$/util/function/Function;I)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/LayoutFactory;->createViewHolder(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->()V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->(Z)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->getItemTypes()Ljava/util/Map; HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onAttachedToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;ILjava/util/List;)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onBindViewHolder(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;I)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onBindViewHolder(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;ILjava/util/List;)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onViewAttachedToWindow(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->registerFactory(Ljava/lang/Class;Lj$/util/function/Function;I)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->registerFactory(Ljava/lang/Class;Lorg/thoughtcrime/securesms/util/adapter/mapping/Factory;)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingDiffCallback;->()V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingModelList;->(Ljava/util/Collection;)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->(Landroid/view/View;)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->onAttachedToWindow()V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->setPayload(Ljava/util/List;)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter$$ExternalSyntheticLambda0;->(II)V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->()V HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->(II)V -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->getItem(I)Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->getItem(I)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel; -HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->getItemViewType(I)I HSPLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->setPagingController(Lorg/signal/paging/PagingController;)V HSPLorg/thoughtcrime/securesms/util/cjkv/CJKVUtil;->isCJKV(Ljava/lang/String;)Z HSPLorg/thoughtcrime/securesms/util/cjkv/CJKVUtil;->isCodepointCJKV(I)Z @@ -28436,17 +27457,7 @@ HSPLorg/thoughtcrime/securesms/util/concurrent/SerialExecutor;->(Ljava/uti HSPLorg/thoughtcrime/securesms/util/concurrent/SerialExecutor;->execute(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/util/concurrent/SerialExecutor;->lambda$execute$0(Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/util/concurrent/SerialExecutor;->scheduleNext()V -HSPLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;Ljava/lang/Runnable;)V HSPLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->(Ljava/util/concurrent/Executor;)V -HSPLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->enqueue(Ljava/lang/Runnable;)Z -HSPLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->execute(Ljava/lang/Runnable;)V -HSPLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->scheduleNext()V -HSPLorg/thoughtcrime/securesms/util/concurrent/SettableFuture;->()V -HSPLorg/thoughtcrime/securesms/util/concurrent/SettableFuture;->(Ljava/lang/Object;)V -HSPLorg/thoughtcrime/securesms/util/concurrent/SettableFuture;->notifyAllListeners()V -HSPLorg/thoughtcrime/securesms/util/concurrent/SettableFuture;->set(Ljava/lang/Object;)Z -HSPLorg/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat;->()V -HSPLorg/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat;->(Landroid/content/Context;)V HSPLorg/thoughtcrime/securesms/util/dynamiclanguage/DynamicLanguageContextWrapper;->getUsersSelectedLocale(Landroid/content/Context;)Ljava/util/Locale; HSPLorg/thoughtcrime/securesms/util/dynamiclanguage/DynamicLanguageContextWrapper;->prepareOverrideConfiguration(Landroid/content/Context;Landroid/content/res/Configuration;)V HSPLorg/thoughtcrime/securesms/util/dynamiclanguage/DynamicLanguageContextWrapper;->updateContext(Landroid/content/Context;)V @@ -28524,15 +27535,9 @@ HSPLorg/thoughtcrime/securesms/util/storage/FileStorage;->getAllFiles(Landroid/c HSPLorg/thoughtcrime/securesms/util/views/DarkOverflowToolbar;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/util/views/DarkOverflowToolbar;->init()V HSPLorg/thoughtcrime/securesms/util/views/NullableStub;->(Landroid/view/ViewStub;)V -HSPLorg/thoughtcrime/securesms/util/views/NullableStub;->get()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/views/NullableStub;->isResolvable()Z -HSPLorg/thoughtcrime/securesms/util/views/NullableStub;->require()Ljava/lang/Object; -HSPLorg/thoughtcrime/securesms/util/views/NullableStub;->resolved()Z HSPLorg/thoughtcrime/securesms/util/views/SlideUpWithSnackbarBehavior;->(Landroid/content/Context;Landroid/util/AttributeSet;)V HSPLorg/thoughtcrime/securesms/util/views/Stub;->(Landroid/view/ViewStub;)V HSPLorg/thoughtcrime/securesms/util/views/Stub;->get()Landroid/view/View; -HSPLorg/thoughtcrime/securesms/util/views/Stub;->getVisibility()I -HSPLorg/thoughtcrime/securesms/util/views/Stub;->isVisible()Z HSPLorg/thoughtcrime/securesms/util/views/Stub;->resolved()Z HSPLorg/thoughtcrime/securesms/util/views/Stub;->setVisibility(I)V HSPLorg/thoughtcrime/securesms/video/exo/ExoPlayerPool$Companion;->()V @@ -28585,7 +27590,14 @@ HSPLorg/webrtc/PeerConnectionFactory;->initialize(Lorg/webrtc/PeerConnectionFact HSPLorg/webrtc/WebRtcClassLoader;->getClassLoader()Ljava/lang/Object; HSPLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->()V HSPLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lorg/whispersystems/signalservice/api/util/CredentialsProvider;Ljava/lang/String;Lorg/whispersystems/signalservice/api/groupsv2/GroupsV2Operations;Z)V +HSPLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->getPreKeyCounts(Lorg/whispersystems/signalservice/api/push/ServiceIdType;)Lorg/whispersystems/signalservice/internal/push/OneTimePreKeyCounts; HSPLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->getSecureValueRecoveryV2(Ljava/lang/String;)Lorg/whispersystems/signalservice/api/svr/SecureValueRecoveryV2; +HSPLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->getSenderCertificate()[B +HSPLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->setAccountAttributes(Lorg/whispersystems/signalservice/api/account/AccountAttributes;)V +HSPLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver$$ExternalSyntheticLambda0;->()V +HSPLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;->(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lorg/whispersystems/signalservice/api/util/CredentialsProvider;Ljava/lang/String;Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Z)V +HSPLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;->retrieveProfile(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)Lorg/signal/core/util/concurrent/ListenableFuture; +HSPLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;->retrieveStickerManifest([B[B)Lorg/whispersystems/signalservice/api/messages/SignalServiceStickerManifest; HSPLorg/whispersystems/signalservice/api/SignalWebSocket$$ExternalSyntheticLambda0;->(Lio/reactivex/rxjava3/subjects/BehaviorSubject;)V HSPLorg/whispersystems/signalservice/api/SignalWebSocket$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->()V @@ -28599,10 +27611,39 @@ HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->getUnidentifiedWebSoc HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->getWebSocket()Lorg/whispersystems/signalservice/internal/websocket/WebSocketConnection; HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->getWebSocketState()Lio/reactivex/rxjava3/core/Observable; HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->readMessageBatch(JILorg/whispersystems/signalservice/api/SignalWebSocket$MessageReceivedCallback;)Z +HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->request(Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;)Lio/reactivex/rxjava3/core/Single; +HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->request(Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;Lj$/util/Optional;)Lio/reactivex/rxjava3/core/Single; HSPLorg/whispersystems/signalservice/api/SignalWebSocket;->waitForSingleMessage(J)Lj$/util/Optional; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->(ZZZZZZZZ)V +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getAnnouncementGroup()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getChangeNumber()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getGiftBadges()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getPaymentActivation()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getPni()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getSenderKey()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getStorage()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getStories()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->toString()Ljava/lang/String; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->(Ljava/lang/String;IZLjava/lang/String;[BZLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;ZLjava/lang/String;ILjava/lang/String;)V +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->(Ljava/lang/String;IZZZLjava/lang/String;[BZZLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;Ljava/lang/String;ILjava/lang/String;)V +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getCapabilities()Lorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getDiscoverableByPhoneNumber()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getFetchesMessages()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getName()Ljava/lang/String; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getPniRegistrationId()I +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getRecoveryPassword()Ljava/lang/String; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getRegistrationId()I +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getRegistrationLock()Ljava/lang/String; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getSignalingKey()Ljava/lang/String; +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getUnidentifiedAccessKey()[B +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getUnrestrictedUnidentifiedAccess()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getVideo()Z +HSPLorg/whispersystems/signalservice/api/account/AccountAttributes;->getVoice()Z HSPLorg/whispersystems/signalservice/api/account/PreKeyCollection;->(Lorg/signal/libsignal/protocol/IdentityKey;Lorg/signal/libsignal/protocol/state/SignedPreKeyRecord;Lorg/signal/libsignal/protocol/state/KyberPreKeyRecord;)V HSPLorg/whispersystems/signalservice/api/account/PreKeyCollection;->getLastResortKyberPreKey()Lorg/signal/libsignal/protocol/state/KyberPreKeyRecord; HSPLorg/whispersystems/signalservice/api/account/PreKeyCollection;->getSignedPreKey()Lorg/signal/libsignal/protocol/state/SignedPreKeyRecord; +HSPLorg/whispersystems/signalservice/api/crypto/UnidentifiedAccess;->createEmptyByteArray(I)[B +HSPLorg/whispersystems/signalservice/api/crypto/UnidentifiedAccess;->deriveAccessKeyFrom(Lorg/signal/libsignal/zkgroup/profiles/ProfileKey;)[B HSPLorg/whispersystems/signalservice/api/groupsv2/ClientZkOperations;->(Lorg/signal/libsignal/zkgroup/ServerPublicParams;)V HSPLorg/whispersystems/signalservice/api/groupsv2/ClientZkOperations;->create(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;)Lorg/whispersystems/signalservice/api/groupsv2/ClientZkOperations; HSPLorg/whispersystems/signalservice/api/groupsv2/ClientZkOperations;->getAuthOperations()Lorg/signal/libsignal/zkgroup/auth/ClientZkAuthOperations; @@ -28652,15 +27693,12 @@ HSPLorg/whispersystems/signalservice/api/payments/Money$MobileCoin;->(Ljav HSPLorg/whispersystems/signalservice/api/payments/Money;->()V HSPLorg/whispersystems/signalservice/api/payments/Money;->mobileCoin(Ljava/math/BigDecimal;)Lorg/whispersystems/signalservice/api/payments/Money$MobileCoin; HSPLorg/whispersystems/signalservice/api/payments/Money;->picoMobileCoin(Ljava/math/BigInteger;)Lorg/whispersystems/signalservice/api/payments/Money$MobileCoin; -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->(ZZZZZZZZZ)V -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isAnnouncementGroup()Z -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isChangeNumber()Z -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isGiftBadges()Z -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isGv1Migration()Z +HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->(ZZZ)V HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isPaymentActivation()Z HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isPnp()Z -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isSenderKey()Z -HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities;->isStories()Z +HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;->$values()[Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType; +HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;->()V +HSPLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;->(Ljava/lang/String;I)V HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI$Companion;->()V HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI$Companion;->from(Ljava/util/UUID;)Lorg/whispersystems/signalservice/api/push/ServiceId$ACI; @@ -28669,6 +27707,7 @@ HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI$Companion;->parseOrT HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->()V HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->(Lorg/signal/libsignal/protocol/ServiceId$Aci;)V HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->equals(Ljava/lang/Object;)Z +HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->getLibSignalAci()Lorg/signal/libsignal/protocol/ServiceId$Aci; HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->hashCode()I HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->parseOrThrow(Ljava/lang/String;)Lorg/whispersystems/signalservice/api/push/ServiceId$ACI; HSPLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->toString()Ljava/lang/String; @@ -28694,13 +27733,36 @@ HSPLorg/whispersystems/signalservice/api/push/ServiceId;->(Lorg/signal/lib HSPLorg/whispersystems/signalservice/api/push/ServiceId;->fromLibSignal(Lorg/signal/libsignal/protocol/ServiceId;)Lorg/whispersystems/signalservice/api/push/ServiceId; HSPLorg/whispersystems/signalservice/api/push/ServiceId;->isUnknown()Z HSPLorg/whispersystems/signalservice/api/push/ServiceId;->toString()Ljava/lang/String; +HSPLorg/whispersystems/signalservice/api/push/ServiceIdType;->$values()[Lorg/whispersystems/signalservice/api/push/ServiceIdType; +HSPLorg/whispersystems/signalservice/api/push/ServiceIdType;->()V +HSPLorg/whispersystems/signalservice/api/push/ServiceIdType;->(Ljava/lang/String;ILjava/lang/String;)V +HSPLorg/whispersystems/signalservice/api/push/ServiceIdType;->queryParam()Ljava/lang/String; HSPLorg/whispersystems/signalservice/api/push/SignalServiceAddress;->(Lorg/whispersystems/signalservice/api/push/ServiceId;Lj$/util/Optional;)V HSPLorg/whispersystems/signalservice/api/push/SignalServiceAddress;->(Lorg/whispersystems/signalservice/api/push/ServiceId;Ljava/lang/String;)V HSPLorg/whispersystems/signalservice/api/push/SignalServiceAddress;->getNumber()Lj$/util/Optional; HSPLorg/whispersystems/signalservice/api/push/SignalServiceAddress;->getServiceId()Lorg/whispersystems/signalservice/api/push/ServiceId; +HSPLorg/whispersystems/signalservice/api/push/exceptions/NonSuccessfulResponseCodeException;->(ILjava/lang/String;)V +HSPLorg/whispersystems/signalservice/api/push/exceptions/NonSuccessfulResponseCodeException;->getCode()I HSPLorg/whispersystems/signalservice/api/services/DonationsService;->()V HSPLorg/whispersystems/signalservice/api/services/DonationsService;->(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lorg/whispersystems/signalservice/api/util/CredentialsProvider;Ljava/lang/String;Lorg/whispersystems/signalservice/api/groupsv2/GroupsV2Operations;Z)V HSPLorg/whispersystems/signalservice/api/services/DonationsService;->(Lorg/whispersystems/signalservice/internal/push/PushServiceSocket;)V +HSPLorg/whispersystems/signalservice/api/services/MessagingService$$ExternalSyntheticLambda4;->(Lorg/whispersystems/signalservice/internal/websocket/ResponseMapper;)V +HSPLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda1;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)V +HSPLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda1;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda2;->()V +HSPLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda3;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)V +HSPLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda3;->apply(Ljava/lang/Object;)Ljava/lang/Object; +HSPLorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseMapper;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/signal/libsignal/zkgroup/profiles/ProfileKeyCredentialRequestContext;)V +HSPLorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseProcessor;->(Lorg/whispersystems/signalservice/internal/ServiceResponse;)V +HSPLorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseProcessor;->getError()Ljava/lang/Throwable; +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->$r8$lambda$qreHJhpvwxlLuI7XzIfP9eBBI24(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->$r8$lambda$vXxdyhUGBLq7AFV9vG9NvMDxbNI(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->()V +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->(Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;Lorg/whispersystems/signalservice/api/SignalWebSocket;)V +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->getProfile(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)Lio/reactivex/rxjava3/core/Single; +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->getProfileRestFallback(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)Lio/reactivex/rxjava3/core/Single; +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->lambda$getProfile$0(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; +HSPLorg/whispersystems/signalservice/api/services/ProfileService;->lambda$getProfileRestFallback$3(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; HSPLorg/whispersystems/signalservice/api/svr/SecureValueRecoveryV2$Companion;->()V HSPLorg/whispersystems/signalservice/api/svr/SecureValueRecoveryV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V HSPLorg/whispersystems/signalservice/api/svr/SecureValueRecoveryV2;->()V @@ -28731,10 +27793,15 @@ HSPLorg/whispersystems/signalservice/api/websocket/WebSocketConnectionState;->is HSPLorg/whispersystems/signalservice/api/websocket/WebSocketConnectionState;->values()[Lorg/whispersystems/signalservice/api/websocket/WebSocketConnectionState; HSPLorg/whispersystems/signalservice/api/websocket/WebSocketUnavailableException;->()V HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->(ILjava/lang/String;Ljava/lang/Object;Ljava/lang/Throwable;Ljava/lang/Throwable;)V +HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->forApplicationError(Ljava/lang/Throwable;ILjava/lang/String;)Lorg/whispersystems/signalservice/internal/ServiceResponse; HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->forResult(Ljava/lang/Object;ILjava/lang/String;)Lorg/whispersystems/signalservice/internal/ServiceResponse; +HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->forUnknownError(Ljava/lang/Throwable;)Lorg/whispersystems/signalservice/internal/ServiceResponse; +HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->getApplicationError()Lj$/util/Optional; +HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->getExecutionError()Lj$/util/Optional; HSPLorg/whispersystems/signalservice/internal/ServiceResponse;->getResult()Lj$/util/Optional; HSPLorg/whispersystems/signalservice/internal/ServiceResponseProcessor$DefaultProcessor;->(Lorg/whispersystems/signalservice/internal/ServiceResponse;)V HSPLorg/whispersystems/signalservice/internal/ServiceResponseProcessor;->(Lorg/whispersystems/signalservice/internal/ServiceResponse;)V +HSPLorg/whispersystems/signalservice/internal/ServiceResponseProcessor;->getError()Ljava/lang/Throwable; HSPLorg/whispersystems/signalservice/internal/ServiceResponseProcessor;->getResult()Ljava/lang/Object; HSPLorg/whispersystems/signalservice/internal/ServiceResponseProcessor;->getResultOrThrow()Ljava/lang/Object; HSPLorg/whispersystems/signalservice/internal/ServiceResponseProcessor;->hasResult()Z @@ -28766,24 +27833,52 @@ HSPLorg/whispersystems/signalservice/internal/configuration/SignalUrl;->getUrl() HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda10;->()V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda11;->()V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda12;->()V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda14;->()V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$1;->(Lorg/whispersystems/signalservice/internal/push/PushServiceSocket;Lorg/signal/core/util/concurrent/SettableFuture;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$1;->onResponse(Lokhttp3/Call;Lokhttp3/Response;)V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$2;->()V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->(Lokhttp3/OkHttpClient;Ljava/lang/String;Lj$/util/Optional;)V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->(Lokhttp3/OkHttpClient;Ljava/lang/String;Lj$/util/Optional;Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder-IA;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->getClient()Lokhttp3/OkHttpClient; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->getHostHeader()Lj$/util/Optional; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->getUrl()Ljava/lang/String; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$EmptyResponseCodeHandler;->()V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$EmptyResponseCodeHandler;->(Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$EmptyResponseCodeHandler-IA;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$EmptyResponseCodeHandler;->handle(ILokhttp3/ResponseBody;)V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ServiceConnectionHolder;->(Lokhttp3/OkHttpClient;Lokhttp3/OkHttpClient;Ljava/lang/String;Lj$/util/Optional;)V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ServiceConnectionHolder;->(Lokhttp3/OkHttpClient;Lokhttp3/OkHttpClient;Ljava/lang/String;Lj$/util/Optional;Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ServiceConnectionHolder-IA;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->-$$Nest$mvalidateServiceResponse(Lorg/whispersystems/signalservice/internal/push/PushServiceSocket;Lokhttp3/Response;)Lokhttp3/Response; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->()V HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lorg/whispersystems/signalservice/api/util/CredentialsProvider;Ljava/lang/String;Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Z)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->buildOkHttpClient(Z)Lokhttp3/OkHttpClient; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->buildServiceRequest(Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;Ljava/util/Map;Lj$/util/Optional;Z)Lokhttp3/Request; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->createCdnClientsMap(Ljava/util/Map;Ljava/util/List;Lj$/util/Optional;Lj$/util/Optional;)Ljava/util/Map; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->createConnectionClient(Lorg/whispersystems/signalservice/internal/configuration/SignalUrl;Ljava/util/List;Lj$/util/Optional;Lj$/util/Optional;)Lokhttp3/OkHttpClient; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->createConnectionHolders([Lorg/whispersystems/signalservice/internal/configuration/SignalUrl;Ljava/util/List;Lj$/util/Optional;Lj$/util/Optional;)[Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->createServiceConnectionHolders([Lorg/whispersystems/signalservice/internal/configuration/SignalUrl;Ljava/util/List;Lj$/util/Optional;Lj$/util/Optional;)[Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ServiceConnectionHolder; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->downloadFromCdn(Ljava/io/OutputStream;JILjava/lang/String;JLorg/whispersystems/signalservice/api/messages/SignalServiceAttachment$ProgressListener;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getAuthorizationHeader(Lorg/whispersystems/signalservice/api/util/CredentialsProvider;)Ljava/lang/String; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getAvailablePreKeys(Lorg/whispersystems/signalservice/api/push/ServiceIdType;)Lorg/whispersystems/signalservice/internal/push/OneTimePreKeyCounts; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getRandom([Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;Ljava/security/SecureRandom;)Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getSenderCertificate()[B +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getServiceConnection(Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;Ljava/util/Map;Lj$/util/Optional;Z)Lokhttp3/Response; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->jsonRequestBody(Ljava/lang/String;)Lokhttp3/RequestBody; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->makeServiceRequest(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->makeServiceRequest(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ResponseCodeHandler;Lj$/util/Optional;)Ljava/lang/String; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->makeServiceRequest(Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;Ljava/util/Map;Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ResponseCodeHandler;Lj$/util/Optional;Z)Lokhttp3/Response; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->retrieveStickerManifest([B)[B +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->retrieveVersionedProfile(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/signal/libsignal/zkgroup/profiles/ProfileKey;Lj$/util/Optional;Ljava/util/Locale;)Lorg/signal/core/util/concurrent/ListenableFuture; +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->setAccountAttributes(Lorg/whispersystems/signalservice/api/account/AccountAttributes;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->submitServiceRequest(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lj$/util/Optional;)Lorg/signal/core/util/concurrent/ListenableFuture; HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->validateConfiguration(Ljava/util/Map;)V +HSPLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->validateServiceResponse(Lokhttp3/Response;)Lokhttp3/Response; HSPLorg/whispersystems/signalservice/internal/push/VerifyAccountResponse;->(Ljava/lang/String;Ljava/lang/String;Z)V HSPLorg/whispersystems/signalservice/internal/push/VerifyAccountResponse;->getPni()Ljava/lang/String; HSPLorg/whispersystems/signalservice/internal/push/VerifyAccountResponse;->getUuid()Ljava/lang/String; HSPLorg/whispersystems/signalservice/internal/push/VerifyAccountResponse;->isStorageCapable()Z +HSPLorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil;->formatLanguages(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +HSPLorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil;->getAcceptLanguageHeader(Ljava/util/Locale;)Ljava/lang/String; +HSPLorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil;->getHeadersWithAcceptLanguage(Ljava/util/Locale;)Ljava/util/Map; HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager$1;->()V HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager;->()V HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager;->(Ljavax/net/ssl/X509TrustManager;)V @@ -28791,10 +27886,27 @@ HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager;->ch HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager;->createFor(Lorg/whispersystems/signalservice/api/push/TrustStore;)[Ljavax/net/ssl/TrustManager; HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager;->createFor([Ljavax/net/ssl/TrustManager;)[Ljavax/net/ssl/TrustManager; HSPLorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager;->getAcceptedIssuers()[Ljava/security/cert/X509Certificate; +HSPLorg/whispersystems/signalservice/internal/util/Hex;->()V +HSPLorg/whispersystems/signalservice/internal/util/Hex;->appendHexChar(Ljava/lang/StringBuffer;I)V +HSPLorg/whispersystems/signalservice/internal/util/Hex;->toStringCondensed([B)Ljava/lang/String; HSPLorg/whispersystems/signalservice/internal/util/JsonUtil;->()V HSPLorg/whispersystems/signalservice/internal/util/JsonUtil;->fromJson(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object; +HSPLorg/whispersystems/signalservice/internal/util/JsonUtil;->toJson(Ljava/lang/Object;)Ljava/lang/String; HSPLorg/whispersystems/signalservice/internal/util/Util;->immutableList([Ljava/lang/Object;)Ljava/util/List; HSPLorg/whispersystems/signalservice/internal/util/Util;->wait(Ljava/lang/Object;J)V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder;->()V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder;->build()Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper; +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->()V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->()V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->(Ljava/util/Map;)V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->(Ljava/util/Map;Lorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper-IA;)V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->extend()Lorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder; +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder;->(Ljava/lang/Class;)V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder;->build()Lorg/whispersystems/signalservice/internal/websocket/ResponseMapper; +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder;->withResponseMapper(Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper;)Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder; +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper;->(Ljava/lang/Class;Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper;Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper;)V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper;->(Ljava/lang/Class;Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper;Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper;Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper-IA;)V +HSPLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper;->extend(Ljava/lang/Class;)Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder; HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->()V HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->(Ljava/lang/String;Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lj$/util/Optional;Ljava/lang/String;Lorg/whispersystems/signalservice/api/websocket/HealthMonitor;Ljava/lang/String;Z)V HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->(Ljava/lang/String;Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lj$/util/Optional;Ljava/lang/String;Lorg/whispersystems/signalservice/api/websocket/HealthMonitor;Z)V @@ -28809,6 +27921,17 @@ HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->lo HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->onFailure(Lokhttp3/WebSocket;Ljava/lang/Throwable;Lokhttp3/Response;)V HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->readRequest(J)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage; HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketConnection;->warn(Ljava/lang/String;Ljava/lang/Throwable;)V +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->()V +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->build()Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage; +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->headers(Ljava/util/List;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->id(Ljava/lang/Long;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->path(Ljava/lang/String;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->verb(Ljava/lang/String;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion$ADAPTER$1;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Lcom/squareup/wire/Syntax;)V +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion;->()V +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;->()V +HSPLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;->(Ljava/lang/String;Ljava/lang/String;Lokio/ByteString;Ljava/util/List;Ljava/lang/Long;Lokio/ByteString;)V HSPLorg/whispersystems/util/StringUtil;->utf8(Ljava/lang/String;)[B HSPLrxdogtag2/DogTagMaybeObserver$$ExternalSyntheticLambda0;->(Lrxdogtag2/DogTagMaybeObserver;)V HSPLrxdogtag2/DogTagMaybeObserver$$ExternalSyntheticLambda1;->(Lrxdogtag2/DogTagMaybeObserver;Lio/reactivex/rxjava3/disposables/Disposable;)V @@ -28939,6 +28062,7 @@ Landroidx/activity/ComponentActivity$2; Landroidx/activity/ComponentActivity$3; Landroidx/activity/ComponentActivity$4; Landroidx/activity/ComponentActivity$5; +Landroidx/activity/ComponentActivity$6; Landroidx/activity/ComponentActivity$Api19Impl; Landroidx/activity/ComponentActivity$NonConfigurationInstances; Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutor; @@ -28950,6 +28074,8 @@ Landroidx/activity/FullyDrawnReporterOwner; Landroidx/activity/OnBackPressedCallback; Landroidx/activity/OnBackPressedDispatcher$LifecycleOnBackPressedCancellable; Landroidx/activity/OnBackPressedDispatcher$OnBackPressedCancellable; +Landroidx/activity/OnBackPressedDispatcher$addCallback$1; +Landroidx/activity/OnBackPressedDispatcher$addCancellableCallback$1; Landroidx/activity/OnBackPressedDispatcher; Landroidx/activity/OnBackPressedDispatcherOwner; Landroidx/activity/R$id; @@ -29014,7 +28140,6 @@ Landroidx/appcompat/resources/R$drawable; Landroidx/appcompat/view/ActionBarPolicy; Landroidx/appcompat/view/ActionMode$Callback; Landroidx/appcompat/view/ActionMode; -Landroidx/appcompat/view/CollapsibleActionView; Landroidx/appcompat/view/ContextThemeWrapper; Landroidx/appcompat/view/SupportMenuInflater$MenuState; Landroidx/appcompat/view/SupportMenuInflater; @@ -29031,7 +28156,6 @@ Landroidx/appcompat/view/menu/MenuPresenter$Callback; Landroidx/appcompat/view/menu/MenuPresenter; Landroidx/appcompat/view/menu/MenuView$ItemView; Landroidx/appcompat/view/menu/MenuView; -Landroidx/appcompat/view/menu/SubMenuBuilder; Landroidx/appcompat/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback; Landroidx/appcompat/widget/ActionMenuPresenter$ActionMenuPopupCallback; Landroidx/appcompat/widget/ActionMenuPresenter$OverflowMenuButton$1; @@ -29044,7 +28168,6 @@ Landroidx/appcompat/widget/ActionMenuView$LayoutParams; Landroidx/appcompat/widget/ActionMenuView$MenuBuilderCallback; Landroidx/appcompat/widget/ActionMenuView$OnMenuItemClickListener; Landroidx/appcompat/widget/ActionMenuView; -Landroidx/appcompat/widget/AppCompatAutoCompleteTextView; Landroidx/appcompat/widget/AppCompatBackgroundHelper; Landroidx/appcompat/widget/AppCompatButton; Landroidx/appcompat/widget/AppCompatCheckBox; @@ -29093,20 +28216,6 @@ Landroidx/appcompat/widget/ResourceManagerInternal$ResourceManagerHooks; Landroidx/appcompat/widget/ResourceManagerInternal; Landroidx/appcompat/widget/ResourcesWrapper; Landroidx/appcompat/widget/RtlSpacingHelper; -Landroidx/appcompat/widget/SearchView$10; -Landroidx/appcompat/widget/SearchView$1; -Landroidx/appcompat/widget/SearchView$2; -Landroidx/appcompat/widget/SearchView$3; -Landroidx/appcompat/widget/SearchView$4; -Landroidx/appcompat/widget/SearchView$5; -Landroidx/appcompat/widget/SearchView$6; -Landroidx/appcompat/widget/SearchView$7; -Landroidx/appcompat/widget/SearchView$8; -Landroidx/appcompat/widget/SearchView$9; -Landroidx/appcompat/widget/SearchView$OnQueryTextListener; -Landroidx/appcompat/widget/SearchView$SearchAutoComplete$1; -Landroidx/appcompat/widget/SearchView$SearchAutoComplete; -Landroidx/appcompat/widget/SearchView; Landroidx/appcompat/widget/ThemeUtils; Landroidx/appcompat/widget/TintContextWrapper; Landroidx/appcompat/widget/TintInfo; @@ -29119,8 +28228,6 @@ Landroidx/appcompat/widget/Toolbar$3; Landroidx/appcompat/widget/Toolbar$ExpandedActionViewMenuPresenter; Landroidx/appcompat/widget/Toolbar$LayoutParams; Landroidx/appcompat/widget/Toolbar$OnMenuItemClickListener; -Landroidx/appcompat/widget/Toolbar$SavedState$1; -Landroidx/appcompat/widget/Toolbar$SavedState; Landroidx/appcompat/widget/Toolbar; Landroidx/appcompat/widget/ToolbarWidgetWrapper$1; Landroidx/appcompat/widget/ToolbarWidgetWrapper; @@ -29157,14 +28264,6 @@ Landroidx/asynclayoutinflater/view/AsyncLayoutInflater$OnInflateFinishedListener Landroidx/asynclayoutinflater/view/AsyncLayoutInflater; Landroidx/camera/camera2/internal/compat/params/OutputConfigurationCompatApi24Impl$OutputConfigurationParamsApi24$$ExternalSyntheticBackport1; Landroidx/camera/view/PreviewView$1$$ExternalSyntheticBackportWithForwarding0; -Landroidx/cardview/R$style; -Landroidx/cardview/R$styleable; -Landroidx/cardview/widget/CardView$1; -Landroidx/cardview/widget/CardView; -Landroidx/cardview/widget/CardViewApi21Impl; -Landroidx/cardview/widget/CardViewDelegate; -Landroidx/cardview/widget/CardViewImpl; -Landroidx/cardview/widget/RoundRectDrawable; Landroidx/collection/ArrayMap$EntrySet; Landroidx/collection/ArrayMap$MapIterator; Landroidx/collection/ArrayMap$ValueCollection; @@ -29198,10 +28297,8 @@ Landroidx/constraintlayout/core/Cache; Landroidx/constraintlayout/core/LinearSystem$Row; Landroidx/constraintlayout/core/LinearSystem$ValuesRow; Landroidx/constraintlayout/core/LinearSystem; -Landroidx/constraintlayout/core/Metrics; Landroidx/constraintlayout/core/Pools$Pool; Landroidx/constraintlayout/core/Pools$SimplePool; -Landroidx/constraintlayout/core/PriorityGoalRow$1; Landroidx/constraintlayout/core/PriorityGoalRow$GoalVariableAccessor; Landroidx/constraintlayout/core/PriorityGoalRow; Landroidx/constraintlayout/core/SolverVariable$Type; @@ -29250,11 +28347,9 @@ Landroidx/constraintlayout/widget/ConstraintSet$Motion; Landroidx/constraintlayout/widget/ConstraintSet$PropertySet; Landroidx/constraintlayout/widget/ConstraintSet$Transform; Landroidx/constraintlayout/widget/ConstraintSet; -Landroidx/constraintlayout/widget/ConstraintsChangedListener; Landroidx/constraintlayout/widget/Guideline; Landroidx/constraintlayout/widget/R$id; Landroidx/constraintlayout/widget/R$styleable; -Landroidx/constraintlayout/widget/SharedValues; Landroidx/constraintlayout/widget/VirtualLayout; Landroidx/coordinatorlayout/R$attr; Landroidx/coordinatorlayout/R$styleable; @@ -29263,8 +28358,6 @@ Landroidx/coordinatorlayout/widget/CoordinatorLayout$Behavior; Landroidx/coordinatorlayout/widget/CoordinatorLayout$HierarchyChangeListener; Landroidx/coordinatorlayout/widget/CoordinatorLayout$LayoutParams; Landroidx/coordinatorlayout/widget/CoordinatorLayout$OnPreDrawListener; -Landroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState$1; -Landroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState; Landroidx/coordinatorlayout/widget/CoordinatorLayout$ViewElevationComparator; Landroidx/coordinatorlayout/widget/CoordinatorLayout; Landroidx/coordinatorlayout/widget/DirectedAcyclicGraph; @@ -29279,7 +28372,6 @@ Landroidx/core/app/ActivityCompat; Landroidx/core/app/AppOpsManagerCompat$Api23Impl$$ExternalSyntheticApiModelOutline1; Landroidx/core/app/AppOpsManagerCompat$Api23Impl; Landroidx/core/app/AppOpsManagerCompat; -Landroidx/core/app/BundleCompat; Landroidx/core/app/ComponentActivity; Landroidx/core/app/CoreComponentFactory; Landroidx/core/app/NavUtils; @@ -29325,12 +28417,6 @@ Landroidx/core/graphics/drawable/WrappedDrawable; Landroidx/core/internal/view/SupportMenu; Landroidx/core/internal/view/SupportMenuItem; Landroidx/core/math/MathUtils; -Landroidx/core/os/BuildCompat$Api30Impl$$ExternalSyntheticApiModelOutline0; -Landroidx/core/os/BuildCompat$Api30Impl; -Landroidx/core/os/BuildCompat; -Landroidx/core/os/BundleCompat$Api18Impl; -Landroidx/core/os/BundleCompat; -Landroidx/core/os/BundleKt; Landroidx/core/os/CancellationSignal$OnCancelListener; Landroidx/core/os/CancellationSignal; Landroidx/core/os/ConfigurationCompat$Api24Impl$$ExternalSyntheticApiModelOutline0; @@ -29347,8 +28433,6 @@ Landroidx/core/os/TraceCompat; Landroidx/core/os/UserManagerCompat$Api24Impl$$ExternalSyntheticApiModelOutline0; Landroidx/core/os/UserManagerCompat$Api24Impl; Landroidx/core/os/UserManagerCompat; -Landroidx/core/text/util/LinkifyCompat$$ExternalSyntheticLambda0; -Landroidx/core/text/util/LinkifyCompat; Landroidx/core/util/Consumer; Landroidx/core/util/ObjectsCompat$Api19Impl; Landroidx/core/util/ObjectsCompat; @@ -29507,9 +28591,6 @@ Landroidx/core/widget/TintableCompoundButton; Landroidx/core/widget/TintableCompoundDrawablesView; Landroidx/customview/poolingcontainer/PoolingContainer; Landroidx/customview/poolingcontainer/R$id; -Landroidx/customview/view/AbsSavedState$1; -Landroidx/customview/view/AbsSavedState$2; -Landroidx/customview/view/AbsSavedState; Landroidx/customview/widget/ExploreByTouchHelper$1; Landroidx/customview/widget/ExploreByTouchHelper$2; Landroidx/customview/widget/ExploreByTouchHelper; @@ -29573,7 +28654,6 @@ Landroidx/fragment/app/Fragment$6; Landroidx/fragment/app/Fragment$7; Landroidx/fragment/app/Fragment$9; Landroidx/fragment/app/Fragment$AnimationInfo; -Landroidx/fragment/app/Fragment$Api19Impl; Landroidx/fragment/app/Fragment$OnPreAttachedListener; Landroidx/fragment/app/Fragment$SavedState; Landroidx/fragment/app/Fragment; @@ -29601,24 +28681,17 @@ Landroidx/fragment/app/FragmentManager$2; Landroidx/fragment/app/FragmentManager$3; Landroidx/fragment/app/FragmentManager$4; Landroidx/fragment/app/FragmentManager$5; -Landroidx/fragment/app/FragmentManager$6; Landroidx/fragment/app/FragmentManager$7; Landroidx/fragment/app/FragmentManager$8; Landroidx/fragment/app/FragmentManager$9; Landroidx/fragment/app/FragmentManager$FragmentIntentSenderContract; -Landroidx/fragment/app/FragmentManager$LifecycleAwareResultListener; Landroidx/fragment/app/FragmentManager$OnBackStackChangedListener; Landroidx/fragment/app/FragmentManager$OpGenerator; Landroidx/fragment/app/FragmentManager; Landroidx/fragment/app/FragmentManagerImpl; -Landroidx/fragment/app/FragmentManagerState$1; -Landroidx/fragment/app/FragmentManagerState; Landroidx/fragment/app/FragmentManagerViewModel$1; Landroidx/fragment/app/FragmentManagerViewModel; Landroidx/fragment/app/FragmentOnAttachListener; -Landroidx/fragment/app/FragmentResultListener; -Landroidx/fragment/app/FragmentState$1; -Landroidx/fragment/app/FragmentState; Landroidx/fragment/app/FragmentStateManager$1; Landroidx/fragment/app/FragmentStateManager$2; Landroidx/fragment/app/FragmentStateManager; @@ -29658,7 +28731,6 @@ Landroidx/lifecycle/DefaultLifecycleObserverAdapter$WhenMappings; Landroidx/lifecycle/DefaultLifecycleObserverAdapter; Landroidx/lifecycle/EmptyActivityLifecycleCallbacks; Landroidx/lifecycle/HasDefaultViewModelProviderFactory; -Landroidx/lifecycle/LegacySavedStateHandleController$OnRecreation; Landroidx/lifecycle/LegacySavedStateHandleController; Landroidx/lifecycle/Lifecycle$Event$Companion$WhenMappings; Landroidx/lifecycle/Lifecycle$Event$Companion; @@ -29700,15 +28772,13 @@ Landroidx/lifecycle/ReportFragment$Companion; Landroidx/lifecycle/ReportFragment$LifecycleCallbacks$Companion; Landroidx/lifecycle/ReportFragment$LifecycleCallbacks; Landroidx/lifecycle/ReportFragment; -Landroidx/lifecycle/SavedStateHandle$$ExternalSyntheticLambda0; -Landroidx/lifecycle/SavedStateHandle$Companion; Landroidx/lifecycle/SavedStateHandle; Landroidx/lifecycle/SavedStateHandleAttacher; Landroidx/lifecycle/SavedStateHandleController; Landroidx/lifecycle/SavedStateHandleSupport$DEFAULT_ARGS_KEY$1; Landroidx/lifecycle/SavedStateHandleSupport$SAVED_STATE_REGISTRY_OWNER_KEY$1; Landroidx/lifecycle/SavedStateHandleSupport$VIEW_MODEL_STORE_OWNER_KEY$1; -Landroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1; +Landroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1; Landroidx/lifecycle/SavedStateHandleSupport; Landroidx/lifecycle/SavedStateHandlesProvider$viewModel$2; Landroidx/lifecycle/SavedStateHandlesProvider; @@ -29717,7 +28787,7 @@ Landroidx/lifecycle/SavedStateViewModelFactory; Landroidx/lifecycle/SavedStateViewModelFactoryKt; Landroidx/lifecycle/Transformations$map$1; Landroidx/lifecycle/Transformations$sam$androidx_lifecycle_Observer$0; -Landroidx/lifecycle/Transformations$switchMap$1$onChanged$1; +Landroidx/lifecycle/Transformations$switchMap$1$1; Landroidx/lifecycle/Transformations$switchMap$1; Landroidx/lifecycle/Transformations; Landroidx/lifecycle/ViewModel; @@ -29768,6 +28838,7 @@ Landroidx/media/MediaSessionManagerImplApi28$RemoteUserInfoImplApi28; Landroidx/media/MediaSessionManagerImplApi28; Landroidx/media/MediaSessionManagerImplBase$RemoteUserInfoImplBase; Landroidx/media/MediaSessionManagerImplBase; +Landroidx/media/session/MediaButtonReceiver; Landroidx/media3/common/AdPlaybackState$$ExternalSyntheticLambda0; Landroidx/media3/common/AdPlaybackState$AdGroup$$ExternalSyntheticLambda0; Landroidx/media3/common/AdPlaybackState$AdGroup; @@ -29777,8 +28848,6 @@ Landroidx/media3/common/AudioAttributes$Builder; Landroidx/media3/common/AudioAttributes; Landroidx/media3/common/AuxEffectInfo; Landroidx/media3/common/BasePlayer; -Landroidx/media3/common/BundleListRetriever$$ExternalSyntheticApiModelOutline0; -Landroidx/media3/common/BundleListRetriever; Landroidx/media3/common/Bundleable$Creator; Landroidx/media3/common/Bundleable; Landroidx/media3/common/DeviceInfo$$ExternalSyntheticLambda0; @@ -29808,7 +28877,6 @@ Landroidx/media3/common/MediaLibraryInfo; Landroidx/media3/common/MediaMetadata$$ExternalSyntheticLambda0; Landroidx/media3/common/MediaMetadata$Builder; Landroidx/media3/common/MediaMetadata; -Landroidx/media3/common/MediaPeriodId; Landroidx/media3/common/MimeTypes; Landroidx/media3/common/ParserException; Landroidx/media3/common/PlaybackException; @@ -29822,22 +28890,24 @@ Landroidx/media3/common/Player$Listener; Landroidx/media3/common/Player$PositionInfo$$ExternalSyntheticLambda0; Landroidx/media3/common/Player$PositionInfo; Landroidx/media3/common/Player; +Landroidx/media3/common/PreviewingVideoGraph$Factory; Landroidx/media3/common/Timeline$$ExternalSyntheticLambda0; Landroidx/media3/common/Timeline$1; Landroidx/media3/common/Timeline$Period$$ExternalSyntheticLambda0; Landroidx/media3/common/Timeline$Period; -Landroidx/media3/common/Timeline$RemotableTimeline; Landroidx/media3/common/Timeline$Window$$ExternalSyntheticLambda0; Landroidx/media3/common/Timeline$Window; Landroidx/media3/common/Timeline; Landroidx/media3/common/TrackGroup; -Landroidx/media3/common/TrackSelectionOverride$$ExternalSyntheticLambda0; -Landroidx/media3/common/TrackSelectionOverride; Landroidx/media3/common/TrackSelectionParameters$$ExternalSyntheticLambda0; +Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences$Builder; +Landroidx/media3/common/TrackSelectionParameters$AudioOffloadPreferences; Landroidx/media3/common/TrackSelectionParameters$Builder; Landroidx/media3/common/TrackSelectionParameters; Landroidx/media3/common/Tracks$$ExternalSyntheticLambda0; Landroidx/media3/common/Tracks; +Landroidx/media3/common/VideoFrameProcessingException; +Landroidx/media3/common/VideoFrameProcessor$Factory; Landroidx/media3/common/VideoSize$$ExternalSyntheticLambda0; Landroidx/media3/common/VideoSize; Landroidx/media3/common/audio/AudioProcessor$AudioFormat; @@ -29847,9 +28917,6 @@ Landroidx/media3/common/audio/AudioProcessorChain; Landroidx/media3/common/audio/BaseAudioProcessor; Landroidx/media3/common/audio/SonicAudioProcessor; Landroidx/media3/common/audio/ToInt16PcmAudioProcessor; -Landroidx/media3/common/text/Cue$$ExternalSyntheticLambda0; -Landroidx/media3/common/text/Cue$Builder; -Landroidx/media3/common/text/Cue; Landroidx/media3/common/text/CueGroup$$ExternalSyntheticLambda0; Landroidx/media3/common/text/CueGroup; Landroidx/media3/common/util/Assertions; @@ -29887,7 +28954,12 @@ Landroidx/media3/common/util/Util$$ExternalSyntheticApiModelOutline3; Landroidx/media3/common/util/Util$$ExternalSyntheticApiModelOutline4; Landroidx/media3/common/util/Util; Landroidx/media3/datasource/DataSource$Factory; +Landroidx/media3/datasource/DataSourceBitmapLoader$$ExternalSyntheticLambda0; +Landroidx/media3/datasource/DataSourceBitmapLoader; Landroidx/media3/datasource/DataSourceException; +Landroidx/media3/datasource/DefaultDataSource$Factory; +Landroidx/media3/datasource/DefaultHttpDataSource$Factory; +Landroidx/media3/datasource/HttpDataSource$RequestProperties; Landroidx/media3/datasource/TransferListener; Landroidx/media3/decoder/Buffer; Landroidx/media3/decoder/CryptoInfo$PatternHolderV24$$ExternalSyntheticApiModelOutline0; @@ -29900,15 +28972,11 @@ Landroidx/media3/decoder/DecoderInputBuffer; Landroidx/media3/exoplayer/AudioBecomingNoisyManager$AudioBecomingNoisyReceiver; Landroidx/media3/exoplayer/AudioBecomingNoisyManager$EventListener; Landroidx/media3/exoplayer/AudioBecomingNoisyManager; -Landroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline1; -Landroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline2; -Landroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline3; -Landroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline5; -Landroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline6; Landroidx/media3/exoplayer/AudioFocusManager$AudioFocusListener; Landroidx/media3/exoplayer/AudioFocusManager$PlayerControl; Landroidx/media3/exoplayer/AudioFocusManager; Landroidx/media3/exoplayer/BaseRenderer; +Landroidx/media3/exoplayer/DecoderCounters; Landroidx/media3/exoplayer/DefaultLivePlaybackSpeedControl$Builder; Landroidx/media3/exoplayer/DefaultLivePlaybackSpeedControl; Landroidx/media3/exoplayer/DefaultLoadControl$Builder; @@ -29929,9 +28997,11 @@ Landroidx/media3/exoplayer/ExoPlayer$Builder$$ExternalSyntheticLambda7; Landroidx/media3/exoplayer/ExoPlayer$Builder$$ExternalSyntheticLambda8; Landroidx/media3/exoplayer/ExoPlayer$Builder; Landroidx/media3/exoplayer/ExoPlayer; -Landroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda15; -Landroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda17; +Landroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticApiModelOutline0; +Landroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda16; Landroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda18; +Landroidx/media3/exoplayer/ExoPlayerImpl$$ExternalSyntheticLambda19; +Landroidx/media3/exoplayer/ExoPlayerImpl$Api23$$ExternalSyntheticApiModelOutline0; Landroidx/media3/exoplayer/ExoPlayerImpl$Api31$$ExternalSyntheticApiModelOutline0; Landroidx/media3/exoplayer/ExoPlayerImpl$Api31; Landroidx/media3/exoplayer/ExoPlayerImpl$ComponentListener; @@ -29969,7 +29039,7 @@ Landroidx/media3/exoplayer/analytics/AnalyticsListener; Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda13; Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda26; Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda49; -Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda62; +Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$$ExternalSyntheticLambda67; Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector$MediaPeriodQueueTracker; Landroidx/media3/exoplayer/analytics/DefaultAnalyticsCollector; Landroidx/media3/exoplayer/analytics/DefaultPlaybackSessionManager$$ExternalSyntheticLambda0; @@ -29988,8 +29058,6 @@ Landroidx/media3/exoplayer/analytics/PlaybackSessionManager$Listener; Landroidx/media3/exoplayer/analytics/PlaybackSessionManager; Landroidx/media3/exoplayer/analytics/PlayerId$LogSessionIdApi31; Landroidx/media3/exoplayer/analytics/PlayerId; -Landroidx/media3/exoplayer/audio/AudioCapabilities$Api23$$ExternalSyntheticApiModelOutline0; -Landroidx/media3/exoplayer/audio/AudioCapabilities$Api23$$ExternalSyntheticApiModelOutline1; Landroidx/media3/exoplayer/audio/AudioCapabilities$Api23; Landroidx/media3/exoplayer/audio/AudioCapabilities; Landroidx/media3/exoplayer/audio/AudioRendererEventListener$EventDispatcher; @@ -30002,6 +29070,8 @@ Landroidx/media3/exoplayer/audio/AudioSink; Landroidx/media3/exoplayer/audio/AudioTrackPositionTracker$Listener; Landroidx/media3/exoplayer/audio/AudioTrackPositionTracker; Landroidx/media3/exoplayer/audio/ChannelMappingAudioProcessor; +Landroidx/media3/exoplayer/audio/DefaultAudioOffloadSupportProvider; +Landroidx/media3/exoplayer/audio/DefaultAudioSink$AudioOffloadSupportProvider; Landroidx/media3/exoplayer/audio/DefaultAudioSink$AudioTrackBufferSizeProvider; Landroidx/media3/exoplayer/audio/DefaultAudioSink$Builder; Landroidx/media3/exoplayer/audio/DefaultAudioSink$DefaultAudioProcessorChain; @@ -30093,9 +29163,12 @@ Landroidx/media3/exoplayer/upstream/SlidingPercentile$$ExternalSyntheticLambda0; Landroidx/media3/exoplayer/upstream/SlidingPercentile$$ExternalSyntheticLambda1; Landroidx/media3/exoplayer/upstream/SlidingPercentile$Sample; Landroidx/media3/exoplayer/upstream/SlidingPercentile; +Landroidx/media3/exoplayer/video/CompositingVideoSinkProvider$ReflectivePreviewingSingleInputVideoGraphFactory; +Landroidx/media3/exoplayer/video/CompositingVideoSinkProvider; Landroidx/media3/exoplayer/video/FixedFrameRateEstimator$Matcher; Landroidx/media3/exoplayer/video/FixedFrameRateEstimator; -Landroidx/media3/exoplayer/video/MediaCodecVideoRenderer$VideoFrameProcessorManager; +Landroidx/media3/exoplayer/video/MediaCodecVideoRenderer$ReflectiveDefaultVideoFrameProcessorFactory$$ExternalSyntheticLambda0; +Landroidx/media3/exoplayer/video/MediaCodecVideoRenderer$ReflectiveDefaultVideoFrameProcessorFactory; Landroidx/media3/exoplayer/video/MediaCodecVideoRenderer; Landroidx/media3/exoplayer/video/VideoFrameMetadataListener; Landroidx/media3/exoplayer/video/VideoFrameReleaseHelper$DisplayHelper; @@ -30104,6 +29177,9 @@ Landroidx/media3/exoplayer/video/VideoFrameReleaseHelper$VSyncSampler; Landroidx/media3/exoplayer/video/VideoFrameReleaseHelper; Landroidx/media3/exoplayer/video/VideoRendererEventListener$EventDispatcher; Landroidx/media3/exoplayer/video/VideoRendererEventListener; +Landroidx/media3/exoplayer/video/VideoSink$RenderControl; +Landroidx/media3/exoplayer/video/VideoSink$VideoSinkException; +Landroidx/media3/exoplayer/video/VideoSinkProvider; Landroidx/media3/exoplayer/video/spherical/CameraMotionListener; Landroidx/media3/exoplayer/video/spherical/CameraMotionRenderer; Landroidx/media3/exoplayer/video/spherical/SphericalGLSurfaceView$VideoSurfaceListener; @@ -30114,17 +29190,20 @@ Landroidx/media3/extractor/DefaultExtractorsFactory$ExtensionLoader; Landroidx/media3/extractor/DefaultExtractorsFactory; Landroidx/media3/extractor/ExtractorsFactory; Landroidx/media3/extractor/metadata/MetadataInputBuffer; +Landroidx/media3/extractor/text/CueDecoder; +Landroidx/media3/extractor/text/DefaultSubtitleParserFactory; Landroidx/media3/extractor/text/SubtitleDecoderException; +Landroidx/media3/extractor/text/SubtitleParser$Factory; Landroidx/media3/session/CacheBitmapLoader; Landroidx/media3/session/CommandButton$$ExternalSyntheticLambda0; Landroidx/media3/session/CommandButton$Builder; Landroidx/media3/session/CommandButton; -Landroidx/media3/session/ConnectedControllersManager$$ExternalSyntheticLambda0; Landroidx/media3/session/ConnectedControllersManager$ConnectedControllerRecord; Landroidx/media3/session/ConnectedControllersManager; Landroidx/media3/session/ConnectionRequest$$ExternalSyntheticLambda0; Landroidx/media3/session/ConnectionRequest; Landroidx/media3/session/ConnectionState$$ExternalSyntheticLambda0; +Landroidx/media3/session/ConnectionState$InProcessBinder; Landroidx/media3/session/ConnectionState; Landroidx/media3/session/DefaultActionFactory; Landroidx/media3/session/DefaultMediaNotificationProvider$$ExternalSyntheticApiModelOutline0; @@ -30137,7 +29216,7 @@ Landroidx/media3/session/IMediaSession$Stub; Landroidx/media3/session/IMediaSession; Landroidx/media3/session/IMediaSessionService$Stub; Landroidx/media3/session/IMediaSessionService; -Landroidx/media3/session/MediaController$$ExternalSyntheticLambda0; +Landroidx/media3/session/LegacyConversions; Landroidx/media3/session/MediaController$Builder$$ExternalSyntheticLambda0; Landroidx/media3/session/MediaController$Builder$1; Landroidx/media3/session/MediaController$Builder; @@ -30149,13 +29228,12 @@ Landroidx/media3/session/MediaController; Landroidx/media3/session/MediaControllerHolder$$ExternalSyntheticLambda0; Landroidx/media3/session/MediaControllerHolder$$ExternalSyntheticLambda1; Landroidx/media3/session/MediaControllerHolder; -Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda113; -Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda118; +Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda104; +Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda108; +Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda114; Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda38; Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda39; Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda41; -Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda81; -Landroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda82; Landroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler$$ExternalSyntheticLambda0; Landroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler; Landroidx/media3/session/MediaControllerImplBase$RemoteSessionTask; @@ -30170,35 +29248,38 @@ Landroidx/media3/session/MediaControllerStub$ControllerTask; Landroidx/media3/session/MediaControllerStub; Landroidx/media3/session/MediaNotification$ActionFactory; Landroidx/media3/session/MediaNotification$Provider; -Landroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda3; -Landroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda6; +Landroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda2; +Landroidx/media3/session/MediaNotificationManager$$ExternalSyntheticLambda5; Landroidx/media3/session/MediaNotificationManager$Api24; Landroidx/media3/session/MediaNotificationManager$MediaControllerListener; Landroidx/media3/session/MediaNotificationManager; Landroidx/media3/session/MediaSession$Builder$1; Landroidx/media3/session/MediaSession$Builder; Landroidx/media3/session/MediaSession$BuilderBase; -Landroidx/media3/session/MediaSession$Callback$-CC; Landroidx/media3/session/MediaSession$Callback; +Landroidx/media3/session/MediaSession$ConnectionResult$AcceptedResultBuilder; Landroidx/media3/session/MediaSession$ConnectionResult; Landroidx/media3/session/MediaSession$ControllerCb; Landroidx/media3/session/MediaSession$ControllerInfo; Landroidx/media3/session/MediaSession$Listener; Landroidx/media3/session/MediaSession; Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda0; +Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda17; +Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda18; Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda1; Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda2; -Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda3; +Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda4; Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda6; -Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda7; -Landroidx/media3/session/MediaSessionImpl$$ExternalSyntheticLambda8; +Landroidx/media3/session/MediaSessionImpl$MediaPlayPauseKeyHandler; Landroidx/media3/session/MediaSessionImpl$PlayerInfoChangedHandler; Landroidx/media3/session/MediaSessionImpl$PlayerListener; Landroidx/media3/session/MediaSessionImpl$RemoteControllerTask; Landroidx/media3/session/MediaSessionImpl; +Landroidx/media3/session/MediaSessionLegacyStub$$ExternalSyntheticLambda3; +Landroidx/media3/session/MediaSessionLegacyStub$Api31$$ExternalSyntheticApiModelOutline0; +Landroidx/media3/session/MediaSessionLegacyStub$Api31; Landroidx/media3/session/MediaSessionLegacyStub$ConnectionTimeoutHandler; Landroidx/media3/session/MediaSessionLegacyStub$ControllerLegacyCbForBroadcast; -Landroidx/media3/session/MediaSessionLegacyStub$MediaPlayPauseKeyHandler; Landroidx/media3/session/MediaSessionLegacyStub; Landroidx/media3/session/MediaSessionService$$ExternalSyntheticLambda0; Landroidx/media3/session/MediaSessionService$Listener; @@ -30206,13 +29287,12 @@ Landroidx/media3/session/MediaSessionService$MediaSessionListener; Landroidx/media3/session/MediaSessionService$MediaSessionServiceStub$$ExternalSyntheticLambda0; Landroidx/media3/session/MediaSessionService$MediaSessionServiceStub; Landroidx/media3/session/MediaSessionService; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda11; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda19; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda25; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda68; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda72; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda76; -Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda81; +Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda24; +Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda56; +Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda70; +Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda73; +Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda77; +Landroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda82; Landroidx/media3/session/MediaSessionStub$Controller2Cb; Landroidx/media3/session/MediaSessionStub$SessionTask; Landroidx/media3/session/MediaSessionStub; @@ -30221,6 +29301,7 @@ Landroidx/media3/session/PlayerInfo$$ExternalSyntheticLambda0; Landroidx/media3/session/PlayerInfo$Builder; Landroidx/media3/session/PlayerInfo$BundlingExclusions$$ExternalSyntheticLambda0; Landroidx/media3/session/PlayerInfo$BundlingExclusions; +Landroidx/media3/session/PlayerInfo$InProcessBinder; Landroidx/media3/session/PlayerInfo; Landroidx/media3/session/PlayerWrapper; Landroidx/media3/session/SequencedFutureManager$SequencedFuture; @@ -30239,8 +29320,6 @@ Landroidx/media3/session/SessionToken$SessionTokenImpl; Landroidx/media3/session/SessionToken; Landroidx/media3/session/SessionTokenImplBase$$ExternalSyntheticLambda0; Landroidx/media3/session/SessionTokenImplBase; -Landroidx/media3/session/SimpleBitmapLoader$$ExternalSyntheticLambda0; -Landroidx/media3/session/SimpleBitmapLoader; Landroidx/media3/ui/AspectRatioFrameLayout$AspectRatioUpdateDispatcher; Landroidx/media3/ui/AspectRatioFrameLayout; Landroidx/media3/ui/PlayerControlView$OnFullScreenModeChangedListener; @@ -30265,16 +29344,13 @@ Landroidx/navigation/NavBackStackEntry$Companion; Landroidx/navigation/NavBackStackEntry$defaultFactory$2; Landroidx/navigation/NavBackStackEntry$savedStateHandle$2; Landroidx/navigation/NavBackStackEntry; -Landroidx/navigation/NavBackStackEntryState$Companion$CREATOR$1; -Landroidx/navigation/NavBackStackEntryState$Companion; -Landroidx/navigation/NavBackStackEntryState; Landroidx/navigation/NavController$$ExternalSyntheticLambda0; Landroidx/navigation/NavController$Companion; Landroidx/navigation/NavController$NavControllerNavigatorState; Landroidx/navigation/NavController$OnDestinationChangedListener; Landroidx/navigation/NavController$activity$1; Landroidx/navigation/NavController$navInflater$2; -Landroidx/navigation/NavController$navigate$4; +Landroidx/navigation/NavController$navigate$5; Landroidx/navigation/NavController$onBackPressedCallback$1; Landroidx/navigation/NavController; Landroidx/navigation/NavControllerViewModel$Companion$FACTORY$1; @@ -30405,8 +29481,6 @@ Landroidx/recyclerview/widget/ItemTouchHelper; Landroidx/recyclerview/widget/LinearLayoutManager$AnchorInfo; Landroidx/recyclerview/widget/LinearLayoutManager$LayoutChunkResult; Landroidx/recyclerview/widget/LinearLayoutManager$LayoutState; -Landroidx/recyclerview/widget/LinearLayoutManager$SavedState$1; -Landroidx/recyclerview/widget/LinearLayoutManager$SavedState; Landroidx/recyclerview/widget/LinearLayoutManager; Landroidx/recyclerview/widget/ListAdapter$1; Landroidx/recyclerview/widget/ListAdapter; @@ -30448,9 +29522,6 @@ Landroidx/recyclerview/widget/RecyclerView$RecycledViewPool$ScrapData; Landroidx/recyclerview/widget/RecyclerView$RecycledViewPool; Landroidx/recyclerview/widget/RecyclerView$Recycler; Landroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver; -Landroidx/recyclerview/widget/RecyclerView$SavedState$1; -Landroidx/recyclerview/widget/RecyclerView$SavedState; -Landroidx/recyclerview/widget/RecyclerView$SimpleOnItemTouchListener; Landroidx/recyclerview/widget/RecyclerView$SmoothScroller$ScrollVectorProvider; Landroidx/recyclerview/widget/RecyclerView$State; Landroidx/recyclerview/widget/RecyclerView$StretchEdgeEffectFactory; @@ -30477,10 +29548,8 @@ Landroidx/recyclerview/widget/ViewTypeStorage$ViewTypeLookup; Landroidx/recyclerview/widget/ViewTypeStorage; Landroidx/savedstate/R$id; Landroidx/savedstate/Recreator$Companion; -Landroidx/savedstate/Recreator$SavedStateProvider; Landroidx/savedstate/Recreator; Landroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0; -Landroidx/savedstate/SavedStateRegistry$AutoRecreated; Landroidx/savedstate/SavedStateRegistry$Companion; Landroidx/savedstate/SavedStateRegistry$SavedStateProvider; Landroidx/savedstate/SavedStateRegistry; @@ -30512,8 +29581,6 @@ Lcom/airbnb/lottie/LottieAnimationView$$ExternalSyntheticLambda1; Lcom/airbnb/lottie/LottieAnimationView$$ExternalSyntheticLambda2; Lcom/airbnb/lottie/LottieAnimationView$1; Lcom/airbnb/lottie/LottieAnimationView$2; -Lcom/airbnb/lottie/LottieAnimationView$SavedState$1; -Lcom/airbnb/lottie/LottieAnimationView$SavedState; Lcom/airbnb/lottie/LottieAnimationView$UserActionTaken; Lcom/airbnb/lottie/LottieAnimationView; Lcom/airbnb/lottie/LottieComposition; @@ -30672,9 +29739,6 @@ Lcom/annimon/stream/Stream$3; Lcom/annimon/stream/Stream; Lcom/annimon/stream/function/BiConsumer; Lcom/annimon/stream/function/BiFunction; -Lcom/annimon/stream/function/BinaryOperator$Util$2; -Lcom/annimon/stream/function/BinaryOperator$Util; -Lcom/annimon/stream/function/BinaryOperator; Lcom/annimon/stream/function/Consumer; Lcom/annimon/stream/function/Function; Lcom/annimon/stream/function/IndexedFunction; @@ -30692,7 +29756,6 @@ Lcom/annimon/stream/iterator/LsaExtIterator; Lcom/annimon/stream/iterator/LsaIterator; Lcom/annimon/stream/iterator/PrimitiveIterator$OfInt; Lcom/annimon/stream/operator/IntArray; -Lcom/annimon/stream/operator/IntRangeClosed; Lcom/annimon/stream/operator/ObjArray; Lcom/annimon/stream/operator/ObjFilter; Lcom/annimon/stream/operator/ObjLimit; @@ -30701,7 +29764,6 @@ Lcom/annimon/stream/operator/ObjMapIndexed; Lcom/annimon/stream/operator/ObjSorted; Lcom/bumptech/glide/GeneratedAppGlideModule; Lcom/bumptech/glide/GeneratedAppGlideModuleImpl; -Lcom/bumptech/glide/GeneratedRequestManagerFactory; Lcom/bumptech/glide/GenericTransitionOptions; Lcom/bumptech/glide/Glide$RequestOptionsFactory; Lcom/bumptech/glide/Glide; @@ -31134,6 +30196,7 @@ Lcom/fasterxml/jackson/core/exc/InputCoercionException; Lcom/fasterxml/jackson/core/exc/StreamReadException; Lcom/fasterxml/jackson/core/io/CharTypes; Lcom/fasterxml/jackson/core/io/IOContext; +Lcom/fasterxml/jackson/core/io/JsonEOFException; Lcom/fasterxml/jackson/core/io/JsonStringEncoder; Lcom/fasterxml/jackson/core/io/NumberInput; Lcom/fasterxml/jackson/core/io/NumberOutput; @@ -31262,6 +30325,7 @@ Lcom/fasterxml/jackson/databind/deser/impl/CreatorCollector; Lcom/fasterxml/jackson/databind/deser/impl/FailingDeserializer; Lcom/fasterxml/jackson/databind/deser/impl/FieldProperty; Lcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$ArrayListInstantiator; +Lcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator; Lcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators; Lcom/fasterxml/jackson/databind/deser/impl/ManagedReferenceProperty; Lcom/fasterxml/jackson/databind/deser/impl/NullsConstantProvider; @@ -31274,15 +30338,28 @@ Lcom/fasterxml/jackson/databind/deser/std/DateDeserializers; Lcom/fasterxml/jackson/databind/deser/std/FromStringDeserializer; Lcom/fasterxml/jackson/databind/deser/std/JdkDeserializers; Lcom/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer; +Lcom/fasterxml/jackson/databind/deser/std/MapDeserializer; +Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer; +Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$DoubleDeserializer; +Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$FloatDeserializer; Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$IntegerDeserializer; Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$LongDeserializer; Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$PrimitiveOrWrapperDeserializer; Lcom/fasterxml/jackson/databind/deser/std/NumberDeserializers; Lcom/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer; +Lcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$BooleanDeser; +Lcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$DoubleDeser; +Lcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$FloatDeser; +Lcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$IntDeser; +Lcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$LongDeser; +Lcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers; Lcom/fasterxml/jackson/databind/deser/std/StdDeserializer; +Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD; +Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer; Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializers; Lcom/fasterxml/jackson/databind/deser/std/StdScalarDeserializer; Lcom/fasterxml/jackson/databind/deser/std/StdValueInstantiator; +Lcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer; Lcom/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer; Lcom/fasterxml/jackson/databind/deser/std/StringDeserializer; Lcom/fasterxml/jackson/databind/deser/std/UUIDDeserializer; @@ -31314,6 +30391,7 @@ Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NCollector; Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NoAnnotations; Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneAnnotation; Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector; +Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector$TwoAnnotations; Lcom/fasterxml/jackson/databind/introspect/AnnotationCollector; Lcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair; Lcom/fasterxml/jackson/databind/introspect/AnnotationMap; @@ -31353,6 +30431,7 @@ Lcom/fasterxml/jackson/databind/jsontype/PolymorphicTypeValidator$Base; Lcom/fasterxml/jackson/databind/jsontype/PolymorphicTypeValidator; Lcom/fasterxml/jackson/databind/jsontype/SubtypeResolver; Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer; +Lcom/fasterxml/jackson/databind/jsontype/TypeSerializer; Lcom/fasterxml/jackson/databind/jsontype/impl/LaissezFaireSubTypeValidator; Lcom/fasterxml/jackson/databind/jsontype/impl/StdSubtypeResolver; Lcom/fasterxml/jackson/databind/jsontype/impl/SubTypeValidator; @@ -31386,6 +30465,7 @@ Lcom/fasterxml/jackson/databind/ser/Serializers$Base; Lcom/fasterxml/jackson/databind/ser/Serializers; Lcom/fasterxml/jackson/databind/ser/impl/FailingSerializer; Lcom/fasterxml/jackson/databind/ser/impl/IndexedListSerializer; +Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Double; Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Empty; Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$SerializerAndMapResult; Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Single; @@ -31448,6 +30528,7 @@ Lcom/fasterxml/jackson/databind/type/CollectionType; Lcom/fasterxml/jackson/databind/type/LogicalType; Lcom/fasterxml/jackson/databind/type/MapLikeType; Lcom/fasterxml/jackson/databind/type/MapType; +Lcom/fasterxml/jackson/databind/type/PlaceholderForType; Lcom/fasterxml/jackson/databind/type/ResolvedRecursiveType; Lcom/fasterxml/jackson/databind/type/SimpleType; Lcom/fasterxml/jackson/databind/type/TypeBase; @@ -31664,10 +30745,6 @@ Lcom/google/android/material/appbar/ViewOffsetHelper; Lcom/google/android/material/appbar/ViewUtilsLollipop; Lcom/google/android/material/button/MaterialButton; Lcom/google/android/material/button/MaterialButtonHelper; -Lcom/google/android/material/card/MaterialCardView; -Lcom/google/android/material/card/MaterialCardViewHelper$$ExternalSyntheticApiModelOutline0; -Lcom/google/android/material/card/MaterialCardViewHelper$1; -Lcom/google/android/material/card/MaterialCardViewHelper; Lcom/google/android/material/chip/Chip$$ExternalSyntheticLambda0; Lcom/google/android/material/chip/Chip$1; Lcom/google/android/material/chip/Chip$ChipTouchHelper; @@ -31748,14 +30825,11 @@ Lcom/google/android/material/shape/ShapePath$PathOperation; Lcom/google/android/material/shape/ShapePath$ShadowCompatOperation; Lcom/google/android/material/shape/ShapePath; Lcom/google/android/material/shape/Shapeable; -Lcom/google/android/material/stateful/ExtendableSavedState$1; -Lcom/google/android/material/stateful/ExtendableSavedState; Lcom/google/android/material/theme/overlay/MaterialThemeOverlay; Lcom/google/common/base/Ascii; Lcom/google/common/base/Charsets; Lcom/google/common/base/ExtraObjectsMethodsForWeb; Lcom/google/common/base/Function; -Lcom/google/common/base/MoreObjects; Lcom/google/common/base/Objects; Lcom/google/common/base/Preconditions; Lcom/google/common/base/Supplier; @@ -31785,17 +30859,12 @@ Lcom/google/common/collect/ObjectArrays; Lcom/google/common/collect/Ordering; Lcom/google/common/collect/RegularImmutableBiMap; Lcom/google/common/collect/RegularImmutableList; -Lcom/google/common/collect/RegularImmutableMap$KeysOrValuesAsList; Lcom/google/common/collect/RegularImmutableMap; Lcom/google/common/collect/RegularImmutableSet; -Lcom/google/common/collect/Sets$2; -Lcom/google/common/collect/Sets$SetView; Lcom/google/common/collect/Sets; +Lcom/google/common/collect/SingletonImmutableSet; Lcom/google/common/collect/UnmodifiableIterator; Lcom/google/common/collect/UnmodifiableListIterator; -Lcom/google/common/primitives/Ints$IntArrayAsList; -Lcom/google/common/primitives/Ints; -Lcom/google/common/primitives/IntsMethodsForWeb; Lcom/google/common/util/concurrent/AbstractFuture$AtomicHelper; Lcom/google/common/util/concurrent/AbstractFuture$Cancellation; Lcom/google/common/util/concurrent/AbstractFuture$Failure; @@ -32002,7 +31071,6 @@ Lcom/google/i18n/phonenumbers/metadata/source/PhoneMetadataFileNameProvider; Lcom/google/i18n/phonenumbers/metadata/source/RegionMetadataSource; Lcom/google/i18n/phonenumbers/metadata/source/RegionMetadataSourceImpl; Lcom/google/protobuf/InvalidProtocolBufferException; -Lcom/klinker/android/send_message/MmsFileProvider; Lcom/makeramen/roundedimageview/RoundedDrawable$1; Lcom/makeramen/roundedimageview/RoundedDrawable; Lcom/mobilecoin/lib/exceptions/BadMnemonicException; @@ -32043,8 +31111,14 @@ Lcom/squareup/wire/ProtoAdapterKt$commonUint32$1; Lcom/squareup/wire/ProtoAdapterKt$commonUint64$1; Lcom/squareup/wire/ProtoAdapterKt$commonWrapper$1; Lcom/squareup/wire/ProtoAdapterKt; +Lcom/squareup/wire/ProtoReader$Companion; +Lcom/squareup/wire/ProtoReader; Lcom/squareup/wire/ProtoWriter; Lcom/squareup/wire/RepeatedProtoAdapter; +Lcom/squareup/wire/ReverseProtoWriter$Companion; +Lcom/squareup/wire/ReverseProtoWriter$forwardBuffer$2; +Lcom/squareup/wire/ReverseProtoWriter$forwardWriter$2; +Lcom/squareup/wire/ReverseProtoWriter; Lcom/squareup/wire/Syntax$Companion; Lcom/squareup/wire/Syntax; Lcom/squareup/wire/WireEnum; @@ -32067,9 +31141,7 @@ Lio/reactivex/rxjava3/core/FlowableEmitter; Lio/reactivex/rxjava3/core/FlowableOnSubscribe; Lio/reactivex/rxjava3/core/FlowableSubscriber; Lio/reactivex/rxjava3/core/Maybe; -Lio/reactivex/rxjava3/core/MaybeEmitter; Lio/reactivex/rxjava3/core/MaybeObserver; -Lio/reactivex/rxjava3/core/MaybeOnSubscribe; Lio/reactivex/rxjava3/core/MaybeSource; Lio/reactivex/rxjava3/core/Observable$1; Lio/reactivex/rxjava3/core/Observable; @@ -32090,6 +31162,7 @@ Lio/reactivex/rxjava3/disposables/Disposable; Lio/reactivex/rxjava3/disposables/DisposableContainer; Lio/reactivex/rxjava3/disposables/ReferenceDisposable; Lio/reactivex/rxjava3/disposables/RunnableDisposable; +Lio/reactivex/rxjava3/exceptions/Exceptions; Lio/reactivex/rxjava3/exceptions/OnErrorNotImplementedException; Lio/reactivex/rxjava3/flowables/ConnectableFlowable; Lio/reactivex/rxjava3/functions/Action; @@ -32124,6 +31197,7 @@ Lio/reactivex/rxjava3/internal/functions/Functions; Lio/reactivex/rxjava3/internal/functions/ObjectHelper$BiObjectPredicate; Lio/reactivex/rxjava3/internal/functions/ObjectHelper; Lio/reactivex/rxjava3/internal/fuseable/ConditionalSubscriber; +Lio/reactivex/rxjava3/internal/fuseable/FuseToFlowable; Lio/reactivex/rxjava3/internal/fuseable/FuseToObservable; Lio/reactivex/rxjava3/internal/fuseable/QueueDisposable; Lio/reactivex/rxjava3/internal/fuseable/QueueFuseable; @@ -32142,6 +31216,7 @@ Lio/reactivex/rxjava3/internal/observers/QueueDrainObserver; Lio/reactivex/rxjava3/internal/observers/QueueDrainSubscriberPad0; Lio/reactivex/rxjava3/internal/observers/QueueDrainSubscriberPad2; Lio/reactivex/rxjava3/internal/observers/QueueDrainSubscriberWip; +Lio/reactivex/rxjava3/internal/observers/ResumeSingleObserver; Lio/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber; Lio/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstream; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest$CombineLatestCoordinator; @@ -32157,6 +31232,7 @@ Lio/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEach$DoOnEachSubsc Lio/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEach; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableFilter$FilterConditionalSubscriber; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableFilter; +Lio/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable$SubscriberObserver; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelper$RequestMax; @@ -32185,6 +31261,8 @@ Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$ReplaySubscribe Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$SizeBoundReplayBuffer; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMap; +Lio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber; +Lio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn$SubscribeOnSubscriber$Request; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn$SubscribeOnSubscriber; Lio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn; @@ -32195,23 +31273,9 @@ Lio/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest$Throttl Lio/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest; Lio/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstream; Lio/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty; Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter$FilterMaybeObserver; Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFilter; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn; Lio/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete$OnErrorCompleteMultiObserver; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver; -Lio/reactivex/rxjava3/internal/operators/maybe/MaybePeek; -Lio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver; -Lio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber; -Lio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle; Lio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver$SwitchMapSingleObserver; Lio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver; Lio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle; @@ -32238,8 +31302,6 @@ Lio/reactivex/rxjava3/internal/operators/observable/ObservableElementAtSingle$El Lio/reactivex/rxjava3/internal/operators/observable/ObservableElementAtSingle; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFilter$FilterObserver; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFilter; -Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver; -Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver$InnerObserver; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver; @@ -32247,7 +31309,6 @@ Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFromArray$FromArrayDisposable; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFromArray; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture; -Lio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber; Lio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher; Lio/reactivex/rxjava3/internal/operators/observable/ObservableJust; Lio/reactivex/rxjava3/internal/operators/observable/ObservableMap$MapObserver; @@ -32288,6 +31349,10 @@ Lio/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed Lio/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed; Lio/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess$DoOnSuccess; Lio/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess; +Lio/reactivex/rxjava3/internal/operators/single/SingleError; +Lio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver; +Lio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback; +Lio/reactivex/rxjava3/internal/operators/single/SingleFlatMap; Lio/reactivex/rxjava3/internal/operators/single/SingleFromCallable; Lio/reactivex/rxjava3/internal/operators/single/SingleJust; Lio/reactivex/rxjava3/internal/operators/single/SingleMap$MapSingleObserver; @@ -32295,6 +31360,10 @@ Lio/reactivex/rxjava3/internal/operators/single/SingleMap; Lio/reactivex/rxjava3/internal/operators/single/SingleObserveOn$ObserveOnSingleObserver; Lio/reactivex/rxjava3/internal/operators/single/SingleObserveOn; Lio/reactivex/rxjava3/internal/operators/single/SingleOnErrorComplete; +Lio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn; +Lio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn; +Lio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver; +Lio/reactivex/rxjava3/internal/operators/single/SingleResumeNext; Lio/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn$SubscribeOnObserver; Lio/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn; Lio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode; @@ -32322,6 +31391,7 @@ Lio/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriber; Lio/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriber; Lio/reactivex/rxjava3/internal/subscribers/LambdaSubscriber; Lio/reactivex/rxjava3/internal/subscriptions/BasicIntQueueSubscription; +Lio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription; Lio/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper; Lio/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList$NonThrowingPredicate; Lio/reactivex/rxjava3/internal/util/ArrayListSupplier; @@ -32376,10 +31446,8 @@ Lj$/time/LocalTime; Lj$/time/OffsetDateTime; Lj$/time/ZoneId; Lj$/time/ZoneOffset; -Lj$/time/ZonedDateTime; Lj$/time/a; Lj$/time/chrono/ChronoLocalDateTime; -Lj$/time/chrono/ChronoZonedDateTime; Lj$/time/chrono/a; Lj$/time/chrono/b; Lj$/time/chrono/e; @@ -32500,7 +31568,6 @@ Lj$/util/function/ToDoubleFunction; Lj$/util/function/ToIntFunction; Lj$/util/function/ToLongFunction; Lj$/util/function/Z; -Lj$/util/function/b; Lj$/util/function/g0; Lj$/util/function/h; Lj$/util/function/j0; @@ -32510,7 +31577,6 @@ Lj$/util/function/p0; Lj$/util/function/t; Lj$/util/g; Lj$/util/m; -Lj$/util/stream/A1; Lj$/util/stream/B0; Lj$/util/stream/B2; Lj$/util/stream/C0; @@ -32520,7 +31586,6 @@ Lj$/util/stream/Collector; Lj$/util/stream/Collectors; Lj$/util/stream/D0; Lj$/util/stream/E0; -Lj$/util/stream/E1; Lj$/util/stream/F0; Lj$/util/stream/F1; Lj$/util/stream/F3; @@ -32555,8 +31620,6 @@ Lj$/util/stream/b; Lj$/util/stream/c2; Lj$/util/stream/c; Lj$/util/stream/g2; -Lj$/util/stream/h2; -Lj$/util/stream/i2; Lj$/util/stream/i; Lj$/util/stream/l; Lj$/util/stream/n; @@ -32666,7 +31729,12 @@ Lkotlin/coroutines/jvm/internal/CoroutineStackFrame; Lkotlin/coroutines/jvm/internal/DebugProbesKt; Lkotlin/coroutines/jvm/internal/RestrictedContinuationImpl; Lkotlin/coroutines/jvm/internal/RestrictedSuspendLambda; +Lkotlin/internal/PlatformImplementations; +Lkotlin/internal/PlatformImplementationsKt; Lkotlin/internal/ProgressionUtilKt; +Lkotlin/internal/jdk7/JDK7PlatformImplementations; +Lkotlin/internal/jdk8/JDK8PlatformImplementations$ReflectSdkVersion; +Lkotlin/internal/jdk8/JDK8PlatformImplementations; Lkotlin/io/CloseableKt; Lkotlin/jvm/JvmClassMappingKt; Lkotlin/jvm/JvmStatic; @@ -32730,6 +31798,11 @@ Lkotlin/properties/Delegates; Lkotlin/properties/ObservableProperty; Lkotlin/properties/ReadOnlyProperty; Lkotlin/properties/ReadWriteProperty; +Lkotlin/random/AbstractPlatformRandom; +Lkotlin/random/FallbackThreadLocalRandom$implStorage$1; +Lkotlin/random/FallbackThreadLocalRandom; +Lkotlin/random/Random$Default; +Lkotlin/random/Random; Lkotlin/ranges/CharProgression; Lkotlin/ranges/CharRange; Lkotlin/ranges/ClosedRange; @@ -33407,7 +32480,6 @@ Lkotlin/reflect/jvm/internal/impl/protobuf/GeneratedMessageLite; Lkotlin/reflect/jvm/internal/impl/protobuf/Internal$EnumLite; Lkotlin/reflect/jvm/internal/impl/protobuf/Internal$EnumLiteMap; Lkotlin/reflect/jvm/internal/impl/protobuf/InvalidProtocolBufferException; -Lkotlin/reflect/jvm/internal/impl/protobuf/LazyField$LazyIterator; Lkotlin/reflect/jvm/internal/impl/protobuf/LazyStringArrayList; Lkotlin/reflect/jvm/internal/impl/protobuf/LazyStringList; Lkotlin/reflect/jvm/internal/impl/protobuf/LiteralByteString; @@ -33493,6 +32565,13 @@ Lkotlin/reflect/jvm/internal/impl/resolve/ResolutionAnchorProviderKt; Lkotlin/reflect/jvm/internal/impl/resolve/calls/inference/CapturedTypeConstructor; Lkotlin/reflect/jvm/internal/impl/resolve/calls/inference/CapturedTypeConstructorImpl; Lkotlin/reflect/jvm/internal/impl/resolve/calls/inference/CapturedTypeConstructorKt; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/BooleanValue; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/EnumValue; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/IntValue; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/IntegerValueConstant; +Lkotlin/reflect/jvm/internal/impl/resolve/constants/StringValue; Lkotlin/reflect/jvm/internal/impl/resolve/descriptorUtil/DescriptorUtilsKt$$Lambda$0; Lkotlin/reflect/jvm/internal/impl/resolve/descriptorUtil/DescriptorUtilsKt$declaresOrInheritsDefaultValue$2; Lkotlin/reflect/jvm/internal/impl/resolve/descriptorUtil/DescriptorUtilsKt; @@ -34081,6 +33160,9 @@ Lorg/conscrypt/AbstractSessionContext$1; Lorg/conscrypt/AbstractSessionContext; Lorg/conscrypt/ActiveSession; Lorg/conscrypt/AddressUtils; +Lorg/conscrypt/AllocatedBuffer; +Lorg/conscrypt/ArrayUtils; +Lorg/conscrypt/BufferAllocator; Lorg/conscrypt/BufferUtils; Lorg/conscrypt/ByteArray; Lorg/conscrypt/ClientSessionContext$HostAndPort; @@ -34103,6 +33185,7 @@ Lorg/conscrypt/EvpMdRef$SHA1; Lorg/conscrypt/EvpMdRef$SHA256; Lorg/conscrypt/ExternalSession$Provider; Lorg/conscrypt/ExternalSession; +Lorg/conscrypt/GCMParameters; Lorg/conscrypt/HandshakeListener; Lorg/conscrypt/Java7ExtendedSSLSession; Lorg/conscrypt/Java8EngineSocket; @@ -34127,6 +33210,9 @@ Lorg/conscrypt/NativeSsl; Lorg/conscrypt/NativeSslSession$Impl; Lorg/conscrypt/NativeSslSession; Lorg/conscrypt/OidData; +Lorg/conscrypt/OpenSSLAeadCipher; +Lorg/conscrypt/OpenSSLAeadCipherAES$GCM; +Lorg/conscrypt/OpenSSLAeadCipherAES; Lorg/conscrypt/OpenSSLBIOInputStream; Lorg/conscrypt/OpenSSLCipher$Mode; Lorg/conscrypt/OpenSSLCipher$Padding; @@ -34262,11 +33348,14 @@ Lorg/signal/core/util/SqlUtil; Lorg/signal/core/util/Stopwatch$Split; Lorg/signal/core/util/Stopwatch$stopAndGetLogString$splitString$1; Lorg/signal/core/util/Stopwatch; +Lorg/signal/core/util/StreamUtil; Lorg/signal/core/util/StringExtensionsKt; Lorg/signal/core/util/StringSerializer; Lorg/signal/core/util/StringUtil; Lorg/signal/core/util/ThreadUtil; Lorg/signal/core/util/ToolbarExtensionsKt; +Lorg/signal/core/util/UpdateAllBuilderPart1; +Lorg/signal/core/util/UpdateAllBuilderPart2; Lorg/signal/core/util/UpdateBuilderPart1; Lorg/signal/core/util/UpdateBuilderPart2; Lorg/signal/core/util/UpdateBuilderPart3; @@ -34277,15 +33366,17 @@ Lorg/signal/core/util/concurrent/DeadlockDetector$$ExternalSyntheticLambda0; Lorg/signal/core/util/concurrent/DeadlockDetector$Companion; Lorg/signal/core/util/concurrent/DeadlockDetector$ExecutorInfo; Lorg/signal/core/util/concurrent/DeadlockDetector; -Lorg/signal/core/util/concurrent/LatestPrioritizedSerialExecutor; +Lorg/signal/core/util/concurrent/FutureMapTransformer; +Lorg/signal/core/util/concurrent/FutureTransformers$Transformer; +Lorg/signal/core/util/concurrent/FutureTransformers; Lorg/signal/core/util/concurrent/LifecycleDisposable; Lorg/signal/core/util/concurrent/LifecycleDisposableKt; -Lorg/signal/core/util/concurrent/MaybeCompat$$ExternalSyntheticLambda0; -Lorg/signal/core/util/concurrent/MaybeCompat; +Lorg/signal/core/util/concurrent/ListenableFuture; Lorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$1; Lorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$2; Lorg/signal/core/util/concurrent/RxExtensions$subscribeWithSubject$3; Lorg/signal/core/util/concurrent/RxExtensions; +Lorg/signal/core/util/concurrent/SettableFuture; Lorg/signal/core/util/concurrent/SignalExecutors$$ExternalSyntheticLambda0; Lorg/signal/core/util/concurrent/SignalExecutors$$ExternalSyntheticLambda1; Lorg/signal/core/util/concurrent/SignalExecutors$1; @@ -34351,13 +33442,12 @@ Lorg/signal/glide/Log$Provider; Lorg/signal/glide/SignalGlideCodecs; Lorg/signal/glide/apng/decode/APNGDecoder; Lorg/signal/glide/common/decode/FrameSeqDecoder; -Lorg/signal/glide/webp/WebpInputStreamResourceDecoder$Companion; -Lorg/signal/glide/webp/WebpInputStreamResourceDecoder; -Lorg/signal/glide/webp/WebpLibraryGlideModule$Companion; -Lorg/signal/glide/webp/WebpLibraryGlideModule; Lorg/signal/libsignal/internal/Native; Lorg/signal/libsignal/internal/NativeHandleGuard$Owner; Lorg/signal/libsignal/internal/NativeHandleGuard; +Lorg/signal/libsignal/net/CdsiLookupResponse$Entry; +Lorg/signal/libsignal/net/CdsiLookupResponse; +Lorg/signal/libsignal/net/Network$Environment; Lorg/signal/libsignal/protocol/IdentityKey; Lorg/signal/libsignal/protocol/IdentityKeyPair; Lorg/signal/libsignal/protocol/InvalidKeyException; @@ -34387,6 +33477,7 @@ Lorg/signal/libsignal/protocol/state/SessionStore; Lorg/signal/libsignal/protocol/state/SignalProtocolStore; Lorg/signal/libsignal/protocol/state/SignedPreKeyRecord; Lorg/signal/libsignal/protocol/state/SignedPreKeyStore; +Lorg/signal/libsignal/protocol/util/ByteUtil; Lorg/signal/libsignal/protocol/util/KeyHelper; Lorg/signal/libsignal/protocol/util/Medium; Lorg/signal/libsignal/protocol/util/Pair; @@ -34400,6 +33491,7 @@ Lorg/signal/libsignal/zkgroup/internal/ByteArray; Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations; Lorg/signal/libsignal/zkgroup/profiles/ExpiringProfileKeyCredential; Lorg/signal/libsignal/zkgroup/profiles/ProfileKey; +Lorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion; Lorg/signal/libsignal/zkgroup/receipts/ClientZkReceiptOperations; Lorg/signal/paging/BufferedPagingController$$ExternalSyntheticLambda1; Lorg/signal/paging/BufferedPagingController$$ExternalSyntheticLambda3; @@ -34428,6 +33520,7 @@ Lorg/signal/ringrtc/CallManager; Lorg/signal/ringrtc/Log$Logger; Lorg/signal/ringrtc/Log; Lorg/signal/ringrtc/WebRtcLogger; +Lorg/thoughtcrime/securesms/AppCapabilities; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda10; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda11; @@ -34490,7 +33583,6 @@ Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda62; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda63; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda64; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda65; -Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda66; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda6; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda7; Lorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda8; @@ -34528,18 +33620,16 @@ Lorg/thoughtcrime/securesms/attachments/PointerAttachment$Companion; Lorg/thoughtcrime/securesms/attachments/PointerAttachment; Lorg/thoughtcrime/securesms/audio/AudioFileInfo; Lorg/thoughtcrime/securesms/audio/AudioHash; -Lorg/thoughtcrime/securesms/audio/AudioRecorder$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/audio/AudioRecorder; -Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion; -Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager26; -Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager; Lorg/thoughtcrime/securesms/audio/AudioRecordingHandler; Lorg/thoughtcrime/securesms/avatar/Avatar$Companion; Lorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId$DoNotPersist; Lorg/thoughtcrime/securesms/avatar/Avatar$DatabaseId; +Lorg/thoughtcrime/securesms/avatar/Avatar$Resource; Lorg/thoughtcrime/securesms/avatar/Avatar$Text; Lorg/thoughtcrime/securesms/avatar/Avatar; Lorg/thoughtcrime/securesms/avatar/AvatarPickerStorage; +Lorg/thoughtcrime/securesms/avatar/AvatarRenderer$$ExternalSyntheticLambda0; +Lorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1; Lorg/thoughtcrime/securesms/avatar/AvatarRenderer; Lorg/thoughtcrime/securesms/avatar/Avatars$ColorPair; Lorg/thoughtcrime/securesms/avatar/Avatars$DefaultAvatar; @@ -34564,11 +33654,6 @@ Lorg/thoughtcrime/securesms/blurhash/BlurHashModelLoader$Factory; Lorg/thoughtcrime/securesms/blurhash/BlurHashResourceDecoder; Lorg/thoughtcrime/securesms/calls/log/CallLogFragment$Callback; Lorg/thoughtcrime/securesms/color/MaterialColor$UnknownColorException; -Lorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda2; -Lorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda3; -Lorg/thoughtcrime/securesms/components/AlbumThumbnailView; Lorg/thoughtcrime/securesms/components/AlertView; Lorg/thoughtcrime/securesms/components/AnimatingToggle; Lorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda0; @@ -34595,16 +33680,7 @@ Lorg/thoughtcrime/securesms/components/ConversationItemFooter$$ExternalSynthetic Lorg/thoughtcrime/securesms/components/ConversationItemFooter$$ExternalSyntheticLambda2; Lorg/thoughtcrime/securesms/components/ConversationItemFooter$OnTouchDelegateChangedListener; Lorg/thoughtcrime/securesms/components/ConversationItemFooter; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnail$Companion; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnail; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState$Creator; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$Creator; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState$Creator; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState; -Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState; Lorg/thoughtcrime/securesms/components/ConversationScrollToView; -Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar$EventListener; Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar; Lorg/thoughtcrime/securesms/components/CornerMask; Lorg/thoughtcrime/securesms/components/DeliveryStatusView$State; @@ -34612,16 +33688,12 @@ Lorg/thoughtcrime/securesms/components/DeliveryStatusView; Lorg/thoughtcrime/securesms/components/ExpirationTimerView; Lorg/thoughtcrime/securesms/components/FromTextView; Lorg/thoughtcrime/securesms/components/HidingLinearLayout; -Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout$Listener; Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout; -Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda2; -Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda6; Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda7; Lorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda8; -Lorg/thoughtcrime/securesms/components/InputPanel$Listener; Lorg/thoughtcrime/securesms/components/InputPanel$MediaListener; Lorg/thoughtcrime/securesms/components/InputPanel$RecordTime; Lorg/thoughtcrime/securesms/components/InputPanel$SlideToCancel; @@ -34629,7 +33701,6 @@ Lorg/thoughtcrime/securesms/components/InputPanel; Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$Companion; Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$KeyboardInsetAnimator; -Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$KeyboardStateListener; Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$keyboardGuideline$2; Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$navigationBarGuideline$2; Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$parentEndGuideline$2; @@ -34659,7 +33730,6 @@ Lorg/thoughtcrime/securesms/components/QuoteView$MessageType; Lorg/thoughtcrime/securesms/components/QuoteView; Lorg/thoughtcrime/securesms/components/RatingManager; Lorg/thoughtcrime/securesms/components/RecyclerViewFastScroller$FastScrollAdapter; -Lorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController; Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$2; Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$3; Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$4; @@ -34670,17 +33740,8 @@ Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollStrategy; Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest; Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1; Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate; -Lorg/thoughtcrime/securesms/components/SearchView; -Lorg/thoughtcrime/securesms/components/SendButton$ScheduledSendListener; Lorg/thoughtcrime/securesms/components/SendButton; Lorg/thoughtcrime/securesms/components/SharedContactView$EventListener; -Lorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport0; -Lorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport1; -Lorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport2; -Lorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher; -Lorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher; -Lorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher; -Lorg/thoughtcrime/securesms/components/ThumbnailView; Lorg/thoughtcrime/securesms/components/TypingIndicatorView; Lorg/thoughtcrime/securesms/components/TypingStatusRepository; Lorg/thoughtcrime/securesms/components/ViewBinderDelegate$1; @@ -34701,8 +33762,6 @@ Lorg/thoughtcrime/securesms/components/emoji/EmojiProvider$1; Lorg/thoughtcrime/securesms/components/emoji/EmojiProvider$EmojiDrawable; Lorg/thoughtcrime/securesms/components/emoji/EmojiProvider; Lorg/thoughtcrime/securesms/components/emoji/EmojiSpan; -Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda2; Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView; @@ -34722,14 +33781,11 @@ Lorg/thoughtcrime/securesms/components/emoji/parsing/EmojiTree$EmojiTreeNode; Lorg/thoughtcrime/securesms/components/emoji/parsing/EmojiTree$Matches; Lorg/thoughtcrime/securesms/components/emoji/parsing/EmojiTree; Lorg/thoughtcrime/securesms/components/emoji/parsing/Fitzpatrick; -Lorg/thoughtcrime/securesms/components/mention/MentionAnnotation$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/components/mention/MentionAnnotation; Lorg/thoughtcrime/securesms/components/mention/MentionDeleter; Lorg/thoughtcrime/securesms/components/mention/MentionRenderer$MultiLineMentionRenderer; Lorg/thoughtcrime/securesms/components/mention/MentionRenderer$SingleLineMentionRenderer; Lorg/thoughtcrime/securesms/components/mention/MentionRenderer; Lorg/thoughtcrime/securesms/components/mention/MentionRendererDelegate; -Lorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher$MentionValidator; Lorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher; Lorg/thoughtcrime/securesms/components/menu/ActionItem; Lorg/thoughtcrime/securesms/components/menu/SignalBottomActionBar$enterAnimation$2; @@ -34752,6 +33808,7 @@ Lorg/thoughtcrime/securesms/components/reminder/PushRegistrationReminder; Lorg/thoughtcrime/securesms/components/reminder/Reminder; Lorg/thoughtcrime/securesms/components/reminder/ServiceOutageReminder; Lorg/thoughtcrime/securesms/components/reminder/UnauthorizedReminder; +Lorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder$Companion$WhenMappings; Lorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder$Companion; Lorg/thoughtcrime/securesms/components/reminder/UsernameOutOfSyncReminder; Lorg/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesRepository$getProfiles$1; @@ -34769,22 +33826,6 @@ Lorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$$External Lorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1; Lorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1; Lorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress$Companion; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setClickable$1; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setFocusable$1; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$Companion; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State; -Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView; Lorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink$Companion; Lorg/thoughtcrime/securesms/components/voice/RetryableInitAudioSink; Lorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController$1; @@ -34896,6 +33937,8 @@ Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel$controller$1; Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel$data$1; Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel$safetyNumberRepository$2; Lorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel; +Lorg/thoughtcrime/securesms/contacts/paged/collections/ContactSearchIterator; +Lorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery; Lorg/thoughtcrime/securesms/contactshare/Contact; Lorg/thoughtcrime/securesms/contactshare/ContactUtil; Lorg/thoughtcrime/securesms/conversation/BodyBubbleLayoutTransition; @@ -34905,14 +33948,11 @@ Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge; Lorg/thoughtcrime/securesms/conversation/ConversationBottomSheetCallback; Lorg/thoughtcrime/securesms/conversation/ConversationData$MessageRequestData; Lorg/thoughtcrime/securesms/conversation/ConversationData; -Lorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider; -Lorg/thoughtcrime/securesms/conversation/ConversationHeaderView; Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args; Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Builder; Lorg/thoughtcrime/securesms/conversation/ConversationIntents$ConversationScreenType; Lorg/thoughtcrime/securesms/conversation/ConversationIntents; -Lorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda6; -Lorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda9; +Lorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/conversation/ConversationItem$1; Lorg/thoughtcrime/securesms/conversation/ConversationItem$AttachmentDownloadClickListener; Lorg/thoughtcrime/securesms/conversation/ConversationItem$ClickListener; @@ -34925,7 +33965,6 @@ Lorg/thoughtcrime/securesms/conversation/ConversationItem$ScheduledIndicatorClic Lorg/thoughtcrime/securesms/conversation/ConversationItem$SharedContactClickListener; Lorg/thoughtcrime/securesms/conversation/ConversationItem$SharedContactEventListener; Lorg/thoughtcrime/securesms/conversation/ConversationItem$SlideClickPassthroughListener; -Lorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener; Lorg/thoughtcrime/securesms/conversation/ConversationItem$TouchDelegateChangedListener; Lorg/thoughtcrime/securesms/conversation/ConversationItem$UrlClickListener; Lorg/thoughtcrime/securesms/conversation/ConversationItem$ViewOnceMessageClickListener; @@ -34933,22 +33972,10 @@ Lorg/thoughtcrime/securesms/conversation/ConversationItem; Lorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$$ExternalSyntheticBackport0; Lorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$$ExternalSyntheticLambda2; Lorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble; -Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Condensed; -Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Detailed; -Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$EditHistory; -Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Standard; -Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; -Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$OnSwipeListener; -Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$SwipeAvailabilityProvider; -Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback; -Lorg/thoughtcrime/securesms/conversation/ConversationItemTouchListener$Callback; -Lorg/thoughtcrime/securesms/conversation/ConversationItemTouchListener; Lorg/thoughtcrime/securesms/conversation/ConversationMessage$ComputedProperties; Lorg/thoughtcrime/securesms/conversation/ConversationMessage$ConversationMessageFactory; Lorg/thoughtcrime/securesms/conversation/ConversationMessage; Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Callback; -Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider$onCreateMenu$1; Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider; Lorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Snapshot; Lorg/thoughtcrime/securesms/conversation/ConversationReactionDelegate; @@ -34958,9 +33985,6 @@ Lorg/thoughtcrime/securesms/conversation/ConversationRepository; Lorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel; Lorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter$EventListener; Lorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter; -Lorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator; -Lorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$ClampingLinearInterpolator; -Lorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper; Lorg/thoughtcrime/securesms/conversation/ConversationTitleView$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/conversation/ConversationTitleView; Lorg/thoughtcrime/securesms/conversation/ConversationUpdateItem$$ExternalSyntheticLambda0; @@ -34972,15 +33996,6 @@ Lorg/thoughtcrime/securesms/conversation/ConversationUpdateItem$PresentOnChange; Lorg/thoughtcrime/securesms/conversation/ConversationUpdateItem$RecipientObserverManager; Lorg/thoughtcrime/securesms/conversation/ConversationUpdateItem$UpdateObserver; Lorg/thoughtcrime/securesms/conversation/ConversationUpdateItem; -Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$1; -Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$Companion; -Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$OnTickListener; -Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick; -Lorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda2; -Lorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/conversation/MarkReadHelper; Lorg/thoughtcrime/securesms/conversation/MessageSendType$Companion; Lorg/thoughtcrime/securesms/conversation/MessageSendType$SignalMessageSendType$Creator; @@ -34992,15 +34007,10 @@ Lorg/thoughtcrime/securesms/conversation/MessageStyler$Result; Lorg/thoughtcrime/securesms/conversation/MessageStyler; Lorg/thoughtcrime/securesms/conversation/ScheduleMessageDialogCallback; Lorg/thoughtcrime/securesms/conversation/ScheduleMessageTimePickerBottomSheet$ScheduleCallback; -Lorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda3; -Lorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda4; -Lorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository; Lorg/thoughtcrime/securesms/conversation/SelectedConversationModel; Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView$Listener; Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView; -Lorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock; Lorg/thoughtcrime/securesms/conversation/clicklisteners/AttachmentCancelClickListener$Companion; Lorg/thoughtcrime/securesms/conversation/clicklisteners/AttachmentCancelClickListener; Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor; @@ -35015,7 +34025,6 @@ Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$Auto; Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$BuiltIn; Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$Companion$CREATOR$1; Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$Companion; -Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$NotSet; Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id; Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$LinearGradient$Creator; Lorg/thoughtcrime/securesms/conversation/colors/ChatColors$LinearGradient; @@ -35024,30 +34033,18 @@ Lorg/thoughtcrime/securesms/conversation/colors/ChatColorsPalette$Bubbles; Lorg/thoughtcrime/securesms/conversation/colors/Colorizable; Lorg/thoughtcrime/securesms/conversation/colors/Colorizer$onGroupMembershipChanged$$inlined$sortedBy$1; Lorg/thoughtcrime/securesms/conversation/colors/Colorizer; -Lorg/thoughtcrime/securesms/conversation/colors/NameColor; Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$edgeEffectFactory$1; Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$itemDecoration$1; Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$scrollListener$1; Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$Companion; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft; Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$ShareOrDraftData; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1$1; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1; -Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2; Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel; -Lorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$Companion; Lorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator; Lorg/thoughtcrime/securesms/conversation/mutiselect/Multiselect; Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Companion; Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection$Single; Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection; -Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; -Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$WhenMappings; Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration; Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart$Attachments; Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectPart$Text; @@ -35058,18 +34055,10 @@ Lorg/thoughtcrime/securesms/conversation/mutiselect/Multiselectable; Lorg/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardBottomSheet$Callback; Lorg/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragmentArgs; Lorg/thoughtcrime/securesms/conversation/ui/error/EnableCallNotificationSettingsDialog$Callback; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryChangedListener; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$1; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$Companion; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$special$$inlined$doOnEachLayout$1; Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2; Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsPopup$Callback; Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$1; Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$Companion; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$None; -Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$Results; Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2; Lorg/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerRepositoryV2; Lorg/thoughtcrime/securesms/conversation/v2/AddToContactsContract$Companion; @@ -35113,81 +34102,36 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSynth Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda6; Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda7; Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$Companion; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder; Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$OnScrollStateChangedListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder$bind$subtitle$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder; Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$Listener; Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reminderStub$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reviewBannerStub$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$unverifiedBannerStub$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$voiceNotePlayerStub$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda10; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda11; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda12; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda13; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda14; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda15; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda16; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda17; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda18; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda8; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda24; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ActionModeCallback; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ActivityResultCallbacks; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$AttachmentKeyboardFragmentListener; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$AttachmentManagerListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$BackPressedDelegate; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$Companion; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ComposeTextEventsListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationBannerListener; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationItemClickListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback$onOptionsMenuCreated$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback$onOptionsMenuCreated$queryListener$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DataObserver; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DisabledInputListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$InputPanelListener; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$InputPanelMediaListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$KeyboardEvents; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$MotionEventRelayDrain; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollDateHeaderHelper; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SearchEventListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SendButtonListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SwipeAvailabilityProvider; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ThreadHeaderMarginDecoration; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ToolbarDependentMarginListener; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$VoiceMessageRecordingSessionCallbacks; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$WhenMappings; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$args$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$binding$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$binding$3; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$conversationGroupViewModel$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$conversationRecipientRepository$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$14; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$4; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$attachListener$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$conversationUpdateTick$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$draftViewModel$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$groupCallViewModel$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$1; @@ -35197,12 +34141,7 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConve Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$6; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeInlineSearch$1$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeInlineSearch$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$8; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$inlineQueryController$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$jumpAndPulseScrollStrategy$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2; @@ -35213,22 +34152,15 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$moveToStartPosi Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$3; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$$inlined$createActivityViewModel$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$onViewCreated$conversationToolbarOnScrollHelper$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentStoryRing$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentTypingIndicator$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentTypingIndicator$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$reactionDelegate$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$recentEmojis$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$registerForResults$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$scheduledMessagesStub$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$searchViewModel$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$1; @@ -35249,9 +34181,6 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewMode Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$viewModel$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$voiceNotePlayerListener$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState$CompleteUnreadState; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState$InitialUnreadState; Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState$None; Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$UnreadState; Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations; @@ -35263,8 +34192,6 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository$grou Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository$groupRecord$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationRecipientRepository; Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda11; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda14; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda19; Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda7; Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$Companion; Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$MessageCounts; @@ -35283,24 +34210,24 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationTooltips$special$$inline Lorg/thoughtcrime/securesms/conversation/v2/ConversationTooltips$special$$inlined$viewModels$default$5; Lorg/thoughtcrime/securesms/conversation/v2/ConversationTooltips; Lorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter$State; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter$ViewHolder; Lorg/thoughtcrime/securesms/conversation/v2/ConversationTypingIndicatorAdapter; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$10; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$11; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$14; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$15; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$17; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda3; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda0; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda1; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda2; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda3; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$5; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6; @@ -35308,26 +34235,21 @@ Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$8; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$9; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$canShowAsBubble$1; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$1; +Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$chatColorsDataObservable$2; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$2; -Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$storyRingState$1; Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel; -Lorg/thoughtcrime/securesms/conversation/v2/DisabledInputView$Listener; Lorg/thoughtcrime/securesms/conversation/v2/DisabledInputView$inflater$2; Lorg/thoughtcrime/securesms/conversation/v2/DisabledInputView; Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState; Lorg/thoughtcrime/securesms/conversation/v2/InputReadyState; Lorg/thoughtcrime/securesms/conversation/v2/MessageRequestViewModel; -Lorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay$Drain; Lorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay; Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState; Lorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel; -Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1; Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel; -Lorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$Companion; -Lorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$SessionCallback; Lorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate; Lorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate; Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource$Companion; @@ -35372,44 +34294,15 @@ Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel$du Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel$updateGroupStateIfNeeded$1; Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel$updateGroupStateIfNeeded$2; Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel; +Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsDrawableInvalidator; Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1; Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$1; Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration; -Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$Companion; -Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable; Lorg/thoughtcrime/securesms/conversation/v2/items/InteractiveConversationElement; +Lorg/thoughtcrime/securesms/conversation/v2/items/ShrinkWrapLinearLayout; Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnDispatchTouchEventListener; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnMeasureListener; Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$Companion; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridgeKt; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda2; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda3; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda4; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda6; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$Companion; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$PassthroughClickListener; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$ReactionMeasureListener; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$replyDelegate$1; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$1; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$Companion; -Lorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener; Lorg/thoughtcrime/securesms/conversation/v2/items/V2Payload; Lorg/thoughtcrime/securesms/conversationlist/ClearFilterViewHolder$OnClearFilterClickListener; Lorg/thoughtcrime/securesms/conversationlist/ConversationFilterBehavior$Callback; @@ -35471,11 +34364,11 @@ Lorg/thoughtcrime/securesms/conversationlist/ConversationListFragment$ArchiveLis Lorg/thoughtcrime/securesms/conversationlist/ConversationListFragment$Callback; Lorg/thoughtcrime/securesms/conversationlist/ConversationListFragment$ContactSearchClickCallbacks; Lorg/thoughtcrime/securesms/conversationlist/ConversationListFragment; -Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda12; -Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda4; +Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda10; +Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda13; +Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda2; Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda6; -Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem$$ExternalSyntheticLambda7; Lorg/thoughtcrime/securesms/conversationlist/ConversationListItem; Lorg/thoughtcrime/securesms/conversationlist/ConversationListItemAnimator; Lorg/thoughtcrime/securesms/conversationlist/ConversationListSearchAdapter$$ExternalSyntheticLambda0; @@ -35505,6 +34398,7 @@ Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$Factory; Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$conversationsState$1; Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$filterRequestState$1; Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$megaphoneState$1; +Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onMegaphoneCompleted$1; Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$onVisible$1$1; Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$pagedData$1; Lorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel$pagedData$2; @@ -35593,6 +34487,8 @@ Lorg/thoughtcrime/securesms/database/CallTable$Call; Lorg/thoughtcrime/securesms/database/CallTable$Companion; Lorg/thoughtcrime/securesms/database/CallTable$Event$Serializer; Lorg/thoughtcrime/securesms/database/CallTable$Event; +Lorg/thoughtcrime/securesms/database/CallTable$ReadState$Serializer; +Lorg/thoughtcrime/securesms/database/CallTable$ReadState; Lorg/thoughtcrime/securesms/database/CallTable; Lorg/thoughtcrime/securesms/database/CdsTable$Companion; Lorg/thoughtcrime/securesms/database/CdsTable; @@ -35601,7 +34497,6 @@ Lorg/thoughtcrime/securesms/database/ChatColorsTable; Lorg/thoughtcrime/securesms/database/DatabaseMonitor; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda10; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda11; -Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda13; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda17; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda20; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda23; @@ -35609,9 +34504,12 @@ Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda24 Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda28; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda29; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda30; +Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda32; +Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda36; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda37; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda40; Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda4; +Lorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver; Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer; Lorg/thoughtcrime/securesms/database/DatabaseObserver; @@ -35635,6 +34533,7 @@ Lorg/thoughtcrime/securesms/database/GroupReceiptTable; Lorg/thoughtcrime/securesms/database/GroupTable$Companion; Lorg/thoughtcrime/securesms/database/GroupTable$MembershipTable$Companion; Lorg/thoughtcrime/securesms/database/GroupTable$MembershipTable; +Lorg/thoughtcrime/securesms/database/GroupTable$Reader; Lorg/thoughtcrime/securesms/database/GroupTable$ShowAsStoryState$Companion; Lorg/thoughtcrime/securesms/database/GroupTable$ShowAsStoryState; Lorg/thoughtcrime/securesms/database/GroupTable; @@ -35647,6 +34546,7 @@ Lorg/thoughtcrime/securesms/database/JobDatabase$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/database/JobDatabase$Companion; Lorg/thoughtcrime/securesms/database/JobDatabase$deleteJobs$1; Lorg/thoughtcrime/securesms/database/JobDatabase$insertJobs$2; +Lorg/thoughtcrime/securesms/database/JobDatabase$updateJobs$2; Lorg/thoughtcrime/securesms/database/JobDatabase; Lorg/thoughtcrime/securesms/database/KeyValueDatabase$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/database/KeyValueDatabase$1; @@ -35733,9 +34633,12 @@ Lorg/thoughtcrime/securesms/database/ReactionTable; Lorg/thoughtcrime/securesms/database/RecipientIdDatabaseReference; Lorg/thoughtcrime/securesms/database/RecipientTable$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/database/RecipientTable$Companion; +Lorg/thoughtcrime/securesms/database/RecipientTable$GetOrInsertResult; Lorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting$Companion; Lorg/thoughtcrime/securesms/database/RecipientTable$MentionSetting; Lorg/thoughtcrime/securesms/database/RecipientTable$MissingRecipientException; +Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState$Companion; +Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberDiscoverableState; Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState$Companion; Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState; Lorg/thoughtcrime/securesms/database/RecipientTable$ProcessPnpTupleResult; @@ -35757,10 +34660,10 @@ Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSynthetic Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getRecipientExtras$1; -Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$forcedUnread$1; -Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$groupMasterKey$1; -Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$identityKey$1; -Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$identityStatus$1; +Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$2; +Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$3; +Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$4; +Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil$getSyncExtras$5; Lorg/thoughtcrime/securesms/database/RecipientTableCursorUtil; Lorg/thoughtcrime/securesms/database/RemappedRecordTables$Companion; Lorg/thoughtcrime/securesms/database/RemappedRecordTables; @@ -35813,6 +34716,7 @@ Lorg/thoughtcrime/securesms/database/SqlCipherDeletingErrorHandler; Lorg/thoughtcrime/securesms/database/SqlCipherErrorHandler$Companion; Lorg/thoughtcrime/securesms/database/SqlCipherErrorHandler; Lorg/thoughtcrime/securesms/database/SqlCipherLibraryLoader; +Lorg/thoughtcrime/securesms/database/StickerTable$StickerPackRecordReader; Lorg/thoughtcrime/securesms/database/StickerTable; Lorg/thoughtcrime/securesms/database/StorySendTable$Companion; Lorg/thoughtcrime/securesms/database/StorySendTable; @@ -35827,8 +34731,9 @@ Lorg/thoughtcrime/securesms/database/ThreadTable$ReadStatus$Companion; Lorg/thoughtcrime/securesms/database/ThreadTable$ReadStatus; Lorg/thoughtcrime/securesms/database/ThreadTable$Reader; Lorg/thoughtcrime/securesms/database/ThreadTable$StaticReader; +Lorg/thoughtcrime/securesms/database/ThreadTable$ThreadIdResult; Lorg/thoughtcrime/securesms/database/ThreadTable$WhenMappings; -Lorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdFor$1; +Lorg/thoughtcrime/securesms/database/ThreadTable$getOrCreateThreadIdResultFor$1; Lorg/thoughtcrime/securesms/database/ThreadTable$update$1$isPinned$2; Lorg/thoughtcrime/securesms/database/ThreadTable$update$1$shouldDelete$2; Lorg/thoughtcrime/securesms/database/ThreadTable$update$1; @@ -35909,21 +34814,18 @@ Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList; Lorg/thoughtcrime/securesms/database/model/databaseprotos/ChatColor; Lorg/thoughtcrime/securesms/database/model/databaseprotos/ExpiringProfileKeyCredentialColumnData; Lorg/thoughtcrime/securesms/database/model/databaseprotos/GiftBadge; +Lorg/thoughtcrime/securesms/database/model/databaseprotos/MessageExtras; Lorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonation$Companion$ADAPTER$1; Lorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonation$Companion; Lorg/thoughtcrime/securesms/database/model/databaseprotos/PendingOneTimeDonation; Lorg/thoughtcrime/securesms/database/model/databaseprotos/RecipientExtras; Lorg/thoughtcrime/securesms/database/model/databaseprotos/Wallpaper; -Lorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding; Lorg/thoughtcrime/securesms/databinding/ConversationInputPanelBinding; Lorg/thoughtcrime/securesms/databinding/ConversationListFilterPullViewBinding; Lorg/thoughtcrime/securesms/databinding/ConversationListTabsBinding; Lorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding; Lorg/thoughtcrime/securesms/databinding/ConversationTitleViewBinding; -Lorg/thoughtcrime/securesms/databinding/OnboardingMegaphoneCardBinding; -Lorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding; Lorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding; -Lorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding; Lorg/thoughtcrime/securesms/dependencies/ApplicationDependencies$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/dependencies/ApplicationDependencies$Provider; Lorg/thoughtcrime/securesms/dependencies/ApplicationDependencies; @@ -35962,6 +34864,7 @@ Lorg/thoughtcrime/securesms/emoji/EmojiJsonParserKt; Lorg/thoughtcrime/securesms/emoji/EmojiJsonRequest; Lorg/thoughtcrime/securesms/emoji/EmojiMetrics; Lorg/thoughtcrime/securesms/emoji/EmojiPage$Asset; +Lorg/thoughtcrime/securesms/emoji/EmojiPage$Disk; Lorg/thoughtcrime/securesms/emoji/EmojiPage; Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$$ExternalSyntheticLambda1; @@ -35975,6 +34878,7 @@ Lorg/thoughtcrime/securesms/emoji/EmojiRemote; Lorg/thoughtcrime/securesms/emoji/EmojiRequest; Lorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$1; Lorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadAssetBasedEmojis$1$parsedData$1; +Lorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1; Lorg/thoughtcrime/securesms/emoji/EmojiSource$Companion; Lorg/thoughtcrime/securesms/emoji/EmojiSource$canonicalToVariations$2; Lorg/thoughtcrime/securesms/emoji/EmojiSource$emojiTree$2; @@ -35982,6 +34886,7 @@ Lorg/thoughtcrime/securesms/emoji/EmojiSource$maxEmojiLength$2; Lorg/thoughtcrime/securesms/emoji/EmojiSource$variationsToCanonical$2; Lorg/thoughtcrime/securesms/emoji/EmojiSource; Lorg/thoughtcrime/securesms/emoji/EmojiSourceKt; +Lorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/emoji/JumboEmoji; Lorg/thoughtcrime/securesms/emoji/ObsoleteEmoji; @@ -36045,6 +34950,8 @@ Lorg/thoughtcrime/securesms/glide/cache/EncryptedCacheDecoder; Lorg/thoughtcrime/securesms/glide/cache/EncryptedCacheEncoder; Lorg/thoughtcrime/securesms/glide/cache/EncryptedCoder; Lorg/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder; +Lorg/thoughtcrime/securesms/glide/cache/WebpSanDecoder$Companion; +Lorg/thoughtcrime/securesms/glide/cache/WebpSanDecoder; Lorg/thoughtcrime/securesms/groups/BadGroupIdException; Lorg/thoughtcrime/securesms/groups/GroupChangeBusyException; Lorg/thoughtcrime/securesms/groups/GroupChangeException; @@ -36053,8 +34960,6 @@ Lorg/thoughtcrime/securesms/groups/GroupId; Lorg/thoughtcrime/securesms/groups/GroupNotAMemberException; Lorg/thoughtcrime/securesms/groups/SelectionLimits$1; Lorg/thoughtcrime/securesms/groups/SelectionLimits; -Lorg/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl$InvalidGroupLinkException; -Lorg/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl$UnknownGroupLinkVersionException; Lorg/thoughtcrime/securesms/groups/v2/GroupManagementRepository; Lorg/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/jobmanager/CompositeScheduler; @@ -36065,6 +34970,7 @@ Lorg/thoughtcrime/securesms/jobmanager/ConstraintInstantiator; Lorg/thoughtcrime/securesms/jobmanager/ConstraintObserver$Notifier; Lorg/thoughtcrime/securesms/jobmanager/ConstraintObserver; Lorg/thoughtcrime/securesms/jobmanager/ExecutorFactory; +Lorg/thoughtcrime/securesms/jobmanager/InAppScheduler$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/jobmanager/InAppScheduler; Lorg/thoughtcrime/securesms/jobmanager/Job$1; Lorg/thoughtcrime/securesms/jobmanager/Job$Factory; @@ -36073,11 +34979,15 @@ Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters; Lorg/thoughtcrime/securesms/jobmanager/Job$Result$ResultType; Lorg/thoughtcrime/securesms/jobmanager/Job$Result; Lorg/thoughtcrime/securesms/jobmanager/Job; +Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda0; +Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda13; +Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda14; +Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda16; +Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda17; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda19; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda20; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda22; -Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda23; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda6; @@ -36087,13 +34997,12 @@ Lorg/thoughtcrime/securesms/jobmanager/JobController$Callback; Lorg/thoughtcrime/securesms/jobmanager/JobController; Lorg/thoughtcrime/securesms/jobmanager/JobInstantiator; Lorg/thoughtcrime/securesms/jobmanager/JobLogger; -Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda10; -Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda14; -Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda15; +Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda11; Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda17; -Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda5; -Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda7; +Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda19; +Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda1; +Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda6; Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda8; Lorg/thoughtcrime/securesms/jobmanager/JobManager$$ExternalSyntheticLambda9; Lorg/thoughtcrime/securesms/jobmanager/JobManager$Chain; @@ -36177,6 +35086,8 @@ Lorg/thoughtcrime/securesms/jobs/ApkUpdateJob$Factory; Lorg/thoughtcrime/securesms/jobs/AttachmentCompressionJob$Factory; Lorg/thoughtcrime/securesms/jobs/AttachmentCopyJob$Factory; Lorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob$Factory; +Lorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob$InvalidPartException; +Lorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob; Lorg/thoughtcrime/securesms/jobs/AttachmentMarkUploadedJob$Factory; Lorg/thoughtcrime/securesms/jobs/AttachmentUploadJob$Factory; Lorg/thoughtcrime/securesms/jobs/AutomaticSessionResetJob$Factory; @@ -36196,11 +35107,17 @@ Lorg/thoughtcrime/securesms/jobs/ConversationShortcutRankingUpdateJob$Factory; Lorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob$Factory; Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Companion; Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory; +Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1; +Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$2; Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob; Lorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob$Factory; Lorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob; Lorg/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob$Factory; +Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda10; +Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda1; +Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda2; +Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda6; @@ -36253,7 +35170,6 @@ Lorg/thoughtcrime/securesms/jobs/LocalBackupJob$Factory; Lorg/thoughtcrime/securesms/jobs/LocalBackupJobApi29$Factory; Lorg/thoughtcrime/securesms/jobs/MarkerJob$Factory; Lorg/thoughtcrime/securesms/jobs/MessageFetchJob$Factory; -Lorg/thoughtcrime/securesms/jobs/MmsSendJob$Factory; Lorg/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob$Factory; Lorg/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob$Factory; Lorg/thoughtcrime/securesms/jobs/MultiDeviceConfigurationUpdateJob$Factory; @@ -36322,6 +35238,7 @@ Lorg/thoughtcrime/securesms/jobs/RetrieveProfileJob; Lorg/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob$Companion; Lorg/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob$Factory; Lorg/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob; +Lorg/thoughtcrime/securesms/jobs/RotateCertificateJob$1; Lorg/thoughtcrime/securesms/jobs/RotateCertificateJob$Factory; Lorg/thoughtcrime/securesms/jobs/RotateCertificateJob; Lorg/thoughtcrime/securesms/jobs/RotateProfileKeyJob$Factory; @@ -36333,10 +35250,9 @@ Lorg/thoughtcrime/securesms/jobs/SendRetryReceiptJob$Factory; Lorg/thoughtcrime/securesms/jobs/SendViewedReceiptJob$Factory; Lorg/thoughtcrime/securesms/jobs/SenderKeyDistributionSendJob$Factory; Lorg/thoughtcrime/securesms/jobs/ServiceOutageDetectionJob$Factory; -Lorg/thoughtcrime/securesms/jobs/SmsSendJob$Factory; -Lorg/thoughtcrime/securesms/jobs/SmsSentJob$Factory; Lorg/thoughtcrime/securesms/jobs/StickerDownloadJob$Factory; Lorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob$Factory; +Lorg/thoughtcrime/securesms/jobs/StickerPackDownloadJob; Lorg/thoughtcrime/securesms/jobs/StorageAccountRestoreJob$Factory; Lorg/thoughtcrime/securesms/jobs/StorageAccountRestoreJob; Lorg/thoughtcrime/securesms/jobs/StorageForcePushJob$Factory; @@ -36356,6 +35272,9 @@ Lorg/thoughtcrime/securesms/jobs/ThreadUpdateJob; Lorg/thoughtcrime/securesms/jobs/TrimThreadJob$Factory; Lorg/thoughtcrime/securesms/jobs/TypingSendJob$Factory; Lorg/thoughtcrime/securesms/jobs/UnableToStartException; +Lorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion$ADAPTER$1; +Lorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData$Companion; +Lorg/thoughtcrime/securesms/jobs/protos/PreKeysSyncJobData; Lorg/thoughtcrime/securesms/keyboard/KeyboardPage; Lorg/thoughtcrime/securesms/keyboard/KeyboardPagerViewModel$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/keyboard/KeyboardPagerViewModel; @@ -36365,6 +35284,8 @@ Lorg/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchRepository; Lorg/thoughtcrime/securesms/keyboard/gif/GifKeyboardPageFragment$Host; Lorg/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment$Callback; Lorg/thoughtcrime/securesms/keyvalue/AccountValues$Companion; +Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState$Companion; +Lorg/thoughtcrime/securesms/keyvalue/AccountValues$UsernameSyncState; Lorg/thoughtcrime/securesms/keyvalue/AccountValues$aciPreKeys$1; Lorg/thoughtcrime/securesms/keyvalue/AccountValues$pniPreKeys$1; Lorg/thoughtcrime/securesms/keyvalue/AccountValues; @@ -36410,7 +35331,7 @@ Lorg/thoughtcrime/securesms/keyvalue/PaymentsValues$liveCurrentCurrency$2; Lorg/thoughtcrime/securesms/keyvalue/PaymentsValues$liveMobileCoinBalance$2; Lorg/thoughtcrime/securesms/keyvalue/PaymentsValues$liveMobileCoinLedger$2; Lorg/thoughtcrime/securesms/keyvalue/PaymentsValues; -Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode; +Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberDiscoverabilityMode; Lorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues; Lorg/thoughtcrime/securesms/keyvalue/PinValues; Lorg/thoughtcrime/securesms/keyvalue/PlainTextSharedPrefsDataStore$Companion; @@ -36438,13 +35359,6 @@ Lorg/thoughtcrime/securesms/keyvalue/TooltipValues; Lorg/thoughtcrime/securesms/keyvalue/UiHints; Lorg/thoughtcrime/securesms/keyvalue/WallpaperValues; Lorg/thoughtcrime/securesms/linkpreview/LinkPreview; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Creator; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$Companion; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2; -Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1; Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2; Lorg/thoughtcrime/securesms/logging/CustomSignalProtocolLogger; Lorg/thoughtcrime/securesms/logging/PersistentLogger$Companion; @@ -36452,7 +35366,6 @@ Lorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequest; Lorg/thoughtcrime/securesms/logging/PersistentLogger$LogRequests; Lorg/thoughtcrime/securesms/logging/PersistentLogger$WriteThread; Lorg/thoughtcrime/securesms/logging/PersistentLogger; -Lorg/thoughtcrime/securesms/logsubmit/LogSectionNotifications$$ExternalSyntheticApiModelOutline2; Lorg/thoughtcrime/securesms/main/MainActivityListHostFragment$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/main/MainActivityListHostFragment$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/main/MainActivityListHostFragment$$ExternalSyntheticLambda2; @@ -36470,8 +35383,11 @@ Lorg/thoughtcrime/securesms/main/MainActivityListHostFragment$special$$inlined$v Lorg/thoughtcrime/securesms/main/MainActivityListHostFragment; Lorg/thoughtcrime/securesms/main/Material3OnScrollHelperBinder; Lorg/thoughtcrime/securesms/main/SearchBinder; +Lorg/thoughtcrime/securesms/mediasend/Media$1; +Lorg/thoughtcrime/securesms/mediasend/Media; Lorg/thoughtcrime/securesms/megaphone/ForeverSchedule; Lorg/thoughtcrime/securesms/megaphone/Megaphone$Builder; +Lorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener; Lorg/thoughtcrime/securesms/megaphone/Megaphone$Style; Lorg/thoughtcrime/securesms/megaphone/Megaphone; Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController; @@ -36486,29 +35402,27 @@ Lorg/thoughtcrime/securesms/megaphone/MegaphoneRepository$$ExternalSyntheticLamb Lorg/thoughtcrime/securesms/megaphone/MegaphoneRepository$Callback; Lorg/thoughtcrime/securesms/megaphone/MegaphoneRepository; Lorg/thoughtcrime/securesms/megaphone/MegaphoneSchedule; +Lorg/thoughtcrime/securesms/megaphone/MegaphoneText$Companion; +Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; Lorg/thoughtcrime/securesms/megaphone/MegaphoneViewBuilder$1; Lorg/thoughtcrime/securesms/megaphone/MegaphoneViewBuilder; -Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda18; +Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda19; +Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda20; Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda21; -Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda2; -Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda3; +Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda22; Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda6; +Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda7; +Lorg/thoughtcrime/securesms/megaphone/Megaphones$$ExternalSyntheticLambda8; Lorg/thoughtcrime/securesms/megaphone/Megaphones$1; Lorg/thoughtcrime/securesms/megaphone/Megaphones$3; Lorg/thoughtcrime/securesms/megaphone/Megaphones$Event; Lorg/thoughtcrime/securesms/megaphone/Megaphones; Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$ActionClickListener; -Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$AddPhotoCardViewHolder; Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardAdapter; -Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder$$ExternalSyntheticLambda0; -Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder$$ExternalSyntheticLambda1; -Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$CardViewHolder; -Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$GroupCardViewHolder; -Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView$InviteCardViewHolder; Lorg/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView; Lorg/thoughtcrime/securesms/megaphone/PinsForAllSchedule; Lorg/thoughtcrime/securesms/megaphone/RecurringSchedule; @@ -36523,12 +35437,13 @@ Lorg/thoughtcrime/securesms/megaphone/RemoteMegaphoneRepository$getRemoteMegapho Lorg/thoughtcrime/securesms/megaphone/RemoteMegaphoneRepository$snooze$1; Lorg/thoughtcrime/securesms/megaphone/RemoteMegaphoneRepository; Lorg/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule; -Lorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule$Companion; -Lorg/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule; Lorg/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver; +Lorg/thoughtcrime/securesms/messagerequests/GroupInfo$Companion; Lorg/thoughtcrime/securesms/messagerequests/GroupInfo; Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo; Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRepository; +Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState$Companion; +Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State; Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; Lorg/thoughtcrime/securesms/messages/IncomingMessageObserver$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/messages/IncomingMessageObserver$2; @@ -36576,6 +35491,7 @@ Lorg/thoughtcrime/securesms/migrations/PinOptOutMigration$Factory; Lorg/thoughtcrime/securesms/migrations/PinReminderMigrationJob$Factory; Lorg/thoughtcrime/securesms/migrations/PniAccountInitializationMigrationJob$Factory; Lorg/thoughtcrime/securesms/migrations/PniMigrationJob$Factory; +Lorg/thoughtcrime/securesms/migrations/PnpLaunchMigrationJob$Factory; Lorg/thoughtcrime/securesms/migrations/PreKeysSyncMigrationJob$Factory; Lorg/thoughtcrime/securesms/migrations/ProfileMigrationJob$Factory; Lorg/thoughtcrime/securesms/migrations/ProfileSharingUpdateMigrationJob$Factory; @@ -36607,10 +35523,6 @@ Lorg/thoughtcrime/securesms/mms/AudioSlide; Lorg/thoughtcrime/securesms/mms/DecryptableStreamUriLoader$DecryptableUri; Lorg/thoughtcrime/securesms/mms/DecryptableStreamUriLoader$Factory; Lorg/thoughtcrime/securesms/mms/GifSlide; -Lorg/thoughtcrime/securesms/mms/GlideApp; -Lorg/thoughtcrime/securesms/mms/GlideOptions; -Lorg/thoughtcrime/securesms/mms/GlideRequest; -Lorg/thoughtcrime/securesms/mms/GlideRequests; Lorg/thoughtcrime/securesms/mms/ImageSlide; Lorg/thoughtcrime/securesms/mms/IncomingMessage$Companion; Lorg/thoughtcrime/securesms/mms/IncomingMessage; @@ -36627,7 +35539,6 @@ Lorg/thoughtcrime/securesms/mms/SignalGlideModule$Companion; Lorg/thoughtcrime/securesms/mms/SignalGlideModule; Lorg/thoughtcrime/securesms/mms/Slide; Lorg/thoughtcrime/securesms/mms/SlideClickListener; -Lorg/thoughtcrime/securesms/mms/SlideDeck$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/mms/SlideDeck; Lorg/thoughtcrime/securesms/mms/SlideFactory$MediaType; Lorg/thoughtcrime/securesms/mms/SlidesClickedListener; @@ -36685,8 +35596,8 @@ Lorg/thoughtcrime/securesms/notifications/v2/NotificationState$notificationItems Lorg/thoughtcrime/securesms/notifications/v2/NotificationState; Lorg/thoughtcrime/securesms/payments/Payment; Lorg/thoughtcrime/securesms/payments/PaymentsAddressException; -Lorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter$PhoneNumber; -Lorg/thoughtcrime/securesms/phonenumbers/PhoneNumberFormatter; +Lorg/thoughtcrime/securesms/permissions/Permissions$$ExternalSyntheticLambda0; +Lorg/thoughtcrime/securesms/permissions/Permissions; Lorg/thoughtcrime/securesms/pin/SvrRepository; Lorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference; Lorg/thoughtcrime/securesms/profiles/AvatarHelper; @@ -36698,10 +35609,16 @@ Lorg/thoughtcrime/securesms/providers/AvatarProvider$Companion; Lorg/thoughtcrime/securesms/providers/AvatarProvider; Lorg/thoughtcrime/securesms/providers/BaseContentProvider; Lorg/thoughtcrime/securesms/providers/BlobContentProvider; +Lorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda10; Lorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda11; +Lorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda1; +Lorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda9; Lorg/thoughtcrime/securesms/providers/BlobProvider$1; +Lorg/thoughtcrime/securesms/providers/BlobProvider$2; +Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder; +Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec; +Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; Lorg/thoughtcrime/securesms/providers/BlobProvider; -Lorg/thoughtcrime/securesms/providers/MmsBodyProvider; Lorg/thoughtcrime/securesms/providers/PartProvider; Lorg/thoughtcrime/securesms/push/AccountManagerFactory; Lorg/thoughtcrime/securesms/push/DomainFrontingDigicertTrustStore; @@ -36716,12 +35633,10 @@ Lorg/thoughtcrime/securesms/ratelimit/RecaptchaRequiredEvent; Lorg/thoughtcrime/securesms/reactions/ReactionsBottomSheetDialogFragment$Callback; Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView; Lorg/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiBottomSheetDialogFragment$Callback; -Lorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda6; -Lorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda9; Lorg/thoughtcrime/securesms/recipients/LiveRecipient; Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache$$ExternalSyntheticLambda2; @@ -36729,6 +35644,7 @@ Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache$$ExternalSyntheticLamb Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache$$ExternalSyntheticLambda4; Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/recipients/LiveRecipientCache; +Lorg/thoughtcrime/securesms/recipients/Recipient$$ExternalSyntheticLambda3; Lorg/thoughtcrime/securesms/recipients/Recipient$Capability; Lorg/thoughtcrime/securesms/recipients/Recipient$Extras; Lorg/thoughtcrime/securesms/recipients/Recipient$FallbackPhotoProvider; @@ -36753,6 +35669,8 @@ Lorg/thoughtcrime/securesms/registration/RegistrationRepository; Lorg/thoughtcrime/securesms/registration/RegistrationUtil; Lorg/thoughtcrime/securesms/registration/VerifyResponse$Companion; Lorg/thoughtcrime/securesms/registration/VerifyResponse; +Lorg/thoughtcrime/securesms/registration/viewmodel/RegistrationViewModel$$ExternalSyntheticLambda3; +Lorg/thoughtcrime/securesms/releasechannel/ReleaseChannel; Lorg/thoughtcrime/securesms/revealable/ViewOnceMessageManager; Lorg/thoughtcrime/securesms/ringrtc/RingRtcLogger; Lorg/thoughtcrime/securesms/s3/S3; @@ -36793,6 +35711,9 @@ Lorg/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId; Lorg/thoughtcrime/securesms/shakereport/ShakeToReport; Lorg/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtil; Lorg/thoughtcrime/securesms/sms/MessageSender$MessageSentEvent; +Lorg/thoughtcrime/securesms/stickers/BlessedPacks$1; +Lorg/thoughtcrime/securesms/stickers/BlessedPacks$Pack; +Lorg/thoughtcrime/securesms/stickers/BlessedPacks; Lorg/thoughtcrime/securesms/stickers/StickerEventListener; Lorg/thoughtcrime/securesms/stickers/StickerLocator; Lorg/thoughtcrime/securesms/stickers/StickerPackInstallEvent; @@ -36853,11 +35774,6 @@ Lorg/thoughtcrime/securesms/util/AppStartup$Task; Lorg/thoughtcrime/securesms/util/AppStartup; Lorg/thoughtcrime/securesms/util/AvatarUtil; Lorg/thoughtcrime/securesms/util/BitmapDecodingException; -Lorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline0; -Lorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline1; -Lorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline2; -Lorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline3; -Lorg/thoughtcrime/securesms/util/BubbleUtil; Lorg/thoughtcrime/securesms/util/ByteUnit$1; Lorg/thoughtcrime/securesms/util/ByteUnit$2; Lorg/thoughtcrime/securesms/util/ByteUnit$3; @@ -36867,18 +35783,14 @@ Lorg/thoughtcrime/securesms/util/CachedInflater$ViewCache$$ExternalSyntheticLamb Lorg/thoughtcrime/securesms/util/CachedInflater$ViewCache$$ExternalSyntheticLambda1; Lorg/thoughtcrime/securesms/util/CachedInflater$ViewCache; Lorg/thoughtcrime/securesms/util/CachedInflater; -Lorg/thoughtcrime/securesms/util/CenteredImageSpan; Lorg/thoughtcrime/securesms/util/CharacterCalculator; Lorg/thoughtcrime/securesms/util/ConfigurationUtil; Lorg/thoughtcrime/securesms/util/ContextUtil; Lorg/thoughtcrime/securesms/util/ConversationShortcutPhoto$Loader$Factory; Lorg/thoughtcrime/securesms/util/ConversationShortcutPhoto; -Lorg/thoughtcrime/securesms/util/ConversationUtil; Lorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2; Lorg/thoughtcrime/securesms/util/DateUtils; Lorg/thoughtcrime/securesms/util/Debouncer; -Lorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate$lazyDefault$2; -Lorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate; Lorg/thoughtcrime/securesms/util/DefaultValueLiveData; Lorg/thoughtcrime/securesms/util/Deferred; Lorg/thoughtcrime/securesms/util/DeviceProperties; @@ -36897,6 +35809,7 @@ Lorg/thoughtcrime/securesms/util/FrameRateTracker; Lorg/thoughtcrime/securesms/util/FullscreenHelper$$ExternalSyntheticApiModelOutline0; Lorg/thoughtcrime/securesms/util/FullscreenHelper; Lorg/thoughtcrime/securesms/util/FutureTaskListener; +Lorg/thoughtcrime/securesms/util/IOFunction; Lorg/thoughtcrime/securesms/util/JavaTimeExtensionsKt; Lorg/thoughtcrime/securesms/util/JsonUtils$SaneJSONObject; Lorg/thoughtcrime/securesms/util/JsonUtils; @@ -36911,9 +35824,6 @@ Lorg/thoughtcrime/securesms/util/LocalMetrics$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/util/LocalMetrics$db$2; Lorg/thoughtcrime/securesms/util/LocalMetrics; Lorg/thoughtcrime/securesms/util/LocaleUtil; -Lorg/thoughtcrime/securesms/util/LongClickMovementMethod$1; -Lorg/thoughtcrime/securesms/util/LongClickMovementMethod; -Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper$1; Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper$2; Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3; @@ -36927,24 +35837,23 @@ Lorg/thoughtcrime/securesms/util/MessageRecordUtil; Lorg/thoughtcrime/securesms/util/NameUtil; Lorg/thoughtcrime/securesms/util/NetworkUtil; Lorg/thoughtcrime/securesms/util/NoCrossfadeChangeDefaultAnimator; -Lorg/thoughtcrime/securesms/util/NullableSavedStateHandleDelegate; +Lorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda2; +Lorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda3; +Lorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda4; +Lorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda5; Lorg/thoughtcrime/securesms/util/ProfileUtil; -Lorg/thoughtcrime/securesms/util/Projection$Corners; Lorg/thoughtcrime/securesms/util/Projection; Lorg/thoughtcrime/securesms/util/ProjectionList; Lorg/thoughtcrime/securesms/util/PushCharacterCalculator$1; Lorg/thoughtcrime/securesms/util/PushCharacterCalculator; Lorg/thoughtcrime/securesms/util/RemoteDeprecation; -Lorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt$delegate$1; -Lorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt; Lorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion$factoryProducer$1; Lorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion; Lorg/thoughtcrime/securesms/util/SavedStateViewModelFactory; Lorg/thoughtcrime/securesms/util/ScreenDensity$1; Lorg/thoughtcrime/securesms/util/ScreenDensity; Lorg/thoughtcrime/securesms/util/SearchUtil$StyleFactory; -Lorg/thoughtcrime/securesms/util/SearchUtil; Lorg/thoughtcrime/securesms/util/ServiceUtil; Lorg/thoughtcrime/securesms/util/SignalLocalMetrics$ColdStart; Lorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen; @@ -36960,11 +35869,6 @@ Lorg/thoughtcrime/securesms/util/SnapToTopDataObserver$ScrollToTop; Lorg/thoughtcrime/securesms/util/SnapToTopDataObserver; Lorg/thoughtcrime/securesms/util/SoftHashMap$SoftValue; Lorg/thoughtcrime/securesms/util/SoftHashMap; -Lorg/thoughtcrime/securesms/util/SpanUtil; -Lorg/thoughtcrime/securesms/util/SplashScreenUtil$$ExternalSyntheticApiModelOutline0; -Lorg/thoughtcrime/securesms/util/SplashScreenUtil$$ExternalSyntheticApiModelOutline1; -Lorg/thoughtcrime/securesms/util/SplashScreenUtil$1; -Lorg/thoughtcrime/securesms/util/SplashScreenUtil; Lorg/thoughtcrime/securesms/util/StorageUtil; Lorg/thoughtcrime/securesms/util/TextSecurePreferences$MediaKeyboardMode; Lorg/thoughtcrime/securesms/util/TextSecurePreferences; @@ -36983,10 +35887,10 @@ Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$3; Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$4; Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$1; -Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$1; -Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$2; -Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$3; Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$4; +Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$5; +Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$6; +Lorg/thoughtcrime/securesms/util/ViewModelFactoryKt$viewModel$$inlined$viewModels$default$7; Lorg/thoughtcrime/securesms/util/ViewUtil; Lorg/thoughtcrime/securesms/util/WakeLockUtil; Lorg/thoughtcrime/securesms/util/WindowUtil; @@ -36996,20 +35900,15 @@ Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter; Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingDiffCallback; Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel; Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModelList; -Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; Lorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter$Placeholder; Lorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter; Lorg/thoughtcrime/securesms/util/cjkv/CJKVUtil; Lorg/thoughtcrime/securesms/util/concurrent/FilteredExecutor$Filter; Lorg/thoughtcrime/securesms/util/concurrent/FilteredExecutor; -Lorg/thoughtcrime/securesms/util/concurrent/ListenableFuture; Lorg/thoughtcrime/securesms/util/concurrent/SerialExecutor$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/util/concurrent/SerialExecutor; -Lorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor$$ExternalSyntheticLambda0; Lorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor; -Lorg/thoughtcrime/securesms/util/concurrent/SettableFuture; -Lorg/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat; Lorg/thoughtcrime/securesms/util/dynamiclanguage/DynamicLanguageContextWrapper; Lorg/thoughtcrime/securesms/util/dynamiclanguage/LanguageString; Lorg/thoughtcrime/securesms/util/dynamiclanguage/LocaleParser; @@ -37071,6 +35970,8 @@ Lorg/whispersystems/signalservice/api/SignalServiceAccountDataStore; Lorg/whispersystems/signalservice/api/SignalServiceAccountManager; Lorg/whispersystems/signalservice/api/SignalServiceDataStore; Lorg/whispersystems/signalservice/api/SignalServiceKyberPreKeyStore; +Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver$$ExternalSyntheticLambda0; +Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver; Lorg/whispersystems/signalservice/api/SignalServicePreKeyStore; Lorg/whispersystems/signalservice/api/SignalServiceSenderKeyStore; Lorg/whispersystems/signalservice/api/SignalServiceSessionStore; @@ -37079,10 +35980,12 @@ Lorg/whispersystems/signalservice/api/SignalSessionLock; Lorg/whispersystems/signalservice/api/SignalWebSocket$$ExternalSyntheticLambda0; Lorg/whispersystems/signalservice/api/SignalWebSocket$MessageReceivedCallback; Lorg/whispersystems/signalservice/api/SignalWebSocket; +Lorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities; +Lorg/whispersystems/signalservice/api/account/AccountAttributes; Lorg/whispersystems/signalservice/api/account/PreKeyCollection; Lorg/whispersystems/signalservice/api/crypto/InvalidCiphertextException; +Lorg/whispersystems/signalservice/api/crypto/UnidentifiedAccess; Lorg/whispersystems/signalservice/api/groupsv2/ClientZkOperations; -Lorg/whispersystems/signalservice/api/groupsv2/GroupLinkNotActiveException; Lorg/whispersystems/signalservice/api/groupsv2/GroupsV2Operations; Lorg/whispersystems/signalservice/api/kbs/MasterKey; Lorg/whispersystems/signalservice/api/messages/SignalServiceAttachment; @@ -37095,24 +35998,36 @@ Lorg/whispersystems/signalservice/api/payments/Money$MobileCoin$$ExternalSynthet Lorg/whispersystems/signalservice/api/payments/Money$MobileCoin; Lorg/whispersystems/signalservice/api/payments/Money$ParseException; Lorg/whispersystems/signalservice/api/payments/Money; +Lorg/whispersystems/signalservice/api/profiles/ProfileAndCredential; Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$Capabilities; +Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType; Lorg/whispersystems/signalservice/api/push/ServiceId$ACI$Companion; Lorg/whispersystems/signalservice/api/push/ServiceId$ACI; Lorg/whispersystems/signalservice/api/push/ServiceId$Companion; Lorg/whispersystems/signalservice/api/push/ServiceId$PNI$Companion; Lorg/whispersystems/signalservice/api/push/ServiceId$PNI; Lorg/whispersystems/signalservice/api/push/ServiceId; +Lorg/whispersystems/signalservice/api/push/ServiceIdType; Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; Lorg/whispersystems/signalservice/api/push/TrustStore; Lorg/whispersystems/signalservice/api/push/exceptions/ConflictException; Lorg/whispersystems/signalservice/api/push/exceptions/ContactManifestMismatchException; Lorg/whispersystems/signalservice/api/push/exceptions/MalformedResponseException; Lorg/whispersystems/signalservice/api/push/exceptions/MissingConfigurationException; +Lorg/whispersystems/signalservice/api/push/exceptions/NetworkFailureException; Lorg/whispersystems/signalservice/api/push/exceptions/NoContentException; Lorg/whispersystems/signalservice/api/push/exceptions/NonSuccessfulResponseCodeException; Lorg/whispersystems/signalservice/api/push/exceptions/NotFoundException; Lorg/whispersystems/signalservice/api/push/exceptions/PushNetworkException; +Lorg/whispersystems/signalservice/api/push/exceptions/RangeException; Lorg/whispersystems/signalservice/api/services/DonationsService; +Lorg/whispersystems/signalservice/api/services/MessagingService$$ExternalSyntheticLambda4; +Lorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda1; +Lorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda2; +Lorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda3; +Lorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseMapper; +Lorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseProcessor; +Lorg/whispersystems/signalservice/api/services/ProfileService; Lorg/whispersystems/signalservice/api/svr/SecureValueRecovery; Lorg/whispersystems/signalservice/api/svr/SecureValueRecoveryV2$Companion; Lorg/whispersystems/signalservice/api/svr/SecureValueRecoveryV2; @@ -37133,7 +36048,6 @@ Lorg/whispersystems/signalservice/internal/ServiceResponseProcessor; Lorg/whispersystems/signalservice/internal/configuration/SignalCdnUrl; Lorg/whispersystems/signalservice/internal/configuration/SignalCdsiUrl; Lorg/whispersystems/signalservice/internal/configuration/SignalKeyBackupServiceUrl; -Lorg/whispersystems/signalservice/internal/configuration/SignalProxy; Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration; Lorg/whispersystems/signalservice/internal/configuration/SignalServiceUrl; Lorg/whispersystems/signalservice/internal/configuration/SignalStorageUrl; @@ -37142,6 +36056,8 @@ Lorg/whispersystems/signalservice/internal/configuration/SignalUrl; Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda10; Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda11; Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda12; +Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda14; +Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$1; Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$2; Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder; Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$EmptyResponseCodeHandler; @@ -37150,11 +36066,24 @@ Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ServiceConnect Lorg/whispersystems/signalservice/internal/push/PushServiceSocket; Lorg/whispersystems/signalservice/internal/push/VerifyAccountResponse; Lorg/whispersystems/signalservice/internal/push/exceptions/GroupPatchNotAcceptedException; +Lorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil; Lorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager$1; Lorg/whispersystems/signalservice/internal/util/BlacklistingTrustManager; +Lorg/whispersystems/signalservice/internal/util/Hex; Lorg/whispersystems/signalservice/internal/util/JsonUtil; Lorg/whispersystems/signalservice/internal/util/Util; +Lorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder; +Lorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper; +Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder; +Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper; +Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper; +Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper; +Lorg/whispersystems/signalservice/internal/websocket/ResponseMapper; Lorg/whispersystems/signalservice/internal/websocket/WebSocketConnection; +Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; +Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion$ADAPTER$1; +Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion; +Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage; Lorg/whispersystems/util/StringUtil; Lrxdogtag2/DogTagMaybeObserver$$ExternalSyntheticLambda0; Lrxdogtag2/DogTagMaybeObserver$$ExternalSyntheticLambda1; @@ -37192,17 +36121,130 @@ Lrxdogtag2/RxDogTag$Configuration; Lrxdogtag2/RxDogTag$NonCheckingConsumer; Lrxdogtag2/RxDogTag; Lrxdogtag2/RxDogTagErrorReceiver; +PLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;->saveState()Landroid/os/Bundle; +PLandroidx/activity/ComponentActivity;->$r8$lambda$OnwlVMZzrLePIRy-6IUDTtLLUV0(Landroidx/activity/ComponentActivity;)Landroid/os/Bundle; +PLandroidx/activity/ComponentActivity;->lambda$new$1()Landroid/os/Bundle; +PLandroidx/activity/ComponentActivity;->onSaveInstanceState(Landroid/os/Bundle;)V PLandroidx/activity/result/ActivityResultRegistry$LifecycleContainer;->clearObservers()V +PLandroidx/activity/result/ActivityResultRegistry;->onSaveInstanceState(Landroid/os/Bundle;)V +PLandroidx/appcompat/app/AppCompatActivity$1;->saveState()Landroid/os/Bundle; +PLandroidx/appcompat/app/AppCompatDelegateImpl;->onSaveInstanceState(Landroid/os/Bundle;)V PLandroidx/appcompat/app/ToolbarActionBar;->onDestroy()V +PLandroidx/appcompat/view/SupportMenuInflater$MenuState;->addSubMenuItem()Landroid/view/SubMenu; +PLandroidx/appcompat/view/SupportMenuInflater$MenuState;->newInstance(Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/Object;)Ljava/lang/Object; PLandroidx/appcompat/view/menu/ActionMenuItemView;->getAccessibilityClassName()Ljava/lang/CharSequence; +PLandroidx/appcompat/view/menu/MenuBuilder;->addSubMenu(IIILjava/lang/CharSequence;)Landroid/view/SubMenu; +PLandroidx/appcompat/view/menu/MenuBuilder;->clearHeader()V +PLandroidx/appcompat/view/menu/MenuBuilder;->getResources()Landroid/content/res/Resources; +PLandroidx/appcompat/view/menu/MenuBuilder;->setHeaderInternal(ILjava/lang/CharSequence;ILandroid/graphics/drawable/Drawable;Landroid/view/View;)V +PLandroidx/appcompat/view/menu/MenuBuilder;->setHeaderTitleInt(Ljava/lang/CharSequence;)Landroidx/appcompat/view/menu/MenuBuilder; +PLandroidx/appcompat/view/menu/MenuItemImpl;->getSubMenu()Landroid/view/SubMenu; +PLandroidx/appcompat/view/menu/MenuItemImpl;->setActionView(Landroid/view/View;)Landroid/view/MenuItem; +PLandroidx/appcompat/view/menu/MenuItemImpl;->setActionView(Landroid/view/View;)Landroidx/core/internal/view/SupportMenuItem; +PLandroidx/appcompat/view/menu/MenuItemImpl;->setOnActionExpandListener(Landroid/view/MenuItem$OnActionExpandListener;)Landroid/view/MenuItem; +PLandroidx/appcompat/view/menu/MenuItemImpl;->setSubMenu(Landroidx/appcompat/view/menu/SubMenuBuilder;)V +PLandroidx/appcompat/view/menu/MenuItemImpl;->setTitle(Ljava/lang/CharSequence;)Landroid/view/MenuItem; +PLandroidx/appcompat/view/menu/SubMenuBuilder;->(Landroid/content/Context;Landroidx/appcompat/view/menu/MenuBuilder;Landroidx/appcompat/view/menu/MenuItemImpl;)V +PLandroidx/appcompat/view/menu/SubMenuBuilder;->getItem()Landroid/view/MenuItem; +PLandroidx/appcompat/view/menu/SubMenuBuilder;->setHeaderTitle(Ljava/lang/CharSequence;)Landroid/view/SubMenu; PLandroidx/appcompat/widget/ActionMenuPresenter;->dismissPopupMenus()Z PLandroidx/appcompat/widget/ActionMenuPresenter;->hideOverflowMenu()Z PLandroidx/appcompat/widget/ActionMenuPresenter;->hideSubMenus()Z +PLandroidx/appcompat/widget/ActionMenuPresenter;->isOverflowMenuShowing()Z PLandroidx/appcompat/widget/ActionMenuView;->dismissPopupMenus()V +PLandroidx/appcompat/widget/ActionMenuView;->isOverflowMenuShowing()Z PLandroidx/appcompat/widget/ActionMenuView;->onDetachedFromWindow()V +PLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->()V +PLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +PLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->initEmojiKeyListener(Landroidx/appcompat/widget/AppCompatEmojiEditTextHelper;)V +PLandroidx/appcompat/widget/AppCompatAutoCompleteTextView;->setCompoundDrawables(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V +PLandroidx/appcompat/widget/AppCompatButton;->onInitializeAccessibilityNodeInfo(Landroid/view/accessibility/AccessibilityNodeInfo;)V +PLandroidx/appcompat/widget/AppCompatButton;->onLayout(ZIIII)V +PLandroidx/appcompat/widget/AppCompatDrawableManager$1;->getTintModeForDrawableRes(I)Landroid/graphics/PorterDuff$Mode; +PLandroidx/appcompat/widget/ForwardingListener;->onViewDetachedFromWindow(Landroid/view/View;)V +PLandroidx/appcompat/widget/LinearLayoutCompat;->getBaseline()I +PLandroidx/appcompat/widget/ResourceManagerInternal;->addTintListToCache(Landroid/content/Context;ILandroid/content/res/ColorStateList;)V +PLandroidx/appcompat/widget/ResourceManagerInternal;->getTintMode(I)Landroid/graphics/PorterDuff$Mode; +PLandroidx/appcompat/widget/SearchView$10;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$1;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$2;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$3;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$4;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$5;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$6;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$7;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$8;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$9;->(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete$1;->(Landroidx/appcompat/widget/SearchView$SearchAutoComplete;)V +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->enoughToFilter()Z +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->getSearchViewTextMinWidthDp()I +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->onFinishInflate()V +PLandroidx/appcompat/widget/SearchView$SearchAutoComplete;->setSearchView(Landroidx/appcompat/widget/SearchView;)V +PLandroidx/appcompat/widget/SearchView;->()V +PLandroidx/appcompat/widget/SearchView;->getDecoratedHint(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; +PLandroidx/appcompat/widget/SearchView;->getQueryHint()Ljava/lang/CharSequence; +PLandroidx/appcompat/widget/SearchView;->isSubmitAreaEnabled()Z +PLandroidx/appcompat/widget/SearchView;->setIconifiedByDefault(Z)V +PLandroidx/appcompat/widget/SearchView;->setMaxWidth(I)V +PLandroidx/appcompat/widget/SearchView;->updateCloseButton()V +PLandroidx/appcompat/widget/SearchView;->updateQueryHint()V +PLandroidx/appcompat/widget/SearchView;->updateSubmitArea()V +PLandroidx/appcompat/widget/SearchView;->updateSubmitButton(Z)V +PLandroidx/appcompat/widget/SearchView;->updateViewsVisibility(Z)V +PLandroidx/appcompat/widget/SearchView;->updateVoiceButton(Z)V +PLandroidx/appcompat/widget/Toolbar$SavedState$1;->()V +PLandroidx/appcompat/widget/Toolbar$SavedState;->()V +PLandroidx/appcompat/widget/Toolbar$SavedState;->(Landroid/os/Parcelable;)V PLandroidx/appcompat/widget/Toolbar$SavedState;->writeToParcel(Landroid/os/Parcel;I)V +PLandroidx/appcompat/widget/Toolbar;->isOverflowMenuShowing()Z PLandroidx/appcompat/widget/Toolbar;->onDetachedFromWindow()V +PLandroidx/appcompat/widget/Toolbar;->onSaveInstanceState()Landroid/os/Parcelable; +PLandroidx/cardview/R$styleable;->()V +PLandroidx/cardview/widget/CardView$1;->(Landroidx/cardview/widget/CardView;)V +PLandroidx/cardview/widget/CardView$1;->getCardBackground()Landroid/graphics/drawable/Drawable; +PLandroidx/cardview/widget/CardView$1;->getCardView()Landroid/view/View; +PLandroidx/cardview/widget/CardView$1;->getPreventCornerOverlap()Z +PLandroidx/cardview/widget/CardView$1;->getUseCompatPadding()Z +PLandroidx/cardview/widget/CardView$1;->setCardBackground(Landroid/graphics/drawable/Drawable;)V +PLandroidx/cardview/widget/CardView$1;->setShadowPadding(IIII)V +PLandroidx/cardview/widget/CardView;->()V +PLandroidx/cardview/widget/CardView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +PLandroidx/cardview/widget/CardView;->access$001(Landroidx/cardview/widget/CardView;IIII)V +PLandroidx/cardview/widget/CardView;->getCardBackgroundColor()Landroid/content/res/ColorStateList; +PLandroidx/cardview/widget/CardView;->getCardElevation()F +PLandroidx/cardview/widget/CardView;->getContentPaddingBottom()I +PLandroidx/cardview/widget/CardView;->getContentPaddingLeft()I +PLandroidx/cardview/widget/CardView;->getContentPaddingRight()I +PLandroidx/cardview/widget/CardView;->getContentPaddingTop()I +PLandroidx/cardview/widget/CardView;->getMaxCardElevation()F +PLandroidx/cardview/widget/CardView;->getPreventCornerOverlap()Z +PLandroidx/cardview/widget/CardView;->getUseCompatPadding()Z +PLandroidx/cardview/widget/CardView;->onMeasure(II)V +PLandroidx/cardview/widget/CardView;->setContentPadding(IIII)V +PLandroidx/cardview/widget/CardViewApi21Impl;->()V +PLandroidx/cardview/widget/CardViewApi21Impl;->getBackgroundColor(Landroidx/cardview/widget/CardViewDelegate;)Landroid/content/res/ColorStateList; +PLandroidx/cardview/widget/CardViewApi21Impl;->getCardBackground(Landroidx/cardview/widget/CardViewDelegate;)Landroidx/cardview/widget/RoundRectDrawable; +PLandroidx/cardview/widget/CardViewApi21Impl;->getElevation(Landroidx/cardview/widget/CardViewDelegate;)F +PLandroidx/cardview/widget/CardViewApi21Impl;->getMaxElevation(Landroidx/cardview/widget/CardViewDelegate;)F +PLandroidx/cardview/widget/CardViewApi21Impl;->getRadius(Landroidx/cardview/widget/CardViewDelegate;)F +PLandroidx/cardview/widget/CardViewApi21Impl;->initStatic()V +PLandroidx/cardview/widget/CardViewApi21Impl;->initialize(Landroidx/cardview/widget/CardViewDelegate;Landroid/content/Context;Landroid/content/res/ColorStateList;FFF)V +PLandroidx/cardview/widget/CardViewApi21Impl;->setMaxElevation(Landroidx/cardview/widget/CardViewDelegate;F)V +PLandroidx/cardview/widget/CardViewApi21Impl;->updatePadding(Landroidx/cardview/widget/CardViewDelegate;)V +PLandroidx/cardview/widget/RoundRectDrawable;->(Landroid/content/res/ColorStateList;F)V +PLandroidx/cardview/widget/RoundRectDrawable;->getColor()Landroid/content/res/ColorStateList; +PLandroidx/cardview/widget/RoundRectDrawable;->getPadding()F +PLandroidx/cardview/widget/RoundRectDrawable;->getRadius()F +PLandroidx/cardview/widget/RoundRectDrawable;->setBackground(Landroid/content/res/ColorStateList;)V +PLandroidx/cardview/widget/RoundRectDrawable;->setPadding(FZZ)V +PLandroidx/cardview/widget/RoundRectDrawable;->updateBounds(Landroid/graphics/Rect;)V +PLandroidx/cardview/widget/RoundRectDrawableWithShadow;->()V +PLandroidx/cardview/widget/RoundRectDrawableWithShadow;->calculateHorizontalPadding(FFZ)F +PLandroidx/cardview/widget/RoundRectDrawableWithShadow;->calculateVerticalPadding(FFZ)F PLandroidx/collection/SimpleArrayMap;->equals(Ljava/lang/Object;)Z +PLandroidx/collection/SparseArrayCompat;->append(ILjava/lang/Object;)V PLandroidx/collection/SparseArrayCompat;->clear()V PLandroidx/concurrent/futures/AbstractResolvableFuture$AtomicHelper;->()V PLandroidx/concurrent/futures/AbstractResolvableFuture$AtomicHelper;->(Landroidx/concurrent/futures/AbstractResolvableFuture$1;)V @@ -37224,55 +36266,144 @@ PLandroidx/concurrent/futures/AbstractResolvableFuture;->set(Ljava/lang/Object;) PLandroidx/concurrent/futures/ResolvableFuture;->()V PLandroidx/concurrent/futures/ResolvableFuture;->create()Landroidx/concurrent/futures/ResolvableFuture; PLandroidx/concurrent/futures/ResolvableFuture;->set(Ljava/lang/Object;)Z +PLandroidx/constraintlayout/core/ArrayRow;->createRowDimensionRatio(Landroidx/constraintlayout/core/SolverVariable;Landroidx/constraintlayout/core/SolverVariable;Landroidx/constraintlayout/core/SolverVariable;Landroidx/constraintlayout/core/SolverVariable;F)Landroidx/constraintlayout/core/ArrayRow; +PLandroidx/constraintlayout/core/ArrayRow;->getPivotCandidate(Landroidx/constraintlayout/core/LinearSystem;[Z)Landroidx/constraintlayout/core/SolverVariable; +PLandroidx/constraintlayout/core/ArrayRow;->initFromRow(Landroidx/constraintlayout/core/LinearSystem$Row;)V +PLandroidx/constraintlayout/core/ArrayRow;->pickPivotInVariables([ZLandroidx/constraintlayout/core/SolverVariable;)Landroidx/constraintlayout/core/SolverVariable; +PLandroidx/constraintlayout/core/LinearSystem;->createExtraVariable()Landroidx/constraintlayout/core/SolverVariable; +PLandroidx/constraintlayout/core/widgets/ConstraintAnchor;->getType()Landroidx/constraintlayout/core/widgets/ConstraintAnchor$Type; PLandroidx/constraintlayout/widget/ConstraintHelper;->setTag(ILjava/lang/Object;)V +PLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState$1;->()V +PLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState;->()V +PLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState;->(Landroid/os/Parcelable;)V PLandroidx/coordinatorlayout/widget/CoordinatorLayout$SavedState;->writeToParcel(Landroid/os/Parcel;I)V PLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onDetachedFromWindow()V +PLandroidx/coordinatorlayout/widget/CoordinatorLayout;->onSaveInstanceState()Landroid/os/Parcelable; +PLandroidx/core/app/ComponentActivity;->onSaveInstanceState(Landroid/os/Bundle;)V +PLandroidx/core/app/NotificationManagerCompat$Api23Impl$$ExternalSyntheticApiModelOutline1;->m(Landroid/app/NotificationManager;)[Landroid/service/notification/StatusBarNotification; +PLandroidx/core/os/BundleKt;->bundleOf([Lkotlin/Pair;)Landroid/os/Bundle; PLandroidx/core/os/HandlerCompat$Api28Impl$$ExternalSyntheticApiModelOutline0;->m(Landroid/os/Handler;Ljava/lang/Runnable;Ljava/lang/Object;J)Z PLandroidx/core/os/HandlerCompat$Api28Impl;->postDelayed(Landroid/os/Handler;Ljava/lang/Runnable;Ljava/lang/Object;J)Z PLandroidx/core/os/HandlerCompat;->postDelayed(Landroid/os/Handler;Ljava/lang/Runnable;Ljava/lang/Object;J)Z -PLandroidx/core/view/NestedScrollingChildHelper;->stopNestedScroll()V +PLandroidx/core/text/util/LinkifyCompat$$ExternalSyntheticLambda0;->()V +PLandroidx/core/text/util/LinkifyCompat;->()V +PLandroidx/core/text/util/LinkifyCompat;->addLinks(Landroid/text/Spannable;I)Z +PLandroidx/core/text/util/LinkifyCompat;->shouldAddLinksFallbackToFramework()Z PLandroidx/core/view/ViewCompat$Api16Impl;->hasTransientState(Landroid/view/View;)Z PLandroidx/core/view/ViewCompat;->hasTransientState(Landroid/view/View;)Z PLandroidx/core/view/ViewGroupKt$descendants$1;->(Landroid/view/ViewGroup;Lkotlin/coroutines/Continuation;)V PLandroidx/core/view/ViewGroupKt$descendants$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation; +PLandroidx/core/view/ViewGroupKt;->getDescendants(Landroid/view/ViewGroup;)Lkotlin/sequences/Sequence; PLandroidx/core/view/ViewKt$allViews$1;->(Landroid/view/View;Lkotlin/coroutines/Continuation;)V PLandroidx/core/view/ViewKt$allViews$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation; PLandroidx/core/view/ViewKt$allViews$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; PLandroidx/core/view/ViewKt;->getAllViews(Landroid/view/View;)Lkotlin/sequences/Sequence; +PLandroidx/core/view/ViewKt;->isVisible(Landroid/view/View;)Z PLandroidx/core/view/accessibility/AccessibilityEventCompat$Api19Impl;->getContentChangeTypes(Landroid/view/accessibility/AccessibilityEvent;)I PLandroidx/core/view/accessibility/AccessibilityEventCompat$Api19Impl;->setContentChangeTypes(Landroid/view/accessibility/AccessibilityEvent;I)V PLandroidx/core/view/accessibility/AccessibilityEventCompat;->getContentChangeTypes(Landroid/view/accessibility/AccessibilityEvent;)I PLandroidx/core/view/accessibility/AccessibilityEventCompat;->setContentChangeTypes(Landroid/view/accessibility/AccessibilityEvent;I)V -PLandroidx/customview/poolingcontainer/PoolingContainer;->callPoolingContainerOnReleaseForChildren(Landroid/view/ViewGroup;)V +PLandroidx/customview/poolingcontainer/PoolingContainerListenerHolder;->onRelease()V +PLandroidx/customview/view/AbsSavedState$1;->()V +PLandroidx/customview/view/AbsSavedState$2;->()V +PLandroidx/customview/view/AbsSavedState;->()V +PLandroidx/customview/view/AbsSavedState;->()V +PLandroidx/customview/view/AbsSavedState;->(Landroid/os/Parcelable;)V +PLandroidx/customview/view/AbsSavedState;->(Landroidx/customview/view/AbsSavedState$1;)V PLandroidx/customview/view/AbsSavedState;->writeToParcel(Landroid/os/Parcel;I)V +PLandroidx/emoji2/text/SpannableBuilder;->getSpanEnd(Ljava/lang/Object;)I +PLandroidx/fragment/app/Fragment$Api19Impl;->cancelPendingInputEvents(Landroid/view/View;)V +PLandroidx/fragment/app/Fragment;->getHost()Ljava/lang/Object; PLandroidx/fragment/app/Fragment;->initState()V PLandroidx/fragment/app/Fragment;->onDestroy()V PLandroidx/fragment/app/Fragment;->onDestroyView()V PLandroidx/fragment/app/Fragment;->onDetach()V +PLandroidx/fragment/app/Fragment;->onSaveInstanceState(Landroid/os/Bundle;)V +PLandroidx/fragment/app/Fragment;->onStop()V PLandroidx/fragment/app/Fragment;->performDestroy()V PLandroidx/fragment/app/Fragment;->performDestroyView()V PLandroidx/fragment/app/Fragment;->performDetach()V +PLandroidx/fragment/app/Fragment;->performSaveInstanceState(Landroid/os/Bundle;)V +PLandroidx/fragment/app/Fragment;->performStop()V +PLandroidx/fragment/app/FragmentActivity$$ExternalSyntheticLambda0;->saveState()Landroid/os/Bundle; +PLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onGetHost()Landroidx/fragment/app/FragmentActivity; +PLandroidx/fragment/app/FragmentActivity$HostCallbacks;->onGetHost()Ljava/lang/Object; +PLandroidx/fragment/app/FragmentActivity;->$r8$lambda$t3WwJ1XbNlapyNW0l552nMkkXdo(Landroidx/fragment/app/FragmentActivity;)Landroid/os/Bundle; +PLandroidx/fragment/app/FragmentActivity;->lambda$init$0()Landroid/os/Bundle; PLandroidx/fragment/app/FragmentContainerView;->addDisappearingFragmentView(Landroid/view/View;)V PLandroidx/fragment/app/FragmentContainerView;->removeView(Landroid/view/View;)V PLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentDestroyed(Landroidx/fragment/app/Fragment;Z)V PLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentDetached(Landroidx/fragment/app/Fragment;Z)V +PLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentSaveInstanceState(Landroidx/fragment/app/Fragment;Landroid/os/Bundle;Z)V +PLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentStopped(Landroidx/fragment/app/Fragment;Z)V PLandroidx/fragment/app/FragmentLifecycleCallbacksDispatcher;->dispatchOnFragmentViewDestroyed(Landroidx/fragment/app/Fragment;Z)V +PLandroidx/fragment/app/FragmentManager$$ExternalSyntheticLambda4;->saveState()Landroid/os/Bundle; +PLandroidx/fragment/app/FragmentManager$6;->(Landroidx/fragment/app/FragmentManager;Ljava/lang/String;Landroidx/fragment/app/FragmentResultListener;Landroidx/lifecycle/Lifecycle;)V +PLandroidx/fragment/app/FragmentManager$6;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V +PLandroidx/fragment/app/FragmentManager$LifecycleAwareResultListener;->(Landroidx/lifecycle/Lifecycle;Landroidx/fragment/app/FragmentResultListener;Landroidx/lifecycle/LifecycleEventObserver;)V +PLandroidx/fragment/app/FragmentManager;->$r8$lambda$sido8p6zuWx0PQxIkv4qM-BRiGM(Landroidx/fragment/app/FragmentManager;)Landroid/os/Bundle; +PLandroidx/fragment/app/FragmentManager;->access$000(Landroidx/fragment/app/FragmentManager;)Ljava/util/Map; PLandroidx/fragment/app/FragmentManager;->access$100(Landroidx/fragment/app/FragmentManager;)Ljava/util/Map; PLandroidx/fragment/app/FragmentManager;->dispatchDestroyView()V +PLandroidx/fragment/app/FragmentManager;->forcePostponedTransactions()V PLandroidx/fragment/app/FragmentManager;->isDestroyed()Z +PLandroidx/fragment/app/FragmentManager;->lambda$attachController$4()Landroid/os/Bundle; +PLandroidx/fragment/app/FragmentManager;->setFragmentResultListener(Ljava/lang/String;Landroidx/lifecycle/LifecycleOwner;Landroidx/fragment/app/FragmentResultListener;)V +PLandroidx/fragment/app/FragmentManagerState$1;->()V +PLandroidx/fragment/app/FragmentManagerState;->()V +PLandroidx/fragment/app/FragmentManagerState;->()V PLandroidx/fragment/app/FragmentManagerState;->writeToParcel(Landroid/os/Parcel;I)V -PLandroidx/fragment/app/FragmentManagerViewModel;->clearNonConfigState(Landroidx/fragment/app/Fragment;)V -PLandroidx/fragment/app/FragmentManagerViewModel;->clearNonConfigStateInternal(Ljava/lang/String;)V +PLandroidx/fragment/app/FragmentManagerViewModel;->clearNonConfigState(Landroidx/fragment/app/Fragment;Z)V +PLandroidx/fragment/app/FragmentManagerViewModel;->clearNonConfigStateInternal(Ljava/lang/String;Z)V PLandroidx/fragment/app/FragmentManagerViewModel;->shouldDestroy(Landroidx/fragment/app/Fragment;)Z +PLandroidx/fragment/app/FragmentState$1;->()V +PLandroidx/fragment/app/FragmentState;->()V +PLandroidx/fragment/app/FragmentState;->(Landroidx/fragment/app/Fragment;)V PLandroidx/fragment/app/FragmentState;->writeToParcel(Landroid/os/Parcel;I)V PLandroidx/fragment/app/FragmentStateManager;->destroy()V PLandroidx/fragment/app/FragmentStateManager;->destroyFragmentView()V PLandroidx/fragment/app/FragmentStateManager;->detach()V +PLandroidx/fragment/app/FragmentStateManager;->saveViewState()V +PLandroidx/fragment/app/FragmentStateManager;->stop()V +PLandroidx/fragment/app/FragmentStore;->getAllSavedState()Ljava/util/HashMap; PLandroidx/fragment/app/FragmentStore;->makeInactive(Landroidx/fragment/app/FragmentStateManager;)V +PLandroidx/fragment/app/FragmentStore;->saveActiveFragments()Ljava/util/ArrayList; +PLandroidx/fragment/app/FragmentStore;->saveAddedFragments()Ljava/util/ArrayList; +PLandroidx/fragment/app/FragmentViewLifecycleOwner;->performSave(Landroid/os/Bundle;)V +PLandroidx/fragment/app/FragmentViewLifecycleOwner;->setCurrentState(Landroidx/lifecycle/Lifecycle$State;)V PLandroidx/fragment/app/SpecialEffectsController;->enqueueRemove(Landroidx/fragment/app/FragmentStateManager;)V +PLandroidx/fragment/app/SpecialEffectsController;->forcePostponedExecutePendingOperations()V +PLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->(Landroidx/savedstate/SavedStateRegistryOwner;Landroid/os/Bundle;)V +PLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel; +PLandroidx/lifecycle/AbstractSavedStateViewModelFactory;->create(Ljava/lang/String;Ljava/lang/Class;)Landroidx/lifecycle/ViewModel; PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onDestroy(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V +PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStop(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V +PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V +PLandroidx/lifecycle/LegacySavedStateHandleController;->create(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;Ljava/lang/String;Landroid/os/Bundle;)Landroidx/lifecycle/SavedStateHandleController; +PLandroidx/lifecycle/LegacySavedStateHandleController;->tryToAddRecreator(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;)V +PLandroidx/lifecycle/LifecycleRegistry;->markState(Landroidx/lifecycle/Lifecycle$State;)V PLandroidx/lifecycle/LiveData$LifecycleBoundObserver;->detachObserver()V +PLandroidx/lifecycle/MediatorLiveData;->onInactive()V +PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V +PLandroidx/lifecycle/SavedStateHandle$$ExternalSyntheticLambda0;->(Landroidx/lifecycle/SavedStateHandle;)V +PLandroidx/lifecycle/SavedStateHandle$Companion;->()V +PLandroidx/lifecycle/SavedStateHandle$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLandroidx/lifecycle/SavedStateHandle$Companion;->createHandle(Landroid/os/Bundle;Landroid/os/Bundle;)Landroidx/lifecycle/SavedStateHandle; +PLandroidx/lifecycle/SavedStateHandle$Companion;->validateValue(Ljava/lang/Object;)Z +PLandroidx/lifecycle/SavedStateHandle;->()V +PLandroidx/lifecycle/SavedStateHandle;->()V +PLandroidx/lifecycle/SavedStateHandle;->access$getACCEPTABLE_CLASSES$cp()[Ljava/lang/Class; +PLandroidx/lifecycle/SavedStateHandle;->get(Ljava/lang/String;)Ljava/lang/Object; +PLandroidx/lifecycle/SavedStateHandle;->savedStateProvider()Landroidx/savedstate/SavedStateRegistry$SavedStateProvider; +PLandroidx/lifecycle/SavedStateHandle;->set(Ljava/lang/String;Ljava/lang/Object;)V +PLandroidx/lifecycle/SavedStateHandleController;->(Ljava/lang/String;Landroidx/lifecycle/SavedStateHandle;)V +PLandroidx/lifecycle/SavedStateHandleController;->attachToLifecycle(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;)V +PLandroidx/lifecycle/SavedStateHandleController;->getHandle()Landroidx/lifecycle/SavedStateHandle; +PLandroidx/lifecycle/SavedStateHandleController;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V +PLandroidx/lifecycle/SavedStateHandlesProvider;->saveState()Landroid/os/Bundle; +PLandroidx/lifecycle/SavedStateHandlesVM;->getHandles()Ljava/util/Map; PLandroidx/lifecycle/ViewModel;->closeWithRuntimeException(Ljava/lang/Object;)V +PLandroidx/lifecycle/ViewModel;->setTagIfAbsent(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; PLandroidx/loader/app/LoaderManager;->()V PLandroidx/loader/app/LoaderManager;->getInstance(Landroidx/lifecycle/LifecycleOwner;)Landroidx/loader/app/LoaderManager; PLandroidx/loader/app/LoaderManagerImpl$LoaderViewModel$1;->()V @@ -37286,18 +36417,68 @@ PLandroidx/loader/app/LoaderManagerImpl$LoaderViewModel;->onCleared()V PLandroidx/loader/app/LoaderManagerImpl;->()V PLandroidx/loader/app/LoaderManagerImpl;->(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/ViewModelStore;)V PLandroidx/loader/app/LoaderManagerImpl;->markForRedelivery()V +PLandroidx/media3/common/util/ListenerSet$ListenerHolder;->release(Landroidx/media3/common/util/ListenerSet$IterationFinishedEvent;)V +PLandroidx/media3/common/util/ListenerSet;->release()V +PLandroidx/media3/common/util/Util;->createHandlerForCurrentLooper()Landroid/os/Handler; +PLandroidx/media3/common/util/Util;->createHandlerForCurrentLooper(Landroid/os/Handler$Callback;)Landroid/os/Handler; +PLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline1;->m(I)Landroid/media/AudioFocusRequest$Builder; +PLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline2;->m()V +PLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline3;->m(Landroid/media/AudioFocusRequest$Builder;Landroid/media/AudioAttributes;)Landroid/media/AudioFocusRequest$Builder; +PLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline5;->m(Landroid/media/AudioFocusRequest$Builder;Landroid/media/AudioManager$OnAudioFocusChangeListener;)Landroid/media/AudioFocusRequest$Builder; +PLandroidx/media3/exoplayer/AudioFocusManager$$ExternalSyntheticApiModelOutline6;->m(Landroid/media/AudioFocusRequest$Builder;)Landroid/media/AudioFocusRequest; +PLandroidx/media3/session/ConnectedControllersManager$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;)V +PLandroidx/media3/session/ConnectedControllersManager$$ExternalSyntheticLambda0;->run()V +PLandroidx/media3/session/ConnectedControllersManager;->$r8$lambda$Vom81RksdvuIVXyQfAu6pd1M7BY(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;)V +PLandroidx/media3/session/ConnectedControllersManager;->lambda$removeController$0(Landroidx/media3/session/MediaSessionImpl;Landroidx/media3/session/MediaSession$ControllerInfo;)V +PLandroidx/media3/session/ConnectedControllersManager;->removeController(Landroidx/media3/session/MediaSession$ControllerInfo;)V +PLandroidx/media3/session/ConnectedControllersManager;->removeController(Ljava/lang/Object;)V +PLandroidx/media3/session/MediaController$$ExternalSyntheticLambda0;->(Landroidx/media3/session/MediaController;)V +PLandroidx/media3/session/MediaController$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V +PLandroidx/media3/session/MediaController$Builder$1;->onDisconnected(Landroidx/media3/session/MediaController;)V +PLandroidx/media3/session/MediaController$Listener$-CC;->$default$onDisconnected(Landroidx/media3/session/MediaController$Listener;Landroidx/media3/session/MediaController;)V +PLandroidx/media3/session/MediaController;->$r8$lambda$7Poy_IVrU20FjlOzoqG4RzKma48(Landroidx/media3/session/MediaController;Landroidx/media3/session/MediaController$Listener;)V PLandroidx/media3/session/MediaController;->createDisconnectedFuture()Lcom/google/common/util/concurrent/ListenableFuture; -PLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda81;->run()V +PLandroidx/media3/session/MediaController;->lambda$release$0(Landroidx/media3/session/MediaController$Listener;)V +PLandroidx/media3/session/MediaController;->release()V +PLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda103;->(Landroidx/media3/session/MediaControllerImplBase;)V +PLandroidx/media3/session/MediaControllerImplBase$$ExternalSyntheticLambda103;->run()V +PLandroidx/media3/session/MediaControllerImplBase$FlushCommandQueueHandler;->release()V PLandroidx/media3/session/MediaControllerImplBase;->$r8$lambda$tIEgcrLv3SECRV9I_ggVsbUKXeY(Landroidx/media3/session/MediaControllerImplBase;)V PLandroidx/media3/session/MediaControllerImplBase;->lambda$release$4()V +PLandroidx/media3/session/MediaControllerImplBase;->release()V PLandroidx/media3/session/MediaControllerStub;->destroy()V +PLandroidx/media3/session/MediaSession$Callback$-CC;->$default$onDisconnected(Landroidx/media3/session/MediaSession$Callback;Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;)V +PLandroidx/media3/session/MediaSessionImpl;->onDisconnectedOnHandler(Landroidx/media3/session/MediaSession$ControllerInfo;)V +PLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda11;->(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/IMediaController;)V +PLandroidx/media3/session/MediaSessionStub$$ExternalSyntheticLambda11;->run()V +PLandroidx/media3/session/MediaSessionStub;->$r8$lambda$-z-kXYeUiIo9LEMOQQqDz14Ng0c(Landroidx/media3/session/MediaSessionStub;Landroidx/media3/session/IMediaController;)V +PLandroidx/media3/session/MediaSessionStub;->lambda$release$18(Landroidx/media3/session/IMediaController;)V +PLandroidx/media3/session/MediaSessionStub;->release(Landroidx/media3/session/IMediaController;I)V +PLandroidx/media3/session/SequencedFutureManager;->lazyRelease(JLjava/lang/Runnable;)V +PLandroidx/media3/session/SequencedFutureManager;->release()V +PLandroidx/navigation/NavBackStackEntry;->saveState(Landroid/os/Bundle;)V +PLandroidx/navigation/NavBackStackEntryState$Companion$CREATOR$1;->()V +PLandroidx/navigation/NavBackStackEntryState$Companion;->()V +PLandroidx/navigation/NavBackStackEntryState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLandroidx/navigation/NavBackStackEntryState;->()V +PLandroidx/navigation/NavBackStackEntryState;->(Landroidx/navigation/NavBackStackEntry;)V PLandroidx/navigation/NavBackStackEntryState;->writeToParcel(Landroid/os/Parcel;I)V +PLandroidx/navigation/NavController;->saveState()Landroid/os/Bundle; PLandroidx/navigation/NavControllerViewModel;->onCleared()V +PLandroidx/navigation/Navigator;->onSaveState()Landroid/os/Bundle; PLandroidx/navigation/fragment/FragmentNavigator$ClearEntryStateViewModel;->getCompleteTransition()Ljava/lang/ref/WeakReference; PLandroidx/navigation/fragment/FragmentNavigator$ClearEntryStateViewModel;->onCleared()V PLandroidx/navigation/fragment/FragmentNavigator$sam$androidx_lifecycle_Observer$0;->equals(Ljava/lang/Object;)Z PLandroidx/navigation/fragment/FragmentNavigator$sam$androidx_lifecycle_Observer$0;->getFunctionDelegate()Lkotlin/Function; +PLandroidx/navigation/fragment/FragmentNavigator;->onSaveState()Landroid/os/Bundle; +PLandroidx/navigation/fragment/NavHostFragment$navHostController$2$$ExternalSyntheticLambda0;->saveState()Landroid/os/Bundle; +PLandroidx/navigation/fragment/NavHostFragment$navHostController$2$$ExternalSyntheticLambda1;->saveState()Landroid/os/Bundle; +PLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->$r8$lambda$S8rYz5PdxQ_qmpQw5Wg04g8YyYI(Landroidx/navigation/fragment/NavHostFragment;)Landroid/os/Bundle; +PLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->$r8$lambda$yvpdz-7lzmuHOSkQDGqC7TUxHHI(Landroidx/navigation/NavHostController;)Landroid/os/Bundle; +PLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->invoke$lambda$5$lambda$2(Landroidx/navigation/NavHostController;)Landroid/os/Bundle; +PLandroidx/navigation/fragment/NavHostFragment$navHostController$2;->invoke$lambda$5$lambda$4(Landroidx/navigation/fragment/NavHostFragment;)Landroid/os/Bundle; PLandroidx/navigation/fragment/NavHostFragment;->onDestroyView()V +PLandroidx/navigation/fragment/NavHostFragment;->onSaveInstanceState(Landroid/os/Bundle;)V PLandroidx/profileinstaller/ProfileInstallReceiver$$ExternalSyntheticLambda0;->()V PLandroidx/profileinstaller/ProfileInstaller$1;->()V PLandroidx/profileinstaller/ProfileInstaller$1;->onResultReceived(ILjava/lang/Object;)V @@ -37325,14 +36506,19 @@ PLandroidx/profileinstaller/ProfileVerifier;->writeProfileVerification(Landroid/ PLandroidx/recyclerview/widget/AdapterListUpdateCallback;->onChanged(IILjava/lang/Object;)V PLandroidx/recyclerview/widget/AsyncDifferConfig;->getDiffCallback()Landroidx/recyclerview/widget/DiffUtil$ItemCallback; PLandroidx/recyclerview/widget/AsyncListDiffer$1$1;->areContentsTheSame(II)Z -PLandroidx/recyclerview/widget/AsyncListDiffer$1$1;->areItemsTheSame(II)Z PLandroidx/recyclerview/widget/AsyncListDiffer$1$1;->getChangePayload(II)Ljava/lang/Object; -PLandroidx/recyclerview/widget/BatchingListUpdateCallback;->onChanged(IILjava/lang/Object;)V PLandroidx/recyclerview/widget/ChildHelper;->removeViewAt(I)V +PLandroidx/recyclerview/widget/ConcatAdapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V +PLandroidx/recyclerview/widget/ConcatAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; PLandroidx/recyclerview/widget/ConcatAdapter;->onDetachedFromRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V +PLandroidx/recyclerview/widget/ConcatAdapter;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/ConcatAdapter;->onViewDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/ConcatAdapter;->onViewRecycled(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V +PLandroidx/recyclerview/widget/ConcatAdapterController;->getWrapper(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Landroidx/recyclerview/widget/NestedAdapterWrapper; +PLandroidx/recyclerview/widget/ConcatAdapterController;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; PLandroidx/recyclerview/widget/ConcatAdapterController;->onDetachedFromRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V +PLandroidx/recyclerview/widget/ConcatAdapterController;->onItemRangeInserted(Landroidx/recyclerview/widget/NestedAdapterWrapper;II)V +PLandroidx/recyclerview/widget/ConcatAdapterController;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/ConcatAdapterController;->onViewDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/ConcatAdapterController;->onViewRecycled(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/DiffUtil$CenteredArray;->get(I)I @@ -37343,68 +36529,110 @@ PLandroidx/recyclerview/widget/DiffUtil$Snake;->()V PLandroidx/recyclerview/widget/DiffUtil$Snake;->diagonalSize()I PLandroidx/recyclerview/widget/DiffUtil$Snake;->hasAdditionOrRemoval()Z PLandroidx/recyclerview/widget/DiffUtil$Snake;->toDiagonal()Landroidx/recyclerview/widget/DiffUtil$Diagonal; -PLandroidx/recyclerview/widget/DiffUtil;->backward(Landroidx/recyclerview/widget/DiffUtil$Range;Landroidx/recyclerview/widget/DiffUtil$Callback;Landroidx/recyclerview/widget/DiffUtil$CenteredArray;Landroidx/recyclerview/widget/DiffUtil$CenteredArray;I)Landroidx/recyclerview/widget/DiffUtil$Snake; PLandroidx/recyclerview/widget/DiffUtil;->forward(Landroidx/recyclerview/widget/DiffUtil$Range;Landroidx/recyclerview/widget/DiffUtil$Callback;Landroidx/recyclerview/widget/DiffUtil$CenteredArray;Landroidx/recyclerview/widget/DiffUtil$CenteredArray;I)Landroidx/recyclerview/widget/DiffUtil$Snake; PLandroidx/recyclerview/widget/GapWorker$LayoutPrefetchRegistryImpl;->lastPrefetchIncludedPosition(I)Z -PLandroidx/recyclerview/widget/GapWorker;->remove(Landroidx/recyclerview/widget/RecyclerView;)V PLandroidx/recyclerview/widget/ItemTouchHelper;->endRecoverAnimation(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Z)V PLandroidx/recyclerview/widget/ItemTouchHelper;->onChildViewDetachedFromWindow(Landroid/view/View;)V PLandroidx/recyclerview/widget/ItemTouchHelper;->removeChildDrawingOrderCallbackIfNecessary(Landroid/view/View;)V +PLandroidx/recyclerview/widget/LinearLayoutManager$SavedState$1;->()V +PLandroidx/recyclerview/widget/LinearLayoutManager$SavedState;->()V +PLandroidx/recyclerview/widget/LinearLayoutManager$SavedState;->()V PLandroidx/recyclerview/widget/LinearLayoutManager$SavedState;->invalidateAnchor()V PLandroidx/recyclerview/widget/LinearLayoutManager$SavedState;->writeToParcel(Landroid/os/Parcel;I)V PLandroidx/recyclerview/widget/LinearLayoutManager;->getChildClosestToEnd()Landroid/view/View; -PLandroidx/recyclerview/widget/LinearLayoutManager;->onDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$Recycler;)V +PLandroidx/recyclerview/widget/LinearLayoutManager;->getChildClosestToStart()Landroid/view/View; +PLandroidx/recyclerview/widget/LinearLayoutManager;->onSaveInstanceState()Landroid/os/Parcelable; +PLandroidx/recyclerview/widget/NestedAdapterWrapper$1;->onItemRangeInserted(II)V +PLandroidx/recyclerview/widget/NestedAdapterWrapper;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V +PLandroidx/recyclerview/widget/NestedAdapterWrapper;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; +PLandroidx/recyclerview/widget/OrientationHelper;->getTotalSpaceChange()I PLandroidx/recyclerview/widget/RecyclerView$5;->removeViewAt(I)V PLandroidx/recyclerview/widget/RecyclerView$6;->markViewHoldersUpdated(IILjava/lang/Object;)V +PLandroidx/recyclerview/widget/RecyclerView$Adapter;->notifyDataSetChanged()V +PLandroidx/recyclerview/widget/RecyclerView$Adapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;ILjava/util/List;)V PLandroidx/recyclerview/widget/RecyclerView$Adapter;->onDetachedFromRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V PLandroidx/recyclerview/widget/RecyclerView$Adapter;->onViewDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V +PLandroidx/recyclerview/widget/RecyclerView$AdapterDataObservable;->notifyChanged()V PLandroidx/recyclerview/widget/RecyclerView$ItemAnimator;->buildAdapterChangeFlagsForAnimations(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)I PLandroidx/recyclerview/widget/RecyclerView$ItemAnimator;->canReuseUpdatedViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Z PLandroidx/recyclerview/widget/RecyclerView$ItemAnimator;->canReuseUpdatedViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Ljava/util/List;)Z PLandroidx/recyclerview/widget/RecyclerView$ItemAnimator;->recordPreLayoutInformation(Landroidx/recyclerview/widget/RecyclerView$State;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;ILjava/util/List;)Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo; -PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->dispatchDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$Recycler;)V -PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;)V -PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView;Landroidx/recyclerview/widget/RecyclerView$Recycler;)V +PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->generateLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Landroidx/recyclerview/widget/RecyclerView$LayoutParams; +PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->getItemCount()I +PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->isMeasurementUpToDate(III)Z PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onItemsUpdated(Landroidx/recyclerview/widget/RecyclerView;II)V PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->onItemsUpdated(Landroidx/recyclerview/widget/RecyclerView;IILjava/lang/Object;)V PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->removeAndRecycleViewAt(ILandroidx/recyclerview/widget/RecyclerView$Recycler;)V PLandroidx/recyclerview/widget/RecyclerView$LayoutManager;->removeViewAt(I)V +PLandroidx/recyclerview/widget/RecyclerView$LayoutParams;->(Landroid/view/ViewGroup$MarginLayoutParams;)V +PLandroidx/recyclerview/widget/RecyclerView$OnScrollListener;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V PLandroidx/recyclerview/widget/RecyclerView$RecycledViewPool;->detach()V PLandroidx/recyclerview/widget/RecyclerView$RecycledViewPool;->putRecycledView(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/RecyclerView$Recycler;->addViewHolderToRecycledViewPool(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Z)V PLandroidx/recyclerview/widget/RecyclerView$Recycler;->dispatchViewRecycled(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V -PLandroidx/recyclerview/widget/RecyclerView$Recycler;->onDetachedFromWindow()V -PLandroidx/recyclerview/widget/RecyclerView$Recycler;->poolingContainerDetach(Landroidx/recyclerview/widget/RecyclerView$Adapter;)V PLandroidx/recyclerview/widget/RecyclerView$Recycler;->recycleCachedViewAt(I)V PLandroidx/recyclerview/widget/RecyclerView$Recycler;->recycleView(Landroid/view/View;)V PLandroidx/recyclerview/widget/RecyclerView$Recycler;->recycleViewHolderInternal(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/RecyclerView$Recycler;->viewRangeUpdate(II)V +PLandroidx/recyclerview/widget/RecyclerView$RecyclerViewDataObserver;->onChanged()V +PLandroidx/recyclerview/widget/RecyclerView$SavedState$1;->()V +PLandroidx/recyclerview/widget/RecyclerView$SavedState;->()V +PLandroidx/recyclerview/widget/RecyclerView$SavedState;->(Landroid/os/Parcelable;)V PLandroidx/recyclerview/widget/RecyclerView$SavedState;->writeToParcel(Landroid/os/Parcel;I)V +PLandroidx/recyclerview/widget/RecyclerView$SimpleOnItemTouchListener;->()V PLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->addChangePayload(Ljava/lang/Object;)V PLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->doesTransientStatePreventRecycling()Z +PLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getAbsoluteAdapterPosition()I PLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->getOldPosition()I PLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->isRecyclable()Z PLandroidx/recyclerview/widget/RecyclerView$ViewHolder;->resetInternal()V PLandroidx/recyclerview/widget/RecyclerView;->access$300(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V PLandroidx/recyclerview/widget/RecyclerView;->access$400(Landroidx/recyclerview/widget/RecyclerView;Landroid/view/View;)V -PLandroidx/recyclerview/widget/RecyclerView;->animateChange(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;ZZ)V PLandroidx/recyclerview/widget/RecyclerView;->canReuseUpdatedViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Z PLandroidx/recyclerview/widget/RecyclerView;->clearNestedRecyclerViewIfNotNested(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLandroidx/recyclerview/widget/RecyclerView;->dispatchChildDetached(Landroid/view/View;)V +PLandroidx/recyclerview/widget/RecyclerView;->dispatchSaveInstanceState(Landroid/util/SparseArray;)V +PLandroidx/recyclerview/widget/RecyclerView;->generateLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Landroid/view/ViewGroup$LayoutParams; PLandroidx/recyclerview/widget/RecyclerView;->onChildDetachedFromWindow(Landroid/view/View;)V -PLandroidx/recyclerview/widget/RecyclerView;->onDetachedFromWindow()V +PLandroidx/recyclerview/widget/RecyclerView;->onSaveInstanceState()Landroid/os/Parcelable; PLandroidx/recyclerview/widget/RecyclerView;->removeOnScrollListener(Landroidx/recyclerview/widget/RecyclerView$OnScrollListener;)V -PLandroidx/recyclerview/widget/RecyclerView;->stopNestedScroll()V -PLandroidx/recyclerview/widget/RecyclerView;->viewRangeUpdate(IILjava/lang/Object;)V PLandroidx/recyclerview/widget/RecyclerViewAccessibilityDelegate$ItemDelegate;->getAndRemoveOriginalDelegateForItem(Landroid/view/View;)Landroidx/core/view/AccessibilityDelegateCompat; -PLandroidx/recyclerview/widget/ViewInfoStore$InfoRecord;->drainCache()V PLandroidx/recyclerview/widget/ViewInfoStore;->addToOldChangeHolders(JLandroidx/recyclerview/widget/RecyclerView$ViewHolder;)V -PLandroidx/recyclerview/widget/ViewInfoStore;->isDisappearing(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Z -PLandroidx/recyclerview/widget/ViewInfoStore;->onDetach()V PLandroidx/recyclerview/widget/ViewInfoStore;->popFromPostLayout(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo; PLandroidx/recyclerview/widget/ViewInfoStore;->popFromPreLayout(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo; PLandroidx/recyclerview/widget/ViewInfoStore;->removeViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V +PLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage$WrapperViewTypeLookup;->globalToLocal(I)I +PLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;->getWrapperForGlobalType(I)Landroidx/recyclerview/widget/NestedAdapterWrapper; +PLandroidx/recyclerview/widget/ViewTypeStorage$IsolatedViewTypeStorage;->obtainViewType(Landroidx/recyclerview/widget/NestedAdapterWrapper;)I +PLandroidx/savedstate/Recreator$SavedStateProvider;->(Landroidx/savedstate/SavedStateRegistry;)V +PLandroidx/savedstate/Recreator$SavedStateProvider;->add(Ljava/lang/String;)V +PLandroidx/savedstate/SavedStateRegistry;->runOnNextRecreation(Ljava/lang/Class;)V +PLandroidx/savedstate/SavedStateRegistryController;->performSave(Landroid/os/Bundle;)V +PLcom/airbnb/lottie/LottieAnimationView$SavedState$1;->()V +PLcom/airbnb/lottie/LottieAnimationView$SavedState;->()V +PLcom/airbnb/lottie/LottieAnimationView$SavedState;->(Landroid/os/Parcelable;)V PLcom/airbnb/lottie/LottieAnimationView$SavedState;->writeToParcel(Landroid/os/Parcel;I)V +PLcom/airbnb/lottie/LottieAnimationView;->onSaveInstanceState()Landroid/os/Parcelable; +PLcom/airbnb/lottie/LottieAnimationView;->setImageResource(I)V +PLcom/airbnb/lottie/LottieDrawable$$ExternalSyntheticLambda9;->run(Lcom/airbnb/lottie/LottieComposition;)V +PLcom/airbnb/lottie/LottieDrawable;->$r8$lambda$riFJCWOqfI5iOFlatZRlwc9qv1U(Lcom/airbnb/lottie/LottieDrawable;Lcom/airbnb/lottie/model/KeyPath;Ljava/lang/Object;Lcom/airbnb/lottie/value/LottieValueCallback;Lcom/airbnb/lottie/LottieComposition;)V +PLcom/airbnb/lottie/LottieDrawable;->getImageAssetsFolder()Ljava/lang/String; +PLcom/airbnb/lottie/LottieDrawable;->getProgress()F +PLcom/airbnb/lottie/LottieDrawable;->getRepeatCount()I +PLcom/airbnb/lottie/LottieDrawable;->getRepeatMode()I +PLcom/airbnb/lottie/LottieDrawable;->isAnimatingOrWillAnimateOnVisible()Z +PLcom/airbnb/lottie/LottieDrawable;->lambda$addValueCallback$14(Lcom/airbnb/lottie/model/KeyPath;Ljava/lang/Object;Lcom/airbnb/lottie/value/LottieValueCallback;Lcom/airbnb/lottie/LottieComposition;)V +PLcom/airbnb/lottie/model/layer/BaseLayer;->removeAnimation(Lcom/airbnb/lottie/animation/keyframe/BaseKeyframeAnimation;)V +PLcom/annimon/stream/Optional;->empty()Lcom/annimon/stream/Optional; +PLcom/annimon/stream/Optional;->orElse(Ljava/lang/Object;)Ljava/lang/Object; +PLcom/annimon/stream/Stream;->empty()Lcom/annimon/stream/Stream; +PLcom/annimon/stream/Stream;->max(Ljava/util/Comparator;)Lcom/annimon/stream/Optional; +PLcom/annimon/stream/Stream;->reduce(Lcom/annimon/stream/function/BiFunction;)Lcom/annimon/stream/Optional; +PLcom/annimon/stream/function/BinaryOperator$Util$2;->(Ljava/util/Comparator;)V +PLcom/annimon/stream/function/BinaryOperator$Util;->maxBy(Ljava/util/Comparator;)Lcom/annimon/stream/function/BinaryOperator; +PLcom/annimon/stream/operator/IntRangeClosed;->(II)V +PLcom/annimon/stream/operator/IntRangeClosed;->hasNext()Z +PLcom/annimon/stream/operator/IntRangeClosed;->nextInt()I PLcom/bumptech/glide/Glide;->unregisterRequestManager(Lcom/bumptech/glide/RequestManager;)V PLcom/bumptech/glide/RequestManager;->onDestroy()V PLcom/bumptech/glide/load/Options;->equals(Ljava/lang/Object;)Z @@ -37415,6 +36643,7 @@ PLcom/bumptech/glide/load/resource/bitmap/DrawableTransformation;->equals(Ljava/ PLcom/bumptech/glide/load/resource/gif/GifDrawableTransformation;->equals(Ljava/lang/Object;)Z PLcom/bumptech/glide/manager/DefaultConnectivityMonitor;->onDestroy()V PLcom/bumptech/glide/manager/LifecycleLifecycle;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLcom/bumptech/glide/manager/LifecycleLifecycle;->onStop(Landroidx/lifecycle/LifecycleOwner;)V PLcom/bumptech/glide/manager/LifecycleLifecycle;->removeListener(Lcom/bumptech/glide/manager/LifecycleListener;)V PLcom/bumptech/glide/manager/LifecycleRequestManagerRetriever$1;->onDestroy()V PLcom/bumptech/glide/manager/RequestTracker;->clearAndRemove(Lcom/bumptech/glide/request/Request;)Z @@ -37426,9 +36655,11 @@ PLcom/bumptech/glide/manager/TargetTracker;->untrack(Lcom/bumptech/glide/request PLcom/bumptech/glide/request/SingleRequest;->canNotifyCleared()Z PLcom/bumptech/glide/request/SingleRequest;->cancel()V PLcom/bumptech/glide/request/SingleRequest;->clear()V +PLcom/bumptech/glide/request/SingleRequest;->isRunning()Z PLcom/bumptech/glide/request/target/BaseTarget;->onDestroy()V PLcom/bumptech/glide/request/target/BaseTarget;->onLoadCleared(Landroid/graphics/drawable/Drawable;)V PLcom/bumptech/glide/request/target/ImageViewTarget;->onLoadCleared(Landroid/graphics/drawable/Drawable;)V +PLcom/bumptech/glide/request/target/ImageViewTarget;->onStop()V PLcom/bumptech/glide/request/target/ViewTarget$SizeDeterminer;->clearCallbacksAndListener()V PLcom/bumptech/glide/request/target/ViewTarget$SizeDeterminer;->removeCallback(Lcom/bumptech/glide/request/target/SizeReadyCallback;)V PLcom/bumptech/glide/request/target/ViewTarget;->maybeRemoveAttachStateListener()V @@ -37437,197 +36668,188 @@ PLcom/bumptech/glide/request/target/ViewTarget;->removeCallback(Lcom/bumptech/gl PLcom/bumptech/glide/util/MultiClassKey;->equals(Ljava/lang/Object;)Z PLcom/bumptech/glide/util/Util;->bothNullOrEqual(Ljava/lang/Object;Ljava/lang/Object;)Z PLcom/bumptech/glide/util/Util;->removeCallbacksOnUiThread(Ljava/lang/Runnable;)V -PLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->_asSet([Ljava/lang/String;)Ljava/util/Set; -PLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->_empty(Ljava/util/Set;ZZZZ)Z -PLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->construct(Ljava/util/Set;ZZZZ)Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; -PLcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value;->from(Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties;)Lcom/fasterxml/jackson/annotation/JsonIgnoreProperties$Value; -PLcom/fasterxml/jackson/core/Base64Variant;->encodeBase64Chunk(I[CI)I -PLcom/fasterxml/jackson/core/Base64Variant;->encodeBase64Partial(II[CI)I -PLcom/fasterxml/jackson/core/Base64Variant;->getMaxLineLength()I -PLcom/fasterxml/jackson/core/Base64Variant;->usesPadding()Z -PLcom/fasterxml/jackson/core/JacksonException;->(Ljava/lang/String;Ljava/lang/Throwable;)V -PLcom/fasterxml/jackson/core/JsonParseException;->(Lcom/fasterxml/jackson/core/JsonParser;Ljava/lang/String;)V -PLcom/fasterxml/jackson/core/JsonParseException;->withRequestPayload(Lcom/fasterxml/jackson/core/util/RequestPayload;)Lcom/fasterxml/jackson/core/JsonParseException; -PLcom/fasterxml/jackson/core/JsonParser;->_constructError(Ljava/lang/String;)Lcom/fasterxml/jackson/core/JsonParseException; -PLcom/fasterxml/jackson/core/JsonProcessingException;->(Ljava/lang/String;Lcom/fasterxml/jackson/core/JsonLocation;)V -PLcom/fasterxml/jackson/core/JsonProcessingException;->(Ljava/lang/String;Lcom/fasterxml/jackson/core/JsonLocation;Ljava/lang/Throwable;)V -PLcom/fasterxml/jackson/core/base/ParserBase;->_getSourceReference()Ljava/lang/Object; -PLcom/fasterxml/jackson/core/base/ParserBase;->_validJsonValueList()Ljava/lang/String; -PLcom/fasterxml/jackson/core/base/ParserMinimalBase;->_getCharDesc(I)Ljava/lang/String; -PLcom/fasterxml/jackson/core/base/ParserMinimalBase;->_reportError(Ljava/lang/String;)V -PLcom/fasterxml/jackson/core/base/ParserMinimalBase;->_reportUnexpectedChar(ILjava/lang/String;)V -PLcom/fasterxml/jackson/core/exc/StreamReadException;->(Lcom/fasterxml/jackson/core/JsonParser;Ljava/lang/String;)V -PLcom/fasterxml/jackson/core/io/IOContext;->getSourceReference()Ljava/lang/Object; -PLcom/fasterxml/jackson/core/io/NumberOutput;->_full3(I[CI)I -PLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_matchFalse()V -PLcom/fasterxml/jackson/core/json/ReaderBasedJsonParser;->_matchTrue()V -PLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeFieldName(Ljava/lang/String;)V -PLcom/fasterxml/jackson/core/json/UTF8JsonGenerator;->writeNumber(I)V -PLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->_handleUnexpectedValue(I)Lcom/fasterxml/jackson/core/JsonToken; -PLcom/fasterxml/jackson/core/json/UTF8StreamJsonParser;->getCurrentLocation()Lcom/fasterxml/jackson/core/JsonLocation; -PLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->_writeBinary(Lcom/fasterxml/jackson/core/Base64Variant;[BII)V -PLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeBinary(Lcom/fasterxml/jackson/core/Base64Variant;[BII)V -PLcom/fasterxml/jackson/core/json/WriterBasedJsonGenerator;->writeNumber(I)V -PLcom/fasterxml/jackson/databind/AnnotationIntrospector;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/DeserializationContext;->constructType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; -PLcom/fasterxml/jackson/databind/DeserializationContext;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/KeyDeserializer; -PLcom/fasterxml/jackson/databind/KeyDeserializer;->()V -PLcom/fasterxml/jackson/databind/cfg/BaseSettings;->getBase64Variant()Lcom/fasterxml/jackson/core/Base64Variant; -PLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->hasKeyDeserializers()Z -PLcom/fasterxml/jackson/databind/cfg/DeserializerFactoryConfig;->keyDeserializers()Ljava/lang/Iterable; -PLcom/fasterxml/jackson/databind/cfg/MapperConfig;->getBase64Variant()Lcom/fasterxml/jackson/core/Base64Variant; -PLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory$ContainerDefaultMappings;->findMapFallback(Lcom/fasterxml/jackson/databind/JavaType;)Ljava/lang/Class; -PLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_findCustomMapDeserializer(Lcom/fasterxml/jackson/databind/type/MapType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -PLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->_mapAbstractMapType(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/DeserializationConfig;)Lcom/fasterxml/jackson/databind/type/MapType; -PLcom/fasterxml/jackson/databind/deser/BasicDeserializerFactory;->createKeyDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/KeyDeserializer; -PLcom/fasterxml/jackson/databind/deser/BeanDeserializerFactory;->_isSetterlessType(Ljava/lang/Class;)Z -PLcom/fasterxml/jackson/databind/deser/DefaultDeserializationContext;->keyDeserializerInstance(Lcom/fasterxml/jackson/databind/introspect/Annotated;Ljava/lang/Object;)Lcom/fasterxml/jackson/databind/KeyDeserializer; -PLcom/fasterxml/jackson/databind/deser/DeserializerCache;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/deser/DeserializerFactory;Lcom/fasterxml/jackson/databind/JavaType;)Lcom/fasterxml/jackson/databind/KeyDeserializer; -PLcom/fasterxml/jackson/databind/deser/Deserializers$Base;->findMapDeserializer(Lcom/fasterxml/jackson/databind/type/MapType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -PLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->canCreateFromObjectWith()Z -PLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->canCreateUsingArrayDelegate()Z -PLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->canCreateUsingDelegate()Z -PLcom/fasterxml/jackson/databind/deser/ValueInstantiator;->createFromObjectWith(Lcom/fasterxml/jackson/databind/DeserializationContext;[Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;Lcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->()V -PLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->()V -PLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->canCreateUsingDefault()Z -PLcom/fasterxml/jackson/databind/deser/impl/JDKValueInstantiators$LinkedHashMapInstantiator;->createUsingDefault(Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer;->getParameters([Lcom/fasterxml/jackson/databind/deser/SettableBeanProperty;)[Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/deser/ValueInstantiator;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;)V -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->(Lcom/fasterxml/jackson/databind/deser/std/MapDeserializer;Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/util/Set;Ljava/util/Set;)V -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->_isStdKeyDeser(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/KeyDeserializer;)Z -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->_readAndBindStringKeyMap(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;Ljava/util/Map;)V -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->isCachable()Z -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->resolve(Lcom/fasterxml/jackson/databind/DeserializationContext;)V -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->setIgnorableProperties(Ljava/util/Set;)V -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->setIncludableProperties(Ljava/util/Set;)V -PLcom/fasterxml/jackson/databind/deser/std/MapDeserializer;->withResolved(Lcom/fasterxml/jackson/databind/KeyDeserializer;Lcom/fasterxml/jackson/databind/jsontype/TypeDeserializer;Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/util/Set;Ljava/util/Set;)Lcom/fasterxml/jackson/databind/deser/std/MapDeserializer; -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->()V -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->(Ljava/lang/Class;Ljava/lang/Boolean;)V -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Boolean; -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$BooleanDeserializer;->deserialize(Lcom/fasterxml/jackson/core/JsonParser;Lcom/fasterxml/jackson/databind/DeserializationContext;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$DoubleDeserializer;->()V -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$DoubleDeserializer;->(Ljava/lang/Class;Ljava/lang/Double;)V -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$FloatDeserializer;->()V -PLcom/fasterxml/jackson/databind/deser/std/NumberDeserializers$FloatDeserializer;->(Ljava/lang/Class;Ljava/lang/Float;)V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$BooleanDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$DoubleDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$FloatDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$IntDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$IntDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$LongDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers$LongDeser;->()V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers;->(Ljava/lang/Class;)V -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -PLcom/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers;->forType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -PLcom/fasterxml/jackson/databind/deser/std/StdDeserializer;->isDefaultKeyDeserializer(Lcom/fasterxml/jackson/databind/KeyDeserializer;)Z -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD;->()V -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD;->(Ljava/lang/Class;)V -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD;->forType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer$StringKD; -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer;->(ILjava/lang/Class;)V -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer;->(ILjava/lang/Class;Lcom/fasterxml/jackson/databind/deser/std/FromStringDeserializer;)V -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer;->forType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializer; -PLcom/fasterxml/jackson/databind/deser/std/StdKeyDeserializers;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/DeserializationConfig;Lcom/fasterxml/jackson/databind/BeanDescription;)Lcom/fasterxml/jackson/databind/KeyDeserializer; -PLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->()V -PLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->()V -PLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->(Lcom/fasterxml/jackson/databind/JsonDeserializer;Lcom/fasterxml/jackson/databind/deser/NullValueProvider;Ljava/lang/Boolean;)V -PLcom/fasterxml/jackson/databind/deser/std/StringArrayDeserializer;->createContextual(Lcom/fasterxml/jackson/databind/DeserializationContext;Lcom/fasterxml/jackson/databind/BeanProperty;)Lcom/fasterxml/jackson/databind/JsonDeserializer; -PLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$NCollector;->asAnnotations()Lcom/fasterxml/jackson/databind/util/Annotations; -PLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$OneCollector;->isPresent(Ljava/lang/annotation/Annotation;)Z -PLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$TwoAnnotations;->(Ljava/lang/Class;Ljava/lang/annotation/Annotation;Ljava/lang/Class;Ljava/lang/annotation/Annotation;)V -PLcom/fasterxml/jackson/databind/introspect/AnnotationCollector$TwoAnnotations;->get(Ljava/lang/Class;)Ljava/lang/annotation/Annotation; -PLcom/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector;->findKeyDeserializer(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Object; -PLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Double;->(Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;)V -PLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Double;->serializerFor(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JsonSerializer; -PLcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap$Single;->newWith(Ljava/lang/Class;Lcom/fasterxml/jackson/databind/JsonSerializer;)Lcom/fasterxml/jackson/databind/ser/impl/PropertySerializerMap; -PLcom/fasterxml/jackson/databind/ser/std/ByteArraySerializer;->serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V -PLcom/fasterxml/jackson/databind/ser/std/ByteArraySerializer;->serialize([BLcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V -PLcom/fasterxml/jackson/databind/ser/std/NumberSerializers$IntegerSerializer;->serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V -PLcom/fasterxml/jackson/databind/type/MapLikeType;->equals(Ljava/lang/Object;)Z -PLcom/fasterxml/jackson/databind/type/PlaceholderForType;->(I)V -PLcom/fasterxml/jackson/databind/type/PlaceholderForType;->actualType()Lcom/fasterxml/jackson/databind/JavaType; -PLcom/fasterxml/jackson/databind/type/PlaceholderForType;->actualType(Lcom/fasterxml/jackson/databind/JavaType;)V -PLcom/fasterxml/jackson/databind/type/PlaceholderForType;->equals(Ljava/lang/Object;)Z -PLcom/fasterxml/jackson/databind/type/TypeBase;->findSuperType(Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; -PLcom/fasterxml/jackson/databind/type/TypeFactory;->_bindingsForSubtype(Lcom/fasterxml/jackson/databind/JavaType;ILjava/lang/Class;Z)Lcom/fasterxml/jackson/databind/type/TypeBindings; -PLcom/fasterxml/jackson/databind/type/TypeFactory;->_resolveTypePlaceholders(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;)Ljava/lang/String; -PLcom/fasterxml/jackson/databind/type/TypeFactory;->_verifyAndResolvePlaceholders(Lcom/fasterxml/jackson/databind/JavaType;Lcom/fasterxml/jackson/databind/JavaType;)Z +PLcom/google/android/gms/common/api/internal/BackgroundDetector;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V PLcom/google/android/material/appbar/AppBarLayout;->clearLiftOnScrollTargetView()V PLcom/google/android/material/appbar/AppBarLayout;->onDetachedFromWindow()V PLcom/google/android/material/appbar/AppBarLayout;->removeOnOffsetChangedListener(Lcom/google/android/material/appbar/AppBarLayout$BaseOnOffsetChangedListener;)V PLcom/google/android/material/appbar/AppBarLayout;->removeOnOffsetChangedListener(Lcom/google/android/material/appbar/AppBarLayout$OnOffsetChangedListener;)V +PLcom/google/android/material/appbar/AppBarLayout;->verifyDrawable(Landroid/graphics/drawable/Drawable;)Z PLcom/google/android/material/appbar/CollapsingToolbarLayout;->onDetachedFromWindow()V PLcom/google/android/material/button/MaterialButton$SavedState$1;->()V PLcom/google/android/material/button/MaterialButton$SavedState;->()V PLcom/google/android/material/button/MaterialButton$SavedState;->(Landroid/os/Parcelable;)V +PLcom/google/android/material/button/MaterialButton$SavedState;->writeToParcel(Landroid/os/Parcel;I)V +PLcom/google/android/material/button/MaterialButton;->getA11yClassName()Ljava/lang/String; +PLcom/google/android/material/button/MaterialButton;->onInitializeAccessibilityNodeInfo(Landroid/view/accessibility/AccessibilityNodeInfo;)V +PLcom/google/android/material/button/MaterialButton;->onLayout(ZIIII)V PLcom/google/android/material/button/MaterialButton;->onSaveInstanceState()Landroid/os/Parcelable; +PLcom/google/android/material/card/MaterialCardView;->()V +PLcom/google/android/material/card/MaterialCardView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLcom/google/android/material/card/MaterialCardView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +PLcom/google/android/material/card/MaterialCardView;->isCheckable()Z +PLcom/google/android/material/card/MaterialCardView;->isChecked()Z +PLcom/google/android/material/card/MaterialCardView;->isDragged()Z +PLcom/google/android/material/card/MaterialCardView;->onAttachedToWindow()V +PLcom/google/android/material/card/MaterialCardView;->onCreateDrawableState(I)[I +PLcom/google/android/material/card/MaterialCardView;->onInitializeAccessibilityNodeInfo(Landroid/view/accessibility/AccessibilityNodeInfo;)V +PLcom/google/android/material/card/MaterialCardView;->onMeasure(II)V +PLcom/google/android/material/card/MaterialCardView;->setAncestorContentPadding(IIII)V +PLcom/google/android/material/card/MaterialCardView;->setBackgroundDrawable(Landroid/graphics/drawable/Drawable;)V +PLcom/google/android/material/card/MaterialCardView;->setBackgroundInternal(Landroid/graphics/drawable/Drawable;)V +PLcom/google/android/material/card/MaterialCardViewHelper$1;->(Lcom/google/android/material/card/MaterialCardViewHelper;Landroid/graphics/drawable/Drawable;IIII)V +PLcom/google/android/material/card/MaterialCardViewHelper$1;->getMinimumHeight()I +PLcom/google/android/material/card/MaterialCardViewHelper$1;->getMinimumWidth()I +PLcom/google/android/material/card/MaterialCardViewHelper$1;->getPadding(Landroid/graphics/Rect;)Z +PLcom/google/android/material/card/MaterialCardViewHelper;->()V +PLcom/google/android/material/card/MaterialCardViewHelper;->(Lcom/google/android/material/card/MaterialCardView;Landroid/util/AttributeSet;II)V +PLcom/google/android/material/card/MaterialCardViewHelper;->calculateHorizontalBackgroundPadding()F +PLcom/google/android/material/card/MaterialCardViewHelper;->calculateVerticalBackgroundPadding()F +PLcom/google/android/material/card/MaterialCardViewHelper;->getBackground()Lcom/google/android/material/shape/MaterialShapeDrawable; +PLcom/google/android/material/card/MaterialCardViewHelper;->getParentCardViewCalculatedCornerPadding()F +PLcom/google/android/material/card/MaterialCardViewHelper;->insetDrawable(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable; +PLcom/google/android/material/card/MaterialCardViewHelper;->isCheckable()Z +PLcom/google/android/material/card/MaterialCardViewHelper;->loadFromAttributes(Landroid/content/res/TypedArray;)V +PLcom/google/android/material/card/MaterialCardViewHelper;->recalculateCheckedIconPosition(II)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setCardBackgroundColor(Landroid/content/res/ColorStateList;)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setCardForegroundColor(Landroid/content/res/ColorStateList;)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setChecked(Z)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setChecked(ZZ)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setCheckedIcon(Landroid/graphics/drawable/Drawable;)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setCheckedIconMargin(I)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setCheckedIconSize(I)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setShapeAppearanceModel(Lcom/google/android/material/shape/ShapeAppearanceModel;)V +PLcom/google/android/material/card/MaterialCardViewHelper;->setUserContentPadding(IIII)V +PLcom/google/android/material/card/MaterialCardViewHelper;->shouldAddCornerPaddingInsideCardBackground()Z +PLcom/google/android/material/card/MaterialCardViewHelper;->shouldAddCornerPaddingOutsideCardBackground()Z +PLcom/google/android/material/card/MaterialCardViewHelper;->updateContentPadding()V +PLcom/google/android/material/card/MaterialCardViewHelper;->updateElevation()V +PLcom/google/android/material/card/MaterialCardViewHelper;->updateRippleColor()V +PLcom/google/android/material/card/MaterialCardViewHelper;->updateStroke()V +PLcom/google/android/material/expandable/ExpandableWidgetHelper;->onSaveInstanceState()Landroid/os/Bundle; PLcom/google/android/material/floatingactionbutton/FloatingActionButton;->onDetachedFromWindow()V +PLcom/google/android/material/floatingactionbutton/FloatingActionButton;->onSaveInstanceState()Landroid/os/Parcelable; PLcom/google/android/material/floatingactionbutton/FloatingActionButtonImpl;->onDetachedFromWindow()V +PLcom/google/android/material/imageview/ShapeableImageView;->drawStroke(Landroid/graphics/Canvas;)V +PLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingBottom()I +PLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingLeft()I +PLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingRight()I +PLcom/google/android/material/imageview/ShapeableImageView;->getContentPaddingTop()I +PLcom/google/android/material/imageview/ShapeableImageView;->getPaddingBottom()I +PLcom/google/android/material/imageview/ShapeableImageView;->getPaddingLeft()I +PLcom/google/android/material/imageview/ShapeableImageView;->getPaddingRight()I +PLcom/google/android/material/imageview/ShapeableImageView;->getPaddingTop()I +PLcom/google/android/material/imageview/ShapeableImageView;->isContentPaddingRelative()Z +PLcom/google/android/material/imageview/ShapeableImageView;->onDraw(Landroid/graphics/Canvas;)V +PLcom/google/android/material/imageview/ShapeableImageView;->onMeasure(II)V +PLcom/google/android/material/imageview/ShapeableImageView;->onSizeChanged(IIII)V +PLcom/google/android/material/imageview/ShapeableImageView;->setPadding(IIII)V +PLcom/google/android/material/imageview/ShapeableImageView;->updateShapeMask(II)V +PLcom/google/android/material/shape/MaterialShapeDrawable;->drawStrokeShape(Landroid/graphics/Canvas;)V +PLcom/google/android/material/shape/MaterialShapeDrawable;->setShadowBitmapDrawingEnable(Z)V +PLcom/google/android/material/shape/MaterialShapeDrawable;->setShadowColor(I)V +PLcom/google/android/material/stateful/ExtendableSavedState$1;->()V +PLcom/google/android/material/stateful/ExtendableSavedState;->()V +PLcom/google/android/material/stateful/ExtendableSavedState;->(Landroid/os/Parcelable;)V PLcom/google/android/material/stateful/ExtendableSavedState;->writeToParcel(Landroid/os/Parcel;I)V +PLcom/google/common/collect/Sets$2;->(Ljava/util/Set;Ljava/util/Set;)V +PLcom/google/common/collect/Sets$2;->isEmpty()Z +PLcom/google/common/collect/Sets$SetView;->()V +PLcom/google/common/collect/Sets$SetView;->(Lcom/google/common/collect/Sets$1;)V +PLcom/google/firebase/messaging/FcmLifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V PLcom/pnikosis/materialishprogress/ProgressWheel$WheelSavedState$1;->()V PLcom/pnikosis/materialishprogress/ProgressWheel$WheelSavedState;->()V PLcom/pnikosis/materialishprogress/ProgressWheel$WheelSavedState;->(Landroid/os/Parcelable;)V PLcom/pnikosis/materialishprogress/ProgressWheel;->onSaveInstanceState()Landroid/os/Parcelable; -PLio/reactivex/rxjava3/core/Flowable;->fromFuture(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)Lio/reactivex/rxjava3/core/Flowable; +PLio/reactivex/rxjava3/core/Flowable;->distinctUntilChanged(Lio/reactivex/rxjava3/functions/BiPredicate;)Lio/reactivex/rxjava3/core/Flowable; +PLio/reactivex/rxjava3/core/Flowable;->switchMapSingle(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Flowable; +PLio/reactivex/rxjava3/core/Maybe;->create(Lio/reactivex/rxjava3/core/MaybeOnSubscribe;)Lio/reactivex/rxjava3/core/Maybe; +PLio/reactivex/rxjava3/core/Maybe;->doOnSuccess(Lio/reactivex/rxjava3/functions/Consumer;)Lio/reactivex/rxjava3/core/Maybe; +PLio/reactivex/rxjava3/core/Maybe;->empty()Lio/reactivex/rxjava3/core/Maybe; +PLio/reactivex/rxjava3/core/Maybe;->flatMap(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Maybe; +PLio/reactivex/rxjava3/core/Maybe;->fromCallable(Ljava/util/concurrent/Callable;)Lio/reactivex/rxjava3/core/Maybe; +PLio/reactivex/rxjava3/core/Maybe;->observeOn(Lio/reactivex/rxjava3/core/Scheduler;)Lio/reactivex/rxjava3/core/Maybe; +PLio/reactivex/rxjava3/core/Observable;->distinctUntilChanged(Lio/reactivex/rxjava3/functions/BiPredicate;)Lio/reactivex/rxjava3/core/Observable; PLio/reactivex/rxjava3/core/Scheduler$PeriodicDirectTask;->dispose()V -PLio/reactivex/rxjava3/core/Single;->error(Lio/reactivex/rxjava3/functions/Supplier;)Lio/reactivex/rxjava3/core/Single; -PLio/reactivex/rxjava3/core/Single;->error(Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/Single; -PLio/reactivex/rxjava3/core/Single;->flatMap(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; -PLio/reactivex/rxjava3/core/Single;->fromFuture(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)Lio/reactivex/rxjava3/core/Single; -PLio/reactivex/rxjava3/core/Single;->onErrorResumeNext(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; -PLio/reactivex/rxjava3/core/Single;->onErrorReturn(Lio/reactivex/rxjava3/functions/Function;)Lio/reactivex/rxjava3/core/Single; -PLio/reactivex/rxjava3/core/Single;->toSingle(Lio/reactivex/rxjava3/core/Flowable;)Lio/reactivex/rxjava3/core/Single; PLio/reactivex/rxjava3/disposables/CompositeDisposable;->clear()V -PLio/reactivex/rxjava3/exceptions/Exceptions;->throwIfFatal(Ljava/lang/Throwable;)V PLio/reactivex/rxjava3/internal/disposables/CancellableDisposable;->dispose()V +PLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->complete(Lio/reactivex/rxjava3/core/MaybeObserver;)V PLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->dispose()V -PLio/reactivex/rxjava3/internal/disposables/EmptyDisposable;->error(Ljava/lang/Throwable;Lio/reactivex/rxjava3/core/SingleObserver;)V PLio/reactivex/rxjava3/internal/disposables/SequentialDisposable;->dispose()V PLio/reactivex/rxjava3/internal/observers/ConsumerSingleObserver;->dispose()V PLio/reactivex/rxjava3/internal/observers/QueueDrainObserver;->cancelled()Z PLio/reactivex/rxjava3/internal/observers/QueueDrainObserver;->done()Z PLio/reactivex/rxjava3/internal/observers/QueueDrainObserver;->enter()Z PLio/reactivex/rxjava3/internal/observers/QueueDrainObserver;->error()Ljava/lang/Throwable; -PLio/reactivex/rxjava3/internal/observers/ResumeSingleObserver;->(Ljava/util/concurrent/atomic/AtomicReference;Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/observers/ResumeSingleObserver;->onError(Ljava/lang/Throwable;)V -PLio/reactivex/rxjava3/internal/observers/ResumeSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V PLio/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest$CombineLatestCoordinator;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest$CombineLatestCoordinator;->cancelAll()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest$CombineLatestInnerSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableCreate$BaseEmitter;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableCreate$LatestAsyncEmitter;->onUnsubscribed()V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture;->(Ljava/util/concurrent/Future;JLjava/util/concurrent/TimeUnit;)V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture;->subscribeActual(Lorg/reactivestreams/Subscriber;)V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable$SubscriberObserver;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableInterval$IntervalSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->clear()V +PLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$BaseObserveOnSubscriber;->requestFusion(I)I +PLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->poll()Ljava/lang/Object; +PLio/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn$ObserveOnSubscriber;->runBackfused()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount$RefCountSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount;->cancel(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount$RefConnection;)V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount;->timeout(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount$RefConnection;)V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->removeFirst()V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$BoundedReplayBuffer;->setFirst(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$Node;)V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$InnerSubscription;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$InnerSubscription;->dispose()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$ReplaySubscriber;->dispose()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$ReplaySubscriber;->remove(Lio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay$InnerSubscription;)V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableReplay;->reset()V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber;->(Lio/reactivex/rxjava3/core/SingleObserver;Ljava/lang/Object;)V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber;->onError(Ljava/lang/Throwable;)V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle$SingleElementSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle;->(Lio/reactivex/rxjava3/core/Flowable;Ljava/lang/Object;)V -PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn$SubscribeOnSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchMap$SwitchMapSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchMap$SwitchMapSubscriber;->disposeInner()V PLio/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest$ThrottleLatestSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver;->dispose()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter;->(Lio/reactivex/rxjava3/core/MaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter;->isDisposed()Z +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate$Emitter;->onSuccess(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate;->(Lio/reactivex/rxjava3/core/MaybeOnSubscribe;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeCreate;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty;->()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty;->()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver;->(Lio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver;->onComplete()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver$InnerObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/functions/Function;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->isDisposed()Z +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten$FlatMapMaybeObserver;->onSuccess(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/functions/Function;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable;->(Ljava/util/concurrent/Callable;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/core/Scheduler;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->onComplete()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->onSuccess(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn$ObserveOnMaybeObserver;->run()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/core/Scheduler;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->(Lio/reactivex/rxjava3/core/MaybeObserver;Lio/reactivex/rxjava3/internal/operators/maybe/MaybePeek;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->onAfterTerminate()V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek$MaybePeekObserver;->onSuccess(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek;->(Lio/reactivex/rxjava3/core/MaybeSource;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Consumer;Lio/reactivex/rxjava3/functions/Action;Lio/reactivex/rxjava3/functions/Action;Lio/reactivex/rxjava3/functions/Action;)V +PLio/reactivex/rxjava3/internal/operators/maybe/MaybePeek;->subscribeActual(Lio/reactivex/rxjava3/core/MaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver;->(Lio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber$SwitchMapSingleObserver;->onSuccess(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->()V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->(Lorg/reactivestreams/Subscriber;Lio/reactivex/rxjava3/functions/Function;Z)V PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->disposeInner()V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->drain()V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->onNext(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle$SwitchMapSingleSubscriber;->request(J)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle;->(Lio/reactivex/rxjava3/core/Flowable;Lio/reactivex/rxjava3/functions/Function;Z)V +PLio/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle;->subscribeActual(Lorg/reactivestreams/Subscriber;)V PLio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver;->dispose()V PLio/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle$SwitchMapSingleMainObserver;->disposeInner()V PLio/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservable$FlatMapObserver;->dispose()V @@ -37644,13 +36866,26 @@ PLio/reactivex/rxjava3/internal/operators/observable/ObservableConcatMap$ConcatM PLio/reactivex/rxjava3/internal/operators/observable/ObservableConcatMap$ConcatMapDelayErrorObserver;->dispose()V PLio/reactivex/rxjava3/internal/operators/observable/ObservableCreate$CreateEmitter;->dispose()V PLio/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEach$DoOnEachObserver;->dispose()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;->(Lio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver$InnerObserver;->onSuccess(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->(Lio/reactivex/rxjava3/core/Observer;Lio/reactivex/rxjava3/functions/Function;Z)V PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->dispose()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe$FlatMapMaybeObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver;->dispose()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver;->drainLoop()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle$FlatMapSingleObserver;->getOrCreateQueue()Lio/reactivex/rxjava3/internal/queue/SpscLinkedArrayQueue; PLio/reactivex/rxjava3/internal/operators/observable/ObservableFromArray$FromArrayDisposable;->dispose()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->(Lio/reactivex/rxjava3/core/Observer;)V PLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->dispose()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->onNext(Ljava/lang/Object;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher$PublisherSubscriber;->onSubscribe(Lorg/reactivestreams/Subscription;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher;->subscribeActual(Lio/reactivex/rxjava3/core/Observer;)V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableMap$MapObserver;->requestFusion(I)I PLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->clear()V +PLio/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn$ObserveOnObserver;->isEmpty()Z PLio/reactivex/rxjava3/internal/operators/observable/ObservableRefCount;->timeout(Lio/reactivex/rxjava3/internal/operators/observable/ObservableRefCount$RefConnection;)V -PLio/reactivex/rxjava3/internal/operators/observable/ObservableReplay$BoundedReplayBuffer;->removeFirst()V PLio/reactivex/rxjava3/internal/operators/observable/ObservableReplay$BoundedReplayBuffer;->setFirst(Lio/reactivex/rxjava3/internal/operators/observable/ObservableReplay$Node;)V PLio/reactivex/rxjava3/internal/operators/observable/ObservableReplay$ReplayObserver;->dispose()V PLio/reactivex/rxjava3/internal/operators/observable/ObservableReplay;->reset()V @@ -37665,31 +36900,6 @@ PLio/reactivex/rxjava3/internal/operators/observable/ObservableSkip$SkipObserver PLio/reactivex/rxjava3/internal/operators/observable/ObservableSwitchMap$SwitchMapObserver;->dispose()V PLio/reactivex/rxjava3/internal/operators/observable/ObservableSwitchMap$SwitchMapObserver;->disposeInner()V PLio/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed$DebounceTimedObserver;->dispose()V -PLio/reactivex/rxjava3/internal/operators/single/SingleError;->(Lio/reactivex/rxjava3/functions/Supplier;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleError;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver;->(Ljava/util/concurrent/atomic/AtomicReference;Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver;->onSuccess(Ljava/lang/Object;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->(Lio/reactivex/rxjava3/core/SingleObserver;Lio/reactivex/rxjava3/functions/Function;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->isDisposed()Z -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap$SingleFlatMapCallback;->onSuccess(Ljava/lang/Object;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleFlatMap;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleMap$MapSingleObserver;->onError(Ljava/lang/Throwable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->(Lio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn;Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->onError(Ljava/lang/Throwable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn$OnErrorReturn;->onSuccess(Ljava/lang/Object;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;Ljava/lang/Object;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver;->(Lio/reactivex/rxjava3/core/SingleObserver;Lio/reactivex/rxjava3/functions/Function;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver;->onError(Ljava/lang/Throwable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext$ResumeMainSingleObserver;->onSubscribe(Lio/reactivex/rxjava3/disposables/Disposable;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext;->(Lio/reactivex/rxjava3/core/SingleSource;Lio/reactivex/rxjava3/functions/Function;)V -PLio/reactivex/rxjava3/internal/operators/single/SingleResumeNext;->subscribeActual(Lio/reactivex/rxjava3/core/SingleObserver;)V -PLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->isEmpty()Z -PLio/reactivex/rxjava3/internal/queue/MpscLinkedQueue;->lvConsumerNode()Lio/reactivex/rxjava3/internal/queue/MpscLinkedQueue$LinkedQueueNode; PLio/reactivex/rxjava3/internal/queue/SpscArrayQueue;->clear()V PLio/reactivex/rxjava3/internal/queue/SpscArrayQueue;->isEmpty()Z PLio/reactivex/rxjava3/internal/schedulers/AbstractDirectTask;->cancelFuture(Ljava/util/concurrent/Future;)V @@ -37699,18 +36909,19 @@ PLio/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriber;- PLio/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/subscribers/LambdaSubscriber;->cancel()V PLio/reactivex/rxjava3/internal/subscribers/LambdaSubscriber;->dispose()V -PLio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription;->(Lorg/reactivestreams/Subscriber;)V -PLio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription;->isCancelled()Z -PLio/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription;->request(J)V PLio/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList;->(I)V PLio/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList;->add(Ljava/lang/Object;)V PLio/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList;->forEachWhile(Lio/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList$NonThrowingPredicate;)V PLio/reactivex/rxjava3/internal/util/AtomicThrowable;->terminate()Ljava/lang/Throwable; PLio/reactivex/rxjava3/internal/util/AtomicThrowable;->tryTerminateAndReport()V PLio/reactivex/rxjava3/internal/util/ExceptionHelper;->terminate(Ljava/util/concurrent/atomic/AtomicReference;)Ljava/lang/Throwable; +PLio/reactivex/rxjava3/internal/util/NotificationLite;->acceptFull(Ljava/lang/Object;Lio/reactivex/rxjava3/core/Observer;)Z PLio/reactivex/rxjava3/internal/util/NotificationLite;->complete()Ljava/lang/Object; +PLio/reactivex/rxjava3/internal/util/OpenHashSet;->rehash()V PLio/reactivex/rxjava3/internal/util/QueueDrainHelper;->checkTerminated(ZZLio/reactivex/rxjava3/core/Observer;ZLio/reactivex/rxjava3/internal/fuseable/SimpleQueue;Lio/reactivex/rxjava3/disposables/Disposable;Lio/reactivex/rxjava3/internal/util/ObservableQueueDrain;)Z PLio/reactivex/rxjava3/internal/util/QueueDrainHelper;->drainLoop(Lio/reactivex/rxjava3/internal/fuseable/SimplePlainQueue;Lio/reactivex/rxjava3/core/Observer;ZLio/reactivex/rxjava3/disposables/Disposable;Lio/reactivex/rxjava3/internal/util/ObservableQueueDrain;)V +PLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy$default(Lio/reactivex/rxjava3/core/Maybe;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/reactivex/rxjava3/disposables/Disposable; +PLio/reactivex/rxjava3/kotlin/SubscribersKt;->subscribeBy(Lio/reactivex/rxjava3/core/Maybe;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Lio/reactivex/rxjava3/disposables/Disposable; PLio/reactivex/rxjava3/observers/DisposableObserver;->dispose()V PLio/reactivex/rxjava3/observers/SerializedObserver;->dispose()V PLio/reactivex/rxjava3/observers/SerializedObserver;->onComplete()V @@ -37722,43 +36933,39 @@ PLio/reactivex/rxjava3/subjects/BehaviorSubject;->onComplete()V PLio/reactivex/rxjava3/subjects/BehaviorSubject;->terminate(Ljava/lang/Object;)[Lio/reactivex/rxjava3/subjects/BehaviorSubject$BehaviorDisposable; PLio/reactivex/rxjava3/subjects/PublishSubject$PublishDisposable;->dispose()V PLio/reactivex/rxjava3/subjects/PublishSubject;->remove(Lio/reactivex/rxjava3/subjects/PublishSubject$PublishDisposable;)V -PLj$/util/d;->remove(Ljava/lang/Object;)Ljava/lang/Object; -PLkotlin/Result;->(Ljava/lang/Object;)V -PLkotlin/Result;->box-impl(Ljava/lang/Object;)Lkotlin/Result; -PLkotlin/Result;->unbox-impl()Ljava/lang/Object; +PLio/reactivex/rxjava3/subjects/SerializedSubject;->test(Ljava/lang/Object;)Z +PLj$/time/chrono/f;->f(J)Z +PLj$/util/DesugarCollections;->a()Ljava/lang/reflect/Constructor; +PLj$/util/Optional;->ifPresent(Lj$/util/function/Consumer;)V +PLj$/util/d;->a(Ljava/util/Set;Ljava/lang/Object;)Ljava/util/Set; +PLj$/util/d;->keySet()Ljava/util/Set; +PLj$/util/function/b;->(Ljava/util/Comparator;I)V +PLj$/util/stream/A1;->(Lj$/util/stream/V2;Ljava/lang/Object;I)V +PLj$/util/stream/E1;->(Lj$/util/function/BinaryOperator;)V +PLj$/util/stream/E1;->accept(Ljava/lang/Object;)V +PLj$/util/stream/E1;->get()Ljava/lang/Object; +PLj$/util/stream/E1;->m()V +PLj$/util/stream/E1;->n(J)V +PLj$/util/stream/E1;->q()Z +PLj$/util/stream/Y1;->limit(J)Lj$/util/stream/Stream; +PLj$/util/stream/Y1;->max(Ljava/util/Comparator;)Lj$/util/Optional; +PLj$/util/stream/h2;->q()Z +PLj$/util/stream/i2;->(Lj$/util/stream/c;IJJ)V +PLj$/util/stream/i2;->B1(ILj$/util/stream/g2;)Lj$/util/stream/g2; +PLj$/util/stream/w0;->C0(JJJ)J +PLj$/util/stream/w0;->S0(J)I +PLj$/util/stream/w0;->k1(Lj$/util/stream/c;JJ)Lj$/util/stream/Stream; +PLj$/util/stream/w0;->p()I +PLkotlin/collections/CollectionsKt;->intersect(Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/Set; PLkotlin/collections/CollectionsKt;->retainAll(Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z PLkotlin/collections/CollectionsKt__MutableCollectionsKt;->filterInPlace$CollectionsKt__MutableCollectionsKt(Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;Z)Z PLkotlin/collections/CollectionsKt__MutableCollectionsKt;->retainAll(Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z -PLkotlin/collections/MapsKt;->mapOf(Lkotlin/Pair;)Ljava/util/Map; -PLkotlin/collections/MapsKt;->plus(Ljava/util/Map;Lkotlin/Pair;)Ljava/util/Map; -PLkotlin/collections/MapsKt__MapsJVMKt;->mapOf(Lkotlin/Pair;)Ljava/util/Map; -PLkotlin/collections/MapsKt__MapsKt;->plus(Ljava/util/Map;Lkotlin/Pair;)Ljava/util/Map; -PLkotlin/reflect/jvm/internal/UtilKt;->createArrayType(Ljava/lang/Class;)Ljava/lang/Class; -PLkotlin/reflect/jvm/internal/impl/descriptors/runtime/components/SignatureSerializer;->fieldDesc(Ljava/lang/reflect/Field;)Ljava/lang/String; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$AnnotationVisitorForMethod;->visitParameterAnnotation(ILkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/descriptors/SourceElement;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$AnnotationArgumentVisitor; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1$MemberAnnotationVisitor;->getSignature()Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader$loadAnnotationsAndInitializers$1;->visitField(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/String;Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/KotlinJvmBinaryClass$AnnotationVisitor; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$AbstractAnnotationArgumentVisitor;->visit(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/Object;)V -PLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$AbstractAnnotationArgumentVisitor;->visitEnum(Lkotlin/reflect/jvm/internal/impl/name/Name;Lkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/name/Name;)V -PLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl$loadAnnotation$1;->visitConstantValue(Lkotlin/reflect/jvm/internal/impl/name/Name;Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue;)V -PLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->access$createConstant(Lkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl;->createConstant(Lkotlin/reflect/jvm/internal/impl/name/Name;Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->fromFieldNameAndDesc(Ljava/lang/String;Ljava/lang/String;)Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature$Companion;->fromMethodSignatureAndParameterIndex(Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;I)Lkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature; -PLkotlin/reflect/jvm/internal/impl/load/kotlin/MemberSignature;->getSignature()Ljava/lang/String; -PLkotlin/reflect/jvm/internal/impl/resolve/constants/BooleanValue;->(Z)V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue;->(Ljava/lang/Object;)V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory;->()V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory;->()V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValueFactory;->createConstantValue(Ljava/lang/Object;)Lkotlin/reflect/jvm/internal/impl/resolve/constants/ConstantValue; -PLkotlin/reflect/jvm/internal/impl/resolve/constants/EnumValue;->(Lkotlin/reflect/jvm/internal/impl/name/ClassId;Lkotlin/reflect/jvm/internal/impl/name/Name;)V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/IntValue;->(I)V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/IntegerValueConstant;->(Ljava/lang/Object;)V -PLkotlin/reflect/jvm/internal/impl/resolve/constants/StringValue;->(Ljava/lang/String;)V +PLkotlin/collections/CollectionsKt__MutableCollectionsKt;->retainAll(Ljava/util/Collection;Ljava/lang/Iterable;)Z +PLkotlin/collections/CollectionsKt___CollectionsKt;->intersect(Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/Set; +PLkotlin/sequences/SequenceScope;->yieldAll(Lkotlin/sequences/Sequence;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; PLkotlin/sequences/SequencesKt;->sequence(Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; PLkotlin/sequences/SequencesKt__SequenceBuilderKt$sequence$$inlined$Sequence$1;->(Lkotlin/jvm/functions/Function2;)V PLkotlin/sequences/SequencesKt__SequenceBuilderKt$sequence$$inlined$Sequence$1;->iterator()Ljava/util/Iterator; -PLkotlin/sequences/SequencesKt__SequenceBuilderKt;->sequence(Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; PLme/leolin/shortcutbadger/ShortcutBadgeException;->(Ljava/lang/String;)V PLme/leolin/shortcutbadger/ShortcutBadgeException;->(Ljava/lang/String;Ljava/lang/Exception;)V PLme/leolin/shortcutbadger/ShortcutBadger;->()V @@ -37799,33 +37006,7 @@ PLme/leolin/shortcutbadger/impl/ZukHomeBadger;->getSupportLaunchers()Ljava/util/ PLme/leolin/shortcutbadger/util/BroadcastHelper;->resolveBroadcast(Landroid/content/Context;Landroid/content/Intent;)Ljava/util/List; PLme/leolin/shortcutbadger/util/BroadcastHelper;->sendDefaultIntentExplicitly(Landroid/content/Context;Landroid/content/Intent;)V PLme/leolin/shortcutbadger/util/BroadcastHelper;->sendIntentExplicitly(Landroid/content/Context;Landroid/content/Intent;)V -PLokhttp3/MediaType;->charset()Ljava/nio/charset/Charset; -PLokhttp3/MediaType;->toString()Ljava/lang/String; -PLokhttp3/OkHttpClient$Builder;->retryOnConnectionFailure(Z)Lokhttp3/OkHttpClient$Builder; -PLokhttp3/RequestBody;->create(Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/RequestBody; -PLokio/AsyncTimeout;->access$getIDLE_TIMEOUT_NANOS$cp()J -PLorg/conscrypt/ArrayUtils;->checkOffsetAndCount(III)V -PLorg/conscrypt/GCMParameters;->(I[B)V -PLorg/conscrypt/GCMParameters;->getIV()[B -PLorg/conscrypt/GCMParameters;->getTLen()I -PLorg/conscrypt/NativeRef$SSL_SESSION;->doFree(J)V -PLorg/conscrypt/OpenSSLAeadCipher;->()V -PLorg/conscrypt/OpenSSLAeadCipher;->(Lorg/conscrypt/OpenSSLCipher$Mode;)V -PLorg/conscrypt/OpenSSLAeadCipher;->allowsNonceReuse()Z -PLorg/conscrypt/OpenSSLAeadCipher;->checkInitialization()V -PLorg/conscrypt/OpenSSLAeadCipher;->checkSupportedTagLength(I)V -PLorg/conscrypt/OpenSSLAeadCipher;->doFinalInternal([BII)I -PLorg/conscrypt/OpenSSLAeadCipher;->engineInitInternal([BLjava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)V -PLorg/conscrypt/OpenSSLAeadCipher;->expand(I)V -PLorg/conscrypt/OpenSSLAeadCipher;->reset()V -PLorg/conscrypt/OpenSSLAeadCipher;->updateInternal([BII[BII)I -PLorg/conscrypt/OpenSSLAeadCipherAES$GCM;->()V -PLorg/conscrypt/OpenSSLAeadCipherAES$GCM;->getEVP_AEAD(I)J -PLorg/conscrypt/OpenSSLAeadCipherAES;->(Lorg/conscrypt/OpenSSLCipher$Mode;)V -PLorg/conscrypt/OpenSSLAeadCipherAES;->checkSupportedKeySize(I)V -PLorg/conscrypt/OpenSSLAeadCipherAES;->getCipherBlockSize()I -PLorg/conscrypt/OpenSSLAeadCipherAES;->getOutputSizeForFinal(I)I -PLorg/conscrypt/Platform;->fromGCMParameterSpec(Ljava/security/spec/AlgorithmParameterSpec;)Lorg/conscrypt/GCMParameters; +PLorg/greenrobot/eventbus/Subscription;->equals(Ljava/lang/Object;)Z PLorg/signal/core/util/ByteSize;->getInKibiBytes()F PLorg/signal/core/util/ByteSize;->getInMebiBytes()F PLorg/signal/core/util/FloatExtensionsKt;->roundedString(FI)Ljava/lang/String; @@ -37835,9 +37016,7 @@ PLorg/signal/core/util/MemoryTracker$AppHeapUsage;->getUsedBytes()J PLorg/signal/core/util/MemoryTracker;->byteDisplay(J)Ljava/lang/String; PLorg/signal/core/util/MemoryTracker;->poll()V PLorg/signal/core/util/PendingIntentFlags;->cancelCurrent()I -PLorg/signal/core/util/StreamUtil;->()V -PLorg/signal/core/util/StreamUtil;->close(Ljava/io/Closeable;)V -PLorg/signal/core/util/StreamUtil;->copy(Ljava/io/InputStream;Ljava/io/OutputStream;)J +PLorg/signal/core/util/StringUtil;->trim(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; PLorg/signal/core/util/concurrent/DeadlockDetector$$ExternalSyntheticLambda0;->run()V PLorg/signal/core/util/concurrent/DeadlockDetector$Companion;->access$isExecutorFull(Lorg/signal/core/util/concurrent/DeadlockDetector$Companion;Ljava/util/concurrent/ExecutorService;)Z PLorg/signal/core/util/concurrent/DeadlockDetector$Companion;->isExecutorFull(Ljava/util/concurrent/ExecutorService;)Z @@ -37847,19 +37026,21 @@ PLorg/signal/core/util/concurrent/DeadlockDetector;->hasPotentialLock([Ljava/lan PLorg/signal/core/util/concurrent/DeadlockDetector;->isWaiting(Ljava/lang/Thread$State;)Z PLorg/signal/core/util/concurrent/DeadlockDetector;->poll()V PLorg/signal/core/util/concurrent/LifecycleDisposable;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/signal/core/util/concurrent/LifecycleDisposable;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/signal/core/util/concurrent/MaybeCompat$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function0;)V +PLorg/signal/core/util/concurrent/MaybeCompat$$ExternalSyntheticLambda0;->subscribe(Lio/reactivex/rxjava3/core/MaybeEmitter;)V +PLorg/signal/core/util/concurrent/MaybeCompat;->$r8$lambda$aPKBr0JUhvb1CVWSMT6CNAHU584(Lkotlin/jvm/functions/Function0;Lio/reactivex/rxjava3/core/MaybeEmitter;)V +PLorg/signal/core/util/concurrent/MaybeCompat;->()V +PLorg/signal/core/util/concurrent/MaybeCompat;->()V +PLorg/signal/core/util/concurrent/MaybeCompat;->fromCallable$lambda$0(Lkotlin/jvm/functions/Function0;Lio/reactivex/rxjava3/core/MaybeEmitter;)V +PLorg/signal/core/util/concurrent/MaybeCompat;->fromCallable(Lkotlin/jvm/functions/Function0;)Lio/reactivex/rxjava3/core/Maybe; +PLorg/signal/core/util/concurrent/SettableFuture;->set(Ljava/lang/Object;)Z PLorg/signal/core/util/concurrent/SignalExecutors$$ExternalSyntheticLambda0;->rejectedExecution(Ljava/lang/Runnable;Ljava/util/concurrent/ThreadPoolExecutor;)V -PLorg/signal/core/util/concurrent/SignalExecutors;->$r8$lambda$0Q0afsv1raKIrq3aP-SuMcT2Ad0(Ljava/lang/Runnable;Ljava/util/concurrent/ThreadPoolExecutor;)V PLorg/signal/core/util/logging/Log$Logger;->i(Ljava/lang/String;Ljava/lang/String;)V PLorg/signal/core/util/logging/Log$Logger;->i(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V PLorg/signal/core/util/logging/Log;->internal()Lorg/signal/core/util/logging/Log$Logger; PLorg/signal/libsignal/protocol/IdentityKey;->equals(Ljava/lang/Object;)Z PLorg/signal/libsignal/protocol/IdentityKey;->getPublicKey()Lorg/signal/libsignal/protocol/ecc/ECPublicKey; -PLorg/signal/libsignal/protocol/ServiceId;->toServiceIdFixedWidthBinary()[B -PLorg/signal/libsignal/protocol/ecc/ECPublicKey;->equals(Ljava/lang/Object;)Z -PLorg/signal/libsignal/protocol/util/ByteUtil;->trim([BI)[B -PLorg/signal/libsignal/zkgroup/profiles/ProfileKey;->getProfileKeyVersion(Lorg/signal/libsignal/protocol/ServiceId$Aci;)Lorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion; -PLorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion;->([B)V -PLorg/signal/libsignal/zkgroup/profiles/ProfileKeyVersion;->serialize()Ljava/lang/String; PLorg/signal/paging/BufferedPagingController$$ExternalSyntheticLambda2;->(Lorg/signal/paging/BufferedPagingController;Ljava/lang/Object;)V PLorg/signal/paging/BufferedPagingController$$ExternalSyntheticLambda2;->run()V PLorg/signal/paging/BufferedPagingController;->$r8$lambda$GxlLAxjfERBgyqmyvxteAPWaQkA(Lorg/signal/paging/BufferedPagingController;Ljava/lang/Object;)V @@ -37869,95 +37050,380 @@ PLorg/signal/paging/DataStatus;->mark(I)V PLorg/signal/paging/FixedSizePagingController$$ExternalSyntheticLambda0;->(Lorg/signal/paging/FixedSizePagingController;Ljava/lang/Object;)V PLorg/signal/paging/FixedSizePagingController$$ExternalSyntheticLambda0;->run()V PLorg/signal/paging/FixedSizePagingController;->$r8$lambda$2jZFFAhs3dG0IThMmzJQSvWvcd0(Lorg/signal/paging/FixedSizePagingController;Ljava/lang/Object;)V -PLorg/signal/paging/FixedSizePagingController;->lambda$onDataItemChanged$2(Ljava/lang/Object;)V PLorg/signal/paging/FixedSizePagingController;->onDataItemChanged(Ljava/lang/Object;)V PLorg/signal/paging/ProxyPagingController;->onDataItemChanged(Ljava/lang/Object;)V -PLorg/thoughtcrime/securesms/AppCapabilities;->()V -PLorg/thoughtcrime/securesms/AppCapabilities;->()V -PLorg/thoughtcrime/securesms/AppCapabilities;->getCapabilities(Z)Lorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities; -PLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda59;->isInternal()Z +PLorg/thoughtcrime/securesms/ApplicationContext$$ExternalSyntheticLambda58;->isInternal()Z PLorg/thoughtcrime/securesms/LoggingFragment;->onDestroy()V +PLorg/thoughtcrime/securesms/LoggingFragment;->onStop()V +PLorg/thoughtcrime/securesms/MainActivity;->onStop()V PLorg/thoughtcrime/securesms/PassphraseRequiredActivity;->onDestroy()V PLorg/thoughtcrime/securesms/PassphraseRequiredActivity;->removeClearKeyReceiver(Landroid/content/Context;)V PLorg/thoughtcrime/securesms/animation/AnimationStartListener;->()V PLorg/thoughtcrime/securesms/animation/AnimationStartListener;->()V PLorg/thoughtcrime/securesms/animation/AnimationStartListener;->onAnimationEnd(Landroid/animation/Animator;)V -PLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->()V -PLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->(ILorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;)V -PLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->getColor()Lorg/thoughtcrime/securesms/avatar/Avatars$ColorPair; -PLorg/thoughtcrime/securesms/avatar/Avatar$Resource;->getResourceId()I -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer$$ExternalSyntheticLambda0;->run()V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar$Resource;)V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer$renderResource$1;->invoke-IoAF18A(Landroid/graphics/Canvas;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->$r8$lambda$LMRb5EH7u5JsF-ZatOYl7HXPvGU(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->createMedia(Landroid/net/Uri;J)Lorg/thoughtcrime/securesms/mediasend/Media; -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->getDIMENSIONS()I -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderAvatar(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderInBackground$lambda$1(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderInBackground(Landroid/content/Context;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V -PLorg/thoughtcrime/securesms/avatar/AvatarRenderer;->renderResource(Landroid/content/Context;Lorg/thoughtcrime/securesms/avatar/Avatar$Resource;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V -PLorg/thoughtcrime/securesms/avatar/Avatars$ColorPair;->getBackgroundColor()I +PLorg/thoughtcrime/securesms/attachments/Attachment;->isInProgress()Z +PLorg/thoughtcrime/securesms/attachments/Attachment;->isPermanentlyFailed()Z +PLorg/thoughtcrime/securesms/audio/AudioRecorder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/audio/AudioRecorder;)V +PLorg/thoughtcrime/securesms/audio/AudioRecorder;->()V +PLorg/thoughtcrime/securesms/audio/AudioRecorder;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/audio/AudioRecordingHandler;)V +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion;->()V +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager$Companion;->create(Landroid/content/Context;Landroid/media/AudioManager$OnAudioFocusChangeListener;)Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager; +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager26;->(Landroid/content/Context;Landroid/media/AudioManager$OnAudioFocusChangeListener;)V +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager;->()V +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager;->(Landroid/content/Context;)V +PLorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager;->create(Landroid/content/Context;Landroid/media/AudioManager$OnAudioFocusChangeListener;)Lorg/thoughtcrime/securesms/audio/AudioRecorderFocusManager; +PLorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;->access$getMessageIdsOpenedThisSession$p(Lorg/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration;)Ljava/util/Set; +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;Ljava/util/List;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;Ljava/util/List;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/components/AlbumThumbnailView;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->inflateLayout(I)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setCancelTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setPlayVideoClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setStartTransferClickListener(Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->setThumbnailClickListener(Lorg/thoughtcrime/securesms/mms/SlideClickListener;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->showSlides(Lcom/bumptech/glide/RequestManager;Ljava/util/List;)V +PLorg/thoughtcrime/securesms/components/AlbumThumbnailView;->sizeClass(I)I +PLorg/thoughtcrime/securesms/components/AnimatingToggle;->display(Landroid/view/View;)V +PLorg/thoughtcrime/securesms/components/AudioView$$ExternalSyntheticLambda0;->onChanged(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/components/AudioView;->$r8$lambda$70S_ChWvvHg6uKYhRw5m0jX0OG0(Lorg/thoughtcrime/securesms/components/AudioView;Lorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;)V +PLorg/thoughtcrime/securesms/components/AudioView;->getPlaybackStateObserver()Landroidx/lifecycle/Observer; +PLorg/thoughtcrime/securesms/components/AudioView;->hasAudioUri()Z +PLorg/thoughtcrime/securesms/components/AudioView;->isTarget(Landroid/net/Uri;)Z PLorg/thoughtcrime/securesms/components/AudioView;->onDetachedFromWindow()V +PLorg/thoughtcrime/securesms/components/AudioView;->onDuration(Landroid/net/Uri;J)V +PLorg/thoughtcrime/securesms/components/AudioView;->onPlaybackState(Lorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;)V +PLorg/thoughtcrime/securesms/components/AudioView;->onProgress(Landroid/net/Uri;DJ)V +PLorg/thoughtcrime/securesms/components/AudioView;->onSpeedChanged(Landroid/net/Uri;F)V +PLorg/thoughtcrime/securesms/components/AudioView;->onStart(Landroid/net/Uri;ZZ)V +PLorg/thoughtcrime/securesms/components/AvatarImageView;->setFallbackPhotoProvider(Lorg/thoughtcrime/securesms/recipients/Recipient$FallbackPhotoProvider;)V +PLorg/thoughtcrime/securesms/components/AvatarImageView;->setOnClickListener(Landroid/view/View$OnClickListener;)V +PLorg/thoughtcrime/securesms/components/ComposeText;->setCursorPositionChangedListener(Lorg/thoughtcrime/securesms/components/ComposeText$CursorPositionChangedListener;)V +PLorg/thoughtcrime/securesms/components/ComposeText;->setInlineQueryChangedListener(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryChangedListener;)V +PLorg/thoughtcrime/securesms/components/ComposeText;->setMentionValidator(Lorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher$MentionValidator;)V +PLorg/thoughtcrime/securesms/components/ComposeText;->setStylingChangedListener(Lorg/thoughtcrime/securesms/components/ComposeText$StylingChangedListener;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter$$ExternalSyntheticLambda2;->onLayoutChange(Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->$r8$lambda$rILpFw6OPAVn7dsgVBus6R0qlZk(Lorg/thoughtcrime/securesms/components/ConversationItemFooter;Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->buildMessageId(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)J +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->disableBubbleBackground()V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->getDateView()Landroid/view/View; +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->getPlaybackSpeedToggleTouchDelegateRect()Landroid/graphics/Rect; +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->hideAudioDurationViews()V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->lambda$init$0(Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->notifyTouchDelegateChanged(Landroid/graphics/Rect;Landroid/view/View;)V PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->onDetachedFromWindow()V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentAudioDuration(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentInsecureIndicator(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentSimInfo(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->presentTimer(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setMessageRecord(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Ljava/util/Locale;Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setOnlyShowSendingStatus(ZLorg/thoughtcrime/securesms/database/model/MessageRecord;)V +PLorg/thoughtcrime/securesms/components/ConversationItemFooter;->setPlaybackSpeedListener(Lorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView$PlaybackSpeedListener;)V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnail$Companion;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnail$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->getFooter()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->setBorderless(Z)V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnail;->showShade(Z)V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState$Creator;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;->(ZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$Creator;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState$Creator;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;->(FZZLorg/thoughtcrime/securesms/mms/SlideClickListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlidesClickedListener;Lorg/thoughtcrime/securesms/mms/SlideClickListener;Landroid/view/View$OnLongClickListener;IIIIIIIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->()V +PLorg/thoughtcrime/securesms/components/ConversationItemThumbnailState;->(Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$ThumbnailViewState;Lorg/thoughtcrime/securesms/components/ConversationItemThumbnailState$AlbumViewState;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/ConversationScrollToView;->formatUnreadCount(I)Ljava/lang/CharSequence; +PLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setOnClickListener(Landroid/view/View$OnClickListener;)V +PLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setShown(Z)V +PLorg/thoughtcrime/securesms/components/ConversationScrollToView;->setUnreadCount(I)V +PLorg/thoughtcrime/securesms/components/ConversationSearchBottomBar;->setEventListener(Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar$EventListener;)V +PLorg/thoughtcrime/securesms/components/CornerMask;->setRadius(I)V +PLorg/thoughtcrime/securesms/components/DeliveryStatusView;->isPending()Z +PLorg/thoughtcrime/securesms/components/ExpirationTimerView;->stopAnimation()V +PLorg/thoughtcrime/securesms/components/HidingLinearLayout;->hide()V +PLorg/thoughtcrime/securesms/components/HidingLinearLayout;->show()V +PLorg/thoughtcrime/securesms/components/InputAwareConstraintLayout;->addInputListener(Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout$Listener;)V +PLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/components/InputPanel$Listener;)V +PLorg/thoughtcrime/securesms/components/InputPanel$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/components/InputPanel$Listener;)V PLorg/thoughtcrime/securesms/components/InputPanel$3;->(Lorg/thoughtcrime/securesms/components/InputPanel;Landroid/view/View;)V PLorg/thoughtcrime/securesms/components/InputPanel$3;->onAnimationStart(Landroid/animation/Animator;)V PLorg/thoughtcrime/securesms/components/InputPanel;->fadeIn(Landroid/view/View;)V PLorg/thoughtcrime/securesms/components/InputPanel;->fadeInNormalComposeViews()V +PLorg/thoughtcrime/securesms/components/InputPanel;->getPlaybackStateObserver()Landroidx/lifecycle/Observer; PLorg/thoughtcrime/securesms/components/InputPanel;->inEditMessageMode()Z PLorg/thoughtcrime/securesms/components/InputPanel;->isRecordingInLockedMode()Z PLorg/thoughtcrime/securesms/components/InputPanel;->onPause()V PLorg/thoughtcrime/securesms/components/InputPanel;->readDimen(I)I -PLorg/thoughtcrime/securesms/components/InputPanel;->setLinkPreview(Lorg/thoughtcrime/securesms/mms/GlideRequests;Lj$/util/Optional;)V +PLorg/thoughtcrime/securesms/components/InputPanel;->setLinkPreview(Lcom/bumptech/glide/RequestManager;Lj$/util/Optional;)V +PLorg/thoughtcrime/securesms/components/InputPanel;->setListener(Lorg/thoughtcrime/securesms/components/InputPanel$Listener;)V +PLorg/thoughtcrime/securesms/components/InputPanel;->setStickerSuggestions(Ljava/util/List;)V PLorg/thoughtcrime/securesms/components/InputPanel;->setVoiceNoteDraft(Lorg/thoughtcrime/securesms/database/DraftTable$Draft;)V +PLorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout;->addKeyboardStateListener(Lorg/thoughtcrime/securesms/components/InsetAwareConstraintLayout$KeyboardStateListener;)V PLorg/thoughtcrime/securesms/components/LinkPreviewView;->onSaveInstanceState()Landroid/os/Parcelable; PLorg/thoughtcrime/securesms/components/LinkPreviewView;->setCorners(II)V +PLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->applyState(Lorg/thoughtcrime/securesms/util/views/Stub;)V +PLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->copy(IIIILorg/thoughtcrime/securesms/mms/SlidesClickedListener;)Lorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState; +PLorg/thoughtcrime/securesms/components/LinkPreviewViewThumbnailState;->getDownloadListener()Lorg/thoughtcrime/securesms/mms/SlidesClickedListener; PLorg/thoughtcrime/securesms/components/MicrophoneRecorderView;->cancelAction(Z)V +PLorg/thoughtcrime/securesms/components/MicrophoneRecorderView;->isRecordingLocked()Z +PLorg/thoughtcrime/securesms/components/Outliner;->setColor(I)V +PLorg/thoughtcrime/securesms/components/Outliner;->setRadii(IIII)V +PLorg/thoughtcrime/securesms/components/Outliner;->setStrokeWidth(F)V +PLorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView;->setPlaybackSpeedListener(Lorg/thoughtcrime/securesms/components/PlaybackSpeedToggleTextView$PlaybackSpeedListener;)V PLorg/thoughtcrime/securesms/components/QuoteView;->onDetachedFromWindow()V +PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->()V +PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->(Landroid/view/ViewGroup;Landroid/animation/LayoutTransition;)V +PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->(Landroid/view/ViewGroup;Landroid/animation/LayoutTransition;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->findRecyclerParent()Landroidx/recyclerview/widget/RecyclerView; +PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->onScrollStateChanged(Landroidx/recyclerview/widget/RecyclerView;I)V +PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->onViewAttachedToWindow(Landroid/view/View;)V PLorg/thoughtcrime/securesms/components/RecyclerViewParentTransitionController;->onViewDetachedFromWindow(Landroid/view/View;)V +PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$3;->test(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$3;->test(Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;)Z +PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;->getPosition()I +PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1;->apply(JLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest;)Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$ScrollToPositionRequest; +PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate$scrollPositionRequests$1;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->isListCommitted()Z +PLorg/thoughtcrime/securesms/components/ScrollToPositionDelegate;->notifyListCommitted()V +PLorg/thoughtcrime/securesms/components/SearchView;->(Landroid/content/Context;)V +PLorg/thoughtcrime/securesms/components/SearchView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLorg/thoughtcrime/securesms/components/SearchView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +PLorg/thoughtcrime/securesms/components/SearchView;->appendEmojiFilter(Landroid/widget/TextView;)[Landroid/text/InputFilter; +PLorg/thoughtcrime/securesms/components/SearchView;->initEmojiFilter()V +PLorg/thoughtcrime/securesms/components/SendButton;->setPopupContainer(Landroid/view/ViewGroup;)V +PLorg/thoughtcrime/securesms/components/SendButton;->setScheduledSendListener(Lorg/thoughtcrime/securesms/components/SendButton$ScheduledSendListener;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport0;->m(Ljava/lang/Object;)Ljava/util/List; +PLorg/thoughtcrime/securesms/components/ThumbnailView$$ExternalSyntheticBackport1;->m(Ljava/lang/Object;)Ljava/util/List; +PLorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;Lorg/thoughtcrime/securesms/components/ThumbnailView$CancelClickDispatcher-IA;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;Lorg/thoughtcrime/securesms/components/ThumbnailView$DownloadClickDispatcher-IA;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher;->(Lorg/thoughtcrime/securesms/components/ThumbnailView;Lorg/thoughtcrime/securesms/components/ThumbnailView$ThumbnailClickDispatcher-IA;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView;->()V +PLorg/thoughtcrime/securesms/components/ThumbnailView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView;->dispatchDraw(Landroid/graphics/Canvas;)V +PLorg/thoughtcrime/securesms/components/ThumbnailView;->fillTargetDimensions([I[I[I)V +PLorg/thoughtcrime/securesms/components/ThumbnailView;->getNonZeroCount([I)I +PLorg/thoughtcrime/securesms/components/ThumbnailView;->hasSameContents(Lorg/thoughtcrime/securesms/mms/Slide;Lorg/thoughtcrime/securesms/mms/Slide;)Z +PLorg/thoughtcrime/securesms/components/ThumbnailView;->onSizeChanged(IIII)V +PLorg/thoughtcrime/securesms/components/ThumbnailView;->setImageResource(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/mms/Slide;ZZ)Lorg/signal/core/util/concurrent/ListenableFuture; +PLorg/thoughtcrime/securesms/components/ThumbnailView;->showSecondaryText(Z)V +PLorg/thoughtcrime/securesms/components/TypingStatusRepository;->getTypists(J)Landroidx/lifecycle/LiveData; PLorg/thoughtcrime/securesms/components/ViewBinderDelegate$1;->invoke(Landroidx/viewbinding/ViewBinding;)V PLorg/thoughtcrime/securesms/components/ViewBinderDelegate$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/ViewBinderDelegate;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->addOnFocusChangeListener(Landroid/view/View$OnFocusChangeListener;)V PLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->removeOnFocusChangeListener(Landroid/view/View$OnFocusChangeListener;)V +PLorg/thoughtcrime/securesms/components/emoji/EmojiEditText;->setOnFocusChangeListener(Landroid/view/View$OnFocusChangeListener;)V PLorg/thoughtcrime/securesms/components/emoji/EmojiProvider$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/emoji/EmojiProvider$EmojiDrawable;Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$LoadResult;)V PLorg/thoughtcrime/securesms/components/emoji/EmojiProvider$$ExternalSyntheticLambda0;->run()V PLorg/thoughtcrime/securesms/components/emoji/EmojiProvider;->$r8$lambda$yWqSXcpiMY6E3k4l81kOhV5ANk4(Lorg/thoughtcrime/securesms/components/emoji/EmojiProvider$EmojiDrawable;Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$LoadResult;)V PLorg/thoughtcrime/securesms/components/emoji/EmojiProvider;->lambda$getEmojiDrawable$0(Lorg/thoughtcrime/securesms/components/emoji/EmojiProvider$EmojiDrawable;Lorg/thoughtcrime/securesms/emoji/EmojiPageCache$LoadResult;)V +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView$$ExternalSyntheticLambda1;->()V +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->$r8$lambda$5IPAQraRDnd37oqJyWeDCIArE8A(Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Ljava/lang/String;)Ljava/lang/Float; +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->ellipsizeAnyTextForMaxLength()V +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->getLastLineWidth()I +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->isJumbomoji()Z +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->lambda$getLongestLineWidth$0(Ljava/lang/String;)Ljava/lang/Float; +PLorg/thoughtcrime/securesms/components/emoji/EmojiTextView;->setMentionBackgroundTint(I)V +PLorg/thoughtcrime/securesms/components/emoji/StaticEmojiPageModel;->getEmoji()Ljava/util/List; +PLorg/thoughtcrime/securesms/components/mention/MentionAnnotation$$ExternalSyntheticLambda1;->()V +PLorg/thoughtcrime/securesms/components/mention/MentionAnnotation;->getMentionAnnotations(Landroid/text/Spanned;)Ljava/util/List; +PLorg/thoughtcrime/securesms/components/mention/MentionAnnotation;->getMentionAnnotations(Landroid/text/Spanned;II)Ljava/util/List; +PLorg/thoughtcrime/securesms/components/mention/MentionRendererDelegate;->setTint(I)V +PLorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher;->setMentionValidator(Lorg/thoughtcrime/securesms/components/mention/MentionValidatorWatcher$MentionValidator;)V PLorg/thoughtcrime/securesms/components/registration/PulsingFloatingActionButton$1$1$$ExternalSyntheticLambda0;->run()V PLorg/thoughtcrime/securesms/components/registration/PulsingFloatingActionButton$1$1;->$r8$lambda$7zbeUa9i765Aa2G9x9qw8f4qjOo(Lorg/thoughtcrime/securesms/components/registration/PulsingFloatingActionButton$1$1;J)V PLorg/thoughtcrime/securesms/components/registration/PulsingFloatingActionButton$1$1;->lambda$onAnimationEnd$0(J)V PLorg/thoughtcrime/securesms/components/registration/PulsingFloatingActionButton;->-$$Nest$mpulse(Lorg/thoughtcrime/securesms/components/registration/PulsingFloatingActionButton;J)V PLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationDelegate;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/settings/app/subscription/completed/TerminalDonationDelegate;->onStop(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1$onViewAttachedToWindow$1;->onStop(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate$1;->onViewDetachedFromWindow(Landroid/view/View;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Companion;->containsPlayableSlides(Ljava/util/List;)Z +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode;->$values()[Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Mode;->(Ljava/lang/String;I)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress$Companion;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->(JJ)V PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$Progress;->equals(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1;->(Landroid/view/View$OnClickListener;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setCancelClickListener$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1;->(Z)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setShowSecondaryText$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2;->(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Ljava/util/List;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setSlides$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1;->(Landroid/view/View$OnClickListener;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setTransferClickListener$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1;->(Z)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView$setVisible$1;->invoke(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;)Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->access$isUpdateToExistingSet(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;Ljava/util/List;)Z +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->access$slidesAsListOfTimestamps(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Ljava/util/List;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->access$verboseLog(Lorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->containsPlayableSlides(Ljava/util/List;)Z +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->getTransferState(Ljava/util/List;)I +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->onAttachedToWindow()V PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->onDetachedFromWindow()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->slidesAsListOfTimestamps(Ljava/util/List;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlView;->verboseLog(Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->(ZZZLjava/util/List;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;Landroid/view/View$OnClickListener;ZLjava/util/Map;Ljava/util/Map;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->getCompressionProgress()Ljava/util/Map; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->getNetworkProgress()Ljava/util/Map; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferControlViewState;->getSlides()Ljava/util/List; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$Companion;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State;->$values()[Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView$State;->(Ljava/lang/String;I)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->()V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->(Landroid/content/Context;Landroid/util/AttributeSet;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->progressPaint(I)Landroid/graphics/Paint; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->stopIconPaint(I)Landroid/graphics/Paint; +PLorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;->trackPaint(I)Landroid/graphics/Paint; +PLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->getVoiceNotePlaybackState()Landroidx/lifecycle/MutableLiveData; PLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getPlayheadPositionMillis()J +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getSpeed()F +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getTrackDuration()J +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->getUri()Landroid/net/Uri; +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->isAutoReset()Z +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlaybackState;->isPlaying()Z +PLorg/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallback;->onDisconnected(Landroidx/media3/session/MediaSession;Landroidx/media3/session/MediaSession$ControllerInfo;)V PLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->onStop(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/components/voice/VoiceNoteProximityWakeLockManager;->unregisterFromLifecycle()V PLorg/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto;->equals(Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/contacts/paged/ContactSearchMediator$sam$androidx_lifecycle_Observer$0;->equals(Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/contacts/paged/ContactSearchMediator$sam$androidx_lifecycle_Observer$0;->getFunctionDelegate()Lkotlin/Function; PLorg/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel;->onCleared()V -PLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->()V -PLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->()V -PLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->hasContactsPermissions(Landroid/content/Context;)Z -PLorg/thoughtcrime/securesms/contacts/sync/ContactDiscovery;->refreshAll(Landroid/content/Context;Z)V +PLorg/thoughtcrime/securesms/conversation/ClipProjectionDrawable;->draw(Landroid/graphics/Canvas;)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider;->(Lorg/thoughtcrime/securesms/conversation/ConversationHeaderView$FallbackPhotoProvider-IA;)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->(Landroid/content/Context;Landroid/util/AttributeSet;)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->(Landroid/content/Context;Landroid/util/AttributeSet;I)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->hideButton()V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->hideDescription()V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->hideSubtitle()V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setAbout(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setAvatar(Lcom/bumptech/glide/RequestManager;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setLinkifyDescription(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->setTitle(Lorg/thoughtcrime/securesms/recipients/Recipient;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/conversation/ConversationHeaderView;->showBackgroundBubble(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->canInitializeFromDatabase()Z +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftContentType()Ljava/lang/String; +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftMedia()Landroid/net/Uri; +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftMediaType()Lorg/thoughtcrime/securesms/mms/SlideFactory$MediaType; +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getDraftText()Ljava/lang/String; +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getMedia()Ljava/util/ArrayList; +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getShareDataTimestamp()J +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->getStickerLocator()Lorg/thoughtcrime/securesms/stickers/StickerLocator; +PLorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;->isBorderless()Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/recipients/RecipientId;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItem;Lorg/thoughtcrime/securesms/conversation/ConversationItem$ThumbnailClickListener-IA;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->canPlayContent()Z PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getBadgeImageView()Landroid/view/View; +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getBodyBubbleCorners(IIII)Lorg/thoughtcrime/securesms/util/Projection$Corners; PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getBubbleViews()Ljava/util/List; +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getColorizerProjections(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/ProjectionList; PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getContactPhotoHolderView()Landroid/view/View; +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getConversationMessage()Lorg/thoughtcrime/securesms/conversation/ConversationMessage; +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getDefaultBubbleColor(Z)I +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getDefaultTopMarginForRecord(Lorg/thoughtcrime/securesms/database/model/MessageRecord;II)I PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getQuotedIndicatorView()Landroid/view/View; PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getReactionsView()Landroid/view/View; PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getReactionsView()Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView; PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getReplyView()Landroid/view/View; +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->getRoot()Landroid/view/ViewGroup; +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasAudio(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasDocument(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasLinkPreview(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasOnlyThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasQuote(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasSharedContact(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasSticker(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->hasThumbnail(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isBorderless(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isCondensedMode()Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isContentCondensed()Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isGiftMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isSingularMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lj$/util/Optional;Lj$/util/Optional;Z)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isStoryReaction(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->isViewOnceMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z PLorg/thoughtcrime/securesms/conversation/ConversationItem;->onDetachedFromWindow()V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->onRecipientChanged(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->readDimen(Landroid/content/Context;I)I +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->setEventListener(Lorg/thoughtcrime/securesms/BindableConversationItem$EventListener;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->setGroupMessageStatus(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->setHasBeenScheduled(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->setOutlinerRadii(Lorg/thoughtcrime/securesms/components/Outliner;IIII)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->setParentScrolling(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->setStoryReactionLabel(Lorg/thoughtcrime/securesms/database/model/MessageRecord;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItem;->shouldDrawBodyBubbleOutline(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)Z +PLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->onSizeChanged(IIII)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setOnSizeChangedListener(Lorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble$OnSizeChangedListener;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setOutliners(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemBodyBubble;->setParentScrolling(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Detailed;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Detailed;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$EditHistory;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$EditHistory;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Standard;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode$Standard;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->(ZILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode;->(ZLkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;->(Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$SwipeAvailabilityProvider;Lorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback$OnSwipeListener;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemSwipeCallback;->attachToRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V +PLorg/thoughtcrime/securesms/conversation/ConversationItemTouchListener;->(Lorg/thoughtcrime/securesms/conversation/ConversationItemTouchListener$Callback;)V +PLorg/thoughtcrime/securesms/conversation/ConversationMessage;->equals(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getDisplayBody(Landroid/content/Context;)Landroid/text/SpannableString; +PLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getMultiselectCollection()Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectCollection; +PLorg/thoughtcrime/securesms/conversation/ConversationMessage;->getThreadRecipient()Lorg/thoughtcrime/securesms/recipients/Recipient; +PLorg/thoughtcrime/securesms/conversation/ConversationMessage;->hasStyleLinks()Z +PLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider$onCreateMenu$1;->(Landroid/view/Menu;Z)V PLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider$onCreateMenu$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider$onCreateMenu$1;->invoke(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->applyTitleSpan(Landroid/view/MenuItem;Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->hideMenuItem(Landroid/view/Menu;I)V +PLorg/thoughtcrime/securesms/conversation/ConversationOptionsMenu$Provider;->setAfterFirstRenderMode(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel;->(Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel;->getSearchResults()Landroidx/lifecycle/LiveData; +PLorg/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter;->setStickers(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator;->(FFF)V +PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator;->(FFFLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator-IA;)V PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$BubblePositionInterpolator;->getInterpolation(F)F +PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$ClampingLinearInterpolator;->(FF)V +PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$ClampingLinearInterpolator;->(FFF)V PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper$ClampingLinearInterpolator;->getInterpolation(F)F +PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->dpToPx(I)I PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->update(Lorg/thoughtcrime/securesms/conversation/v2/items/InteractiveConversationElement;FF)V PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->updateBodyBubbleTransition(Ljava/util/List;FF)V PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->updateContactPhotoHolderTransition(Landroid/view/View;FF)V @@ -37965,103 +37431,517 @@ PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->upd PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->updateReactionsTransition(Landroid/view/View;FF)V PLorg/thoughtcrime/securesms/conversation/ConversationSwipeAnimationHelper;->updateReplyIconTransition(Landroid/view/View;FFF)V PLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->onSaveInstanceState()Landroid/os/Parcelable; +PLorg/thoughtcrime/securesms/conversation/ConversationTitleView;->setVerified(Z)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$1;->(Lkotlin/jvm/functions/Function0;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->()V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->(Lkotlin/jvm/functions/Function0;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->(Lorg/thoughtcrime/securesms/conversation/ConversationUpdateTick$OnTickListener;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onPause(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onResume(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onStart(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/ConversationUpdateTick;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda0;->()V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda1;->()V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V PLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda2;->run()V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper$$ExternalSyntheticLambda3;->run()V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->$r8$lambda$gcFI10LhFCaBEmJzQp8t_xBcU8U(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V PLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->$r8$lambda$h27hRrs_Rwv2sGlsmjqcW0dGIZI(Lorg/thoughtcrime/securesms/conversation/MarkReadHelper;J)V PLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->lambda$onViewsRevealed$0(J)V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->lambda$onViewsRevealed$1(J)V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->onViewsRevealed(J)V +PLorg/thoughtcrime/securesms/conversation/MarkReadHelper;->stopIgnoringViewReveals(Ljava/lang/Long;)V +PLorg/thoughtcrime/securesms/conversation/MessageStyler$Result;->getHasStyleLinks()Z +PLorg/thoughtcrime/securesms/conversation/MessageStyler;->boldStyle()Landroid/text/style/CharacterStyle; +PLorg/thoughtcrime/securesms/conversation/MessageStyler;->italicStyle()Landroid/text/style/CharacterStyle; +PLorg/thoughtcrime/securesms/conversation/MessageStyler;->monoStyle()Landroid/text/style/CharacterStyle; +PLorg/thoughtcrime/securesms/conversation/MessageStyler;->strikethroughStyle()Landroid/text/style/CharacterStyle; +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda3;->(Lio/reactivex/rxjava3/core/ObservableEmitter;J)V +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda4;->cancel()V +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda5;->(J)V +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository$$ExternalSyntheticLambda5;->subscribe(Lio/reactivex/rxjava3/core/ObservableEmitter;)V +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->$r8$lambda$2XiX_Dh66c_pIVZzuRFfoiDjp1A(JLio/reactivex/rxjava3/core/ObservableEmitter;)V PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->$r8$lambda$ej8HJIkF2PUVMbFRXSAuhVdCWz4(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->getScheduledMessageCount$lambda$6$lambda$5(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->getScheduledMessageCount$lambda$6(JLio/reactivex/rxjava3/core/ObservableEmitter;)V +PLorg/thoughtcrime/securesms/conversation/ScheduledMessagesRepository;->getScheduledMessageCount(J)Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->clearDraft()V +PLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->getPlaybackStateObserver()Landroidx/lifecycle/Observer; +PLorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView;->setListener(Lorg/thoughtcrime/securesms/conversation/VoiceNoteDraftView$Listener;)V +PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->()V +PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->(Landroidx/activity/ComponentActivity;)V +PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onPause(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onResume(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onStart(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->onStop(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/VoiceRecorderWakeLock;->release()V -PLorg/thoughtcrime/securesms/conversation/colors/AvatarColor;->random()Lorg/thoughtcrime/securesms/conversation/colors/AvatarColor; +PLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$NotSet;->()V +PLorg/thoughtcrime/securesms/conversation/colors/ChatColors$Id$NotSet;->()V +PLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getDefaultColor(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)I +PLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingFooterIconColor(Landroid/content/Context;Z)I +PLorg/thoughtcrime/securesms/conversation/colors/Colorizer;->getIncomingFooterTextColor(Landroid/content/Context;Z)I +PLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer$scrollListener$1;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V +PLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getLayerXfermode$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Landroid/graphics/PorterDuffXfermode; +PLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$getLayoutManager(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;)Landroidx/recyclerview/widget/LinearLayoutManager; +PLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->access$setUseLayer$p(Lorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;Z)V +PLorg/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer;->getLayoutManager()Landroidx/recyclerview/widget/LinearLayoutManager; PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)V PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$$ExternalSyntheticLambda0;->run()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->(Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;Ljava/lang/CharSequence;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->component1()Lorg/thoughtcrime/securesms/database/DraftTable$Drafts; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft;->component2()Ljava/lang/CharSequence; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1;->(Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$getShareOrDraftData$1;->invoke()Lkotlin/Pair; PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->$r8$lambda$SLYPkhFM2MVtyCpgHajSG6aOkdY(Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/database/DraftTable;Ljava/util/concurrent/Executor;Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/database/ThreadTable;Lorg/thoughtcrime/securesms/database/DraftTable;Ljava/util/concurrent/Executor;Lorg/thoughtcrime/securesms/conversation/ConversationIntents$Args;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->access$getShareOrDraftDataInternal(Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)Lkotlin/Pair; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->getShareOrDraftData(J)Lio/reactivex/rxjava3/core/Maybe; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->getShareOrDraftDataInternal(J)Lkotlin/Pair; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->loadDraftsInternal(J)Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository$DatabaseDraft; PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->saveDrafts$lambda$9(Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;Lorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;J)V PLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;->saveDrafts(JLorg/thoughtcrime/securesms/database/DraftTable$Drafts;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->(JLorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->(JLorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;ILkotlin/jvm/internal/DefaultConstructorMarker;)V PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->copy(JLorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;Lorg/thoughtcrime/securesms/database/DraftTable$Draft;)Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->copyAndSetDrafts$default(Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;JLorg/thoughtcrime/securesms/database/DraftTable$Drafts;ILjava/lang/Object;)Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->copyAndSetDrafts(JLorg/thoughtcrime/securesms/database/DraftTable$Drafts;)Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->getThreadId()J +PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->getVoiceNoteDraft()Lorg/thoughtcrime/securesms/database/DraftTable$Draft; PLorg/thoughtcrime/securesms/conversation/drafts/DraftState;->toDrafts()Lorg/thoughtcrime/securesms/database/DraftTable$Drafts; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1$1;->(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;Lorg/thoughtcrime/securesms/database/DraftTable$Drafts;)V PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1$1;->invoke(Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;)Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1;->(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1;->accept(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$1;->accept(Lkotlin/Pair;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel$loadShareOrDraftData$2;->apply(Lkotlin/Pair;)Lio/reactivex/rxjava3/core/MaybeSource; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->()V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->(JLorg/thoughtcrime/securesms/conversation/drafts/DraftRepository;)V +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->access$getStore$p(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;)Lorg/thoughtcrime/securesms/util/rx/RxStore; PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->access$saveDrafts(Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;)Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->getState()Lio/reactivex/rxjava3/core/Flowable; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->getVoiceNoteDraft()Lorg/thoughtcrime/securesms/database/DraftTable$Draft; +PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->loadShareOrDraftData(J)Lio/reactivex/rxjava3/core/Maybe; PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->onCleared()V PLorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel;->saveDrafts(Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;)Lorg/thoughtcrime/securesms/conversation/drafts/DraftState; +PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$$ExternalSyntheticLambda1;->(Landroidx/recyclerview/widget/RecyclerView;)V +PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator$$ExternalSyntheticLambda1;->run()V +PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->$r8$lambda$IJ0Uk3eauzGuBkd_D1PotCUrlIQ(Landroidx/recyclerview/widget/RecyclerView;)V +PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->animateAppearance(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;Landroidx/recyclerview/widget/RecyclerView$ItemAnimator$ItemHolderInfo;)Z PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->endAnimations()V PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->endSlideAnimations()V +PLorg/thoughtcrime/securesms/conversation/mutiselect/ConversationItemAnimator;->onAnimationFinished$lambda$4(Landroidx/recyclerview/widget/RecyclerView;)V +PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->$values()[Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; +PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->()V +PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->(Ljava/lang/String;I)V +PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference;->values()[Lorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$Difference; +PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration$WhenMappings;->()V +PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->consumePulseRequest(Lorg/thoughtcrime/securesms/conversation/ConversationAdapterBridge;)V PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->onPause(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$$ExternalSyntheticLambda1;->onFocusChange(Landroid/view/View;Z)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onPause(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onResume(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onStart(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$2;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$special$$inlined$doOnEachLayout$1;->(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2$special$$inlined$doOnEachLayout$1;->onLayoutChange(Landroid/view/View;IIIIIIII)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->$r8$lambda$GRwMc6fkPK5Q2WrXsl-thUTyAds(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;Landroid/view/View;Z)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->()V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->(Landroidx/fragment/app/Fragment;Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;Landroid/view/View;Landroid/view/ViewGroup;Lorg/thoughtcrime/securesms/components/ComposeText;)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->_init_$lambda$0(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;Landroid/view/View;Z)V PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->access$dismiss(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->access$getEmojiPopup$p(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;)Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsPopup; +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->dismiss()V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->onOrientationChange(Z)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2;->updateList(Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$Results;)V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$None;->()V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2$None;->()V +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->getResults()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2;->getSelection()Lio/reactivex/rxjava3/core/Observable; PLorg/thoughtcrime/securesms/conversation/v2/BubbleLayoutTransitionListener;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/v2/BubbleLayoutTransitionListener;->onPause(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/v2/BubbleLayoutTransitionListener;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->getVoiceNoteMediaController()Lorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController; PLorg/thoughtcrime/securesms/conversation/v2/ConversationActivity;->onDestroy()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda5;->createViewHolder(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$$ExternalSyntheticLambda7;->createViewHolder(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/View;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->canPlayContent()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->getDisplayMode()Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ConversationViewHolder;->showProjectionArea()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/View;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$IncomingMediaViewHolder;->bind(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/View;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$ThreadHeaderViewHolder;->bind(Ljava/lang/Object;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$onDetachedFromRecyclerView$$inlined$filterIsInstance$1;->()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$onDetachedFromRecyclerView$$inlined$filterIsInstance$1;->()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$onDetachedFromRecyclerView$$inlined$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean; PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2$onDetachedFromRecyclerView$$inlined$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->$r8$lambda$0GW66dll143qhTHiVUdlBHolclI(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->$r8$lambda$u2AJxgyeBquqI1nF9ok3s6g0b5Q(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->_init_$lambda$4(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->_init_$lambda$6(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getColorizer$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Lorg/thoughtcrime/securesms/conversation/colors/Colorizer; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getCondensedMode$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getHasWallpaper$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getInlineContent$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Lorg/thoughtcrime/securesms/conversation/ConversationMessage; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$getLifecycleOwner$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Landroidx/lifecycle/LifecycleOwner; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->access$get_selected$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;)Ljava/util/HashSet; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getClickListener()Lorg/thoughtcrime/securesms/conversation/ConversationAdapter$ItemClickListener; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getColorizer()Lorg/thoughtcrime/securesms/conversation/colors/Colorizer; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getDisplayMode()Lorg/thoughtcrime/securesms/conversation/ConversationItemDisplayMode; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getNextMessage(I)Lorg/thoughtcrime/securesms/database/model/MessageRecord; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getPreviousMessage(I)Lorg/thoughtcrime/securesms/database/model/MessageRecord; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getRequestManager()Lcom/bumptech/glide/RequestManager; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->getSearchQuery()Ljava/lang/String; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->hasNoConversationMessages()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->hasWallpaper()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->isParentInScroll()Z PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->onDetachedFromRecyclerView(Landroidx/recyclerview/widget/RecyclerView;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->onViewRecycled(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->onViewRecycled(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->setSearchQuery(Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;->updateSearchQuery(Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reminderStub$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reminderStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reviewBannerStub$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$reviewBannerStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$unverifiedBannerStub$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$unverifiedBannerStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$voiceNotePlayerStub$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$voiceNotePlayerStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearReminder()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearRequestReview()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearUnverifiedBanner()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->clearVoiceNotePlayer()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getReminderStub()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getReviewBannerStub()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getUnverifiedBannerStub()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->getVoiceNotePlayerStub()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->hide(Lorg/thoughtcrime/securesms/util/views/Stub;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView;->setListener(Lorg/thoughtcrime/securesms/conversation/v2/ConversationBannerView$Listener;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda14;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda16;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda18;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda19;->(Lkotlin/jvm/functions/Function1;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda20;->(Lkotlin/jvm/functions/Function1;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda21;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda22;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$$ExternalSyntheticLambda23;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$AttachmentKeyboardFragmentListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$BackPressedDelegate;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ComposeTextEventsListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ComposeTextEventsListener;->onFocusChange(Landroid/view/View;Z)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationBannerListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback$onOptionsMenuCreated$1;->(Landroidx/appcompat/widget/SearchView;Landroidx/appcompat/widget/SearchView$OnQueryTextListener;Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroid/view/Menu;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback$onOptionsMenuCreated$queryListener$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback;->clearExpiring()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ConversationOptionsMenuCallback;->onOptionsMenuCreated(Landroid/view/Menu;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DataObserver;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DataObserver;->onItemRangeChanged(II)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DisabledInputListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$InputPanelListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$KeyboardEvents;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2;Landroidx/recyclerview/widget/LinearLayoutManager;Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onPause(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onResume(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onStart(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$LastScrolledPositionUpdater;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$MotionEventRelayDrain;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollDateHeaderHelper;->bind(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$$ExternalSyntheticLambda0;->(Lkotlin/jvm/functions/Function1;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1;->invoke(J)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener$onScrolled$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->$r8$lambda$SqiWUifYWEV36mNfvnPsrkHWoAw(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->onScrolled$lambda$0(Lkotlin/jvm/functions/Function1;Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;->presentComposeDivider()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SearchEventListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SendButtonListener;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$SwipeAvailabilityProvider;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$VoiceMessageRecordingSessionCallbacks;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$binding$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$binding$3;->invoke(Lorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10;->invoke(Lj$/util/Optional;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$10;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$11;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$12;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$14;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15;->()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15;->()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15;->test(Ljava/lang/Object;Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$15;->test(Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16;->accept(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$16;->accept(Lorg/thoughtcrime/securesms/conversation/drafts/DraftState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17;->invoke(I)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$17;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18;->invoke(Lj$/util/Optional;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$18;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1;->()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1;->()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1;->test(Ljava/lang/Object;Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$1;->test(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$2;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$3;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$4;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$attachListener$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$doAfterFirstRender$conversationUpdateTick$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$draftViewModel$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$draftViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$5;->invoke()Ljava/lang/Object; PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$6;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$7;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeConversationThreadUi$8;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeInlineSearch$1$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeInlineSearch$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeLinkPreviews$1;->invoke(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeSearch$2;->invoke(Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$initializeStickerSuggestions$1;->invoke(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$inlineQueryController$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$inlineQueryController$2;->invoke()Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2;->invoke(Landroidx/lifecycle/SavedStateHandle;)Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$linkPreviewViewModel$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$motionEventRelay$2;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$motionEventRelay$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$moveToStartPosition$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$moveToStartPosition$1;->invoke()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Ljava/util/List;Lkotlin/jvm/internal/Ref$BooleanRef;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$$ExternalSyntheticLambda0;->run()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1$1;->run()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1;->(Landroid/view/View;Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4$invoke$lambda$1$$inlined$doAfterNextLayout$1;->onLayoutChange(Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->$r8$lambda$oOR6vln5-HH0T67uKvvWOaEanvw(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Ljava/util/List;Lkotlin/jvm/internal/Ref$BooleanRef;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->invoke$lambda$1(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Ljava/util/List;Lkotlin/jvm/internal/Ref$BooleanRef;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$observeConversationThread$4;->invoke(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentGroupCallJoinButton$2;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentTypingIndicator$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$presentTypingIndicator$2;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0;->(Lkotlin/jvm/functions/Function1;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0;->equals(Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0;->getFunctionDelegate()Lkotlin/Function; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$sam$androidx_lifecycle_Observer$0;->onChanged(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$scheduledMessagesStub$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$scheduledMessagesStub$2;->invoke()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$searchViewModel$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$searchViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$4;->invoke()Landroidx/lifecycle/ViewModelStore; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$4;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$5;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$5;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$6;->invoke()Landroidx/lifecycle/ViewModelProvider$Factory; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$activityViewModels$default$6;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$6;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$6;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$7;->invoke()Landroidx/lifecycle/ViewModelStore; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$7;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$8;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$8;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$9;->invoke()Landroidx/lifecycle/ViewModelProvider$Factory; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$special$$inlined$viewModels$default$9;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewModel$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$stickerViewModel$2;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$doAfterFirstRender(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getAdapter$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getAnimationsAllowed$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getComposeText(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/components/ComposeText; PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getComposeTextEventsListener$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ComposeTextEventsListener; PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getDataObserver$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$DataObserver; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getInlineQueryViewModel$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryViewModelV2; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getInputPanel(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/components/InputPanel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getLayoutManager$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Landroidx/recyclerview/widget/ConversationLayoutManager; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getMarkReadHelper$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/MarkReadHelper; PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getScrollListener$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getScrollToPositionDelegate$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/components/ScrollToPositionDelegate; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getSearchMenuItem$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Landroid/view/MenuItem; PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$getTextDraftSaveDebouncer$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Lorg/thoughtcrime/securesms/util/Debouncer; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$handleScheduledMessagesCountChange(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;I)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$invalidateOptionsMenu(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$isScrolledToBottom(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$isSearchRequested$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$onRecipientChanged(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentIdentityRecordsState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentRequestReviewState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$presentScrollButtons(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$setAnimationsAllowed$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Z)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$setScrollListener$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment$ScrollListener;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$setSearchMenuItem$p(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;Landroid/view/MenuItem;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->access$updateToggleButtonState(Lorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getDraftViewModel()Lorg/thoughtcrime/securesms/conversation/drafts/DraftViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getInlineQueryController()Lorg/thoughtcrime/securesms/conversation/ui/inlinequery/InlineQueryResultsControllerV2; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getLinkPreviewViewModel()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getMotionEventRelay()Lorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getScheduledMessagesStub()Lorg/thoughtcrime/securesms/util/views/Stub; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSearchNav()Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSearchViewModel()Lorg/thoughtcrime/securesms/conversation/ConversationSearchViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSendButton()Lorg/thoughtcrime/securesms/components/SendButton; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getSendEditButton()Landroid/widget/ImageButton; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getShareDataTimestampViewModel()Lorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getStickerViewModel()Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->getVoiceNoteMediaController()Lorg/thoughtcrime/securesms/components/voice/VoiceNoteMediaController; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->handleScheduledMessagesCountChange(I)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeInlineSearch()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeLinkPreviews()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeSearch()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->initializeStickerSuggestions()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->isScrolledToBottom()Z PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onDestroyView()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onPause()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->onRecipientChanged(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentGroupCallJoinButton()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentIdentityRecordsState(Lorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentRequestReviewState(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentScrollButtons(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->presentTypingIndicator()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationFragment;->updateToggleButtonState()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;Landroid/view/View;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->bind(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->getHeight()I +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->getItemView()Landroid/view/View; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations$DateHeaderViewHolder;->updateForWallpaper()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->access$timestamp(Lorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationMessageElement;)J +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->getHasWallpaper()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->setCurrentItems(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations;->updateUnreadState(Ljava/util/List;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda12;->(JJ)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda12;->run()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda14;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda14;->call()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda19;->(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda19;->call()Ljava/lang/Object; PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda9;->(J)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository$$ExternalSyntheticLambda9;->run()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$-gMXe-w-Xm5jHJapWlyQ6eOUlEE(JJ)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$ATtSNJzojyDhPrLSHCNff4Xrn4s(J)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$KdCOHPNqejWN1AhOnsjSsYWIQ1E(Lorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lj$/util/Optional; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->$r8$lambda$jYghkNuRsI_xLxRgZRxsCeMcFTc(Lorg/thoughtcrime/securesms/database/model/GroupRecord;Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->getReminder(Lorg/thoughtcrime/securesms/database/model/GroupRecord;)Lio/reactivex/rxjava3/core/Maybe; PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->markLastSeen$lambda$28(J)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->markLastSeen(J)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->setLastVisibleMessageTimestamp$lambda$5(JJ)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->setLastVisibleMessageTimestamp(JJ)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationRepository;->startExpirationTimeout(Ljava/util/List;)V PLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->equals(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->onComplete()V -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->onNext(Ljava/lang/Object;)V -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$16;->onNext(Ljava/util/List;)V -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3$$ExternalSyntheticLambda3;->cancel()V -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->$r8$lambda$V11cxEHo-PxLzOR7edRE3YltJBk(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$3;->apply$lambda$4$lambda$3(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$6;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->getHasMentions()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->getShowScrollButtons()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->getUnreadCount()I +PLorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;->toString()Ljava/lang/String; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$12;->apply(Lkotlin/Unit;Lj$/util/Optional;)Lj$/util/Optional; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$13;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$17;->onComplete()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$17;->onNext(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$17;->onNext(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4$$ExternalSyntheticLambda4;->cancel()V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->$r8$lambda$DeiphTJKC3SI_gAZ1faGZoiWX80(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$4;->apply$lambda$4$lambda$3(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$7;->invoke(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$canShowAsBubble$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1;->(Lorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$getRequestReviewState$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1;->test(Lj$/util/Optional;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$groupMemberServiceIds$1;->test(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1;->(ZZ)V +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel$setShowScrollButtonsForScrollPosition$1;->invoke(Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState;)Lorg/thoughtcrime/securesms/conversation/v2/ConversationScrollButtonState; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getGroupMemberServiceIds()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getHasMessageRequestState()Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getIdentityRecordsObservable()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getRecipient()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getReminder()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getRequestReviewState()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getScheduledMessagesCount()Lio/reactivex/rxjava3/core/Observable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getScrollButtonState()Lio/reactivex/rxjava3/core/Flowable; +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->getSearchQuery()Lio/reactivex/rxjava3/core/Observable; PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->markLastSeen()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->onCleared()V PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->setLastScrolled(J)V -PLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->equals(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/conversation/v2/ConversationViewModel;->setShowScrollButtonsForScrollPosition(ZZ)V +PLorg/thoughtcrime/securesms/conversation/v2/DisabledInputView;->setListener(Lorg/thoughtcrime/securesms/conversation/v2/DisabledInputView$Listener;)V +PLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->isGroup()Z +PLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->isUnverified()Z +PLorg/thoughtcrime/securesms/conversation/v2/IdentityRecordsState;->isVerified()Z +PLorg/thoughtcrime/securesms/conversation/v2/InputReadyState;->getGroupRecord()Lorg/thoughtcrime/securesms/database/model/GroupRecord; +PLorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay;->()V +PLorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay;->()V +PLorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay;->setDrain(Lorg/thoughtcrime/securesms/conversation/v2/MotionEventRelay$Drain;)V +PLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->()V +PLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$IndividualReviewState;Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$GroupReviewState;)V +PLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->(Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$IndividualReviewState;Lorg/thoughtcrime/securesms/conversation/v2/RequestReviewState$GroupReviewState;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/RequestReviewState;->shouldShowReviewBanner()Z +PLorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel;->()V +PLorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel;->()V +PLorg/thoughtcrime/securesms/conversation/v2/ShareDataTimestampViewModel;->getTimestamp()J +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1;->(Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;)V +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1;->apply(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel$stickers$1;->apply(Ljava/lang/String;)Lio/reactivex/rxjava3/core/SingleSource; +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->()V +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository;)V +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->(Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->access$getStickerSearchRepository$p(Lorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;)Lorg/thoughtcrime/securesms/stickers/StickerSearchRepository; +PLorg/thoughtcrime/securesms/conversation/v2/StickerSuggestionsViewModel;->getStickers()Lio/reactivex/rxjava3/core/Flowable; +PLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate;->()V +PLorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate;->(Landroidx/fragment/app/Fragment;Lorg/thoughtcrime/securesms/audio/AudioRecorder;Lorg/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate$SessionCallback;)V +PLorg/thoughtcrime/securesms/conversation/v2/computed/FormattedDate;->getValue()Ljava/lang/String; PLorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource;->load(Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/conversation/v2/data/ConversationDataSource;->load(Lorg/thoughtcrime/securesms/conversation/v2/data/ConversationElementKey;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel; PLorg/thoughtcrime/securesms/conversation/v2/data/ConversationElementKey$Companion;->()V @@ -38083,62 +37963,180 @@ PLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->areContentsTheS PLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->areItemsTheSame(Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->areItemsTheSame(Lorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;)Z PLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->getChangePayload(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/data/ThreadHeader;->getRecipientInfo()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo; PLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->equals(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallState;->getHasCapacity()Z +PLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->getState()Lio/reactivex/rxjava3/core/Flowable; PLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupCallViewModel;->onCleared()V PLorg/thoughtcrime/securesms/conversation/v2/groups/ConversationGroupViewModel;->onCleared()V +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData;->getChatColors()Lorg/thoughtcrime/securesms/conversation/colors/ChatColors; +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData;->getMask()Landroid/graphics/drawable/Drawable; +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsItemDecoration$onDraw$$inlined$filterIsInstance$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->(Lkotlin/jvm/functions/Function0;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getMask()Landroid/graphics/drawable/Drawable; +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->getOpacity()I +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->setCorners(Lorg/thoughtcrime/securesms/util/Projection$Corners;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable;->setLocalChatColors(Lorg/thoughtcrime/securesms/conversation/colors/ChatColors;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/ShrinkWrapLinearLayout;->onMeasure(II)V +PLorg/thoughtcrime/securesms/conversation/v2/items/ShrinkWrapLinearLayout;->shrinkWrapWidthMeasureSpec(I)I +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->addOnMeasureListener(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnMeasureListener;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->removeOnMeasureListener(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnMeasureListener;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;->setOnDispatchTouchEventListener(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout$OnDispatchTouchEventListener;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->$values()[Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->(Ljava/lang/String;IFF)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->getBottomPadding()F +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->getTopPadding()F +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->isEndingShape()Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;->isStartingShape()Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->access$getCollapsedSpacing$cp()F +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->access$getDefaultSpacing$cp()F +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->getCornersLTR()Lorg/thoughtcrime/securesms/util/Projection$Corners; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isSingularMessage(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isStartOfMessageCluster(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;Z)Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->isWithinClusteringTime(Lorg/thoughtcrime/securesms/database/model/MessageRecord;Lorg/thoughtcrime/securesms/database/model/MessageRecord;)Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape;->setBodyBubbleCorners(FFFF)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lorg/thoughtcrime/securesms/components/AvatarImageView;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Landroid/view/ViewGroup;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lcom/google/android/material/imageview/ShapeableImageView;Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView;Lorg/thoughtcrime/securesms/components/DeliveryStatusView;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/ExpirationTimerView;Landroid/view/View;Landroid/widget/Space;Lorg/thoughtcrime/securesms/components/AlertView;Z)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getAlert()Lorg/thoughtcrime/securesms/components/AlertView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getBody()Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getBodyWrapper()Landroid/view/ViewGroup; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getDeliveryStatus()Lorg/thoughtcrime/securesms/components/DeliveryStatusView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterBackground()Landroid/view/View; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterDate()Landroid/widget/TextView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterExpiry()Lorg/thoughtcrime/securesms/components/ExpirationTimerView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getFooterSpace()Landroid/widget/Space; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getReactions()Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getReply()Lcom/google/android/material/imageview/ShapeableImageView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getRoot()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getSenderBadge()Lorg/thoughtcrime/securesms/badges/BadgeImageView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getSenderName()Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->getSenderPhoto()Lorg/thoughtcrime/securesms/components/AvatarImageView; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;->isIncoming()Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridgeKt;->bridge(Lorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;)Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda0;->onLayoutChange(Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda3;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda4;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/conversation/ConversationAdapter$ItemClickListener;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$PassthroughClickListener;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$ReactionMeasureListener;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$bodyBubbleDrawable$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$bodyBubbleDrawable$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$bodyBubbleDrawable$1;->invoke()Lorg/thoughtcrime/securesms/conversation/v2/items/ChatColorsDrawable$ChatColorsData; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$footerDrawable$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$footerDrawable$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$replyDelegate$1;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder$senderDrawable$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->$r8$lambda$ocilDMoff9b132TfYhzB6ol1qqk(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->_init_$lambda$0(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;Landroid/view/View;IIIIIIII)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->bind(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->canPlayContent()Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->getConversationMessage()Lorg/thoughtcrime/securesms/conversation/ConversationMessage; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->getShape()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->invalidateFooterDrawable(Landroid/view/ViewGroup;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->isContentCondensed()Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->isForcedFooter()Z +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentAlert()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentDate()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentDeliveryStatus()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentFooterBackground()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentFooterEndPadding()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentFooterExpiry()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentReactions()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentSenderNameBackground()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->presentSenderNameColor()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->setConversationMessage(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->setShape(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape$MessageShape;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder;->showProjectionArea()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2;->invoke(Landroid/content/Context;Z)Ljava/lang/Integer; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme$getBodyTextColor$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getBodyBubbleColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)I +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)I +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getFooterBubbleColor(Lorg/thoughtcrime/securesms/conversation/ConversationMessage;)I +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme;->getReplyIconBackgroundColor()I +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils;->linkifyUrlLinks(Landroid/text/Spannable;ZLorg/thoughtcrime/securesms/util/UrlClickHandler;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->getShapeDelegate()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemShape; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemViewHolder;->getThemeDelegate()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState;->$values()[Lorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState; +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate$DisplayState;->(Ljava/lang/String;I)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Ljava/util/List;Landroid/view/View;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Landroid/widget/Space;Lorg/thoughtcrime/securesms/util/views/Stub;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->displayTuckedIntoBody()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate;->onPreMeasure()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$Companion;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener;->()V +PLorg/thoughtcrime/securesms/conversation/v2/items/V2OnDispatchTouchEventListener;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationContext;Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyBindingBridge;)V PLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onDestroyView()V +PLorg/thoughtcrime/securesms/conversationlist/ConversationListFragment;->onStop()V PLorg/thoughtcrime/securesms/conversationlist/ConversationListViewModel;->onCleared()V -PLorg/thoughtcrime/securesms/conversationlist/model/Conversation;->equals(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->getSelfProfileKey()Lorg/signal/libsignal/zkgroup/profiles/ProfileKey; -PLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->profileKeyOptional([B)Lj$/util/Optional; -PLorg/thoughtcrime/securesms/crypto/ProfileKeyUtil;->profileKeyOrNull([B)Lorg/signal/libsignal/zkgroup/profiles/ProfileKey; -PLorg/thoughtcrime/securesms/database/AttachmentTable;->getAttachment(Lorg/thoughtcrime/securesms/attachments/AttachmentId;)Lorg/thoughtcrime/securesms/attachments/DatabaseAttachment; -PLorg/thoughtcrime/securesms/database/CallTable;->getLatestRingingCalls()Ljava/util/List; -PLorg/thoughtcrime/securesms/database/CallTable;->markRingingCallsAsMissed()V +PLorg/thoughtcrime/securesms/conversationlist/chatfilter/ConversationListFilterPullView;->onSaveInstanceState()Landroid/os/Parcelable; +PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda13;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda13;->run()V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda1;->run()V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda26;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda26;->run()V -PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/recipients/RecipientId;)V -PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda5;->run()V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda6;->(Lorg/thoughtcrime/securesms/database/DatabaseObserver;J)V PLorg/thoughtcrime/securesms/database/DatabaseObserver$$ExternalSyntheticLambda6;->run()V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$2v1Sb-6JCd9xjyyzfbH5tKTRWy8(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$6H_TtixOHSa7Tr30medlqcHry2c(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$8PzBCQMLi_6Y7FOR98cRbpXw-Xk(Lorg/thoughtcrime/securesms/database/DatabaseObserver;JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V -PLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$XcpL0fyOGdTr1sc4d0z4i8eoe14(Lorg/thoughtcrime/securesms/database/DatabaseObserver;Lorg/thoughtcrime/securesms/recipients/RecipientId;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->$r8$lambda$ZjxWKgbWA1SSTmnWoVneQana_Lk(Lorg/thoughtcrime/securesms/database/DatabaseObserver;J)V -PLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyStoryObservers$35(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$notifyVerboseConversationListeners$20(J)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$registerScheduledMessageObserver$14(JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->lambda$unregisterObserver$18(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V -PLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyStoryObservers(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->notifyVerboseConversationListeners(Ljava/util/Set;)V +PLorg/thoughtcrime/securesms/database/DatabaseObserver;->registerScheduledMessageObserver(JLorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->unregisterMapped(Ljava/util/Map;Ljava/lang/Object;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->unregisterObserver(Lorg/thoughtcrime/securesms/database/DatabaseObserver$MessageObserver;)V PLorg/thoughtcrime/securesms/database/DatabaseObserver;->unregisterObserver(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/DatabaseTable;->notifyVerboseConversationListeners(Ljava/util/Set;)V PLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->(Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V PLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->addIfNotNull(Lorg/thoughtcrime/securesms/database/DraftTable$Draft;)V +PLorg/thoughtcrime/securesms/database/DraftTable$Drafts;->getDraftOfType(Ljava/lang/String;)Lorg/thoughtcrime/securesms/database/DraftTable$Draft; PLorg/thoughtcrime/securesms/database/DraftTable;->clearDrafts(J)V -PLorg/thoughtcrime/securesms/database/JobDatabase;->updateJobAfterRetry(Ljava/lang/String;JIJ[B)V PLorg/thoughtcrime/securesms/database/MessageTable$markExpireStarted$1;->(Ljava/util/Collection;)V PLorg/thoughtcrime/securesms/database/MessageTable$markExpireStarted$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/database/MessageTable$markExpireStarted$1;->invoke(Lorg/thoughtcrime/securesms/database/SQLiteDatabase;)V -PLorg/thoughtcrime/securesms/database/MessageTable;->getAllStoriesFor(Lorg/thoughtcrime/securesms/recipients/RecipientId;I)Lorg/thoughtcrime/securesms/database/MessageTable$Reader; PLorg/thoughtcrime/securesms/database/MessageTable;->getMessagePositionOnOrAfterTimestamp(JJ)I PLorg/thoughtcrime/securesms/database/MessageTable;->getMessagesForNotificationState(Ljava/util/Collection;)Landroid/database/Cursor; +PLorg/thoughtcrime/securesms/database/MessageTable;->getScheduledMessageCountForThread(J)I PLorg/thoughtcrime/securesms/database/MessageTable;->markExpireStarted(Ljava/util/Collection;)V PLorg/thoughtcrime/securesms/database/MessageTable;->setMessagesReadSince(JJ)Ljava/util/List; PLorg/thoughtcrime/securesms/database/MessageTable;->setReactionsSeen(JJ)V -PLorg/thoughtcrime/securesms/database/RecipientTable$GetOrInsertResult;->(Lorg/thoughtcrime/securesms/recipients/RecipientId;Z)V -PLorg/thoughtcrime/securesms/database/RecipientTable$GetOrInsertResult;->getRecipientId()Lorg/thoughtcrime/securesms/recipients/RecipientId; -PLorg/thoughtcrime/securesms/database/RecipientTable;->insertReleaseChannelRecipient()Lorg/thoughtcrime/securesms/recipients/RecipientId; -PLorg/thoughtcrime/securesms/database/RecipientTable;->setMuted(Lorg/thoughtcrime/securesms/recipients/RecipientId;J)V -PLorg/thoughtcrime/securesms/database/RecipientTable;->setProfileAvatar(Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isBundleKeyExchange(J)Z +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isFailedMessageType(J)Z +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPendingInsecureSmsFallbackType(J)Z +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPendingMessageType(J)Z +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isPendingSecureSmsFallbackType(J)Z +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isRateLimited(J)Z +PLorg/thoughtcrime/securesms/database/MessageTypes$-CC;->isSecureType(J)Z PLorg/thoughtcrime/securesms/database/RxDatabaseObserver$$ExternalSyntheticLambda1;->cancel()V -PLorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;->onChanged()V PLorg/thoughtcrime/securesms/database/RxDatabaseObserver;->$r8$lambda$6u1bbd117Cl1h38MfeI7BgZPo1A(Lorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;)V PLorg/thoughtcrime/securesms/database/RxDatabaseObserver;->databaseFlowable$lambda$1$lambda$0(Lorg/thoughtcrime/securesms/database/RxDatabaseObserver$RxObserver;)V PLorg/thoughtcrime/securesms/database/ThreadTable$setReadSince$1;->(Ljava/util/Map;Lorg/thoughtcrime/securesms/database/ThreadTable;Ljava/util/List;ZLkotlin/jvm/internal/Ref$BooleanRef;)V @@ -38152,184 +38150,113 @@ PLorg/thoughtcrime/securesms/database/ThreadTable;->setReadSince(Ljava/util/Map; PLorg/thoughtcrime/securesms/database/ThreadTable;->setReadSince(Lorg/thoughtcrime/securesms/notifications/v2/ConversationId;ZJ)Ljava/util/List; PLorg/thoughtcrime/securesms/database/ThreadTable;->update(JZZ)Z PLorg/thoughtcrime/securesms/database/identity/IdentityRecordList;->equals(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isKeyExchange()Z +PLorg/thoughtcrime/securesms/database/model/DisplayRecord;->isPending()Z +PLorg/thoughtcrime/securesms/database/model/MessageRecord;->isBundleKeyExchange()Z +PLorg/thoughtcrime/securesms/database/model/MessageRecord;->isJumbomoji(Landroid/content/Context;)Z PLorg/thoughtcrime/securesms/database/model/ProfileAvatarFileDetails;->equals(Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/database/model/StoryViewState$Companion$$ExternalSyntheticLambda3;->cancel()V PLorg/thoughtcrime/securesms/database/model/StoryViewState$Companion;->$r8$lambda$_YM1i9V93JIKhbRirbAeb_98VJw(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/model/StoryViewState$Companion;->getState$lambda$3$lambda$2(Lorg/thoughtcrime/securesms/database/DatabaseObserver$Observer;)V PLorg/thoughtcrime/securesms/database/model/ThreadRecord;->isForcedUnread()Z -PLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getProfileService()Lorg/whispersystems/signalservice/api/services/ProfileService; -PLorg/thoughtcrime/securesms/dependencies/ApplicationDependencies;->getSignalServiceMessageReceiver()Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver; -PLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideProfileService(Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;Lorg/whispersystems/signalservice/api/SignalWebSocket;)Lorg/whispersystems/signalservice/api/services/ProfileService; -PLorg/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider;->provideSignalServiceMessageReceiver(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;)Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver; -PLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version$Companion;->writeVersion(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->access$getObjectMapper$cp()Lcom/fasterxml/jackson/databind/ObjectMapper; -PLorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;->writeVersion(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/emoji/EmojiFiles;->getBaseDirectory(Landroid/content/Context;)Ljava/io/File; -PLorg/thoughtcrime/securesms/emoji/EmojiFiles;->openForReading(Landroid/content/Context;Ljava/lang/String;)Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->()V -PLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->(Landroid/net/Uri;)V -PLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->equals(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->getUri()Landroid/net/Uri; -PLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->hashCode()I -PLorg/thoughtcrime/securesms/emoji/EmojiPage$Disk;->toString()Ljava/lang/String; +PLorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding;->(Landroid/view/View;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lorg/thoughtcrime/securesms/components/AvatarImageView;Landroid/widget/LinearLayout;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Lcom/google/android/material/button/MaterialButton;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Landroid/view/View;Landroidx/constraintlayout/widget/ConstraintLayout;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V +PLorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/ConversationHeaderViewBinding; +PLorg/thoughtcrime/securesms/databinding/ConversationSearchNavBinding;->getRoot()Lorg/thoughtcrime/securesms/components/ConversationSearchBottomBar; +PLorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding;->(Landroid/view/View;Landroidx/constraintlayout/widget/Guideline;Landroidx/appcompat/widget/AppCompatImageView;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/components/transfercontrols/TransferProgressView;Landroidx/constraintlayout/widget/Guideline;)V +PLorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding; +PLorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding;->inflate(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/databinding/TransferControlsViewBinding; +PLorg/thoughtcrime/securesms/databinding/V2ConversationFragmentBinding;->getRoot()Lorg/thoughtcrime/securesms/components/InputAwareConstraintLayout; +PLorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;->(Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout;Lorg/thoughtcrime/securesms/badges/BadgeImageView;Lorg/thoughtcrime/securesms/components/AvatarImageView;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;Lorg/thoughtcrime/securesms/conversation/v2/items/ShrinkWrapLinearLayout;Lorg/thoughtcrime/securesms/components/ExpirationTimerView;Landroid/view/View;Landroid/widget/TextView;Lorg/thoughtcrime/securesms/reactions/ReactionsConversationView;Lcom/google/android/material/imageview/ShapeableImageView;Landroid/widget/Space;Lorg/thoughtcrime/securesms/components/emoji/EmojiTextView;)V +PLorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;->bind(Landroid/view/View;)Lorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding; +PLorg/thoughtcrime/securesms/databinding/V2ConversationItemTextOnlyIncomingBinding;->getRoot()Lorg/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemLayout; PLorg/thoughtcrime/securesms/emoji/EmojiPageCache$LoadResult$Immediate;->()V PLorg/thoughtcrime/securesms/emoji/EmojiPageCache$LoadResult$Immediate;->(Landroid/graphics/Bitmap;)V PLorg/thoughtcrime/securesms/emoji/EmojiPageCache$LoadResult$Immediate;->getBitmap()Landroid/graphics/Bitmap; -PLorg/thoughtcrime/securesms/emoji/EmojiPageCache;->clear()V -PLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->()V -PLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->()V -PLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->invoke(Landroid/net/Uri;)Lorg/thoughtcrime/securesms/emoji/EmojiPage; -PLorg/thoughtcrime/securesms/emoji/EmojiSource$Companion$loadRemoteBasedEmojis$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda4;->(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/emoji/JumboEmoji$$ExternalSyntheticLambda4;->run()V -PLorg/thoughtcrime/securesms/emoji/JumboEmoji;->$r8$lambda$1MZfAT8L5tWrN2t8lIV1c9aeWgA(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/emoji/JumboEmoji;->updateCurrentVersion$lambda$1$lambda$0(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->put(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Ljava/lang/String;Ljava/lang/String;)V -PLorg/thoughtcrime/securesms/fonts/FontFileMap$Companion;->setMap(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Lorg/thoughtcrime/securesms/fonts/FontFileMap;)V -PLorg/thoughtcrime/securesms/fonts/FontFileMap;->(Ljava/util/Map;)V -PLorg/thoughtcrime/securesms/fonts/FontFileMap;->access$getObjectMapper$cp()Lcom/fasterxml/jackson/databind/ObjectMapper; -PLorg/thoughtcrime/securesms/fonts/FontFileMap;->copy(Ljava/util/Map;)Lorg/thoughtcrime/securesms/fonts/FontFileMap; -PLorg/thoughtcrime/securesms/fonts/FontFileMap;->getMap()Ljava/util/Map; -PLorg/thoughtcrime/securesms/fonts/Fonts;->loadFontIntoTypeface(Landroid/content/Context;Lorg/thoughtcrime/securesms/fonts/FontVersion;Ljava/lang/String;)Landroid/graphics/Typeface; +PLorg/thoughtcrime/securesms/emoji/EmojiSource$maxEmojiLength$2;->invoke()Ljava/lang/Integer; +PLorg/thoughtcrime/securesms/emoji/EmojiSource$maxEmojiLength$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/emoji/EmojiSource;->getMaxEmojiLength()I +PLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->access$maxOrZero(Ljava/util/List;)I +PLorg/thoughtcrime/securesms/emoji/EmojiSourceKt;->maxOrZero(Ljava/util/List;)I +PLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController$RangeComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I +PLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4PlaybackController;->onScrolled(Landroidx/recyclerview/widget/RecyclerView;II)V PLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->onPause(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4ProjectionPlayerHolder;->onStop(Landroidx/lifecycle/LifecycleOwner;)V PLorg/thoughtcrime/securesms/giph/mp4/GiphyMp4VideoPlayer;->getExoPlayer()Landroidx/media3/exoplayer/ExoPlayer; -PLorg/thoughtcrime/securesms/jobmanager/InAppScheduler$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/jobmanager/InAppScheduler;)V -PLorg/thoughtcrime/securesms/jobmanager/InAppScheduler$$ExternalSyntheticLambda0;->run()V -PLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->$r8$lambda$hBEn_48T9NK-BhOmjEIwF4k281g(Lorg/thoughtcrime/securesms/jobmanager/InAppScheduler;)V -PLorg/thoughtcrime/securesms/jobmanager/InAppScheduler;->lambda$schedule$0()V PLorg/thoughtcrime/securesms/jobmanager/Job$Parameters$Builder;->setPriority(I)Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters$Builder; -PLorg/thoughtcrime/securesms/jobmanager/Job$Result;->failure()Lorg/thoughtcrime/securesms/jobmanager/Job$Result; -PLorg/thoughtcrime/securesms/jobmanager/Job$Result;->getBackoffInterval()J -PLorg/thoughtcrime/securesms/jobmanager/Job$Result;->retry(J)Lorg/thoughtcrime/securesms/jobmanager/Job$Result; -PLorg/thoughtcrime/securesms/jobmanager/Job;->onRetry()V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda0;->()V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda0;->accept(Ljava/lang/Object;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda13;->()V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda13;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda14;->(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobStorage;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda14;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda16;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda16;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda17;->(Lorg/thoughtcrime/securesms/jobmanager/JobController;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController$$ExternalSyntheticLambda17;->accept(Ljava/lang/Object;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$AFTJhIYz2IJLxa5cdEvspxyDnpk(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobmanager/JobController;->$r8$lambda$_WG2KEwBlGL1eFDhBUpj1kHB45I(Lorg/thoughtcrime/securesms/jobmanager/JobController;Lorg/thoughtcrime/securesms/jobmanager/Job;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$onFailure$3(Lorg/thoughtcrime/securesms/jobmanager/persistence/JobSpec;)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobmanager/JobController;->lambda$onFailure$4(Lorg/thoughtcrime/securesms/jobmanager/Job;)V -PLorg/thoughtcrime/securesms/jobmanager/JobController;->onFailure(Lorg/thoughtcrime/securesms/jobmanager/Job;)Ljava/util/List; -PLorg/thoughtcrime/securesms/jobmanager/JobController;->onRetry(Lorg/thoughtcrime/securesms/jobmanager/Job;J)V -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getBoolean(Ljava/lang/String;)Z -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getBooleanOrDefault(Ljava/lang/String;Z)Z -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getLong(Ljava/lang/String;)J -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->getString(Ljava/lang/String;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->hasBoolean(Ljava/lang/String;)Z -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->hasString(Ljava/lang/String;)Z -PLorg/thoughtcrime/securesms/jobmanager/JsonJobData;->throwIfAbsent(Ljava/util/Map;Ljava/lang/String;)V -PLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob; -PLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lkotlin/jvm/internal/DefaultConstructorMarker;)V -PLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->onRun()V -PLorg/thoughtcrime/securesms/jobs/AccountConsistencyWorkerJob;->onShouldRetry(Ljava/lang/Exception;)Z -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->()V -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->(JLorg/thoughtcrime/securesms/attachments/AttachmentId;Z)V -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;JLorg/thoughtcrime/securesms/attachments/AttachmentId;Z)V -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->constructQueueString(Lorg/thoughtcrime/securesms/attachments/AttachmentId;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->getFactoryKey()Ljava/lang/String; -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->onAdded()V -PLorg/thoughtcrime/securesms/jobs/AttachmentDownloadJob;->serialize()[B -PLorg/thoughtcrime/securesms/jobs/BaseJob;->getNextRunAttemptBackoff(ILjava/lang/Exception;)J PLorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob;->()V PLorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob;->()V PLorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;)V PLorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob;->enqueue()V PLorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob;->getFactoryKey()Ljava/lang/String; PLorg/thoughtcrime/securesms/jobs/ConversationShortcutUpdateJob;->serialize()[B -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob; -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1;->(Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/util/concurrent/CountDownLatch;)V -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$1;->invoke(Lorg/thoughtcrime/securesms/mediasend/Media;)V -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob$setAvatar$2;->(Ljava/util/concurrent/CountDownLatch;)V -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->access$getContext$p$s1046862181(Lorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;)Landroid/content/Context; -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->onRun()V -PLorg/thoughtcrime/securesms/jobs/CreateReleaseChannelJob;->setAvatar(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V -PLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob; -PLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/recipients/Recipient;ZLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob-IA;)V -PLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->onRun()V -PLorg/thoughtcrime/securesms/jobs/DirectoryRefreshJob;->shouldTrace()Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda0;->()V -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda1;->(Ljava/lang/String;)V -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda1;->test(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda2;->(Ljava/lang/String;)V -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda2;->test(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob$$ExternalSyntheticLambda3;->()V -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->$r8$lambda$QoH7dcHnoANVuwa796Z9UVq8P10(Ljava/lang/String;Ljava/io/File;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->$r8$lambda$svSYKFZ54wbzF4p08Dr861zOX4Y(Ljava/lang/String;Ljava/io/File;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->clearOldEmojiData(Landroid/content/Context;Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->lambda$clearOldEmojiData$2(Ljava/lang/String;Ljava/io/File;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->lambda$clearOldEmojiData$3(Ljava/lang/String;Ljava/io/File;)Z -PLorg/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob;->markComplete(Lorg/thoughtcrime/securesms/emoji/EmojiFiles$Version;)V -PLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getDependencySpecsThatDependOnJob(Ljava/lang/String;)Ljava/util/List; -PLorg/thoughtcrime/securesms/jobs/FastJobStorage;->getSingleLayerOfDependencySpecsThatDependOnJob(Ljava/lang/String;)Ljava/util/List; -PLorg/thoughtcrime/securesms/jobs/FastJobStorage;->updateJobAfterRetry(Ljava/lang/String;JIJ[B)V -PLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$onRun$listener$1;->onSuccess(Landroid/graphics/Typeface;)V -PLorg/thoughtcrime/securesms/jobs/FontDownloaderJob$onRun$listener$1;->onSuccess(Ljava/lang/Object;)V -PLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob; -PLorg/thoughtcrime/securesms/jobs/GroupRingCleanupJob;->onRun()V -PLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob; -PLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob-IA;)V -PLorg/thoughtcrime/securesms/jobs/MultiDeviceProfileKeyUpdateJob;->onFailure()V -PLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->onFailure()V -PLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->onShouldRetry(Ljava/lang/Exception;)Z -PLorg/thoughtcrime/securesms/jobs/PreKeysSyncJob;->syncPreKeys(Lorg/whispersystems/signalservice/api/push/ServiceIdType;Lorg/whispersystems/signalservice/api/push/ServiceId;Lorg/whispersystems/signalservice/api/SignalServiceAccountDataStore;Lorg/thoughtcrime/securesms/crypto/storage/PreKeyMetadataStore;)V -PLorg/thoughtcrime/securesms/jobs/ProfileUploadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/ProfileUploadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/ProfileUploadJob; -PLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;Lorg/thoughtcrime/securesms/jobs/ProfileUploadJob-IA;)V -PLorg/thoughtcrime/securesms/jobs/ProfileUploadJob;->onFailure()V -PLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/RefreshAttributesJob; -PLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;ZLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob-IA;)V -PLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->onFailure()V -PLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->onRun()V -PLorg/thoughtcrime/securesms/jobs/RefreshAttributesJob;->onShouldRetry(Ljava/lang/Exception;)Z -PLorg/thoughtcrime/securesms/jobs/RotateCertificateJob$1;->()V -PLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->onFailure()V -PLorg/thoughtcrime/securesms/jobs/RotateCertificateJob;->onShouldRetry(Ljava/lang/Exception;)Z -PLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob; -PLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->getLocaleCodes()Ljava/util/List; -PLorg/thoughtcrime/securesms/jobs/StoryOnboardingDownloadJob;->onRun()V -PLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobmanager/Job; -PLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob$Factory;->create(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;[B)Lorg/thoughtcrime/securesms/jobs/ThreadUpdateJob; -PLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->(Lorg/thoughtcrime/securesms/jobmanager/Job$Parameters;JLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob-IA;)V -PLorg/thoughtcrime/securesms/jobs/ThreadUpdateJob;->onRun()V -PLorg/thoughtcrime/securesms/keyvalue/AccountValues;->getDeviceName()Ljava/lang/String; -PLorg/thoughtcrime/securesms/keyvalue/CertificateType;->values()[Lorg/thoughtcrime/securesms/keyvalue/CertificateType; -PLorg/thoughtcrime/securesms/keyvalue/EmojiValues;->getJumboEmojiSheets(I)Ljava/util/HashSet; -PLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues$PhoneNumberListingMode;->isDiscoverable()Z -PLorg/thoughtcrime/securesms/keyvalue/PhoneNumberPrivacyValues;->getAllCertificateTypes()Ljava/util/Collection; -PLorg/thoughtcrime/securesms/keyvalue/ReleaseChannelValues;->setReleaseChannelRecipientId(Lorg/thoughtcrime/securesms/recipients/RecipientId;)V -PLorg/thoughtcrime/securesms/keyvalue/StoryValues;->setHasDownloadedOnboardingStory(Z)V -PLorg/thoughtcrime/securesms/keyvalue/SvrValues;->getMasterKey()Lorg/whispersystems/signalservice/api/kbs/MasterKey; -PLorg/thoughtcrime/securesms/keyvalue/SvrValues;->getRecoveryPassword()Ljava/lang/String; -PLorg/thoughtcrime/securesms/keyvalue/SvrValues;->isRegistrationLockEnabled()Z +PLorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;->values()[Lorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme; +PLorg/thoughtcrime/securesms/keyvalue/SettingsValues;->isLinkPreviewsEnabled()Z +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Companion;->forNoLinks()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState$Creator;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->(Ljava/lang/String;ZZLorg/thoughtcrime/securesms/linkpreview/LinkPreview;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository$Error;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->(Ljava/lang/String;ZZLorg/thoughtcrime/securesms/linkpreview/LinkPreview;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository$Error;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->hasContent()Z +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;->hasLinks()Z +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$Companion;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedLinkPreviewState$2;->invoke()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1;->(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2$savedStateDisposable$1;->invoke(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->(Landroidx/lifecycle/SavedStateHandle;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;Z)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->(Landroidx/lifecycle/SavedStateHandle;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewRepository;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->access$setSavedLinkPreviewState(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->getLinkPreviewState()Lio/reactivex/rxjava3/core/Flowable; +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->getSavedLinkPreviewState()Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState; PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->onCleared()V +PLorg/thoughtcrime/securesms/linkpreview/LinkPreviewViewModelV2;->setSavedLinkPreviewState(Lorg/thoughtcrime/securesms/linkpreview/LinkPreviewState;)V +PLorg/thoughtcrime/securesms/logsubmit/LogSectionNotifications$$ExternalSyntheticApiModelOutline2;->m(Landroid/app/NotificationChannel;)Z PLorg/thoughtcrime/securesms/main/MainActivityListHostFragment;->onDestroyView()V -PLorg/thoughtcrime/securesms/mediasend/Media$1;->()V -PLorg/thoughtcrime/securesms/mediasend/Media;->()V -PLorg/thoughtcrime/securesms/mediasend/Media;->(Landroid/net/Uri;Ljava/lang/String;JIIJJZZLj$/util/Optional;Lj$/util/Optional;Lj$/util/Optional;)V -PLorg/thoughtcrime/securesms/mediasend/Media;->getUri()Landroid/net/Uri; -PLorg/thoughtcrime/securesms/messages/IncomingMessageObserver;->getDecryptionDrained()Z -PLorg/thoughtcrime/securesms/mms/PartAuthority;->getEmojiFilename(Landroid/net/Uri;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/megaphone/BasicMegaphoneView$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/megaphone/Megaphone;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)V +PLorg/thoughtcrime/securesms/megaphone/BasicMegaphoneView$$ExternalSyntheticLambda2;->(Lorg/thoughtcrime/securesms/megaphone/Megaphone;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)V +PLorg/thoughtcrime/securesms/megaphone/BasicMegaphoneView;->(Landroid/content/Context;)V +PLorg/thoughtcrime/securesms/megaphone/BasicMegaphoneView;->init(Landroid/content/Context;)V +PLorg/thoughtcrime/securesms/megaphone/BasicMegaphoneView;->onAttachedToWindow()V +PLorg/thoughtcrime/securesms/megaphone/BasicMegaphoneView;->present(Lorg/thoughtcrime/securesms/megaphone/Megaphone;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)V +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->canSnooze()Z +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->getBody()Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->getButtonText()Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->getImageRes()I +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->getOnVisibleListener()Lorg/thoughtcrime/securesms/megaphone/Megaphone$EventListener; +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->getSecondaryButtonText()Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->getTitle()Lorg/thoughtcrime/securesms/megaphone/MegaphoneText; +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->hasButton()Z +PLorg/thoughtcrime/securesms/megaphone/Megaphone;->hasSecondaryButton()Z +PLorg/thoughtcrime/securesms/megaphone/MegaphoneText;->hasText()Z +PLorg/thoughtcrime/securesms/megaphone/MegaphoneText;->resolve(Landroid/content/Context;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/megaphone/MegaphoneViewBuilder;->buildBasicMegaphone(Landroid/content/Context;Lorg/thoughtcrime/securesms/megaphone/Megaphone;Lorg/thoughtcrime/securesms/megaphone/MegaphoneActionController;)Landroid/view/View; +PLorg/thoughtcrime/securesms/messagerequests/GroupInfo;->getDescription()Ljava/lang/String; +PLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component1()Lorg/thoughtcrime/securesms/recipients/Recipient; +PLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component2()Lorg/thoughtcrime/securesms/messagerequests/GroupInfo; +PLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component3()Ljava/util/List; +PLorg/thoughtcrime/securesms/messagerequests/MessageRequestRecipientInfo;->component4()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState; +PLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->equals(Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/messagerequests/MessageRequestState;->getState()Lorg/thoughtcrime/securesms/messagerequests/MessageRequestState$State; +PLorg/thoughtcrime/securesms/mms/AttachmentManager;->isAttachmentPresent()Z +PLorg/thoughtcrime/securesms/mms/ImageSlide;->hasPlaceholder()Z +PLorg/thoughtcrime/securesms/mms/Slide;->asAttachment()Lorg/thoughtcrime/securesms/attachments/Attachment; +PLorg/thoughtcrime/securesms/mms/Slide;->getCaption()Lj$/util/Optional; +PLorg/thoughtcrime/securesms/mms/Slide;->getFileSize()J +PLorg/thoughtcrime/securesms/mms/Slide;->getPlaceholderBlur()Lorg/thoughtcrime/securesms/blurhash/BlurHash; +PLorg/thoughtcrime/securesms/mms/SlideDeck$$ExternalSyntheticLambda0;->()V +PLorg/thoughtcrime/securesms/mms/SlideDeck$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z PLorg/thoughtcrime/securesms/notifications/MarkReadReceiver;->()V PLorg/thoughtcrime/securesms/notifications/MarkReadReceiver;->process(Ljava/util/List;)V -PLorg/thoughtcrime/securesms/notifications/NotificationCancellationHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/NotificationManager;)[Landroid/service/notification/StatusBarNotification; PLorg/thoughtcrime/securesms/notifications/NotificationCancellationHelper;->()V PLorg/thoughtcrime/securesms/notifications/NotificationCancellationHelper;->cancelAllMessageNotifications(Landroid/content/Context;Ljava/util/Set;)V PLorg/thoughtcrime/securesms/notifications/NotificationCancellationHelper;->cancelLegacy(Landroid/content/Context;I)V @@ -38371,124 +38298,134 @@ PLorg/thoughtcrime/securesms/notifications/v2/NotificationState;->toString()Ljav PLorg/thoughtcrime/securesms/notifications/v2/NotificationStateProvider;->()V PLorg/thoughtcrime/securesms/notifications/v2/NotificationStateProvider;->()V PLorg/thoughtcrime/securesms/notifications/v2/NotificationStateProvider;->constructNotificationState(Ljava/util/Map;Lorg/thoughtcrime/securesms/notifications/profiles/NotificationProfile;)Lorg/thoughtcrime/securesms/notifications/v2/NotificationState; -PLorg/thoughtcrime/securesms/permissions/Permissions$$ExternalSyntheticLambda0;->(Landroid/content/Context;)V -PLorg/thoughtcrime/securesms/permissions/Permissions$$ExternalSyntheticLambda0;->test(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/permissions/Permissions;->$r8$lambda$Q0AcdMcPXUgr1QQ_HDTcoSx0sHo(Landroid/content/Context;Ljava/lang/String;)Z -PLorg/thoughtcrime/securesms/permissions/Permissions;->()V -PLorg/thoughtcrime/securesms/permissions/Permissions;->hasAll(Landroid/content/Context;[Ljava/lang/String;)Z -PLorg/thoughtcrime/securesms/permissions/Permissions;->isRuntimePermissionsRequired()Z -PLorg/thoughtcrime/securesms/permissions/Permissions;->lambda$hasAll$2(Landroid/content/Context;Ljava/lang/String;)Z PLorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference;->equals(Ljava/lang/Object;)Z -PLorg/thoughtcrime/securesms/profiles/AvatarHelper;->getOutputStream(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;Z)Ljava/io/OutputStream; -PLorg/thoughtcrime/securesms/profiles/AvatarHelper;->setAvatar(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/io/InputStream;)V -PLorg/thoughtcrime/securesms/profiles/ProfileName;->asGiven(Ljava/lang/String;)Lorg/thoughtcrime/securesms/profiles/ProfileName; -PLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda10;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;J)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda10;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda1;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;Ljava/io/OutputStream;Landroid/net/Uri;Landroid/content/Context;)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda1;->call()Ljava/lang/Object; -PLorg/thoughtcrime/securesms/providers/BlobProvider$$ExternalSyntheticLambda9;->(JLandroid/net/Uri;)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$2;->()V -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Ljava/io/InputStream;J)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->(Lorg/thoughtcrime/securesms/providers/BlobProvider;Ljava/io/InputStream;JLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder-IA;)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->buildBlobSpec(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder;->createForSingleSessionOnDisk(Landroid/content/Context;)Landroid/net/Uri; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$fgetid(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetData(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetFileName(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetFileSize(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)J -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetId(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetMimeType(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->-$$Nest$mgetStorageType(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->(Ljava/io/InputStream;Ljava/lang/String;Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;Ljava/lang/String;Ljava/lang/String;J)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->(Ljava/io/InputStream;Ljava/lang/String;Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;Ljava/lang/String;Ljava/lang/String;JLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec-IA;)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getData()Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getFileName()Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getFileSize()J -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getId()Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getMimeType()Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;->getStorageType()Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->$values()[Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->-$$Nest$mencode(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->-$$Nest$misMemory(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Z -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->-$$Nest$smdecode(Ljava/lang/String;)Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->()V -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->(Ljava/lang/String;ILjava/lang/String;Z)V -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->decode(Ljava/lang/String;)Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->encode()Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->isMemory()Z -PLorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;->values()[Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->$r8$lambda$hszeKLE-J5rLAuyYe0jTaWcOLg4(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;JLjava/io/File;)Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->$r8$lambda$vEFatZFK1evY8Xp8zObuRkcU_8Q(Lorg/thoughtcrime/securesms/providers/BlobProvider;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;Ljava/io/OutputStream;Landroid/net/Uri;Landroid/content/Context;)Landroid/net/Uri; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->-$$Nest$mwriteBlobSpecToDisk(Lorg/thoughtcrime/securesms/providers/BlobProvider;Landroid/content/Context;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Landroid/net/Uri; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->buildFileName(Ljava/lang/String;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->buildUri(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Landroid/net/Uri; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->forData(Ljava/io/InputStream;J)Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobBuilder; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->getAttachmentSecret(Landroid/content/Context;)Lorg/thoughtcrime/securesms/crypto/AttachmentSecret; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->getBlobRepresentation(Landroid/content/Context;Landroid/net/Uri;Lorg/thoughtcrime/securesms/util/IOFunction;Lorg/thoughtcrime/securesms/util/IOFunction;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->getDirectory(Lorg/thoughtcrime/securesms/providers/BlobProvider$StorageType;)Ljava/lang/String; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->getStream(Landroid/content/Context;Landroid/net/Uri;)Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->getStream(Landroid/content/Context;Landroid/net/Uri;J)Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->isAuthority(Landroid/net/Uri;)Z -PLorg/thoughtcrime/securesms/providers/BlobProvider;->lambda$getStream$1(Landroid/content/Context;JLjava/io/File;)Ljava/io/InputStream; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->lambda$writeBlobSpecToDiskAsync$4(Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;Ljava/io/OutputStream;Landroid/net/Uri;Landroid/content/Context;)Landroid/net/Uri; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->waitUntilInitialized()V -PLorg/thoughtcrime/securesms/providers/BlobProvider;->writeBlobSpecToDisk(Landroid/content/Context;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Landroid/net/Uri; -PLorg/thoughtcrime/securesms/providers/BlobProvider;->writeBlobSpecToDiskAsync(Landroid/content/Context;Lorg/thoughtcrime/securesms/providers/BlobProvider$BlobSpec;)Ljava/util/concurrent/Future; -PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda4;->contentsMatch(Ljava/lang/Object;Ljava/lang/Object;)Z +PLorg/thoughtcrime/securesms/preferences/widgets/NotificationPrivacyPreference;->isDisplayContact()Z +PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda0;->run()V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda3;->onChanged(Ljava/lang/Object;)V PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda7;->(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda7;->run()V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda9;->(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient$$ExternalSyntheticLambda9;->run()V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$4o-q--s8xb4fbde9teliyQxlyww(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$CYcq6dHxZW6RfEGMe0s6kvofKaE(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$pGM0bNiB06y_fkMUloVDwF8BcLs(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->$r8$lambda$snuajGLvOLM6I1QDJohSseUuY1E(Lorg/thoughtcrime/securesms/recipients/LiveRecipient;Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$new$0(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$new$1(Lorg/thoughtcrime/securesms/recipients/Recipient;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$observeForever$6(Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->lambda$removeForeverObserver$7(Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V +PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->observeForever(Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V PLorg/thoughtcrime/securesms/recipients/LiveRecipient;->removeForeverObserver(Lorg/thoughtcrime/securesms/recipients/RecipientForeverObserver;)V -PLorg/thoughtcrime/securesms/recipients/Recipient$$ExternalSyntheticLambda3;->()V -PLorg/thoughtcrime/securesms/recipients/Recipient;->getProfileKey()[B -PLorg/thoughtcrime/securesms/recipients/Recipient;->shouldHideStory()Z -PLorg/thoughtcrime/securesms/recipients/RecipientUtil;->toSignalServiceAddress(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; -PLorg/thoughtcrime/securesms/registration/viewmodel/RegistrationViewModel$$ExternalSyntheticLambda3;->()V -PLorg/thoughtcrime/securesms/registration/viewmodel/RegistrationViewModel$$ExternalSyntheticLambda3;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->()V -PLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->()V -PLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->insertReleaseChannelMessage$default(Lorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/lang/String;JLjava/lang/String;IILjava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Lorg/thoughtcrime/securesms/database/model/StoryType;ILjava/lang/Object;)Lorg/thoughtcrime/securesms/database/MessageTable$InsertResult; -PLorg/thoughtcrime/securesms/releasechannel/ReleaseChannel;->insertReleaseChannelMessage(Lorg/thoughtcrime/securesms/recipients/RecipientId;Ljava/lang/String;JLjava/lang/String;IILjava/lang/String;Ljava/lang/String;Lorg/thoughtcrime/securesms/database/model/databaseprotos/BodyRangeList;Lorg/thoughtcrime/securesms/database/model/StoryType;)Lorg/thoughtcrime/securesms/database/MessageTable$InsertResult; +PLorg/thoughtcrime/securesms/recipients/Recipient;->getCombinedAboutAndEmoji()Ljava/lang/String; +PLorg/thoughtcrime/securesms/recipients/Recipient;->getContactUri()Landroid/net/Uri; +PLorg/thoughtcrime/securesms/recipients/Recipient;->getNotificationChannel()Ljava/lang/String; +PLorg/thoughtcrime/securesms/recipients/Recipient;->getPhoneNumberSharing()Lorg/thoughtcrime/securesms/database/RecipientTable$PhoneNumberSharingState; +PLorg/thoughtcrime/securesms/recipients/Recipient;->shouldShowE164()Z PLorg/thoughtcrime/securesms/service/ExpiringMessageManager$$ExternalSyntheticLambda0;->()V PLorg/thoughtcrime/securesms/service/ExpiringMessageManager;->scheduleDeletion(Ljava/util/List;)V +PLorg/thoughtcrime/securesms/stickers/StickerSearchRepository;->searchByEmoji(Ljava/lang/String;)Lio/reactivex/rxjava3/core/Single; PLorg/thoughtcrime/securesms/stories/tabs/ConversationListTabsViewModel;->onCleared()V +PLorg/thoughtcrime/securesms/util/AppForegroundObserver;->removeListener(Lorg/thoughtcrime/securesms/util/AppForegroundObserver$Listener;)V +PLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/NotificationManager;Ljava/lang/String;Ljava/lang/String;)Landroid/app/NotificationChannel; +PLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline1;->m(Landroid/app/NotificationManager;)Z +PLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline2;->m(Landroid/app/NotificationManager;)I +PLorg/thoughtcrime/securesms/util/BubbleUtil$$ExternalSyntheticApiModelOutline3;->m(Landroid/app/NotificationManager;)Z PLorg/thoughtcrime/securesms/util/BubbleUtil$BubbleState;->$values()[Lorg/thoughtcrime/securesms/util/BubbleUtil$BubbleState; PLorg/thoughtcrime/securesms/util/BubbleUtil$BubbleState;->()V PLorg/thoughtcrime/securesms/util/BubbleUtil$BubbleState;->(Ljava/lang/String;I)V +PLorg/thoughtcrime/securesms/util/BubbleUtil;->()V +PLorg/thoughtcrime/securesms/util/ConversationUtil;->()V +PLorg/thoughtcrime/securesms/util/ConversationUtil;->getChannelId(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/util/ConversationUtil;->getShortcutId(Lorg/thoughtcrime/securesms/recipients/RecipientId;)Ljava/lang/String; PLorg/thoughtcrime/securesms/util/ConversationUtil;->refreshRecipientShortcuts()V +PLorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/DateUtils$sameDayDateFormat$2;->invoke()Ljava/text/SimpleDateFormat; +PLorg/thoughtcrime/securesms/util/DateUtils;->getConversationDateHeaderString(Landroid/content/Context;Ljava/util/Locale;J)Ljava/lang/String; +PLorg/thoughtcrime/securesms/util/DateUtils;->isSameExtendedRelativeTimestamp(JJ)Z PLorg/thoughtcrime/securesms/util/Debouncer;->clear()V -PLorg/thoughtcrime/securesms/util/FeatureFlags;->getDefaultMaxBackoff()J -PLorg/thoughtcrime/securesms/util/JsonUtils;->fromJson([BLjava/lang/Class;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate$lazyDefault$2;->(Lkotlin/jvm/functions/Function0;)V +PLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate$lazyDefault$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V +PLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->getLazyDefault()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->getValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/DefaultSavedStateHandleDelegate;->setValue(Ljava/lang/Object;Lkotlin/reflect/KProperty;Ljava/lang/Object;)V PLorg/thoughtcrime/securesms/util/LeakyBucketLimiter$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/util/LeakyBucketLimiter;)V PLorg/thoughtcrime/securesms/util/LeakyBucketLimiter$$ExternalSyntheticLambda0;->run()V PLorg/thoughtcrime/securesms/util/LeakyBucketLimiter;->$r8$lambda$1L8FIPWGmHakh7u9Krsm8K4DSjQ(Lorg/thoughtcrime/securesms/util/LeakyBucketLimiter;)V PLorg/thoughtcrime/securesms/util/LeakyBucketLimiter;->drip()V PLorg/thoughtcrime/securesms/util/LeakyBucketLimiter;->run(Ljava/lang/Runnable;)V +PLorg/thoughtcrime/securesms/util/LongClickMovementMethod$1;->(Lorg/thoughtcrime/securesms/util/LongClickMovementMethod;)V +PLorg/thoughtcrime/securesms/util/LongClickMovementMethod;->(Landroid/content/Context;)V +PLorg/thoughtcrime/securesms/util/LongClickMovementMethod;->getInstance(Landroid/content/Context;)Lorg/thoughtcrime/securesms/util/LongClickMovementMethod; +PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;IIII)V +PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$$ExternalSyntheticLambda0;->onAnimationUpdate(Landroid/animation/ValueAnimator;)V PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper$3;->onStop(Landroidx/lifecycle/LifecycleOwner;)V +PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->$r8$lambda$T0JnL_tDtAWK4RNMpbrK8xUunio(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;IIIILandroid/animation/ValueAnimator;)V PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->access$getAnimator$p(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;)Landroid/animation/ValueAnimator; PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->access$getSetStatusBarColor$p(Lorg/thoughtcrime/securesms/util/Material3OnScrollHelper;)Lkotlin/jvm/functions/Function1; PLorg/thoughtcrime/securesms/util/Material3OnScrollHelper;->getPreviousStatusBarColor()I -PLorg/thoughtcrime/securesms/util/MediaUtil;->isVideo(Ljava/lang/String;)Z -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda0;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda3;->(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda3;->call()Ljava/lang/Object; -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda4;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/thoughtcrime/securesms/recipients/Recipient;)V -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda4;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/thoughtcrime/securesms/util/ProfileUtil$$ExternalSyntheticLambda5;->(Lorg/thoughtcrime/securesms/recipients/Recipient;)V -PLorg/thoughtcrime/securesms/util/ProfileUtil;->$r8$lambda$64DRPwLhDKidiYVBrJ1oGsaeSVY(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/internal/ServiceResponse;)Lorg/signal/libsignal/protocol/util/Pair; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->$r8$lambda$cqO5Ws54dRBOxkD_sPlVLlSYwIg(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->$r8$lambda$dDuBqdOM1yCYB_18NZWtjJd7BlA(Lorg/whispersystems/signalservice/api/services/ProfileService;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;)Lio/reactivex/rxjava3/core/SingleSource; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->lambda$retrieveProfile$0(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->lambda$retrieveProfile$1(Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/internal/ServiceResponse;)Lorg/signal/libsignal/protocol/util/Pair; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->lambda$retrieveProfile$2(Lorg/whispersystems/signalservice/api/services/ProfileService;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;)Lio/reactivex/rxjava3/core/SingleSource; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->retrieveProfile(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Z)Lio/reactivex/rxjava3/core/Single; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->retrieveProfileSync(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Z)Lorg/whispersystems/signalservice/api/profiles/ProfileAndCredential; -PLorg/thoughtcrime/securesms/util/ProfileUtil;->toSignalServiceAddress(Landroid/content/Context;Lorg/thoughtcrime/securesms/recipients/Recipient;)Lorg/whispersystems/signalservice/api/push/SignalServiceAddress; -PLorg/thoughtcrime/securesms/util/SoftHashMap;->clear()V -PLorg/thoughtcrime/securesms/util/TextSecurePreferences;->isUniversalUnidentifiedAccess(Landroid/content/Context;)Z +PLorg/thoughtcrime/securesms/util/MediaUtil;->isInstantVideoSupported(Lorg/thoughtcrime/securesms/mms/Slide;)Z +PLorg/thoughtcrime/securesms/util/NullableSavedStateHandleDelegate;->(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;)V +PLorg/thoughtcrime/securesms/util/Projection$Corners;->()V +PLorg/thoughtcrime/securesms/util/Projection$Corners;->(F)V +PLorg/thoughtcrime/securesms/util/Projection$Corners;->([F)V +PLorg/thoughtcrime/securesms/util/Projection$Corners;->toRelativeRadii(Z)[F +PLorg/thoughtcrime/securesms/util/ProjectionList;->getSize()I +PLorg/thoughtcrime/securesms/util/ProjectionList;->size()I +PLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt$delegate$1;->(Ljava/lang/Object;)V +PLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt;->delegate(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;)Lkotlin/properties/ReadWriteProperty; +PLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt;->delegate(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;Ljava/lang/Object;)Lkotlin/properties/ReadWriteProperty; +PLorg/thoughtcrime/securesms/util/SavedStateHandleExtensionsKt;->delegate(Landroidx/lifecycle/SavedStateHandle;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; +PLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion$factoryProducer$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory$Companion$factoryProducer$1;->invoke()Lorg/thoughtcrime/securesms/util/SavedStateViewModelFactory; +PLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory;->(Lkotlin/jvm/functions/Function1;Landroidx/savedstate/SavedStateRegistryOwner;)V +PLorg/thoughtcrime/securesms/util/SavedStateViewModelFactory;->create(Ljava/lang/String;Ljava/lang/Class;Landroidx/lifecycle/SavedStateHandle;)Landroidx/lifecycle/ViewModel; +PLorg/thoughtcrime/securesms/util/SearchUtil;->getHighlightedSpan(Ljava/util/Locale;Lorg/thoughtcrime/securesms/util/SearchUtil$StyleFactory;Landroid/text/Spannable;Ljava/lang/String;I)Landroid/text/Spannable; +PLorg/thoughtcrime/securesms/util/ServiceUtil;->getAudioManager(Landroid/content/Context;)Landroid/media/AudioManager; +PLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onDataPostedToMain()V +PLorg/thoughtcrime/securesms/util/SignalLocalMetrics$ConversationOpen;->onRenderFinished()V +PLorg/thoughtcrime/securesms/util/SplashScreenUtil$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/Activity;)Landroid/window/SplashScreen; +PLorg/thoughtcrime/securesms/util/SplashScreenUtil$$ExternalSyntheticApiModelOutline1;->m(Landroid/window/SplashScreen;I)V +PLorg/thoughtcrime/securesms/util/SplashScreenUtil$1;->()V +PLorg/thoughtcrime/securesms/util/SplashScreenUtil;->setSplashScreenThemeIfNecessary(Landroid/app/Activity;Lorg/thoughtcrime/securesms/keyvalue/SettingsValues$Theme;)V +PLorg/thoughtcrime/securesms/util/ThemeUtil;->getAttribute(Landroid/content/Context;ILjava/lang/String;)Ljava/lang/String; +PLorg/thoughtcrime/securesms/util/ThemeUtil;->isDarkTheme(Landroid/content/Context;)Z PLorg/thoughtcrime/securesms/util/Util;->clamp(FFF)F +PLorg/thoughtcrime/securesms/util/Util;->hashCode([Ljava/lang/Object;)I +PLorg/thoughtcrime/securesms/util/Util;->isEmpty(Ljava/util/Collection;)Z +PLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->getVisible(Landroid/view/View;)Z +PLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->padding$default(Landroid/view/View;IIIIILjava/lang/Object;)V +PLorg/thoughtcrime/securesms/util/ViewExtensionsKt;->padding(Landroid/view/View;IIII)V +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$1;->invoke()Landroidx/fragment/app/Fragment; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$2;->invoke()Landroidx/lifecycle/ViewModelStoreOwner; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$2;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$3;->invoke()Landroidx/lifecycle/ViewModelStore; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$3;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$4;->invoke()Landroidx/lifecycle/viewmodel/CreationExtras; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$$inlined$viewModels$default$4;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$1;->invoke()Landroidx/savedstate/SavedStateRegistryOwner; +PLorg/thoughtcrime/securesms/util/ViewModelFactoryKt$savedStateViewModel$1;->invoke()Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/ViewUtil;->animateOut(Landroid/view/View;Landroid/view/animation/Animation;I)Lorg/signal/core/util/concurrent/ListenableFuture; +PLorg/thoughtcrime/securesms/util/ViewUtil;->fadeOut(Landroid/view/View;I)Lorg/signal/core/util/concurrent/ListenableFuture; +PLorg/thoughtcrime/securesms/util/ViewUtil;->fadeOut(Landroid/view/View;II)Lorg/signal/core/util/concurrent/ListenableFuture; +PLorg/thoughtcrime/securesms/util/ViewUtil;->getAlphaAnimation(FFI)Landroid/view/animation/Animation; +PLorg/thoughtcrime/securesms/util/ViewUtil;->getLeftMargin(Landroid/view/View;)I +PLorg/thoughtcrime/securesms/util/ViewUtil;->getRightMargin(Landroid/view/View;)I +PLorg/thoughtcrime/securesms/util/ViewUtil;->getTopMargin(Landroid/view/View;)I +PLorg/thoughtcrime/securesms/util/ViewUtil;->setTopMargin(Landroid/view/View;I)V +PLorg/thoughtcrime/securesms/util/ViewUtil;->setVisibilityIfNonNull(Landroid/view/View;I)V +PLorg/thoughtcrime/securesms/util/ViewUtil;->updateLayoutParamsIfNonNull(Landroid/view/View;II)V +PLorg/thoughtcrime/securesms/util/adapter/mapping/LayoutFactory;->createViewHolder(Landroid/view/ViewGroup;)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onBindViewHolder(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;ILjava/util/List;)V +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onBindViewHolder(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;I)V +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onBindViewHolder(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;ILjava/util/List;)V +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Landroidx/recyclerview/widget/RecyclerView$ViewHolder; +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onCreateViewHolder(Landroid/view/ViewGroup;I)Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder; +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onViewAttachedToWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onViewAttachedToWindow(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;)V PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onViewDetachedFromWindow(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;)V PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingAdapter;->onViewDetachedFromWindow(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;)V PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingDiffCallback;->areContentsTheSame(Ljava/lang/Object;Ljava/lang/Object;)Z @@ -38498,134 +38435,21 @@ PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingDiffCallback;->areItems PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingDiffCallback;->getChangePayload(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingDiffCallback;->getChangePayload(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel;Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel;)Ljava/lang/Object; PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel$-CC;->$default$getChangePayload(Lorg/thoughtcrime/securesms/util/adapter/mapping/MappingModel;Ljava/lang/Object;)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->(Landroid/view/View;)V +PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->onAttachedToWindow()V PLorg/thoughtcrime/securesms/util/adapter/mapping/MappingViewHolder;->onDetachedFromWindow()V +PLorg/thoughtcrime/securesms/util/adapter/mapping/PagingMappingAdapter;->getItem(I)Ljava/lang/Object; +PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor$$ExternalSyntheticLambda0;->(Lorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;Ljava/lang/Runnable;)V PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor$$ExternalSyntheticLambda0;->run()V PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->$r8$lambda$axI96jKiGgASw-5DyS1pXfSexxk(Lorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;Ljava/lang/Runnable;)V +PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->enqueue(Ljava/lang/Runnable;)Z +PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->execute(Ljava/lang/Runnable;)V PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->lambda$enqueue$0(Ljava/lang/Runnable;)V +PLorg/thoughtcrime/securesms/util/concurrent/SerialMonoLifoExecutor;->scheduleNext()V +PLorg/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat;->()V +PLorg/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat;->(Landroid/content/Context;)V PLorg/thoughtcrime/securesms/util/rx/RxStore;->dispose()V -PLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->getPreKeyCounts(Lorg/whispersystems/signalservice/api/push/ServiceIdType;)Lorg/whispersystems/signalservice/internal/push/OneTimePreKeyCounts; -PLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->getSenderCertificate()[B -PLorg/whispersystems/signalservice/api/SignalServiceAccountManager;->setAccountAttributes(Lorg/whispersystems/signalservice/api/account/AccountAttributes;)V -PLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver$$ExternalSyntheticLambda0;->()V -PLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;->(Lorg/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration;Lorg/whispersystems/signalservice/api/util/CredentialsProvider;Ljava/lang/String;Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Z)V -PLorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;->retrieveProfile(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)Lorg/whispersystems/signalservice/internal/util/concurrent/ListenableFuture; -PLorg/whispersystems/signalservice/api/SignalWebSocket;->request(Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;)Lio/reactivex/rxjava3/core/Single; -PLorg/whispersystems/signalservice/api/SignalWebSocket;->request(Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;Lj$/util/Optional;)Lio/reactivex/rxjava3/core/Single; -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->(ZZZZZZZZ)V -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getAnnouncementGroup()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getChangeNumber()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getGiftBadges()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getPaymentActivation()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getPni()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getSenderKey()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getStorage()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->getStories()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;->toString()Ljava/lang/String; -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->(Ljava/lang/String;IZLjava/lang/String;[BZLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;ZLjava/lang/String;ILjava/lang/String;)V -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->(Ljava/lang/String;IZZZLjava/lang/String;[BZZLorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities;Ljava/lang/String;ILjava/lang/String;)V -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getCapabilities()Lorg/whispersystems/signalservice/api/account/AccountAttributes$Capabilities; -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getDiscoverableByPhoneNumber()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getFetchesMessages()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getName()Ljava/lang/String; -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getPniRegistrationId()I -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getRecoveryPassword()Ljava/lang/String; -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getRegistrationId()I -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getRegistrationLock()Ljava/lang/String; -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getSignalingKey()Ljava/lang/String; -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getUnidentifiedAccessKey()[B -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getUnrestrictedUnidentifiedAccess()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getVideo()Z -PLorg/whispersystems/signalservice/api/account/AccountAttributes;->getVoice()Z -PLorg/whispersystems/signalservice/api/crypto/UnidentifiedAccess;->createEmptyByteArray(I)[B -PLorg/whispersystems/signalservice/api/crypto/UnidentifiedAccess;->deriveAccessKeyFrom(Lorg/signal/libsignal/zkgroup/profiles/ProfileKey;)[B -PLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;->$values()[Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType; -PLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;->()V -PLorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;->(Ljava/lang/String;I)V -PLorg/whispersystems/signalservice/api/push/ServiceId$ACI;->getLibSignalAci()Lorg/signal/libsignal/protocol/ServiceId$Aci; -PLorg/whispersystems/signalservice/api/push/ServiceIdType;->$values()[Lorg/whispersystems/signalservice/api/push/ServiceIdType; -PLorg/whispersystems/signalservice/api/push/ServiceIdType;->()V -PLorg/whispersystems/signalservice/api/push/ServiceIdType;->(Ljava/lang/String;ILjava/lang/String;)V -PLorg/whispersystems/signalservice/api/push/ServiceIdType;->queryParam()Ljava/lang/String; -PLorg/whispersystems/signalservice/api/push/exceptions/NonSuccessfulResponseCodeException;->(ILjava/lang/String;)V -PLorg/whispersystems/signalservice/api/push/exceptions/NonSuccessfulResponseCodeException;->getCode()I -PLorg/whispersystems/signalservice/api/services/MessagingService$$ExternalSyntheticLambda4;->(Lorg/whispersystems/signalservice/internal/websocket/ResponseMapper;)V -PLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda1;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)V -PLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda1;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda2;->()V -PLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda3;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)V -PLorg/whispersystems/signalservice/api/services/ProfileService$$ExternalSyntheticLambda3;->apply(Ljava/lang/Object;)Ljava/lang/Object; -PLorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseMapper;->(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Lorg/signal/libsignal/zkgroup/profiles/ProfileKeyCredentialRequestContext;)V -PLorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseProcessor;->(Lorg/whispersystems/signalservice/internal/ServiceResponse;)V -PLorg/whispersystems/signalservice/api/services/ProfileService$ProfileResponseProcessor;->getError()Ljava/lang/Throwable; -PLorg/whispersystems/signalservice/api/services/ProfileService;->$r8$lambda$qreHJhpvwxlLuI7XzIfP9eBBI24(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; -PLorg/whispersystems/signalservice/api/services/ProfileService;->$r8$lambda$vXxdyhUGBLq7AFV9vG9NvMDxbNI(Lorg/whispersystems/signalservice/api/services/ProfileService;Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; -PLorg/whispersystems/signalservice/api/services/ProfileService;->()V -PLorg/whispersystems/signalservice/api/services/ProfileService;->(Lorg/signal/libsignal/zkgroup/profiles/ClientZkProfileOperations;Lorg/whispersystems/signalservice/api/SignalServiceMessageReceiver;Lorg/whispersystems/signalservice/api/SignalWebSocket;)V -PLorg/whispersystems/signalservice/api/services/ProfileService;->getProfile(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)Lio/reactivex/rxjava3/core/Single; -PLorg/whispersystems/signalservice/api/services/ProfileService;->getProfileRestFallback(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;)Lio/reactivex/rxjava3/core/Single; -PLorg/whispersystems/signalservice/api/services/ProfileService;->lambda$getProfile$0(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; -PLorg/whispersystems/signalservice/api/services/ProfileService;->lambda$getProfileRestFallback$3(Lorg/whispersystems/signalservice/api/push/SignalServiceAddress;Lj$/util/Optional;Lorg/whispersystems/signalservice/api/profiles/SignalServiceProfile$RequestType;Ljava/util/Locale;Ljava/lang/Throwable;)Lio/reactivex/rxjava3/core/SingleSource; -PLorg/whispersystems/signalservice/internal/ServiceResponse;->forApplicationError(Ljava/lang/Throwable;ILjava/lang/String;)Lorg/whispersystems/signalservice/internal/ServiceResponse; -PLorg/whispersystems/signalservice/internal/ServiceResponse;->forUnknownError(Ljava/lang/Throwable;)Lorg/whispersystems/signalservice/internal/ServiceResponse; -PLorg/whispersystems/signalservice/internal/ServiceResponse;->getApplicationError()Lj$/util/Optional; -PLorg/whispersystems/signalservice/internal/ServiceResponse;->getExecutionError()Lj$/util/Optional; -PLorg/whispersystems/signalservice/internal/ServiceResponseProcessor;->getError()Ljava/lang/Throwable; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$$ExternalSyntheticLambda14;->()V -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$1;->(Lorg/whispersystems/signalservice/internal/push/PushServiceSocket;Lorg/whispersystems/signalservice/internal/util/concurrent/SettableFuture;)V -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$1;->onResponse(Lokhttp3/Call;Lokhttp3/Response;)V -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->getClient()Lokhttp3/OkHttpClient; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->getHostHeader()Lj$/util/Optional; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;->getUrl()Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket$EmptyResponseCodeHandler;->handle(ILokhttp3/ResponseBody;)V -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->-$$Nest$mvalidateServiceResponse(Lorg/whispersystems/signalservice/internal/push/PushServiceSocket;Lokhttp3/Response;)Lokhttp3/Response; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->buildOkHttpClient(Z)Lokhttp3/OkHttpClient; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->buildServiceRequest(Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;Ljava/util/Map;Lj$/util/Optional;Z)Lokhttp3/Request; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getAuthorizationHeader(Lorg/whispersystems/signalservice/api/util/CredentialsProvider;)Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getAvailablePreKeys(Lorg/whispersystems/signalservice/api/push/ServiceIdType;)Lorg/whispersystems/signalservice/internal/push/OneTimePreKeyCounts; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getRandom([Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder;Ljava/security/SecureRandom;)Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ConnectionHolder; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getSenderCertificate()[B -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->getServiceConnection(Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;Ljava/util/Map;Lj$/util/Optional;Z)Lokhttp3/Response; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->jsonRequestBody(Ljava/lang/String;)Lokhttp3/RequestBody; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->makeServiceRequest(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->makeServiceRequest(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ResponseCodeHandler;Lj$/util/Optional;)Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->makeServiceRequest(Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;Ljava/util/Map;Lorg/whispersystems/signalservice/internal/push/PushServiceSocket$ResponseCodeHandler;Lj$/util/Optional;Z)Lokhttp3/Response; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->retrieveVersionedProfile(Lorg/whispersystems/signalservice/api/push/ServiceId$ACI;Lorg/signal/libsignal/zkgroup/profiles/ProfileKey;Lj$/util/Optional;Ljava/util/Locale;)Lorg/whispersystems/signalservice/internal/util/concurrent/ListenableFuture; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->setAccountAttributes(Lorg/whispersystems/signalservice/api/account/AccountAttributes;)V -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->submitServiceRequest(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lj$/util/Optional;)Lorg/whispersystems/signalservice/internal/util/concurrent/ListenableFuture; -PLorg/whispersystems/signalservice/internal/push/PushServiceSocket;->validateServiceResponse(Lokhttp3/Response;)Lokhttp3/Response; -PLorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil;->formatLanguages(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil;->getAcceptLanguageHeader(Ljava/util/Locale;)Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/push/http/AcceptLanguagesUtil;->getHeadersWithAcceptLanguage(Ljava/util/Locale;)Ljava/util/Map; -PLorg/whispersystems/signalservice/internal/util/JsonUtil;->toJson(Ljava/lang/Object;)Ljava/lang/String; -PLorg/whispersystems/signalservice/internal/util/concurrent/FutureMapTransformer;->(Lorg/whispersystems/signalservice/internal/util/concurrent/ListenableFuture;Lorg/whispersystems/signalservice/internal/util/concurrent/FutureTransformers$Transformer;)V -PLorg/whispersystems/signalservice/internal/util/concurrent/FutureMapTransformer;->get(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object; -PLorg/whispersystems/signalservice/internal/util/concurrent/FutureTransformers;->map(Lorg/whispersystems/signalservice/internal/util/concurrent/ListenableFuture;Lorg/whispersystems/signalservice/internal/util/concurrent/FutureTransformers$Transformer;)Lorg/whispersystems/signalservice/internal/util/concurrent/ListenableFuture; -PLorg/whispersystems/signalservice/internal/util/concurrent/SettableFuture;->()V -PLorg/whispersystems/signalservice/internal/util/concurrent/SettableFuture;->get()Ljava/lang/Object; -PLorg/whispersystems/signalservice/internal/util/concurrent/SettableFuture;->get(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object; -PLorg/whispersystems/signalservice/internal/util/concurrent/SettableFuture;->notifyAllListeners()V -PLorg/whispersystems/signalservice/internal/util/concurrent/SettableFuture;->setException(Ljava/lang/Throwable;)Z -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder;->()V -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder;->build()Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper; -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->()V -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->()V -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->(Ljava/util/Map;)V -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->(Ljava/util/Map;Lorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper-IA;)V -PLorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper;->extend()Lorg/whispersystems/signalservice/internal/websocket/DefaultErrorMapper$Builder; -PLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder;->(Ljava/lang/Class;)V -PLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder;->build()Lorg/whispersystems/signalservice/internal/websocket/ResponseMapper; -PLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder;->withResponseMapper(Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper;)Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder; -PLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper;->(Ljava/lang/Class;Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper;Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper;)V -PLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper;->(Ljava/lang/Class;Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$CustomResponseMapper;Lorg/whispersystems/signalservice/internal/websocket/ErrorMapper;Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper-IA;)V -PLorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper;->extend(Ljava/lang/Class;)Lorg/whispersystems/signalservice/internal/websocket/DefaultResponseMapper$Builder; -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->()V -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->build()Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage; -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->headers(Ljava/util/List;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->id(Ljava/lang/Long;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->path(Ljava/lang/String;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder;->verb(Ljava/lang/String;)Lorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Builder; -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion$ADAPTER$1;->(Lcom/squareup/wire/FieldEncoding;Lkotlin/reflect/KClass;Lcom/squareup/wire/Syntax;)V -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion;->()V -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;->()V -PLorg/whispersystems/signalservice/internal/websocket/WebSocketRequestMessage;->(Ljava/lang/String;Ljava/lang/String;Lokio/ByteString;Ljava/util/List;Ljava/lang/Long;Lokio/ByteString;)V +PLorg/thoughtcrime/securesms/util/views/NullableStub;->isResolvable()Z +PLorg/thoughtcrime/securesms/util/views/NullableStub;->resolved()Z +PLorg/thoughtcrime/securesms/util/views/Stub;->getVisibility()I +PLorg/thoughtcrime/securesms/util/views/Stub;->isVisible()Z diff --git a/app/src/main/java/org/selfAuthentication/SelfAuthenticationDialogBuilder.kt b/app/src/main/java/org/selfAuthentication/SelfAuthenticationDialogBuilder.kt deleted file mode 100644 index b6c1756e..00000000 --- a/app/src/main/java/org/selfAuthentication/SelfAuthenticationDialogBuilder.kt +++ /dev/null @@ -1,63 +0,0 @@ -package org.selfAuthentication - -import android.app.Activity -import android.app.AlertDialog -import android.view.View -import com.tm.androidcopysdk.AndroidCopySDK -import com.tm.androidcopysdk.ISendLogCallback -import com.tm.androidcopysdk.utils.PrefManager -import org.archiver.ArchivePreferenceConstants -import org.tm.archive.R - - -class SelfAuthenticationDialogBuilder : ISendLogCallback{ - lateinit var mLogsSentContext : Activity - lateinit var mProgressDialog : View - - fun doSendLogsClicked(context: Activity, view : View) { - mLogsSentContext = context - val builder = AlertDialog.Builder(context) - mProgressDialog = view - - builder.setTitle(R.string.not_activated_user_dialog_title) - builder.setMessage(context.getString(R.string.not_activated_user_dialog_message)) - - builder.setPositiveButton(R.string.DebugSendLogs) { dialog, which -> - -// mProgressDialog.show() - mProgressDialog.visibility = View.VISIBLE - AndroidCopySDK.getInstance(context).sentLogs( - context, - this, - PrefManager.getStringPref(context, ArchivePreferenceConstants.PREF_KEY_DEVICE_PHONE_NUMBER, ""), - "Signal Archiver logs", - PrefManager.getStringPref(context, ArchivePreferenceConstants.PREF_KEY_DEVICE_NAME, ""), - "", - "", - "", - "", - ArchivePreferenceConstants.GENERATE_TOK_NAME, - ArchivePreferenceConstants.GENERATE_TOK_PASS - ) - } - builder.setNegativeButton(R.string.OK, null) - builder.show() - - } - - override fun sendLogFailure() { - if(::mProgressDialog.isInitialized) { -// mProgressDialog.dismiss() - mProgressDialog.visibility = View.GONE - } - } - - override fun sendLogSucceed() { - if(::mProgressDialog.isInitialized) { -// mProgressDialog.dismiss() - mProgressDialog.visibility = View.GONE - } - } - - -} \ No newline at end of file diff --git a/app/src/main/java/org/selfAuthentication/SelfAuthenticatorConstants.kt b/app/src/main/java/org/selfAuthentication/SelfAuthenticatorConstants.kt deleted file mode 100644 index 32e545b1..00000000 --- a/app/src/main/java/org/selfAuthentication/SelfAuthenticatorConstants.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.archive.selfAuthentication - -class SelfAuthenticatorConstants { - - companion object{ - - val selfVersion = "1.1.1" - - val selfAuthenticationSucceed = "selfAuthenticationSucceed" - val selfAuthenticationFailed = "selfAuthenticationFailed" - var isAuthenticationProcessOpened = false - } -} \ No newline at end of file diff --git a/app/src/main/java/org/tm/archive/ApplicationContext.java b/app/src/main/java/org/tm/archive/ApplicationContext.java index 979c47d8..12be0496 100644 --- a/app/src/main/java/org/tm/archive/ApplicationContext.java +++ b/app/src/main/java/org/tm/archive/ApplicationContext.java @@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; import androidx.multidex.MultiDexApplication; +import com.bumptech.glide.Glide; import com.google.android.gms.security.ProviderInstaller; import org.archiver.FCMConnector; @@ -56,9 +57,11 @@ import org.tm.archive.jobs.CheckServiceReachabilityJob; import org.tm.archive.jobs.DownloadLatestEmojiDataJob; import org.tm.archive.jobs.EmojiSearchIndexDownloadJob; import org.tm.archive.jobs.ExternalLaunchDonationJob; +import org.tm.archive.jobs.FcmRefreshJob; import org.tm.archive.jobs.FontDownloaderJob; import org.tm.archive.jobs.GroupRingCleanupJob; import org.tm.archive.jobs.GroupV2UpdateSelfProfileKeyJob; +import org.tm.archive.jobs.LinkedDeviceInactiveCheckJob; import org.tm.archive.jobs.MultiDeviceContactUpdateJob; import org.tm.archive.jobs.PnpInitializeDevicesJob; import org.tm.archive.jobs.PreKeysSyncJob; @@ -74,7 +77,6 @@ import org.tm.archive.logging.CustomSignalProtocolLogger; import org.tm.archive.logging.PersistentLogger; import org.tm.archive.messageprocessingalarm.RoutineMessageFetchReceiver; import org.tm.archive.migrations.ApplicationMigrations; -import org.tm.archive.mms.GlideApp; import org.tm.archive.mms.SignalGlideComponents; import org.tm.archive.mms.SignalGlideModule; import org.tm.archive.providers.BlobProvider; @@ -127,6 +129,10 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr private static final String TAG = Log.tag(ApplicationContext.class); + /* public static ApplicationContext getInstance(Context context) { + return (ApplicationContext)context.getApplicationContext(); + }*///*TM_SA*/ + @Override public void onCreate() { Tracer.getInstance().start("Application#onCreate()"); @@ -174,7 +180,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addBlocking("ring-rtc", this::initializeRingRtc) .addBlocking("glide", () -> SignalGlideModule.setRegisterGlideComponents(new SignalGlideComponents())) .addNonBlocking(() -> RegistrationUtil.maybeMarkRegistrationComplete()) - .addNonBlocking(() -> GlideApp.get(this)) + .addNonBlocking(() -> Glide.get(this)) .addNonBlocking(this::cleanAvatarStorage) .addNonBlocking(this::initializeRevealableMessageManager) .addNonBlocking(this::initializePendingRetryReceiptManager) @@ -186,7 +192,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addNonBlocking(this::initializeCleanup) .addNonBlocking(this::initializeGlideCodecs) .addNonBlocking(StorageSyncHelper::scheduleRoutineSync) - .addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop()) + .addNonBlocking(this::beginJobLoop) .addNonBlocking(EmojiSource::refresh) .addNonBlocking(() -> ApplicationDependencies.getGiphyMp4Cache().onAppStart(this)) .addNonBlocking(this::ensureProfileUploaded) @@ -194,7 +200,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addPostRender(() -> ApplicationDependencies.getDeletedCallEventManager().scheduleIfNecessary()) .addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this)) .addPostRender(this::initializeExpiringMessageManager) - .addPostRender(() -> SignalStore.settings().setDefaultSms(Util.isDefaultSmsProvider(this))) .addPostRender(this::initializeTrimThreadsByDateManager) .addPostRender(RefreshSvrCredentialsJob::enqueueIfNecessary) .addPostRender(() -> DownloadLatestEmojiDataJob.scheduleIfNecessary(this)) @@ -212,6 +217,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addPostRender(() -> ApplicationDependencies.getRecipientCache().warmUp()) .addPostRender(AccountConsistencyWorkerJob::enqueueIfNecessary) .addPostRender(GroupRingCleanupJob::enqueue) + .addPostRender(LinkedDeviceInactiveCheckJob::enqueueIfNecessary) .execute(); Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms"); @@ -270,7 +276,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr public void checkBuildExpiration() { if (Util.getTimeUntilBuildExpiry() <= 0 && !SignalStore.misc().isClientDeprecated()) { Log.w(TAG, "Build expired!"); - SignalStore.misc().markClientDeprecated(); + SignalStore.misc().setClientDeprecated(true); } } @@ -304,7 +310,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr @VisibleForTesting protected void initializeLogging() { - Log.initialize(FeatureFlags::internalUser, new AndroidLogger(), new PersistentLogger(this)); // TM_SA + Log.initialize(FeatureFlags::internalUser, new AndroidLogger(), new PersistentLogger(this)); SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger()); @@ -463,6 +469,11 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr } } + @VisibleForTesting + protected void beginJobLoop() { + ApplicationDependencies.getJobManager().beginJobLoop(); + } + @WorkerThread private void initializeBlobProvider() { BlobProvider.getInstance().initialize(this); diff --git a/app/src/main/java/org/tm/archive/AvatarPreviewActivity.java b/app/src/main/java/org/tm/archive/AvatarPreviewActivity.java index 1f4b2986..258a69b7 100644 --- a/app/src/main/java/org/tm/archive/AvatarPreviewActivity.java +++ b/app/src/main/java/org/tm/archive/AvatarPreviewActivity.java @@ -18,6 +18,7 @@ import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityOptionsCompat; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.GlideException; @@ -32,7 +33,6 @@ import org.tm.archive.contacts.avatars.ContactPhoto; import org.tm.archive.contacts.avatars.FallbackContactPhoto; import org.tm.archive.contacts.avatars.ProfileContactPhoto; import org.tm.archive.contacts.avatars.ResourceContactPhoto; -import org.tm.archive.mms.GlideApp; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.FullscreenHelper; @@ -96,7 +96,7 @@ public final class AvatarPreviewActivity extends PassphraseRequiredActivity { Resources resources = this.getResources(); - GlideApp.with(this) + Glide.with(this) .asBitmap() .load(contactPhoto) .fallback(fallbackPhoto.asCallCard(this)) diff --git a/app/src/main/java/org/tm/archive/BindableConversationItem.java b/app/src/main/java/org/tm/archive/BindableConversationItem.java index 32a841d7..4bee641d 100644 --- a/app/src/main/java/org/tm/archive/BindableConversationItem.java +++ b/app/src/main/java/org/tm/archive/BindableConversationItem.java @@ -8,6 +8,8 @@ import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.Observer; +import com.bumptech.glide.RequestManager; + import org.signal.ringrtc.CallLinkRootKey; import org.tm.archive.components.voice.VoiceNotePlaybackState; import org.tm.archive.contactshare.Contact; @@ -26,7 +28,6 @@ import org.tm.archive.groups.GroupId; import org.tm.archive.groups.GroupMigrationMembershipChange; import org.tm.archive.linkpreview.LinkPreview; import org.tm.archive.mediapreview.MediaIntentFactory; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.stickers.StickerLocator; @@ -41,7 +42,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable, @NonNull ConversationMessage messageRecord, @NonNull Optional previousMessageRecord, @NonNull Optional nextMessageRecord, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull Set batchSelected, @NonNull Recipient recipients, @@ -122,5 +123,8 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable, void onEditedIndicatorClicked(@NonNull MessageRecord messageRecord); void onShowGroupDescriptionClicked(@NonNull String groupName, @NonNull String description, boolean shouldLinkifyWebLinks); void onJoinCallLink(@NonNull CallLinkRootKey callLinkRootKey); + void onShowSafetyTips(boolean forGroup); + void onReportSpamLearnMoreClicked(); + void onMessageRequestAcceptOptionsClicked(); } } diff --git a/app/src/main/java/org/tm/archive/BindableConversationListItem.java b/app/src/main/java/org/tm/archive/BindableConversationListItem.java index 74bb2bba..50225c60 100644 --- a/app/src/main/java/org/tm/archive/BindableConversationListItem.java +++ b/app/src/main/java/org/tm/archive/BindableConversationListItem.java @@ -3,9 +3,10 @@ package org.tm.archive; import androidx.annotation.NonNull; import androidx.lifecycle.LifecycleOwner; +import com.bumptech.glide.RequestManager; + import org.tm.archive.conversationlist.model.ConversationSet; import org.tm.archive.database.model.ThreadRecord; -import org.tm.archive.mms.GlideRequests; import java.util.Locale; import java.util.Set; @@ -14,7 +15,7 @@ public interface BindableConversationListItem extends Unbindable { void bind(@NonNull LifecycleOwner lifecycleOwner, @NonNull ThreadRecord thread, - @NonNull GlideRequests glideRequests, @NonNull Locale locale, + @NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull Set typingThreads, @NonNull ConversationSet selectedConversations); diff --git a/app/src/main/java/org/tm/archive/BlockUnblockDialog.java b/app/src/main/java/org/tm/archive/BlockUnblockDialog.java index 4e85eb55..acb5e5d8 100644 --- a/app/src/main/java/org/tm/archive/BlockUnblockDialog.java +++ b/app/src/main/java/org/tm/archive/BlockUnblockDialog.java @@ -11,16 +11,36 @@ import androidx.lifecycle.Lifecycle; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import org.tm.archive.database.SignalDatabase; -import org.tm.archive.recipients.Recipient; import org.signal.core.util.concurrent.SimpleTask; +import org.signal.storageservice.protos.groups.local.DecryptedPendingMember; +import org.tm.archive.database.SignalDatabase; +import org.tm.archive.database.model.GroupRecord; +import org.tm.archive.recipients.Recipient; +import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; +import org.whispersystems.signalservice.api.push.ServiceId; + +import java.util.List; +import java.util.Optional; + +import okio.ByteString; /** * This should be used whenever we want to prompt the user to block/unblock a recipient. */ public final class BlockUnblockDialog { - private BlockUnblockDialog() { } + private BlockUnblockDialog() {} + + public static void showReportSpamFor(@NonNull Context context, + @NonNull Lifecycle lifecycle, + @NonNull Recipient recipient, + @NonNull Runnable onReportSpam, + @Nullable Runnable onBlockAndReportSpam) + { + SimpleTask.run(lifecycle, + () -> buildReportSpamFor(context, recipient, onReportSpam, onBlockAndReportSpam), + AlertDialog.Builder::show); + } public static void showBlockFor(@NonNull Context context, @NonNull Lifecycle lifecycle, @@ -137,4 +157,37 @@ public final class BlockUnblockDialog { return builder; } + + @WorkerThread + private static AlertDialog.Builder buildReportSpamFor(@NonNull Context context, + @NonNull Recipient recipient, + @NonNull Runnable onReportSpam, + @Nullable Runnable onBlockAndReportSpam) + { + recipient = recipient.resolve(); + + AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context) + .setTitle(R.string.BlockUnblockDialog_report_spam_title) + .setPositiveButton(R.string.BlockUnblockDialog_report_spam, (d, w) -> onReportSpam.run()); + + if (onBlockAndReportSpam != null) { + builder.setNeutralButton(android.R.string.cancel, null) + .setNegativeButton(R.string.BlockUnblockDialog_report_spam_and_block, (d, w) -> onBlockAndReportSpam.run()); + } else { + builder.setNegativeButton(android.R.string.cancel, null); + } + + if (recipient.isGroup()) { + Recipient adder = SignalDatabase.groups().getGroupInviter(recipient.requireGroupId()); + if (adder != null) { + builder.setMessage(context.getString(R.string.BlockUnblockDialog_report_spam_group_named_adder, adder.getDisplayName(context))); + } else { + builder.setMessage(R.string.BlockUnblockDialog_report_spam_group_unknown_adder); + } + } else { + builder.setMessage(R.string.BlockUnblockDialog_report_spam_description); + } + + return builder; + } } diff --git a/app/src/main/java/org/tm/archive/ContactSelectionActivity.java b/app/src/main/java/org/tm/archive/ContactSelectionActivity.java index adabd389..30190e82 100644 --- a/app/src/main/java/org/tm/archive/ContactSelectionActivity.java +++ b/app/src/main/java/org/tm/archive/ContactSelectionActivity.java @@ -24,14 +24,17 @@ import androidx.annotation.NonNull; import androidx.appcompat.widget.Toolbar; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import org.signal.core.util.DimensionUnit; import org.signal.core.util.logging.Log; import org.tm.archive.components.ContactFilterView; import org.tm.archive.contacts.ContactSelectionDisplayMode; import org.tm.archive.contacts.sync.ContactDiscovery; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.RecipientId; +import org.tm.archive.util.DisplayMetricsUtil; import org.tm.archive.util.DynamicNoActionBarTheme; import org.tm.archive.util.DynamicTheme; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.ServiceUtil; import org.tm.archive.util.Util; @@ -70,8 +73,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit @Override protected void onCreate(Bundle icicle, boolean ready) { if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) { - boolean includeSms = Util.isDefaultSmsProvider(this) && SignalStore.misc().getSmsExportPhase().allowSmsFeatures(); - int displayMode = includeSms ? ContactSelectionDisplayMode.FLAG_ALL : ContactSelectionDisplayMode.FLAG_PUSH | ContactSelectionDisplayMode.FLAG_ACTIVE_GROUPS | ContactSelectionDisplayMode.FLAG_INACTIVE_GROUPS | ContactSelectionDisplayMode.FLAG_SELF; + int displayMode = ContactSelectionDisplayMode.FLAG_PUSH | ContactSelectionDisplayMode.FLAG_ACTIVE_GROUPS | ContactSelectionDisplayMode.FLAG_INACTIVE_GROUPS | ContactSelectionDisplayMode.FLAG_SELF; getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode); } @@ -99,6 +101,10 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit private void initializeContactFilterView() { this.contactFilterView = findViewById(R.id.contact_filter_edit_text); + + if (getResources().getDisplayMetrics().heightPixels >= DimensionUnit.DP.toPixels(600)) { + this.contactFilterView.focusAndShowKeyboard(); + } } private void initializeToolbar() { diff --git a/app/src/main/java/org/tm/archive/ContactSelectionListAdapter.kt b/app/src/main/java/org/tm/archive/ContactSelectionListAdapter.kt index bc4193b1..2cdba858 100644 --- a/app/src/main/java/org/tm/archive/ContactSelectionListAdapter.kt +++ b/app/src/main/java/org/tm/archive/ContactSelectionListAdapter.kt @@ -27,6 +27,8 @@ class ContactSelectionListAdapter( registerFactory(RefreshContactsModel::class.java, LayoutFactory({ RefreshContactsViewHolder(it, onClickCallbacks::onRefreshContactsClicked) }, R.layout.contact_selection_refresh_action_item)) registerFactory(MoreHeaderModel::class.java, LayoutFactory({ MoreHeaderViewHolder(it) }, R.layout.contact_search_section_header)) registerFactory(EmptyModel::class.java, LayoutFactory({ EmptyViewHolder(it) }, R.layout.contact_selection_empty_state)) + registerFactory(FindByUsernameModel::class.java, LayoutFactory({ FindByUsernameViewHolder(it, onClickCallbacks::onFindByUsernameClicked) }, R.layout.contact_selection_find_by_username_item)) + registerFactory(FindByPhoneNumberModel::class.java, LayoutFactory({ FindByPhoneNumberViewHolder(it, onClickCallbacks::onFindByPhoneNumberClicked) }, R.layout.contact_selection_find_by_phone_number_item)) } class NewGroupModel : MappingModel { @@ -44,6 +46,16 @@ class ContactSelectionListAdapter( override fun areContentsTheSame(newItem: RefreshContactsModel): Boolean = true } + class FindByUsernameModel : MappingModel { + override fun areItemsTheSame(newItem: FindByUsernameModel): Boolean = true + override fun areContentsTheSame(newItem: FindByUsernameModel): Boolean = true + } + + class FindByPhoneNumberModel : MappingModel { + override fun areItemsTheSame(newItem: FindByPhoneNumberModel): Boolean = true + override fun areContentsTheSame(newItem: FindByPhoneNumberModel): Boolean = true + } + class MoreHeaderModel : MappingModel { override fun areItemsTheSame(newItem: MoreHeaderModel): Boolean = true @@ -92,13 +104,33 @@ class ContactSelectionListAdapter( } } + private class FindByPhoneNumberViewHolder(itemView: View, onClickListener: () -> Unit) : MappingViewHolder(itemView) { + + init { + itemView.setOnClickListener { onClickListener() } + } + + override fun bind(model: FindByPhoneNumberModel) = Unit + } + + private class FindByUsernameViewHolder(itemView: View, onClickListener: () -> Unit) : MappingViewHolder(itemView) { + + init { + itemView.setOnClickListener { onClickListener() } + } + + override fun bind(model: FindByUsernameModel) = Unit + } + class ArbitraryRepository : org.tm.archive.contacts.paged.ArbitraryRepository { enum class ArbitraryRow(val code: String) { NEW_GROUP("new-group"), INVITE_TO_SIGNAL("invite-to-signal"), MORE_HEADING("more-heading"), - REFRESH_CONTACTS("refresh-contacts"); + REFRESH_CONTACTS("refresh-contacts"), + FIND_BY_USERNAME("find-by-username"), + FIND_BY_PHONE_NUMBER("find-by-phone-number"); companion object { fun fromCode(code: String) = values().first { it.code == code } @@ -120,6 +152,8 @@ class ContactSelectionListAdapter( ArbitraryRow.INVITE_TO_SIGNAL -> InviteToSignalModel() ArbitraryRow.MORE_HEADING -> MoreHeaderModel() ArbitraryRow.REFRESH_CONTACTS -> RefreshContactsModel() + ArbitraryRow.FIND_BY_PHONE_NUMBER -> FindByPhoneNumberModel() + ArbitraryRow.FIND_BY_USERNAME -> FindByUsernameModel() } } } @@ -128,5 +162,7 @@ class ContactSelectionListAdapter( fun onNewGroupClicked() fun onInviteToSignalClicked() fun onRefreshContactsClicked() + fun onFindByPhoneNumberClicked() + fun onFindByUsernameClicked() } } diff --git a/app/src/main/java/org/tm/archive/ContactSelectionListFragment.java b/app/src/main/java/org/tm/archive/ContactSelectionListFragment.java index 8875ed77..6b3c853f 100644 --- a/app/src/main/java/org/tm/archive/ContactSelectionListFragment.java +++ b/app/src/main/java/org/tm/archive/ContactSelectionListFragment.java @@ -76,6 +76,7 @@ import org.tm.archive.profiles.manage.UsernameRepository.UsernameAciFetchResult; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.CommunicationActions; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.TextSecurePreferences; import org.tm.archive.util.UsernameUtil; import org.tm.archive.util.ViewUtil; @@ -141,6 +142,7 @@ public final class ContactSelectionListFragment extends LoggingFragment { private ContactSearchMediator contactSearchMediator; @Nullable private NewConversationCallback newConversationCallback; + @Nullable private FindByCallback findByCallback; @Nullable private NewCallCallback newCallCallback; @Nullable private ScrollCallback scrollCallback; @Nullable private OnItemLongClickListener onItemLongClickListener; @@ -161,6 +163,10 @@ public final class ContactSelectionListFragment extends LoggingFragment { newConversationCallback = (NewConversationCallback) context; } + if (context instanceof FindByCallback) { + findByCallback = (FindByCallback) context; + } + if (context instanceof NewCallCallback) { newCallCallback = (NewCallCallback) context; } @@ -379,6 +385,16 @@ public final class ContactSelectionListFragment extends LoggingFragment { newConversationCallback.onNewGroup(false); } + @Override + public void onFindByPhoneNumberClicked() { + findByCallback.onFindByPhoneNumber(); + } + + @Override + public void onFindByUsernameClicked() { + findByCallback.onFindByUsername(); + } + @Override public void onInviteToSignalClicked() { if (newConversationCallback != null) { @@ -660,6 +676,10 @@ public final class ContactSelectionListFragment extends LoggingFragment { } } + public void addRecipientToSelectionIfAble(@NonNull RecipientId recipientId) { + listClickListener.onItemClick(new ContactSearchKey.RecipientSearchKey(recipientId, false)); + } + private class ListClickListener { public void onItemClick(ContactSearchKey contact) { boolean isUnknown = contact instanceof ContactSearchKey.UnknownRecipientKey; @@ -870,10 +890,15 @@ public final class ContactSelectionListFragment extends LoggingFragment { return ContactSearchConfiguration.build(builder -> { builder.setQuery(contactSearchState.getQuery()); - if (newConversationCallback != null) { + if (newConversationCallback != null && !hasQuery) { builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.NEW_GROUP.getCode()); } + if (findByCallback != null && !hasQuery) { + builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.FIND_BY_USERNAME.getCode()); + builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.FIND_BY_PHONE_NUMBER.getCode()); + } + if (transportType != null) { if (!hasQuery && includeRecents) { builder.addSection(new ContactSearchConfiguration.Section.Recents( @@ -888,12 +913,14 @@ public final class ContactSelectionListFragment extends LoggingFragment { )); } + boolean hideHeader = newCallCallback != null || (newConversationCallback != null && !hasQuery); builder.addSection(new ContactSearchConfiguration.Section.Individuals( includeSelf, transportType, - newCallCallback == null, + !hideHeader, null, - !hideLetterHeaders() + !hideLetterHeaders(), + newConversationCallback != null ? ContactSearchSortOrder.RECENCY : ContactSearchSortOrder.NATURAL )); } @@ -919,7 +946,7 @@ public final class ContactSelectionListFragment extends LoggingFragment { builder.username(newRowMode); } - if (newCallCallback != null || newConversationCallback != null) { + if ((newCallCallback != null || newConversationCallback != null) && !hasQuery) { addMoreSection(builder); builder.withEmptyState(emptyBuilder -> { emptyBuilder.addSection(ContactSearchConfiguration.Section.Empty.INSTANCE); @@ -1011,6 +1038,12 @@ public final class ContactSelectionListFragment extends LoggingFragment { void onNewGroup(boolean forceV1); } + public interface FindByCallback { + void onFindByUsername(); + + void onFindByPhoneNumber(); + } + public interface NewCallCallback { void onInvite(); } diff --git a/app/src/main/java/org/tm/archive/DeviceActivity.java b/app/src/main/java/org/tm/archive/DeviceActivity.java index 1a705c48..88bfea3c 100644 --- a/app/src/main/java/org/tm/archive/DeviceActivity.java +++ b/app/src/main/java/org/tm/archive/DeviceActivity.java @@ -3,6 +3,7 @@ package org.tm.archive; import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; +import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; @@ -28,6 +29,7 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.qr.kitkat.ScanListener; import org.tm.archive.crypto.ProfileKeyUtil; import org.tm.archive.dependencies.ApplicationDependencies; +import org.tm.archive.jobs.LinkedDeviceInactiveCheckJob; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.permissions.Permissions; import org.signal.core.util.Base64; @@ -48,6 +50,8 @@ public class DeviceActivity extends PassphraseRequiredActivity private static final String TAG = Log.tag(DeviceActivity.class); + private static final String EXTRA_DIRECT_TO_SCANNER = "add"; + private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -56,6 +60,13 @@ public class DeviceActivity extends PassphraseRequiredActivity private DeviceLinkFragment deviceLinkFragment; private MenuItem cameraSwitchItem = null; + + public static Intent getIntentForScanner(Context context) { + Intent intent = new Intent(context, DeviceActivity.class); + intent.putExtra(EXTRA_DIRECT_TO_SCANNER, true); + return intent; + } + @Override public void onPreCreate() { dynamicTheme.onCreate(this); @@ -79,7 +90,7 @@ public class DeviceActivity extends PassphraseRequiredActivity this.deviceListFragment.setAddDeviceButtonListener(this); this.deviceAddFragment.setScanListener(this); - if (getIntent().getBooleanExtra("add", false)) { + if (getIntent().getBooleanExtra(EXTRA_DIRECT_TO_SCANNER, false)) { initFragment(R.id.fragment_container, deviceAddFragment, dynamicLanguage.getCurrentLocale()); } else { initFragment(R.id.fragment_container, deviceListFragment, dynamicLanguage.getCurrentLocale()); @@ -221,6 +232,8 @@ public class DeviceActivity extends PassphraseRequiredActivity protected void onPostExecute(Integer result) { super.onPostExecute(result); + LinkedDeviceInactiveCheckJob.enqueue(); + Context context = DeviceActivity.this; switch (result) { diff --git a/app/src/main/java/org/tm/archive/DeviceListFragment.java b/app/src/main/java/org/tm/archive/DeviceListFragment.java index 3c64e164..25877d18 100644 --- a/app/src/main/java/org/tm/archive/DeviceListFragment.java +++ b/app/src/main/java/org/tm/archive/DeviceListFragment.java @@ -27,6 +27,7 @@ import org.signal.core.util.logging.Log; import org.tm.archive.database.loaders.DeviceListLoader; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.devicelist.Device; +import org.tm.archive.jobs.LinkedDeviceInactiveCheckJob; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.util.TextSecurePreferences; import org.tm.archive.util.task.ProgressDialogAsyncTask; @@ -166,6 +167,7 @@ public class DeviceListFragment extends ListFragment super.onPostExecute(result); if (result) { getLoaderManager().restartLoader(0, null, DeviceListFragment.this); + LinkedDeviceInactiveCheckJob.enqueue(); } else { Toast.makeText(getActivity(), R.string.DeviceListActivity_network_failed, Toast.LENGTH_LONG).show(); } diff --git a/app/src/main/java/org/tm/archive/DeviceProvisioningActivity.java b/app/src/main/java/org/tm/archive/DeviceProvisioningActivity.java index 1a082dca..875d365b 100644 --- a/app/src/main/java/org/tm/archive/DeviceProvisioningActivity.java +++ b/app/src/main/java/org/tm/archive/DeviceProvisioningActivity.java @@ -26,9 +26,7 @@ public class DeviceProvisioningActivity extends PassphraseRequiredActivity { .setTitle(getString(R.string.DeviceProvisioningActivity_link_a_signal_device)) .setMessage(getString(R.string.DeviceProvisioningActivity_it_looks_like_youre_trying_to_link_a_signal_device_using_a_3rd_party_scanner)) .setPositiveButton(R.string.DeviceProvisioningActivity_continue, (dialog1, which) -> { - Intent intent = new Intent(DeviceProvisioningActivity.this, DeviceActivity.class); - intent.putExtra("add", true); - startActivity(intent); + startActivity(DeviceActivity.getIntentForScanner(this)); finish(); }) .setNegativeButton(android.R.string.cancel, (dialog12, which) -> { @@ -38,7 +36,6 @@ public class DeviceProvisioningActivity extends PassphraseRequiredActivity { .setOnDismissListener(dialog13 -> finish()) .create(); - dialog.setIcon(getResources().getDrawable(R.drawable.ic_launcher_foreground)); dialog.show(); } } diff --git a/app/src/main/java/org/tm/archive/GroupMembersDialog.java b/app/src/main/java/org/tm/archive/GroupMembersDialog.java index 5efd676d..693bcb33 100644 --- a/app/src/main/java/org/tm/archive/GroupMembersDialog.java +++ b/app/src/main/java/org/tm/archive/GroupMembersDialog.java @@ -54,7 +54,6 @@ public final class GroupMembersDialog { } private void contactClick(@NonNull Recipient recipient) { - RecipientBottomSheetDialogFragment.create(recipient.getId(), groupRecipient.requireGroupId()) - .show(fragmentActivity.getSupportFragmentManager(), "BOTTOM"); + RecipientBottomSheetDialogFragment.show(fragmentActivity.getSupportFragmentManager(), recipient.getId(), groupRecipient.requireGroupId()); } } diff --git a/app/src/main/java/org/tm/archive/InviteActivity.java b/app/src/main/java/org/tm/archive/InviteActivity.java index 74409afd..a59ca2d6 100644 --- a/app/src/main/java/org/tm/archive/InviteActivity.java +++ b/app/src/main/java/org/tm/archive/InviteActivity.java @@ -17,17 +17,16 @@ import android.widget.Toast; import androidx.annotation.AnimRes; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import org.signal.core.util.concurrent.ListenableFuture.Listener; import org.tm.archive.components.ContactFilterView; import org.tm.archive.components.ContactFilterView.OnFilterChangedListener; import org.tm.archive.contacts.ContactSelectionDisplayMode; import org.tm.archive.contacts.SelectedContact; -import org.tm.archive.database.SignalDatabase; import org.tm.archive.groups.SelectionLimits; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.mms.OutgoingMessage; @@ -38,7 +37,6 @@ import org.tm.archive.util.DynamicNoActionBarInviteTheme; import org.tm.archive.util.DynamicTheme; import org.tm.archive.util.Util; import org.tm.archive.util.ViewUtil; -import org.tm.archive.util.concurrent.ListenableFuture.Listener; import org.tm.archive.util.task.ProgressDialogAsyncTask; import org.tm.archive.util.text.AfterTextChanged; @@ -121,14 +119,9 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac smsSendButton.setOnClickListener(new SmsSendClickListener()); contactFilter.setOnFilterChangedListener(new ContactFilterChangedListener()); - if (Util.isDefaultSmsProvider(this) && SignalStore.misc().getSmsExportPhase().isSmsSupported()) { - shareButton.setOnClickListener(new ShareClickListener()); - smsButton.setOnClickListener(new SmsClickListener()); - } else { - smsButton.setVisibility(View.GONE); - shareText.setText(R.string.InviteActivity_share); - shareButton.setOnClickListener(new ShareClickListener()); - } + smsButton.setVisibility(View.GONE); + shareText.setText(R.string.InviteActivity_share); + shareButton.setOnClickListener(new ShareClickListener()); } private Animation loadAnimation(@AnimRes int animResId) { @@ -202,13 +195,6 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac } } - private class SmsClickListener implements OnClickListener { - @Override - public void onClick(View v) { - ViewUtil.animateIn(smsSendFrame, slideInAnimation); - } - } - private class SmsCancelClickListener implements OnClickListener { @Override public void onClick(View v) { diff --git a/app/src/main/java/org/tm/archive/MainActivity.java b/app/src/main/java/org/tm/archive/MainActivity.java index f6dbe9b1..66c90068 100644 --- a/app/src/main/java/org/tm/archive/MainActivity.java +++ b/app/src/main/java/org/tm/archive/MainActivity.java @@ -2,33 +2,20 @@ package org.tm.archive; import android.annotation.SuppressLint; import android.app.Activity; -import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.view.View; import android.view.ViewTreeObserver; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; import androidx.lifecycle.ViewModelProvider; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.tm.androidcopysdk.network.appSettings.UpdateEvent; -import com.tm.androidcopysdk.network.appSettings.WorkerIntentService; -import com.tm.androidcopysdk.utils.PrefManager; -import com.tm.logger.Log; -import org.archiver.ArchivePreferenceConstants; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import org.selfAuthentication.SelfAuthenticatorManager; import org.signal.core.util.concurrent.LifecycleDisposable; import org.signal.donations.StripeApi; import org.tm.archive.components.DebugLogsPromptDialogFragment; @@ -37,7 +24,6 @@ import org.tm.archive.components.settings.app.AppSettingsActivity; import org.tm.archive.components.voice.VoiceNoteMediaController; import org.tm.archive.components.voice.VoiceNoteMediaControllerOwner; import org.tm.archive.conversationlist.RelinkDevicesReminderBottomSheetFragment; -import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.devicetransfer.olddevice.OldDeviceExitActivity; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.net.DeviceTransferBlockingInterceptor; @@ -63,7 +49,6 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot private ConversationListTabsViewModel conversationListTabsViewModel; private VitalsViewModel vitalsViewModel; - private final LifecycleDisposable lifecycleDisposable = new LifecycleDisposable(); private boolean onFirstRender = false; @@ -122,8 +107,6 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot ); } - - @SuppressLint("NewApi") private void presentVitalsState(VitalsViewModel.State state) { switch (state) { @@ -169,7 +152,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot .setMessage(R.string.OldDeviceTransferLockedDialog__your_signal_account_has_been_transferred_to_your_new_device) .setPositiveButton(R.string.OldDeviceTransferLockedDialog__done, (d, w) -> OldDeviceExitActivity.exit(this)) .setNegativeButton(R.string.OldDeviceTransferLockedDialog__cancel_and_activate_this_device, (d, w) -> { - SignalStore.misc().clearOldDeviceTransferLocked(); + SignalStore.misc().setOldDeviceTransferLocked(false); DeviceTransferBlockingInterceptor.getInstance().unblockNetwork(); }) .setCancelable(false) @@ -186,7 +169,6 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot vitalsViewModel.checkSlowNotificationHeuristics(); } - @Override protected void onStop() { super.onStop(); diff --git a/app/src/main/java/org/tm/archive/NewConversationActivity.java b/app/src/main/java/org/tm/archive/NewConversationActivity.java index 835450fc..375336eb 100644 --- a/app/src/main/java/org/tm/archive/NewConversationActivity.java +++ b/app/src/main/java/org/tm/archive/NewConversationActivity.java @@ -50,6 +50,9 @@ import org.tm.archive.groups.ui.creategroup.CreateGroupActivity; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; +import org.tm.archive.recipients.RecipientRepository; +import org.tm.archive.recipients.ui.findby.FindByActivity; +import org.tm.archive.recipients.ui.findby.FindByMode; import org.tm.archive.util.CommunicationActions; import org.tm.archive.util.views.SimpleProgressDialog; @@ -70,14 +73,16 @@ import io.reactivex.rxjava3.disposables.Disposable; * @author Moxie Marlinspike */ public class NewConversationActivity extends ContactSelectionActivity - implements ContactSelectionListFragment.NewConversationCallback, ContactSelectionListFragment.OnItemLongClickListener + implements ContactSelectionListFragment.NewConversationCallback, ContactSelectionListFragment.OnItemLongClickListener, ContactSelectionListFragment.FindByCallback { @SuppressWarnings("unused") private static final String TAG = Log.tag(NewConversationActivity.class); - private ContactsManagementViewModel viewModel; - private ActivityResultLauncher contactLauncher; + private ContactsManagementViewModel viewModel; + private ActivityResultLauncher contactLauncher; + private ActivityResultLauncher createGroupLauncher; + private ActivityResultLauncher findByLauncher; private final LifecycleDisposable disposables = new LifecycleDisposable(); @@ -99,13 +104,23 @@ public class NewConversationActivity extends ContactSelectionActivity } }); + findByLauncher = registerForActivityResult(new FindByActivity.Contract(), result -> { + if (result != null) { + launch(result); + } + }); + + createGroupLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { + if (result.getResultCode() == RESULT_OK) { + finish(); + } + }); + viewModel = new ViewModelProvider(this, factory).get(ContactsManagementViewModel.class); } @Override public void onBeforeContactSelected(boolean isFromUnknownSearchKey, @NonNull Optional recipientId, String number, @NonNull Consumer callback) { - boolean smsSupported = SignalStore.misc().getSmsExportPhase().allowSmsFeatures(); - if (recipientId.isPresent()) { launch(Recipient.resolved(recipientId.get())); } else { @@ -116,33 +131,19 @@ public class NewConversationActivity extends ContactSelectionActivity AlertDialog progress = SimpleProgressDialog.show(this); - SimpleTask.run(getLifecycle(), () -> { - Recipient resolved = Recipient.external(this, number); - - if (!resolved.isRegistered() || !resolved.hasServiceId()) { - Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh."); - try { - ContactDiscovery.refresh(this, resolved, false, TimeUnit.SECONDS.toMillis(10)); - resolved = Recipient.resolved(resolved.getId()); - } catch (IOException e) { - Log.w(TAG, "[onContactSelected] Failed to refresh directory for new contact."); - return null; - } - } - - return resolved; - }, resolved -> { + SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(this, number), result -> { progress.dismiss(); - if (resolved != null) { - if (smsSupported || resolved.isRegistered() && resolved.hasServiceId()) { + if (result instanceof RecipientRepository.LookupResult.Success) { + Recipient resolved = Recipient.resolved(((RecipientRepository.LookupResult.Success) result).getRecipientId()); + if (resolved.isRegistered() && resolved.hasServiceId()) { launch(resolved); - } else { - new MaterialAlertDialogBuilder(this) - .setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, resolved.getDisplayName(this))) - .setPositiveButton(android.R.string.ok, null) - .show(); } + } else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) { + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number)) + .setPositiveButton(android.R.string.ok, null) + .show(); } else { new MaterialAlertDialogBuilder(this) .setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again) @@ -150,8 +151,6 @@ public class NewConversationActivity extends ContactSelectionActivity .show(); } }); - } else if (smsSupported) { - launch(Recipient.external(this, number)); } } @@ -163,7 +162,12 @@ public class NewConversationActivity extends ContactSelectionActivity } private void launch(Recipient recipient) { - Disposable disposable = ConversationIntents.createBuilder(this, recipient.getId(), -1L) + launch(recipient.getId()); + } + + + private void launch(RecipientId recipientId) { + Disposable disposable = ConversationIntents.createBuilder(this, recipientId, -1L) .map(builder -> builder .withDraftText(getIntent().getStringExtra(Intent.EXTRA_TEXT)) .withDataUri(getIntent().getData()) @@ -206,7 +210,7 @@ public class NewConversationActivity extends ContactSelectionActivity } private void handleCreateGroup() { - startActivity(CreateGroupActivity.newIntent(this)); + createGroupLauncher.launch(CreateGroupActivity.newIntent(this)); } private void handleInvite() { @@ -231,7 +235,17 @@ public class NewConversationActivity extends ContactSelectionActivity @Override public void onNewGroup(boolean forceV1) { handleCreateGroup(); - finish(); +// finish(); + } + + @Override + public void onFindByUsername() { + findByLauncher.launch(FindByMode.USERNAME); + } + + @Override + public void onFindByPhoneNumber() { + findByLauncher.launch(FindByMode.PHONE_NUMBER); } @Override @@ -286,7 +300,7 @@ public class NewConversationActivity extends ContactSelectionActivity return null; } - if (recipient.isRegistered() || (SignalStore.misc().getSmsExportPhase().allowSmsFeatures())) { + if (recipient.isRegistered()) { return new ActionItem( R.drawable.ic_phone_right_24, getString(R.string.NewConversationActivity__audio_call), diff --git a/app/src/main/java/org/tm/archive/PassphrasePromptActivity.java b/app/src/main/java/org/tm/archive/PassphrasePromptActivity.java index bdfade45..b5c423a2 100644 --- a/app/src/main/java/org/tm/archive/PassphrasePromptActivity.java +++ b/app/src/main/java/org/tm/archive/PassphrasePromptActivity.java @@ -374,7 +374,7 @@ public class PassphrasePromptActivity extends PassphraseActivity { @Override public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { Log.i(TAG, "onAuthenticationSucceeded"); - fingerprintPrompt.setImageResource(R.drawable.ic_check_white_48dp); + fingerprintPrompt.setImageResource(R.drawable.symbol_check_white_48); fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.green_500), PorterDuff.Mode.SRC_IN); fingerprintPrompt.animate().setInterpolator(new BounceInterpolator()).scaleX(1.1f).scaleY(1.1f).setDuration(500).setListener(new AnimationCompleteListener() { @Override @@ -388,7 +388,7 @@ public class PassphrasePromptActivity extends PassphraseActivity { public void onAuthenticationFailed() { Log.w(TAG, "onAuthenticationFailed()"); - fingerprintPrompt.setImageResource(R.drawable.ic_close_white_48dp); + fingerprintPrompt.setImageResource(R.drawable.symbol_x_white_48); fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.red_500), PorterDuff.Mode.SRC_IN); TranslateAnimation shake = new TranslateAnimation(0, 30, 0, 0); diff --git a/app/src/main/java/org/tm/archive/PromptMmsActivity.java b/app/src/main/java/org/tm/archive/PromptMmsActivity.java deleted file mode 100644 index beb1d7f2..00000000 --- a/app/src/main/java/org/tm/archive/PromptMmsActivity.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.tm.archive; - -import android.content.Intent; -import android.os.Bundle; -import android.widget.Button; - -import org.tm.archive.preferences.MmsPreferencesActivity; - -public class PromptMmsActivity extends PassphraseRequiredActivity { - - @Override - protected void onCreate(Bundle bundle, boolean ready) { - setContentView(R.layout.prompt_apn_activity); - initializeResources(); - } - - private void initializeResources() { - Button okButton = findViewById(R.id.ok_button); - Button cancelButton = findViewById(R.id.cancel_button); - - okButton.setOnClickListener(v -> { - Intent intent = new Intent(PromptMmsActivity.this, MmsPreferencesActivity.class); - intent.putExtras(PromptMmsActivity.this.getIntent().getExtras()); - startActivity(intent); - finish(); - }); - - cancelButton.setOnClickListener(v -> finish()); - } - -} diff --git a/app/src/main/java/org/tm/archive/SignalBaseActivity.java b/app/src/main/java/org/tm/archive/SignalBaseActivity.java index 0f9076e7..6ec031a9 100644 --- a/app/src/main/java/org/tm/archive/SignalBaseActivity.java +++ b/app/src/main/java/org/tm/archive/SignalBaseActivity.java @@ -28,7 +28,7 @@ import java.util.Objects; * screen lock. */ public abstract class SignalBaseActivity extends AppCompatActivity {//*TM_SA*/change BaseActivity to SignalBaseActivity - private static final String TAG = Log.tag(SignalBaseActivity.class); + private static final String TAG = Log.tag(BaseActivity.class); @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/org/tm/archive/WebRtcCallActivity.java b/app/src/main/java/org/tm/archive/WebRtcCallActivity.java index 823d5671..5bed23e8 100644 --- a/app/src/main/java/org/tm/archive/WebRtcCallActivity.java +++ b/app/src/main/java/org/tm/archive/WebRtcCallActivity.java @@ -137,6 +137,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan public static final String EXTRA_ENABLE_VIDEO_IF_AVAILABLE = WebRtcCallActivity.class.getCanonicalName() + ".ENABLE_VIDEO_IF_AVAILABLE"; public static final String EXTRA_STARTED_FROM_FULLSCREEN = WebRtcCallActivity.class.getCanonicalName() + ".STARTED_FROM_FULLSCREEN"; public static final String EXTRA_STARTED_FROM_CALL_LINK = WebRtcCallActivity.class.getCanonicalName() + ".STARTED_FROM_CALL_LINK"; + public static final String EXTRA_LAUNCH_IN_PIP = WebRtcCallActivity.class.getCanonicalName() + ".STARTED_FROM_CALL_LINK"; private CallParticipantsListUpdatePopupWindow participantUpdateWindow; private CallStateUpdatePopupWindow callStateUpdatePopupWindow; @@ -159,6 +160,8 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan private LifecycleDisposable lifecycleDisposable; private long lastCallLinkDisconnectDialogShowTime; private ControlsAndInfoController controlsAndInfo; + private boolean enterPipOnResume; + private long lastProcessedIntentTimestamp; private Disposable ephemeralStateDisposable = Disposable.empty(); @@ -264,6 +267,11 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan } }, TimeUnit.SECONDS.toMillis(1)); } + + if (enterPipOnResume) { + enterPipOnResume = false; + enterPipModeIfPossible(); + } } @Override @@ -299,10 +307,16 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan requestNewSizesThrottle.clear(); } + ApplicationDependencies.getSignalCallManager().setEnableVideo(false); + if (!viewModel.isCallStarting()) { CallParticipantsState state = viewModel.getCallParticipantsStateSnapshot(); - if (state != null && state.getCallState().isPreJoinOrNetworkUnavailable()) { - ApplicationDependencies.getSignalCallManager().cancelPreJoin(); + if (state != null) { + if (state.getCallState().isPreJoinOrNetworkUnavailable()) { + ApplicationDependencies.getSignalCallManager().cancelPreJoin(); + } else if (state.getCallState().getInOngoingCall() && isInPipMode()) { + ApplicationDependencies.getSignalCallManager().relaunchPipOnForeground(); + } } } } @@ -361,6 +375,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan Log.d(TAG, "Intent: Action: " + intent.getAction()); Log.d(TAG, "Intent: EXTRA_STARTED_FROM_FULLSCREEN: " + intent.getBooleanExtra(EXTRA_STARTED_FROM_FULLSCREEN, false)); Log.d(TAG, "Intent: EXTRA_ENABLE_VIDEO_IF_AVAILABLE: " + intent.getBooleanExtra(EXTRA_ENABLE_VIDEO_IF_AVAILABLE, false)); + Log.d(TAG, "Intent: EXTRA_LAUNCH_IN_PIP: " + intent.getBooleanExtra(EXTRA_LAUNCH_IN_PIP, false)); } private void processIntent(@NonNull Intent intent) { @@ -373,6 +388,12 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan } else if (END_CALL_ACTION.equals(intent.getAction())) { handleEndCall(); } + + if (System.currentTimeMillis() - lastProcessedIntentTimestamp > TimeUnit.SECONDS.toMillis(1)) { + enterPipOnResume = intent.getBooleanExtra(EXTRA_LAUNCH_IN_PIP, false); + } + + lastProcessedIntentTimestamp = System.currentTimeMillis(); } private void initializePendingParticipantFragmentListener() { @@ -765,7 +786,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan if (isFinishing()) return; // XXX Stuart added this check above, not sure why, so I'm repeating in ignorance. - moxie new MaterialAlertDialogBuilder(this) .setTitle(R.string.RedPhone_number_not_registered) - .setIcon(R.drawable.ic_warning) + .setIcon(R.drawable.symbol_error_triangle_fill_24) .setMessage(R.string.RedPhone_the_number_you_dialed_does_not_support_secure_voice) .setCancelable(true) .setPositiveButton(R.string.RedPhone_got_it, (d, w) -> handleTerminate(event.getRecipient(), HangupMessage.Type.NORMAL)) @@ -851,8 +872,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan } private boolean isSystemPipEnabledAndAvailable() { - return Build.VERSION.SDK_INT >= 26 && - getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); + return Build.VERSION.SDK_INT >= 26 && getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); } private void delayedFinish() { diff --git a/app/src/main/java/org/tm/archive/attachments/AttachmentId.kt b/app/src/main/java/org/tm/archive/attachments/AttachmentId.kt index 0879e976..245ac9a4 100644 --- a/app/src/main/java/org/tm/archive/attachments/AttachmentId.kt +++ b/app/src/main/java/org/tm/archive/attachments/AttachmentId.kt @@ -3,13 +3,14 @@ package org.tm.archive.attachments import android.os.Parcelable import com.fasterxml.jackson.annotation.JsonProperty import kotlinx.parcelize.Parcelize +import org.signal.core.util.DatabaseId @Parcelize data class AttachmentId( @JsonProperty("rowId") @JvmField val id: Long -) : Parcelable { +) : Parcelable, DatabaseId { val isValid: Boolean get() = id >= 0 @@ -17,4 +18,8 @@ data class AttachmentId( override fun toString(): String { return "AttachmentId::$id" } + + override fun serialize(): String { + return id.toString() + } } diff --git a/app/src/main/java/org/tm/archive/attachments/DatabaseAttachment.kt b/app/src/main/java/org/tm/archive/attachments/DatabaseAttachment.kt index 13b09eee..aaea04e2 100644 --- a/app/src/main/java/org/tm/archive/attachments/DatabaseAttachment.kt +++ b/app/src/main/java/org/tm/archive/attachments/DatabaseAttachment.kt @@ -22,6 +22,9 @@ class DatabaseAttachment : Attachment { @JvmField val hasData: Boolean + @JvmField + val dataHash: String? + private val hasThumbnail: Boolean val displayOrder: Int @@ -53,7 +56,8 @@ class DatabaseAttachment : Attachment { audioHash: AudioHash?, transformProperties: TransformProperties?, displayOrder: Int, - uploadTimestamp: Long + uploadTimestamp: Long, + dataHash: String? ) : super( contentType = contentType!!, transferState = transferProgress, @@ -81,6 +85,7 @@ class DatabaseAttachment : Attachment { this.attachmentId = attachmentId this.mmsId = mmsId this.hasData = hasData + this.dataHash = dataHash this.hasThumbnail = hasThumbnail this.displayOrder = displayOrder } @@ -88,6 +93,7 @@ class DatabaseAttachment : Attachment { constructor(parcel: Parcel) : super(parcel) { attachmentId = ParcelCompat.readParcelable(parcel, AttachmentId::class.java.classLoader, AttachmentId::class.java)!! hasData = ParcelUtil.readBoolean(parcel) + dataHash = parcel.readString() hasThumbnail = ParcelUtil.readBoolean(parcel) mmsId = parcel.readLong() displayOrder = parcel.readInt() @@ -97,6 +103,7 @@ class DatabaseAttachment : Attachment { super.writeToParcel(dest, flags) dest.writeParcelable(attachmentId, 0) ParcelUtil.writeBoolean(dest, hasData) + dest.writeString(dataHash) ParcelUtil.writeBoolean(dest, hasThumbnail) dest.writeLong(mmsId) dest.writeInt(displayOrder) diff --git a/app/src/main/java/org/tm/archive/attachments/PointerAttachment.kt b/app/src/main/java/org/tm/archive/attachments/PointerAttachment.kt index dd1db0f9..50ce63f0 100644 --- a/app/src/main/java/org/tm/archive/attachments/PointerAttachment.kt +++ b/app/src/main/java/org/tm/archive/attachments/PointerAttachment.kt @@ -2,6 +2,7 @@ package org.tm.archive.attachments import android.net.Uri import android.os.Parcel +import androidx.annotation.VisibleForTesting import org.signal.core.util.Base64.encodeWithPadding import org.tm.archive.blurhash.BlurHash import org.tm.archive.database.AttachmentTable @@ -14,7 +15,8 @@ import org.whispersystems.signalservice.internal.push.DataMessage import java.util.Optional class PointerAttachment : Attachment { - private constructor( + @VisibleForTesting + constructor( contentType: String, transferState: Int, size: Long, diff --git a/app/src/main/java/org/tm/archive/audio/AudioWaveFormGenerator.java b/app/src/main/java/org/tm/archive/audio/AudioWaveFormGenerator.java index eaddcf2b..f403ca25 100644 --- a/app/src/main/java/org/tm/archive/audio/AudioWaveFormGenerator.java +++ b/app/src/main/java/org/tm/archive/audio/AudioWaveFormGenerator.java @@ -12,7 +12,7 @@ import androidx.annotation.WorkerThread; import org.signal.core.util.logging.Log; import org.tm.archive.media.DecryptableUriMediaInput; -import org.tm.archive.media.MediaInput; +import org.tm.archive.video.interfaces.MediaInput; import java.io.IOException; import java.nio.ByteBuffer; @@ -57,12 +57,6 @@ public final class AudioWaveFormGenerator { throw new IOException("Mime not audio"); } - //**TM_SA**//S - if(mime.equals("audio/ac3")){ - throw new IOException("Ac3 Audio type not supported"); - } - //**TM_SA**//E - MediaCodec codec = MediaCodec.createDecoderByType(mime); if (totalDurationUs == 0) { diff --git a/app/src/main/java/org/tm/archive/avatar/picker/AvatarPickerItem.kt b/app/src/main/java/org/tm/archive/avatar/picker/AvatarPickerItem.kt index 731025fd..8fe7b4e4 100644 --- a/app/src/main/java/org/tm/archive/avatar/picker/AvatarPickerItem.kt +++ b/app/src/main/java/org/tm/archive/avatar/picker/AvatarPickerItem.kt @@ -8,12 +8,12 @@ import android.widget.TextView import androidx.appcompat.content.res.AppCompatResources import androidx.core.view.setPadding import com.airbnb.lottie.SimpleColorFilter +import com.bumptech.glide.Glide import org.tm.archive.R import org.tm.archive.avatar.Avatar import org.tm.archive.avatar.AvatarRenderer import org.tm.archive.avatar.Avatars import org.tm.archive.mms.DecryptableStreamUriLoader -import org.tm.archive.mms.GlideApp import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingModel @@ -132,12 +132,12 @@ object AvatarPickerItem { } is Avatar.Photo -> { textView.visible = false - GlideApp.with(imageView).load(DecryptableStreamUriLoader.DecryptableUri(model.avatar.uri)).into(imageView) + Glide.with(imageView).load(DecryptableStreamUriLoader.DecryptableUri(model.avatar.uri)).into(imageView) } is Avatar.Resource -> { imageView.setPadding((imageView.width * 0.2).toInt()) textView.visible = false - GlideApp.with(imageView).clear(imageView) + Glide.with(imageView).clear(imageView) imageView.setImageResource(model.avatar.resourceId) imageView.colorFilter = SimpleColorFilter(model.avatar.color.foregroundColor) imageView.background.colorFilter = SimpleColorFilter(model.avatar.color.backgroundColor) diff --git a/app/src/main/java/org/tm/archive/avatar/view/AvatarView.kt b/app/src/main/java/org/tm/archive/avatar/view/AvatarView.kt index eb991d4e..a3d02dd4 100644 --- a/app/src/main/java/org/tm/archive/avatar/view/AvatarView.kt +++ b/app/src/main/java/org/tm/archive/avatar/view/AvatarView.kt @@ -5,10 +5,10 @@ import android.util.AttributeSet import android.view.View import android.widget.FrameLayout import androidx.core.content.res.use +import com.bumptech.glide.RequestManager import org.tm.archive.R import org.tm.archive.components.AvatarImageView import org.tm.archive.database.model.StoryViewState -import org.tm.archive.mms.GlideRequests import org.tm.archive.recipients.Recipient import org.tm.archive.stories.Stories import org.tm.archive.util.visible @@ -76,7 +76,7 @@ class AvatarView @JvmOverloads constructor( /** * Displays Note-to-Self */ - fun displayChatAvatar(requestManager: GlideRequests, recipient: Recipient, isQuickContactEnabled: Boolean) { + fun displayChatAvatar(requestManager: RequestManager, recipient: Recipient, isQuickContactEnabled: Boolean) { avatar.setAvatar(requestManager, recipient, isQuickContactEnabled) } diff --git a/app/src/main/java/org/tm/archive/backup/FullBackupExporter.java b/app/src/main/java/org/tm/archive/backup/FullBackupExporter.java index ac8ae70b..da2013d7 100644 --- a/app/src/main/java/org/tm/archive/backup/FullBackupExporter.java +++ b/app/src/main/java/org/tm/archive/backup/FullBackupExporter.java @@ -160,7 +160,7 @@ public class FullBackupExporter extends FullBackupBase { for (String table : tables) { throwIfCanceled(cancellationSignal); if (table.equals(MessageTable.TABLE_NAME)) { - count = exportTable(table, input, outputStream, cursor -> isNonExpiringMessage(cursor), null, count, estimatedCount, cancellationSignal); + count = exportTable(table, input, outputStream, cursor -> isNonExpiringMessage(input, cursor), null, count, estimatedCount, cancellationSignal); } else if (table.equals(ReactionTable.TABLE_NAME)) { count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, CursorUtil.requireLong(cursor, ReactionTable.MESSAGE_ID)), null, count, estimatedCount, cancellationSignal); } else if (table.equals(MentionTable.TABLE_NAME)) { @@ -579,25 +579,34 @@ public class FullBackupExporter extends FullBackupBase { return count; } - private static boolean isNonExpiringMessage(@NonNull Cursor cursor) { - long expiresIn = CursorUtil.requireLong(cursor, MessageTable.EXPIRES_IN); - boolean viewOnce = CursorUtil.requireBoolean(cursor, MessageTable.VIEW_ONCE); + private static boolean isNonExpiringMessage(@NonNull SQLiteDatabase db, @NonNull Cursor cursor) { + long id = CursorUtil.requireLong(cursor, MessageTable.ID); + long expireStarted = CursorUtil.requireLong(cursor, MessageTable.EXPIRE_STARTED); + long expiresIn = CursorUtil.requireLong(cursor, MessageTable.EXPIRES_IN); + long latestRevisionId = CursorUtil.requireLong(cursor, MessageTable.LATEST_REVISION_ID); - if (expiresIn == 0 && !viewOnce) { - return true; + long expiresAt = expireStarted + expiresIn; + long timeRemaining = expiresAt - System.currentTimeMillis(); + + if (latestRevisionId > 0 && latestRevisionId != id ) { + return isForNonExpiringMessage(db, latestRevisionId); } - return expiresIn > EXPIRATION_BACKUP_THRESHOLD; + if (expireStarted > 0 && timeRemaining <= EXPIRATION_BACKUP_THRESHOLD) { + return false; + } + + return true; } private static boolean isForNonExpiringMessage(@NonNull SQLiteDatabase db, long messageId) { - String[] columns = new String[] { MessageTable.EXPIRES_IN, MessageTable.VIEW_ONCE }; + String[] columns = new String[] { MessageTable.ID, MessageTable.EXPIRE_STARTED, MessageTable.EXPIRES_IN, MessageTable.LATEST_REVISION_ID }; String where = MessageTable.ID + " = ?"; String[] args = SqlUtil.buildArgs(messageId); try (Cursor mmsCursor = db.query(MessageTable.TABLE_NAME, columns, where, args, null, null, null)) { if (mmsCursor != null && mmsCursor.moveToFirst()) { - return isNonExpiringMessage(mmsCursor); + return isNonExpiringMessage(db, mmsCursor); } } diff --git a/app/src/main/java/org/tm/archive/backup/FullBackupImporter.java b/app/src/main/java/org/tm/archive/backup/FullBackupImporter.java index 6e58c3fb..e4530ee9 100644 --- a/app/src/main/java/org/tm/archive/backup/FullBackupImporter.java +++ b/app/src/main/java/org/tm/archive/backup/FullBackupImporter.java @@ -155,11 +155,9 @@ public class FullBackupImporter extends FullBackupBase { } private static void processVersion(@NonNull SQLiteDatabase db, DatabaseVersion version) throws IOException { - //**TM_SA**//s - /*if (version.version == null || version.version > db.getVersion()) { + if (version.version == null || version.version > db.getVersion()) { throw new DatabaseDowngradeException(db.getVersion(), version.version != null ? version.version : -1); - }*/ - //**TM_SA**//s + } db.setVersion(version.version); } @@ -196,7 +194,7 @@ public class FullBackupImporter extends FullBackupBase { private static void processAttachment(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret, @NonNull SQLiteDatabase db, @NonNull Attachment attachment, BackupRecordInputStream inputStream) throws IOException { - File dataFile = AttachmentTable.newFile(context); + File dataFile = AttachmentTable.newDataFile(context); Pair output = ModernEncryptingPartOutputStream.createFor(attachmentSecret, dataFile, false); boolean isLegacyTable = SqlUtil.tableExists(db, "part"); diff --git a/app/src/main/java/org/tm/archive/backup/v2/BackupRepository.kt b/app/src/main/java/org/tm/archive/backup/v2/BackupRepository.kt index d7d8a91e..d837de0d 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/BackupRepository.kt @@ -5,10 +5,16 @@ package org.tm.archive.backup.v2 +import org.signal.core.util.Base64 import org.signal.core.util.EventTimer import org.signal.core.util.logging.Log import org.signal.core.util.withinTransaction +import org.signal.libsignal.messagebackup.MessageBackup +import org.signal.libsignal.messagebackup.MessageBackup.ValidationResult +import org.signal.libsignal.messagebackup.MessageBackupKey +import org.signal.libsignal.protocol.ServiceId.Aci import org.signal.libsignal.zkgroup.profiles.ProfileKey +import org.tm.archive.attachments.DatabaseAttachment import org.tm.archive.backup.v2.database.ChatItemImportInserter import org.tm.archive.backup.v2.database.clearAllDataForBackupRestore import org.tm.archive.backup.v2.processor.AccountDataProcessor @@ -16,6 +22,7 @@ import org.tm.archive.backup.v2.processor.CallLogBackupProcessor import org.tm.archive.backup.v2.processor.ChatBackupProcessor import org.tm.archive.backup.v2.processor.ChatItemBackupProcessor import org.tm.archive.backup.v2.processor.RecipientBackupProcessor +import org.tm.archive.backup.v2.proto.BackupInfo import org.tm.archive.backup.v2.stream.BackupExportWriter import org.tm.archive.backup.v2.stream.EncryptedBackupReader import org.tm.archive.backup.v2.stream.EncryptedBackupWriter @@ -23,13 +30,22 @@ import org.tm.archive.backup.v2.stream.PlainTextBackupReader import org.tm.archive.backup.v2.stream.PlainTextBackupWriter import org.tm.archive.database.SignalDatabase import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.groups.GroupId +import org.tm.archive.jobs.RequestGroupV2InfoJob import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.RecipientId import org.whispersystems.signalservice.api.NetworkResult -import org.whispersystems.signalservice.api.archive.ArchiveGetBackupInfoResponse +import org.whispersystems.signalservice.api.archive.ArchiveGetMediaItemsResponse +import org.whispersystems.signalservice.api.archive.ArchiveMediaRequest +import org.whispersystems.signalservice.api.archive.ArchiveMediaResponse import org.whispersystems.signalservice.api.archive.ArchiveServiceCredential +import org.whispersystems.signalservice.api.archive.BatchArchiveMediaResponse +import org.whispersystems.signalservice.api.archive.DeleteArchivedMediaRequest +import org.whispersystems.signalservice.api.backup.BackupKey +import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI +import org.whispersystems.signalservice.internal.crypto.PaddingInputStream import java.io.ByteArrayOutputStream import java.io.InputStream import kotlin.time.Duration.Companion.milliseconds @@ -37,6 +53,7 @@ import kotlin.time.Duration.Companion.milliseconds object BackupRepository { private val TAG = Log.tag(BackupRepository::class.java) + private const val VERSION = 1L fun export(plaintext: Boolean = false): ByteArray { val eventTimer = EventTimer() @@ -53,7 +70,15 @@ object BackupRepository { ) } + val exportState = ExportState(System.currentTimeMillis()) + writer.use { + writer.write( + BackupInfo( + version = VERSION, + backupTimeMs = exportState.backupTime + ) + ) // Note: Without a transaction, we may export inconsistent state. But because we have a transaction, // writes from other threads are blocked. This is something to think more about. SignalDatabase.rawDatabase.withinTransaction { @@ -62,12 +87,12 @@ object BackupRepository { eventTimer.emit("account") } - RecipientBackupProcessor.export { + RecipientBackupProcessor.export(exportState) { writer.write(it) eventTimer.emit("recipient") } - ChatBackupProcessor.export { frame -> + ChatBackupProcessor.export(exportState) { frame -> writer.write(frame) eventTimer.emit("thread") } @@ -77,7 +102,7 @@ object BackupRepository { eventTimer.emit("call") } - ChatItemBackupProcessor.export { frame -> + ChatItemBackupProcessor.export(exportState) { frame -> writer.write(frame) eventTimer.emit("message") } @@ -89,6 +114,13 @@ object BackupRepository { return outputStream.toByteArray() } + fun validate(length: Long, inputStreamFactory: () -> InputStream, selfData: SelfData): ValidationResult { + val masterKey = SignalStore.svr().getOrCreateMasterKey() + val key = MessageBackupKey(masterKey.serialize(), Aci.parseFromBinary(selfData.aci.toByteArray())) + + return MessageBackup.validate(key, MessageBackup.Purpose.REMOTE_BACKUP, inputStreamFactory, length) + } + fun import(length: Long, inputStreamFactory: () -> InputStream, selfData: SelfData, plaintext: Boolean = false) { val eventTimer = EventTimer() @@ -103,6 +135,15 @@ object BackupRepository { ) } + val header = frameReader.getHeader() + if (header == null) { + Log.e(TAG, "Backup is missing header!") + return + } else if (header.version > VERSION) { + Log.e(TAG, "Backup version is newer than we understand: ${header.version}") + return + } + // Note: Without a transaction, bad imports could lead to lost data. But because we have a transaction, // writes from other threads are blocked. This is something to think more about. SignalDatabase.rawDatabase.withinTransaction { @@ -118,6 +159,7 @@ object BackupRepository { SignalDatabase.recipients.setProfileKey(selfId, selfData.profileKey) SignalDatabase.recipients.setProfileSharing(selfId, true) + eventTimer.emit("setup") val backupState = BackupState() val chatItemInserter: ChatItemImportInserter = ChatItemBackupProcessor.beginImport(backupState) @@ -162,13 +204,21 @@ object BackupRepository { } } + val groups = SignalDatabase.groups.getGroups() + while (groups.hasNext()) { + val group = groups.next() + if (group.id.isV2) { + ApplicationDependencies.getJobManager().add(RequestGroupV2InfoJob(group.id as GroupId.V2)) + } + } + Log.d(TAG, "import() ${eventTimer.stop().summary}") } /** * Returns an object with details about the remote backup state. */ - fun getRemoteBackupState(): NetworkResult { + fun getRemoteBackupState(): NetworkResult { val api = ApplicationDependencies.getSignalServiceAccountManager().archiveApi val backupKey = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey() @@ -182,6 +232,18 @@ object BackupRepository { } .then { credential -> api.getBackupInfo(backupKey, credential) + .map { it to credential } + } + .then { pair -> + val (info, credential) = pair + api.debugGetUploadedMediaItemMetadata(backupKey, credential) + .also { Log.i(TAG, "MediaItemMetadataResult: $it") } + .map { mediaObjects -> + BackupMetadata( + usedSpace = info.usedSpace ?: 0, + mediaCount = mediaObjects.size.toLong() + ) + } } } @@ -219,6 +281,77 @@ object BackupRepository { .also { Log.i(TAG, "OverallResult: $it") } is NetworkResult.Success } + /** + * Returns an object with details about the remote backup state. + */ + fun debugGetArchivedMediaState(): NetworkResult> { + val api = ApplicationDependencies.getSignalServiceAccountManager().archiveApi + val backupKey = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey() + + return api + .triggerBackupIdReservation(backupKey) + .then { getAuthCredential() } + .then { credential -> + api.debugGetUploadedMediaItemMetadata(backupKey, credential) + } + } + + fun archiveMedia(attachment: DatabaseAttachment): NetworkResult { + val api = ApplicationDependencies.getSignalServiceAccountManager().archiveApi + val backupKey = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey() + + return api + .triggerBackupIdReservation(backupKey) + .then { getAuthCredential() } + .then { credential -> + api.archiveAttachmentMedia( + backupKey = backupKey, + serviceCredential = credential, + item = attachment.toArchiveMediaRequest(backupKey) + ) + } + .also { Log.i(TAG, "backupMediaResult: $it") } + } + + fun archiveMedia(attachments: List): NetworkResult { + val api = ApplicationDependencies.getSignalServiceAccountManager().archiveApi + val backupKey = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey() + + return api + .triggerBackupIdReservation(backupKey) + .then { getAuthCredential() } + .then { credential -> + api.archiveAttachmentMedia( + backupKey = backupKey, + serviceCredential = credential, + items = attachments.map { it.toArchiveMediaRequest(backupKey) } + ) + } + .also { Log.i(TAG, "backupMediaResult: $it") } + } + + fun deleteArchivedMedia(attachments: List): NetworkResult { + val api = ApplicationDependencies.getSignalServiceAccountManager().archiveApi + val backupKey = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey() + + val mediaToDelete = attachments.map { + DeleteArchivedMediaRequest.ArchivedMediaObject( + cdn = 3, // TODO [cody] store and reuse backup cdn returned from copy/move call + mediaId = backupKey.deriveMediaId(Base64.decode(it.dataHash!!)).toString() + ) + } + + return getAuthCredential() + .then { credential -> + api.deleteArchivedMedia( + backupKey = backupKey, + serviceCredential = credential, + mediaToDelete = mediaToDelete + ) + } + .also { Log.i(TAG, "deleteBackupMediaResult: $it") } + } + /** * Retrieves an auth credential, preferring a cached value if available. */ @@ -246,6 +379,26 @@ object BackupRepository { val e164: String, val profileKey: ProfileKey ) + + private fun DatabaseAttachment.toArchiveMediaRequest(backupKey: BackupKey): ArchiveMediaRequest { + val mediaSecrets = backupKey.deriveMediaSecrets(Base64.decode(dataHash!!)) + return ArchiveMediaRequest( + sourceAttachment = ArchiveMediaRequest.SourceAttachment( + cdn = cdnNumber, + key = remoteLocation!! + ), + objectLength = AttachmentCipherStreamUtil.getCiphertextLength(PaddingInputStream.getPaddedSize(size)).toInt(), + mediaId = mediaSecrets.id.toString(), + hmacKey = Base64.encodeWithPadding(mediaSecrets.macKey), + encryptionKey = Base64.encodeWithPadding(mediaSecrets.cipherKey), + iv = Base64.encodeWithPadding(mediaSecrets.iv) + ) + } +} + +class ExportState(val backupTime: Long) { + val recipientIds = HashSet() + val threadIds = HashSet() } class BackupState { @@ -255,3 +408,8 @@ class BackupState { val chatIdToBackupRecipientId = HashMap() val callIdToType = HashMap() } + +class BackupMetadata( + val usedSpace: Long, + val mediaCount: Long +) diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/AttachmentTableBackupExtensions.kt b/app/src/main/java/org/tm/archive/backup/v2/database/AttachmentTableBackupExtensions.kt index 31f3eb64..4bddeb22 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/AttachmentTableBackupExtensions.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/AttachmentTableBackupExtensions.kt @@ -5,9 +5,9 @@ package org.tm.archive.backup.v2.database -import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.tm.archive.database.AttachmentTable fun AttachmentTable.clearAllDataForBackupRestore() { - writableDatabase.delete(AttachmentTable.TABLE_NAME).run() + writableDatabase.deleteAll(AttachmentTable.TABLE_NAME) } diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/CallTableBackupExtensions.kt b/app/src/main/java/org/tm/archive/backup/v2/database/CallTableBackupExtensions.kt index 485cc198..1a2812a6 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/CallTableBackupExtensions.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/CallTableBackupExtensions.kt @@ -39,17 +39,12 @@ fun CallTable.restoreCallLogFromBackup(call: BackupCall, backupState: BackupStat Call.Type.UNKNOWN_TYPE -> return } - val event = when (call.event) { - Call.Event.DELETE -> CallTable.Event.DELETE - Call.Event.JOINED -> CallTable.Event.JOINED - Call.Event.GENERIC_GROUP_CALL -> CallTable.Event.GENERIC_GROUP_CALL - Call.Event.DECLINED -> CallTable.Event.DECLINED - Call.Event.ACCEPTED -> CallTable.Event.ACCEPTED - Call.Event.MISSED -> CallTable.Event.MISSED - Call.Event.OUTGOING_RING -> CallTable.Event.OUTGOING_RING - Call.Event.OUTGOING -> CallTable.Event.ONGOING - Call.Event.NOT_ACCEPTED -> CallTable.Event.NOT_ACCEPTED - Call.Event.UNKNOWN_EVENT -> return + val event = when (call.state) { + Call.State.MISSED -> CallTable.Event.MISSED + Call.State.COMPLETED -> CallTable.Event.ACCEPTED + Call.State.DECLINED_BY_USER -> CallTable.Event.DECLINED + Call.State.DECLINED_BY_NOTIFICATION_PROFILE -> CallTable.Event.MISSED_NOTIFICATION_PROFILE + Call.State.UNKNOWN_EVENT -> return } val direction = if (call.outgoing) CallTable.Direction.OUTGOING else CallTable.Direction.INCOMING @@ -62,7 +57,8 @@ fun CallTable.restoreCallLogFromBackup(call: BackupCall, backupState: BackupStat CallTable.TYPE to CallTable.Type.serialize(type), CallTable.DIRECTION to CallTable.Direction.serialize(direction), CallTable.EVENT to CallTable.Event.serialize(event), - CallTable.TIMESTAMP to call.timestamp + CallTable.TIMESTAMP to call.timestamp, + CallTable.RINGER to if (call.ringerRecipientId != null) backupState.backupToLocalRecipientId[call.ringerRecipientId]?.toLong() else null ) writableDatabase.insert(CallTable.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values) @@ -102,18 +98,18 @@ class CallLogIterator(private val cursor: Cursor) : Iterator, Close }, timestamp = cursor.requireLong(CallTable.TIMESTAMP), ringerRecipientId = if (cursor.isNull(CallTable.RINGER)) null else cursor.requireLong(CallTable.RINGER), - event = when (event) { - CallTable.Event.ONGOING -> Call.Event.OUTGOING - CallTable.Event.OUTGOING_RING -> Call.Event.OUTGOING_RING - CallTable.Event.ACCEPTED -> Call.Event.ACCEPTED - CallTable.Event.DECLINED -> Call.Event.DECLINED - CallTable.Event.GENERIC_GROUP_CALL -> Call.Event.GENERIC_GROUP_CALL - CallTable.Event.JOINED -> Call.Event.JOINED - CallTable.Event.MISSED, - CallTable.Event.MISSED_NOTIFICATION_PROFILE -> Call.Event.MISSED - CallTable.Event.DELETE -> Call.Event.DELETE - CallTable.Event.RINGING -> Call.Event.UNKNOWN_EVENT - CallTable.Event.NOT_ACCEPTED -> Call.Event.NOT_ACCEPTED + state = when (event) { + CallTable.Event.ONGOING -> Call.State.COMPLETED + CallTable.Event.OUTGOING_RING -> Call.State.COMPLETED + CallTable.Event.ACCEPTED -> Call.State.COMPLETED + CallTable.Event.DECLINED -> Call.State.DECLINED_BY_USER + CallTable.Event.GENERIC_GROUP_CALL -> Call.State.COMPLETED + CallTable.Event.JOINED -> Call.State.COMPLETED + CallTable.Event.MISSED -> Call.State.MISSED + CallTable.Event.MISSED_NOTIFICATION_PROFILE -> Call.State.DECLINED_BY_NOTIFICATION_PROFILE + CallTable.Event.DELETE -> Call.State.COMPLETED + CallTable.Event.RINGING -> Call.State.MISSED + CallTable.Event.NOT_ACCEPTED -> Call.State.MISSED } ) } diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemExportIterator.kt b/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemExportIterator.kt index e40681d0..7a58d432 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemExportIterator.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemExportIterator.kt @@ -9,6 +9,7 @@ import android.database.Cursor import com.annimon.stream.Stream import okio.ByteString.Companion.toByteString import org.signal.core.util.Base64 +import org.signal.core.util.Base64.decode import org.signal.core.util.Base64.decodeOrThrow import org.signal.core.util.logging.Log import org.signal.core.util.requireBlob @@ -16,12 +17,15 @@ import org.signal.core.util.requireBoolean import org.signal.core.util.requireInt import org.signal.core.util.requireLong import org.signal.core.util.requireString +import org.tm.archive.attachments.DatabaseAttachment import org.tm.archive.backup.v2.proto.CallChatUpdate import org.tm.archive.backup.v2.proto.ChatItem import org.tm.archive.backup.v2.proto.ChatUpdateMessage import org.tm.archive.backup.v2.proto.ExpirationTimerChatUpdate +import org.tm.archive.backup.v2.proto.FilePointer import org.tm.archive.backup.v2.proto.GroupCallChatUpdate import org.tm.archive.backup.v2.proto.IndividualCallChatUpdate +import org.tm.archive.backup.v2.proto.MessageAttachment import org.tm.archive.backup.v2.proto.ProfileChangeChatUpdate import org.tm.archive.backup.v2.proto.Quote import org.tm.archive.backup.v2.proto.Reaction @@ -40,11 +44,16 @@ import org.tm.archive.database.SignalDatabase.Companion.calls import org.tm.archive.database.documents.IdentityKeyMismatchSet import org.tm.archive.database.documents.NetworkFailureSet import org.tm.archive.database.model.GroupCallUpdateDetailsUtil +import org.tm.archive.database.model.GroupsV2UpdateMessageConverter +import org.tm.archive.database.model.Mention import org.tm.archive.database.model.ReactionRecord import org.tm.archive.database.model.databaseprotos.BodyRangeList +import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context +import org.tm.archive.database.model.databaseprotos.MessageExtras import org.tm.archive.database.model.databaseprotos.ProfileChangeDetails import org.tm.archive.database.model.databaseprotos.SessionSwitchoverEvent import org.tm.archive.database.model.databaseprotos.ThreadMergeEvent +import org.tm.archive.keyvalue.SignalStore import org.tm.archive.mms.QuoteModel import org.tm.archive.util.JsonUtils import org.whispersystems.signalservice.api.push.ServiceId.ACI @@ -99,6 +108,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } val reactionsById: Map> = SignalDatabase.reactions.getReactionsForMessages(records.keys) + val mentionsById: Map> = SignalDatabase.mentions.getMentionsForMessages(records.keys) + val attachmentsById: Map> = SignalDatabase.attachments.getAttachmentsForMessages(records.keys) val groupReceiptsById: Map> = SignalDatabase.groupReceipts.getGroupReceiptInfoForMessages(records.keys) for ((id, record) in records) { @@ -110,14 +121,23 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: MessageTypes.isIdentityUpdate(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.IDENTITY_UPDATE)) MessageTypes.isIdentityVerified(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.IDENTITY_VERIFIED)) MessageTypes.isIdentityDefault(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.IDENTITY_DEFAULT)) - MessageTypes.isChangeNumber(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.CHANGE_NUMBER)) - MessageTypes.isBoostRequest(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.BOOST_REQUEST)) + MessageTypes.isChangeNumber(record.type) -> { + builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.CHANGE_NUMBER)) + builder.sms = false + } + MessageTypes.isBoostRequest(record.type) -> { + builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.BOOST_REQUEST)) + builder.sms = false + } MessageTypes.isEndSessionType(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.END_SESSION)) MessageTypes.isChatSessionRefresh(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.CHAT_SESSION_REFRESH)) MessageTypes.isBadDecryptType(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.BAD_DECRYPT)) MessageTypes.isPaymentsActivated(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.PAYMENTS_ACTIVATED)) MessageTypes.isPaymentsRequestToActivate(record.type) -> builder.updateMessage = ChatUpdateMessage(simpleUpdate = SimpleChatUpdate(type = SimpleChatUpdate.Type.PAYMENT_ACTIVATION_REQUEST)) - MessageTypes.isExpirationTimerUpdate(record.type) -> builder.updateMessage = ChatUpdateMessage(expirationTimerChange = ExpirationTimerChatUpdate((record.expiresIn / 1000).toInt())) + MessageTypes.isExpirationTimerUpdate(record.type) -> { + builder.updateMessage = ChatUpdateMessage(expirationTimerChange = ExpirationTimerChatUpdate(record.expiresIn.toInt())) + builder.expiresInMs = null + } MessageTypes.isProfileChange(record.type) -> { builder.updateMessage = ChatUpdateMessage( profileChange = try { @@ -133,6 +153,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: ProfileChangeChatUpdate() } ) + builder.sms = false } MessageTypes.isSessionSwitchoverType(record.type) -> { builder.updateMessage = ChatUpdateMessage( @@ -154,6 +175,26 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } ) } + MessageTypes.isGroupV2(record.type) && MessageTypes.isGroupUpdate(record.type) -> { + val groupChange = record.messageExtras?.gv2UpdateDescription?.groupChangeUpdate + if (groupChange != null) { + builder.updateMessage = ChatUpdateMessage( + groupChange = groupChange + ) + } else if (record.body != null) { + try { + val decoded: ByteArray = decode(record.body) + val context = DecryptedGroupV2Context.ADAPTER.decode(decoded) + builder.updateMessage = ChatUpdateMessage( + groupChange = GroupsV2UpdateMessageConverter.translateDecryptedChange(selfIds = SignalStore.account().getServiceIds(), context) + ) + } catch (e: IOException) { + continue + } + } else { + continue + } + } MessageTypes.isCallLog(record.type) -> { val call = calls.getCallByMessageId(record.id) if (call != null) { @@ -161,10 +202,10 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } else { when { MessageTypes.isMissedAudioCall(record.type) -> { - builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_AUDIO_CALL))) + builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_INCOMING_AUDIO_CALL))) } MessageTypes.isMissedVideoCall(record.type) -> { - builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_VIDEO_CALL))) + builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_INCOMING_VIDEO_CALL))) } MessageTypes.isIncomingAudioCall(record.type) -> { builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.INCOMING_AUDIO_CALL))) @@ -203,11 +244,11 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } } } - record.body == null -> { - Log.w(TAG, "Record missing a body, skipping") + record.body == null && !attachmentsById.containsKey(record.id) -> { + Log.w(TAG, "Record missing a body and doesnt have attachments, skipping") continue } - else -> builder.standardMessage = record.toTextMessage(reactionsById[id]) + else -> builder.standardMessage = record.toStandardMessage(reactionsById[id], mentions = mentionsById[id], attachments = attachmentsById[record.id]) } buffer += builder.build() @@ -241,7 +282,6 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: chatId = record.threadId authorId = record.fromRecipientId dateSent = record.dateSent - sealedSender = record.sealedSender expireStartDate = if (record.expireStarted > 0) record.expireStarted else null expiresInMs = if (record.expiresIn > 0) record.expiresIn else null revisions = emptyList() @@ -255,19 +295,28 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: incoming = ChatItem.IncomingMessageDetails( dateServerSent = record.dateServer, dateReceived = record.dateReceived, - read = record.read + read = record.read, + sealedSender = record.sealedSender ) } } } - private fun BackupMessageRecord.toTextMessage(reactionRecords: List?): StandardMessage { + private fun BackupMessageRecord.toStandardMessage(reactionRecords: List?, mentions: List?, attachments: List?): StandardMessage { + val text = if (body == null) { + null + } else { + Text( + body = this.body, + bodyRanges = (this.bodyRanges?.toBackupBodyRanges() ?: emptyList()) + (mentions?.toBackupBodyRanges() ?: emptyList()) + ) + } + val quotedAttachments = attachments?.filter { it.quote } ?: emptyList() + val messageAttachments = attachments?.filter { !it.quote } ?: emptyList() return StandardMessage( - quote = this.toQuote(), - text = Text( - body = this.body!!, - bodyRanges = this.bodyRanges?.toBackupBodyRanges() ?: emptyList() - ), + quote = this.toQuote(quotedAttachments), + text = text, + attachments = messageAttachments.toBackupAttachments(), // TODO Link previews! linkPreview = emptyList(), longText = null, @@ -275,14 +324,14 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: ) } - private fun BackupMessageRecord.toQuote(): Quote? { + private fun BackupMessageRecord.toQuote(attachments: List? = null): Quote? { return if (this.quoteTargetSentTimestamp != MessageTable.QUOTE_NOT_PRESENT_ID && this.quoteAuthor > 0) { - // TODO Attachments! val type = QuoteModel.Type.fromCode(this.quoteType) Quote( targetSentTimestamp = this.quoteTargetSentTimestamp.takeIf { !this.quoteMissing && it != MessageTable.QUOTE_TARGET_MISSING_ID }, authorId = this.quoteAuthor, text = this.quoteBody, + attachments = attachments?.toBackupQuoteAttachments() ?: emptyList(), bodyRanges = this.quoteBodyRanges?.toBackupBodyRanges() ?: emptyList(), type = when (type) { QuoteModel.Type.NORMAL -> Quote.Type.NORMAL @@ -294,6 +343,54 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } } + private fun List.toBackupQuoteAttachments(): List { + return this.map { attachment -> + Quote.QuotedAttachment( + contentType = attachment.contentType, + fileName = attachment.fileName, + thumbnail = attachment.toBackupAttachment() + ) + } + } + + private fun DatabaseAttachment.toBackupAttachment(): MessageAttachment { + return MessageAttachment( + pointer = FilePointer( + attachmentLocator = FilePointer.AttachmentLocator( + cdnKey = this.remoteLocation ?: "", + cdnNumber = this.cdnNumber, + uploadTimestamp = this.uploadTimestamp + ), + key = if (remoteKey != null) decode(remoteKey).toByteString() else null, + contentType = this.contentType, + size = this.size.toInt(), + incrementalMac = this.incrementalDigest?.toByteString(), + incrementalMacChunkSize = this.incrementalMacChunkSize, + fileName = this.fileName, + width = this.width, + height = this.height, + caption = this.caption, + blurHash = this.blurHash?.hash + ) + ) + } + + private fun List.toBackupAttachments(): List { + return this.map { attachment -> + attachment.toBackupAttachment() + } + } + + private fun List.toBackupBodyRanges(): List { + return this.map { + BackupBodyRange( + start = it.start, + length = it.length, + mentionAci = SignalDatabase.recipients.getRecord(it.recipientId).aci?.toByteString() + ) + } + } + private fun ByteArray.toBackupBodyRanges(): List { val decoded: BodyRangeList = try { BodyRangeList.ADAPTER.decode(this) @@ -306,7 +403,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: BackupBodyRange( start = it.start, length = it.length, - mentionAci = it.mentionUuid?.let { UuidUtil.parseOrThrow(it) }?.toByteArray()?.toByteString(), + mentionAci = it.mentionUuid?.let { uuid -> UuidUtil.parseOrThrow(uuid) }?.toByteArray()?.toByteString(), style = it.style?.toBackupBodyRangeStyle() ) } @@ -412,6 +509,17 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } } + private fun ByteArray?.parseMessageExtras(): MessageExtras? { + if (this == null) { + return null + } + return try { + MessageExtras.ADAPTER.decode(this) + } catch (e: java.lang.Exception) { + null + } + } + private fun Cursor.toBackupMessageRecord(): BackupMessageRecord { return BackupMessageRecord( id = this.requireLong(MessageTable.ID), @@ -443,7 +551,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: receiptTimestamp = this.requireLong(MessageTable.RECEIPT_TIMESTAMP), networkFailureRecipientIds = this.requireString(MessageTable.NETWORK_FAILURES).parseNetworkFailures(), identityMismatchRecipientIds = this.requireString(MessageTable.MISMATCHED_IDENTITIES).parseIdentityMismatches(), - baseType = this.requireLong(COLUMN_BASE_TYPE) + baseType = this.requireLong(COLUMN_BASE_TYPE), + messageExtras = this.requireBlob(MessageTable.MESSAGE_EXTRAS).parseMessageExtras() ) } @@ -477,6 +586,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: val read: Boolean, val networkFailureRecipientIds: Set, val identityMismatchRecipientIds: Set, - val baseType: Long + val baseType: Long, + val messageExtras: MessageExtras? ) } diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemImportInserter.kt b/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemImportInserter.kt index 92a53fd2..764a5d8a 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemImportInserter.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/ChatItemImportInserter.kt @@ -10,13 +10,17 @@ import androidx.core.content.contentValuesOf import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.logging.Log +import org.signal.core.util.orNull import org.signal.core.util.requireLong import org.signal.core.util.toInt +import org.tm.archive.attachments.Attachment +import org.tm.archive.attachments.PointerAttachment import org.tm.archive.backup.v2.BackupState import org.tm.archive.backup.v2.proto.BodyRange import org.tm.archive.backup.v2.proto.ChatItem import org.tm.archive.backup.v2.proto.ChatUpdateMessage import org.tm.archive.backup.v2.proto.IndividualCallChatUpdate +import org.tm.archive.backup.v2.proto.MessageAttachment import org.tm.archive.backup.v2.proto.Quote import org.tm.archive.backup.v2.proto.Reaction import org.tm.archive.backup.v2.proto.SendStatus @@ -28,11 +32,15 @@ import org.tm.archive.database.MessageTable import org.tm.archive.database.MessageTypes import org.tm.archive.database.ReactionTable import org.tm.archive.database.SQLiteDatabase +import org.tm.archive.database.SignalDatabase import org.tm.archive.database.documents.IdentityKeyMismatch import org.tm.archive.database.documents.IdentityKeyMismatchSet import org.tm.archive.database.documents.NetworkFailure import org.tm.archive.database.documents.NetworkFailureSet +import org.tm.archive.database.model.Mention import org.tm.archive.database.model.databaseprotos.BodyRangeList +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription +import org.tm.archive.database.model.databaseprotos.MessageExtras import org.tm.archive.database.model.databaseprotos.ProfileChangeDetails import org.tm.archive.database.model.databaseprotos.SessionSwitchoverEvent import org.tm.archive.database.model.databaseprotos.ThreadMergeEvent @@ -40,7 +48,12 @@ import org.tm.archive.mms.QuoteModel import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.util.JsonUtils +import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer +import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId +import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage +import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.util.UuidUtil +import java.util.Optional /** * An object that will ingest all fo the [ChatItem]s you want to write, buffer them until hitting a specified batch size, and then batch insert them @@ -152,7 +165,6 @@ class ChatItemImportInserter( if (buffer.size == 0) { return false } - buildBulkInsert(MessageTable.TABLE_NAME, MESSAGE_COLUMNS, buffer.messages).forEach { db.rawQuery("${it.query.where} RETURNING ${MessageTable.ID}", it.query.whereArgs).use { cursor -> var index = 0 @@ -177,6 +189,8 @@ class ChatItemImportInserter( messageId = SqlUtil.getNextAutoIncrementId(db, MessageTable.TABLE_NAME) + buffer.reset() + return true } @@ -202,6 +216,38 @@ class ChatItemImportInserter( } } } + if (this.standardMessage != null) { + val bodyRanges = this.standardMessage.text?.bodyRanges + if (!bodyRanges.isNullOrEmpty()) { + val mentions = bodyRanges.filter { it.mentionAci != null && it.start != null && it.length != null } + .mapNotNull { + val aci = ServiceId.ACI.parseOrNull(it.mentionAci!!) + + if (aci != null && !aci.isUnknown) { + val id = RecipientId.from(aci) + Mention(id, it.start!!, it.length!!) + } else { + null + } + } + if (mentions.isNotEmpty()) { + followUp = { messageId -> + SignalDatabase.mentions.insert(threadId, messageId, mentions) + } + } + } + val attachments = this.standardMessage.attachments.mapNotNull { attachment -> + attachment.toLocalAttachment() + } + val quoteAttachments = this.standardMessage.quote?.attachments?.mapNotNull { + it.toLocalAttachment() + } ?: emptyList() + if (attachments.isNotEmpty()) { + followUp = { messageRowId -> + SignalDatabase.attachments.insertAttachmentsForMessage(messageRowId, attachments, quoteAttachments) + } + } + } return MessageInsert(contentValues, followUp) } @@ -217,7 +263,7 @@ class ChatItemImportInserter( contentValues.put(MessageTable.TO_RECIPIENT_ID, (if (this.outgoing != null) chatRecipientId else selfId).serialize()) contentValues.put(MessageTable.THREAD_ID, threadId) contentValues.put(MessageTable.DATE_RECEIVED, this.incoming?.dateReceived ?: this.dateSent) - contentValues.put(MessageTable.RECEIPT_TIMESTAMP, this.outgoing?.sendStatus?.maxOf { it.lastStatusUpdateTimestamp } ?: 0) + contentValues.put(MessageTable.RECEIPT_TIMESTAMP, this.outgoing?.sendStatus?.maxOfOrNull { it.lastStatusUpdateTimestamp } ?: 0) contentValues.putNull(MessageTable.LATEST_REVISION_ID) contentValues.putNull(MessageTable.ORIGINAL_MESSAGE_ID) contentValues.put(MessageTable.REVISION_NUMBER, 0) @@ -241,8 +287,9 @@ class ChatItemImportInserter( contentValues.put(MessageTable.VIEWED_COLUMN, 0) contentValues.put(MessageTable.HAS_READ_RECEIPT, 0) contentValues.put(MessageTable.HAS_DELIVERY_RECEIPT, 0) - contentValues.put(MessageTable.UNIDENTIFIED, this.sealedSender?.toInt()) + contentValues.put(MessageTable.UNIDENTIFIED, this.incoming?.sealedSender?.toInt() ?: 0) contentValues.put(MessageTable.READ, this.incoming?.read?.toInt() ?: 0) + contentValues.put(MessageTable.NOTIFIED, 1) } contentValues.put(MessageTable.QUOTE_ID, 0) @@ -265,7 +312,6 @@ class ChatItemImportInserter( val reactions: List = when { this.standardMessage != null -> this.standardMessage.reactions this.contactMessage != null -> this.contactMessage.reactions - this.voiceMessage != null -> this.voiceMessage.reactions this.stickerMessage != null -> this.stickerMessage.reactions else -> emptyList() } @@ -342,7 +388,7 @@ class ChatItemImportInserter( this.put(MessageTable.BODY, standardMessage.text.body) if (standardMessage.text.bodyRanges.isNotEmpty()) { - this.put(MessageTable.MESSAGE_RANGES, standardMessage.text.bodyRanges.toLocalBodyRanges()?.encode() as ByteArray?) + this.put(MessageTable.MESSAGE_RANGES, standardMessage.text.bodyRanges.toLocalBodyRanges()?.encode()) } } @@ -355,23 +401,24 @@ class ChatItemImportInserter( var typeFlags: Long = 0 when { updateMessage.simpleUpdate != null -> { + val typeWithoutBase = (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) typeFlags = when (updateMessage.simpleUpdate.type) { - SimpleChatUpdate.Type.UNKNOWN -> 0 - SimpleChatUpdate.Type.JOINED_SIGNAL -> MessageTypes.JOINED_TYPE - SimpleChatUpdate.Type.IDENTITY_UPDATE -> MessageTypes.KEY_EXCHANGE_IDENTITY_UPDATE_BIT - SimpleChatUpdate.Type.IDENTITY_VERIFIED -> MessageTypes.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT - SimpleChatUpdate.Type.IDENTITY_DEFAULT -> MessageTypes.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT + SimpleChatUpdate.Type.UNKNOWN -> typeWithoutBase + SimpleChatUpdate.Type.JOINED_SIGNAL -> MessageTypes.JOINED_TYPE or typeWithoutBase + SimpleChatUpdate.Type.IDENTITY_UPDATE -> MessageTypes.KEY_EXCHANGE_IDENTITY_UPDATE_BIT or typeWithoutBase + SimpleChatUpdate.Type.IDENTITY_VERIFIED -> MessageTypes.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT or typeWithoutBase + SimpleChatUpdate.Type.IDENTITY_DEFAULT -> MessageTypes.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT or typeWithoutBase SimpleChatUpdate.Type.CHANGE_NUMBER -> MessageTypes.CHANGE_NUMBER_TYPE SimpleChatUpdate.Type.BOOST_REQUEST -> MessageTypes.BOOST_REQUEST_TYPE - SimpleChatUpdate.Type.END_SESSION -> MessageTypes.END_SESSION_BIT - SimpleChatUpdate.Type.CHAT_SESSION_REFRESH -> MessageTypes.ENCRYPTION_REMOTE_FAILED_BIT - SimpleChatUpdate.Type.BAD_DECRYPT -> MessageTypes.BAD_DECRYPT_TYPE - SimpleChatUpdate.Type.PAYMENTS_ACTIVATED -> MessageTypes.SPECIAL_TYPE_PAYMENTS_ACTIVATED - SimpleChatUpdate.Type.PAYMENT_ACTIVATION_REQUEST -> MessageTypes.SPECIAL_TYPE_PAYMENTS_ACTIVATE_REQUEST + SimpleChatUpdate.Type.END_SESSION -> MessageTypes.END_SESSION_BIT or typeWithoutBase + SimpleChatUpdate.Type.CHAT_SESSION_REFRESH -> MessageTypes.ENCRYPTION_REMOTE_FAILED_BIT or typeWithoutBase + SimpleChatUpdate.Type.BAD_DECRYPT -> MessageTypes.BAD_DECRYPT_TYPE or typeWithoutBase + SimpleChatUpdate.Type.PAYMENTS_ACTIVATED -> MessageTypes.SPECIAL_TYPE_PAYMENTS_ACTIVATED or typeWithoutBase + SimpleChatUpdate.Type.PAYMENT_ACTIVATION_REQUEST -> MessageTypes.SPECIAL_TYPE_PAYMENTS_ACTIVATE_REQUEST or typeWithoutBase } } updateMessage.expirationTimerChange != null -> { - typeFlags = MessageTypes.EXPIRATION_TIMER_UPDATE_BIT + typeFlags = getAsLong(MessageTable.TYPE) or MessageTypes.EXPIRATION_TIMER_UPDATE_BIT put(MessageTable.EXPIRES_IN, updateMessage.expirationTimerChange.expiresInMs.toLong()) } updateMessage.profileChange != null -> { @@ -381,12 +428,12 @@ class ChatItemImportInserter( put(MessageTable.BODY, Base64.encodeWithPadding(profileChangeDetails)) } updateMessage.sessionSwitchover != null -> { - typeFlags = MessageTypes.SESSION_SWITCHOVER_TYPE + typeFlags = MessageTypes.SESSION_SWITCHOVER_TYPE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) val sessionSwitchoverDetails = SessionSwitchoverEvent(e164 = updateMessage.sessionSwitchover.e164.toString()).encode() put(MessageTable.BODY, Base64.encodeWithPadding(sessionSwitchoverDetails)) } updateMessage.threadMerge != null -> { - typeFlags = MessageTypes.THREAD_MERGE_TYPE + typeFlags = MessageTypes.THREAD_MERGE_TYPE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) val threadMergeDetails = ThreadMergeEvent(previousE164 = updateMessage.threadMerge.previousE164.toString()).encode() put(MessageTable.BODY, Base64.encodeWithPadding(threadMergeDetails)) } @@ -401,8 +448,10 @@ class ChatItemImportInserter( IndividualCallChatUpdate.Type.INCOMING_VIDEO_CALL -> MessageTypes.INCOMING_VIDEO_CALL_TYPE IndividualCallChatUpdate.Type.OUTGOING_AUDIO_CALL -> MessageTypes.OUTGOING_AUDIO_CALL_TYPE IndividualCallChatUpdate.Type.OUTGOING_VIDEO_CALL -> MessageTypes.OUTGOING_VIDEO_CALL_TYPE - IndividualCallChatUpdate.Type.MISSED_AUDIO_CALL -> MessageTypes.MISSED_AUDIO_CALL_TYPE - IndividualCallChatUpdate.Type.MISSED_VIDEO_CALL -> MessageTypes.MISSED_VIDEO_CALL_TYPE + IndividualCallChatUpdate.Type.MISSED_INCOMING_AUDIO_CALL -> MessageTypes.MISSED_AUDIO_CALL_TYPE + IndividualCallChatUpdate.Type.MISSED_INCOMING_VIDEO_CALL -> MessageTypes.MISSED_VIDEO_CALL_TYPE + IndividualCallChatUpdate.Type.UNANSWERED_OUTGOING_AUDIO_CALL -> MessageTypes.OUTGOING_AUDIO_CALL_TYPE + IndividualCallChatUpdate.Type.UNANSWERED_OUTGOING_VIDEO_CALL -> MessageTypes.OUTGOING_VIDEO_CALL_TYPE IndividualCallChatUpdate.Type.UNKNOWN -> typeFlags } } @@ -410,8 +459,19 @@ class ChatItemImportInserter( // Calls don't use the incoming/outgoing flags, so we overwrite the flags here this.put(MessageTable.TYPE, typeFlags) } + updateMessage.groupChange != null -> { + put(MessageTable.BODY, "") + put( + MessageTable.MESSAGE_EXTRAS, + MessageExtras( + gv2UpdateDescription = + GV2UpdateDescription(groupChangeUpdate = updateMessage.groupChange) + ).encode() + ) + typeFlags = getAsLong(MessageTable.TYPE) or MessageTypes.GROUP_V2_BIT or MessageTypes.GROUP_UPDATE_BIT + } } - this.put(MessageTable.TYPE, getAsLong(MessageTable.TYPE) or typeFlags) + this.put(MessageTable.TYPE, typeFlags) } private fun ContentValues.addQuote(quote: Quote) { @@ -470,7 +530,7 @@ class ChatItemImportInserter( } return BodyRangeList( - ranges = this.map { bodyRange -> + ranges = this.filter { it.mentionAci == null }.map { bodyRange -> BodyRangeList.BodyRange( mentionUuid = bodyRange.mentionAci?.let { UuidUtil.fromByteString(it) }?.toString(), style = bodyRange.style?.let { @@ -503,6 +563,39 @@ class ChatItemImportInserter( } } + private fun MessageAttachment.toLocalAttachment(contentType: String? = pointer?.contentType, fileName: String? = pointer?.fileName): Attachment? { + if (pointer == null) return null + if (pointer.attachmentLocator != null) { + val signalAttachmentPointer = SignalServiceAttachmentPointer( + pointer.attachmentLocator.cdnNumber, + SignalServiceAttachmentRemoteId.from(pointer.attachmentLocator.cdnKey), + contentType, + pointer.key?.toByteArray(), + Optional.ofNullable(pointer.size), + Optional.empty(), + pointer.width ?: 0, + pointer.height ?: 0, + Optional.empty(), + Optional.ofNullable(pointer.incrementalMac?.toByteArray()), + pointer.incrementalMacChunkSize ?: 0, + Optional.ofNullable(fileName), + flag == MessageAttachment.Flag.VOICE_MESSAGE, + flag == MessageAttachment.Flag.BORDERLESS, + flag == MessageAttachment.Flag.GIF, + Optional.ofNullable(pointer.caption), + Optional.ofNullable(pointer.blurHash), + pointer.attachmentLocator.uploadTimestamp + ) + return PointerAttachment.forPointer(Optional.of(signalAttachmentPointer)).orNull() + } + return null + } + + private fun Quote.QuotedAttachment.toLocalAttachment(): Attachment? { + return thumbnail?.toLocalAttachment(this.contentType, this.fileName) + ?: if (this.contentType == null) null else PointerAttachment.forPointer(SignalServiceDataMessage.Quote.QuotedAttachment(contentType = this.contentType!!, fileName = this.fileName, thumbnail = null)).orNull() + } + private class MessageInsert(val contentValues: ContentValues, val followUp: ((Long) -> Unit)?) private class Buffer( @@ -512,5 +605,11 @@ class ChatItemImportInserter( ) { val size: Int get() = listOf(messages.size, reactions.size, groupReceipts.size).max() + + fun reset() { + messages.clear() + reactions.clear() + groupReceipts.clear() + } } } diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/DistributionListTablesBackupExtensions.kt b/app/src/main/java/org/tm/archive/backup/v2/database/DistributionListTablesBackupExtensions.kt index 3cb3e3bf..132508d6 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/DistributionListTablesBackupExtensions.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/DistributionListTablesBackupExtensions.kt @@ -7,7 +7,7 @@ package org.tm.archive.backup.v2.database import okio.ByteString.Companion.toByteString import org.signal.core.util.CursorUtil -import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.readToList import org.signal.core.util.requireLong @@ -28,38 +28,45 @@ import org.tm.archive.backup.v2.proto.DistributionList as BackupDistributionList private val TAG = Log.tag(DistributionListTables::class.java) +data class DistributionRecipient(val id: RecipientId, val record: DistributionListRecord) + fun DistributionListTables.getAllForBackup(): List { val records = readableDatabase .select() .from(DistributionListTables.ListTable.TABLE_NAME) + .where(DistributionListTables.ListTable.IS_NOT_DELETED) .run() .readToList { cursor -> val id: DistributionListId = DistributionListId.from(cursor.requireLong(DistributionListTables.ListTable.ID)) val privacyMode: DistributionListPrivacyMode = cursor.requireObject(DistributionListTables.ListTable.PRIVACY_MODE, DistributionListPrivacyMode.Serializer) - - DistributionListRecord( - id = id, - name = cursor.requireNonNullString(DistributionListTables.ListTable.NAME), - distributionId = DistributionId.from(cursor.requireNonNullString(DistributionListTables.ListTable.DISTRIBUTION_ID)), - allowsReplies = CursorUtil.requireBoolean(cursor, DistributionListTables.ListTable.ALLOWS_REPLIES), - rawMembers = getRawMembers(id, privacyMode), - members = getMembers(id), - deletedAtTimestamp = 0L, - isUnknown = CursorUtil.requireBoolean(cursor, DistributionListTables.ListTable.IS_UNKNOWN), - privacyMode = privacyMode + val recipientId: RecipientId = RecipientId.from(cursor.requireLong(DistributionListTables.ListTable.RECIPIENT_ID)) + DistributionRecipient( + id = recipientId, + record = DistributionListRecord( + id = id, + name = cursor.requireNonNullString(DistributionListTables.ListTable.NAME), + distributionId = DistributionId.from(cursor.requireNonNullString(DistributionListTables.ListTable.DISTRIBUTION_ID)), + allowsReplies = CursorUtil.requireBoolean(cursor, DistributionListTables.ListTable.ALLOWS_REPLIES), + rawMembers = getRawMembers(id, privacyMode), + members = getMembers(id), + deletedAtTimestamp = 0L, + isUnknown = CursorUtil.requireBoolean(cursor, DistributionListTables.ListTable.IS_UNKNOWN), + privacyMode = privacyMode + ) ) } return records - .map { record -> + .map { recipient -> BackupRecipient( + id = recipient.id.toLong(), distributionList = BackupDistributionList( - name = record.name, - distributionId = record.distributionId.asUuid().toByteArray().toByteString(), - allowReplies = record.allowsReplies, - deletionTimestamp = record.deletedAtTimestamp, - privacyMode = record.privacyMode.toBackupPrivacyMode(), - memberRecipientIds = record.members.map { it.toLong() } + name = recipient.record.name, + distributionId = recipient.record.distributionId.asUuid().toByteArray().toByteString(), + allowReplies = recipient.record.allowsReplies, + deletionTimestamp = recipient.record.deletedAtTimestamp, + privacyMode = recipient.record.privacyMode.toBackupPrivacyMode(), + memberRecipientIds = recipient.record.members.map { it.toLong() } ) ) } @@ -88,12 +95,10 @@ fun DistributionListTables.restoreFromBackup(dlist: BackupDistributionList, back fun DistributionListTables.clearAllDataForBackupRestore() { writableDatabase - .delete(DistributionListTables.ListTable.TABLE_NAME) - .run() + .deleteAll(DistributionListTables.ListTable.TABLE_NAME) writableDatabase - .delete(DistributionListTables.MembershipTable.TABLE_NAME) - .run() + .deleteAll(DistributionListTables.MembershipTable.TABLE_NAME) } private fun DistributionListPrivacyMode.toBackupPrivacyMode(): BackupDistributionList.PrivacyMode { diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/MessageTableBackupExtensions.kt b/app/src/main/java/org/tm/archive/backup/v2/database/MessageTableBackupExtensions.kt index c4a9e0b4..9e0c9203 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/MessageTableBackupExtensions.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/MessageTableBackupExtensions.kt @@ -11,11 +11,12 @@ import org.signal.core.util.select import org.tm.archive.backup.v2.BackupState import org.tm.archive.database.MessageTable import org.tm.archive.database.MessageTypes +import java.util.concurrent.TimeUnit private val TAG = Log.tag(MessageTable::class.java) private const val BASE_TYPE = "base_type" -fun MessageTable.getMessagesForBackup(): ChatItemExportIterator { +fun MessageTable.getMessagesForBackup(backupTime: Long): ChatItemExportIterator { val cursor = readableDatabase .select( MessageTable.ID, @@ -47,18 +48,17 @@ fun MessageTable.getMessagesForBackup(): ChatItemExportIterator { MessageTable.READ, MessageTable.NETWORK_FAILURES, MessageTable.MISMATCHED_IDENTITIES, - "${MessageTable.TYPE} & ${MessageTypes.BASE_TYPE_MASK} AS ${ChatItemExportIterator.COLUMN_BASE_TYPE}" + "${MessageTable.TYPE} & ${MessageTypes.BASE_TYPE_MASK} AS ${ChatItemExportIterator.COLUMN_BASE_TYPE}", + MessageTable.MESSAGE_EXTRAS ) .from(MessageTable.TABLE_NAME) .where( """ - $BASE_TYPE IN ( - ${MessageTypes.BASE_INBOX_TYPE}, - ${MessageTypes.BASE_OUTBOX_TYPE}, - ${MessageTypes.BASE_SENT_TYPE}, - ${MessageTypes.BASE_SENDING_TYPE}, - ${MessageTypes.BASE_SENT_FAILED_TYPE} - ) OR ${MessageTable.IS_CALL_TYPE_CLAUSE} + ( + ${MessageTable.EXPIRE_STARTED} = 0 + OR + (${MessageTable.EXPIRES_IN} > 0 AND (${MessageTable.EXPIRE_STARTED} + ${MessageTable.EXPIRES_IN}) > $backupTime + ${TimeUnit.DAYS.toMillis(1)}) + ) """ ) .orderBy("${MessageTable.DATE_RECEIVED} ASC") diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/RecipientTableBackupExtensions.kt b/app/src/main/java/org/tm/archive/backup/v2/database/RecipientTableBackupExtensions.kt index cda46f9c..918e3e9c 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/RecipientTableBackupExtensions.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/RecipientTableBackupExtensions.kt @@ -10,7 +10,7 @@ import android.database.Cursor import okio.ByteString.Companion.toByteString import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil -import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.nullIfBlank import org.signal.core.util.requireBoolean @@ -22,23 +22,31 @@ import org.signal.core.util.select import org.signal.core.util.toInt import org.signal.core.util.update import org.signal.libsignal.zkgroup.InvalidInputException +import org.signal.libsignal.zkgroup.groups.GroupMasterKey +import org.signal.storageservice.protos.groups.local.DecryptedGroup import org.tm.archive.backup.v2.BackupState import org.tm.archive.backup.v2.proto.AccountData import org.tm.archive.backup.v2.proto.Contact import org.tm.archive.backup.v2.proto.Group import org.tm.archive.backup.v2.proto.Self +import org.tm.archive.conversation.colors.AvatarColorHash import org.tm.archive.database.GroupTable import org.tm.archive.database.RecipientTable import org.tm.archive.database.RecipientTableCursorUtil import org.tm.archive.database.SignalDatabase import org.tm.archive.database.model.databaseprotos.RecipientExtras import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.groups.GroupId +import org.tm.archive.groups.v2.processing.GroupsV2StateProcessor +import org.tm.archive.keyvalue.SignalStore import org.tm.archive.phonenumbers.PhoneNumberFormatter import org.tm.archive.profiles.ProfileName import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId +import org.tm.archive.storage.StorageSyncHelper import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI +import org.whispersystems.signalservice.api.util.toByteArray import java.io.Closeable typealias BackupRecipient = org.tm.archive.backup.v2.proto.Recipient @@ -94,7 +102,8 @@ fun RecipientTable.getGroupsForBackup(): BackupGroupIterator { "${RecipientTable.TABLE_NAME}.${RecipientTable.MUTE_UNTIL}", "${RecipientTable.TABLE_NAME}.${RecipientTable.EXTRAS}", "${GroupTable.TABLE_NAME}.${GroupTable.V2_MASTER_KEY}", - "${GroupTable.TABLE_NAME}.${GroupTable.SHOW_AS_STORY_STATE}" + "${GroupTable.TABLE_NAME}.${GroupTable.SHOW_AS_STORY_STATE}", + "${GroupTable.TABLE_NAME}.${GroupTable.TITLE}" ) .from( """ @@ -102,6 +111,7 @@ fun RecipientTable.getGroupsForBackup(): BackupGroupIterator { INNER JOIN ${GroupTable.TABLE_NAME} ON ${RecipientTable.TABLE_NAME}.${RecipientTable.ID} = ${GroupTable.TABLE_NAME}.${GroupTable.RECIPIENT_ID} """ ) + .where("${GroupTable.TABLE_NAME}.${GroupTable.V2_MASTER_KEY} IS NOT NULL") .run() return BackupGroupIterator(cursor) @@ -115,8 +125,10 @@ fun RecipientTable.restoreRecipientFromBackup(recipient: BackupRecipient, backup // TODO Also, should we move this when statement up to mimic the export? Kinda weird that this calls distributionListTable functions return when { recipient.contact != null -> restoreContactFromBackup(recipient.contact) + recipient.group != null -> restoreGroupFromBackup(recipient.group) recipient.distributionList != null -> SignalDatabase.distributionLists.restoreFromBackup(recipient.distributionList, backupState) recipient.self != null -> Recipient.self().id + recipient.releaseNotes != null -> restoreReleaseNotes() else -> { Log.w(TAG, "Unrecognized recipient type!") null @@ -155,7 +167,7 @@ fun RecipientTable.restoreSelfFromBackup(accountData: AccountData, selfId: Recip } fun RecipientTable.clearAllDataForBackupRestore() { - writableDatabase.delete(RecipientTable.TABLE_NAME).run() + writableDatabase.deleteAll(RecipientTable.TABLE_NAME) SqlUtil.resetAutoIncrementValue(writableDatabase, RecipientTable.TABLE_NAME) RecipientId.clearCache() @@ -177,6 +189,7 @@ private fun RecipientTable.restoreContactFromBackup(contact: Contact): Recipient .values( RecipientTable.BLOCKED to contact.blocked, RecipientTable.HIDDEN to contact.hidden, + RecipientTable.TYPE to RecipientTable.RecipientType.INDIVIDUAL.id, RecipientTable.PROFILE_FAMILY_NAME to contact.profileFamilyName.nullIfBlank(), RecipientTable.PROFILE_GIVEN_NAME to contact.profileGivenName.nullIfBlank(), RecipientTable.PROFILE_JOINED_NAME to ProfileName.fromParts(contact.profileGivenName.nullIfBlank(), contact.profileFamilyName.nullIfBlank()).toString().nullIfBlank(), @@ -193,6 +206,50 @@ private fun RecipientTable.restoreContactFromBackup(contact: Contact): Recipient return id } +private fun RecipientTable.restoreReleaseNotes(): RecipientId { + val releaseChannelId: RecipientId = insertReleaseChannelRecipient() + SignalStore.releaseChannelValues().setReleaseChannelRecipientId(releaseChannelId) + + setProfileName(releaseChannelId, ProfileName.asGiven("Signal")) + setMuted(releaseChannelId, Long.MAX_VALUE) + return releaseChannelId +} + +private fun RecipientTable.restoreGroupFromBackup(group: Group): RecipientId { + val masterKey = GroupMasterKey(group.masterKey.toByteArray()) + val groupId = GroupId.v2(masterKey) + + val placeholderState = DecryptedGroup.Builder() + .revision(GroupsV2StateProcessor.PLACEHOLDER_REVISION) + .build() + + val values = ContentValues().apply { + put(RecipientTable.GROUP_ID, groupId.toString()) + put(RecipientTable.AVATAR_COLOR, AvatarColorHash.forGroupId(groupId).serialize()) + put(RecipientTable.PROFILE_SHARING, group.whitelisted) + put(RecipientTable.TYPE, RecipientTable.RecipientType.GV2.id) + put(RecipientTable.STORAGE_SERVICE_ID, Base64.encodeWithPadding(StorageSyncHelper.generateKey())) + if (group.hideStory) { + val extras = RecipientExtras.Builder().hideStory(true).build() + put(RecipientTable.EXTRAS, extras.encode()) + } + } + + val recipientId = writableDatabase.insert(RecipientTable.TABLE_NAME, null, values) + val groupValues = ContentValues().apply { + put(GroupTable.RECIPIENT_ID, recipientId) + put(GroupTable.GROUP_ID, groupId.toString()) + put(GroupTable.TITLE, group.name) + put(GroupTable.V2_MASTER_KEY, masterKey.serialize()) + put(GroupTable.V2_DECRYPTED_GROUP, placeholderState.encode()) + put(GroupTable.V2_REVISION, placeholderState.revision) + put(GroupTable.SHOW_AS_STORY_STATE, group.storySendMode.toGroupShowAsStoryState().code) + } + writableDatabase.insert(GroupTable.TABLE_NAME, null, groupValues) + + return RecipientId.from(recipientId) +} + private fun Contact.toLocalExtras(): RecipientExtras { return RecipientExtras( hideStory = this.hideStory @@ -235,8 +292,8 @@ class BackupContactIterator(private val cursor: Cursor, private val selfId: Long return BackupRecipient( id = id, contact = Contact( - aci = aci?.toByteArray()?.toByteString(), - pni = pni?.toByteArray()?.toByteString(), + aci = aci?.rawUuid?.toByteArray()?.toByteString(), + pni = pni?.rawUuid?.toByteArray()?.toByteString(), username = cursor.requireString(RecipientTable.USERNAME), e164 = cursor.requireString(RecipientTable.E164)?.e164ToLong(), blocked = cursor.requireBoolean(RecipientTable.BLOCKED), @@ -280,7 +337,8 @@ class BackupGroupIterator(private val cursor: Cursor) : Iterator GroupTable.ShowAsStoryState.ALWAYS + Group.StorySendMode.DISABLED -> GroupTable.ShowAsStoryState.NEVER + Group.StorySendMode.DEFAULT -> GroupTable.ShowAsStoryState.IF_ACTIVE + } +} + private val Contact.formattedE164: String? get() { return e164?.let { diff --git a/app/src/main/java/org/tm/archive/backup/v2/database/ThreadTableBackupExtensions.kt b/app/src/main/java/org/tm/archive/backup/v2/database/ThreadTableBackupExtensions.kt index bf0ae10d..ece74932 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/database/ThreadTableBackupExtensions.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/database/ThreadTableBackupExtensions.kt @@ -6,15 +6,16 @@ package org.tm.archive.backup.v2.database import android.database.Cursor +import androidx.core.content.contentValuesOf import org.signal.core.util.SqlUtil import org.signal.core.util.insertInto import org.signal.core.util.logging.Log import org.signal.core.util.requireBoolean import org.signal.core.util.requireInt import org.signal.core.util.requireLong -import org.signal.core.util.select import org.signal.core.util.toInt import org.tm.archive.backup.v2.proto.Chat +import org.tm.archive.database.RecipientTable import org.tm.archive.database.ThreadTable import org.tm.archive.recipients.RecipientId import java.io.Closeable @@ -22,16 +23,21 @@ import java.io.Closeable private val TAG = Log.tag(ThreadTable::class.java) fun ThreadTable.getThreadsForBackup(): ChatIterator { - val cursor = readableDatabase - .select( - ThreadTable.ID, - ThreadTable.RECIPIENT_ID, - ThreadTable.ARCHIVED, - ThreadTable.PINNED, - ThreadTable.EXPIRES_IN - ) - .from(ThreadTable.TABLE_NAME) - .run() + //language=sql + val query = """ + SELECT + ${ThreadTable.TABLE_NAME}.${ThreadTable.ID}, + ${ThreadTable.RECIPIENT_ID}, + ${ThreadTable.PINNED}, + ${ThreadTable.READ}, + ${ThreadTable.ARCHIVED}, + ${RecipientTable.TABLE_NAME}.${RecipientTable.MESSAGE_EXPIRATION_TIME}, + ${RecipientTable.TABLE_NAME}.${RecipientTable.MUTE_UNTIL}, + ${RecipientTable.TABLE_NAME}.${RecipientTable.MENTION_SETTING} + FROM ${ThreadTable.TABLE_NAME} + LEFT OUTER JOIN ${RecipientTable.TABLE_NAME} ON ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} = ${RecipientTable.TABLE_NAME}.${RecipientTable.ID} + """ + val cursor = readableDatabase.query(query) return ChatIterator(cursor) } @@ -43,14 +49,29 @@ fun ThreadTable.clearAllDataForBackupRestore() { } fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId): Long? { - return writableDatabase + val threadId = writableDatabase .insertInto(ThreadTable.TABLE_NAME) .values( ThreadTable.RECIPIENT_ID to recipientId.serialize(), ThreadTable.PINNED to chat.pinnedOrder, - ThreadTable.ARCHIVED to chat.archived.toInt() + ThreadTable.ARCHIVED to chat.archived.toInt(), + ThreadTable.READ to if (chat.markedUnread) ThreadTable.ReadStatus.FORCED_UNREAD.serialize() else ThreadTable.ReadStatus.READ.serialize(), + ThreadTable.ACTIVE to 1 ) .run() + writableDatabase + .update( + RecipientTable.TABLE_NAME, + contentValuesOf( + RecipientTable.MENTION_SETTING to (if (chat.dontNotifyForMentionsIfMuted) RecipientTable.MentionSetting.DO_NOT_NOTIFY.id else RecipientTable.MentionSetting.ALWAYS_NOTIFY.id), + RecipientTable.MUTE_UNTIL to chat.muteUntilMs, + RecipientTable.MESSAGE_EXPIRATION_TIME to chat.expirationTimerMs + ), + "${RecipientTable.ID} = ?", + SqlUtil.buildArgs(recipientId.toLong()) + ) + + return threadId } class ChatIterator(private val cursor: Cursor) : Iterator, Closeable { @@ -68,7 +89,10 @@ class ChatIterator(private val cursor: Cursor) : Iterator, Closeable { recipientId = cursor.requireLong(ThreadTable.RECIPIENT_ID), archived = cursor.requireBoolean(ThreadTable.ARCHIVED), pinnedOrder = cursor.requireInt(ThreadTable.PINNED), - expirationTimerMs = cursor.requireLong(ThreadTable.EXPIRES_IN) + expirationTimerMs = cursor.requireLong(RecipientTable.MESSAGE_EXPIRATION_TIME), + muteUntilMs = cursor.requireLong(RecipientTable.MUTE_UNTIL), + markedUnread = ThreadTable.ReadStatus.deserialize(cursor.requireInt(ThreadTable.READ)) == ThreadTable.ReadStatus.FORCED_UNREAD, + dontNotifyForMentionsIfMuted = RecipientTable.MentionSetting.DO_NOT_NOTIFY.id == cursor.requireInt(RecipientTable.MENTION_SETTING) ) } diff --git a/app/src/main/java/org/tm/archive/backup/v2/processor/AccountDataProcessor.kt b/app/src/main/java/org/tm/archive/backup/v2/processor/AccountDataProcessor.kt index 76006710..538ca727 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/processor/AccountDataProcessor.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/processor/AccountDataProcessor.kt @@ -17,6 +17,7 @@ import org.tm.archive.database.SignalDatabase.Companion.recipients import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.jobs.RetrieveProfileAvatarJob import org.tm.archive.keyvalue.PhoneNumberPrivacyValues +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId @@ -27,6 +28,7 @@ import org.whispersystems.signalservice.api.push.UsernameLinkComponents import org.whispersystems.signalservice.api.storage.StorageRecordProtoUtil.defaultAccountRecord import org.whispersystems.signalservice.api.subscriptions.SubscriberId import org.whispersystems.signalservice.api.util.UuidUtil +import kotlin.jvm.optionals.getOrNull object AccountDataProcessor { @@ -46,27 +48,27 @@ object AccountDataProcessor { familyName = self.profileName.familyName, avatarUrlPath = self.profileAvatar ?: "", subscriptionManuallyCancelled = SignalStore.donationsValues().isUserManuallyCancelled(), - username = SignalStore.account().username, + username = self.username.getOrNull(), subscriberId = subscriber?.subscriberId?.bytes?.toByteString() ?: defaultAccountRecord.subscriberId, subscriberCurrencyCode = subscriber?.currencyCode ?: defaultAccountRecord.subscriberCurrencyCode, accountSettings = AccountData.AccountSettings( storyViewReceiptsEnabled = SignalStore.storyValues().viewedReceiptsEnabled, - noteToSelfMarkedUnread = record != null && record.syncExtras.isForcedUnread, typingIndicators = TextSecurePreferences.isTypingIndicatorsEnabled(context), readReceipts = TextSecurePreferences.isReadReceiptsEnabled(context), sealedSenderIndicators = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context), linkPreviews = SignalStore.settings().isLinkPreviewsEnabled, - notDiscoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberListingMode.isUnlisted, + notDiscoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode == PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE, phoneNumberSharingMode = SignalStore.phoneNumberPrivacy().phoneNumberSharingMode.toBackupPhoneNumberSharingMode(), preferContactAvatars = SignalStore.settings().isPreferSystemContactPhotos, universalExpireTimer = SignalStore.settings().universalExpireTimer, - preferredReactionEmoji = SignalStore.emojiValues().reactions, + preferredReactionEmoji = SignalStore.emojiValues().rawReactions, storiesDisabled = SignalStore.storyValues().isFeatureDisabled, hasViewedOnboardingStory = SignalStore.storyValues().userHasViewedOnboardingStory, hasSetMyStoriesPrivacy = SignalStore.storyValues().userHasBeenNotifiedAboutStories, keepMutedChatsArchived = SignalStore.settings().shouldKeepMutedChatsArchived(), displayBadgesOnProfile = SignalStore.donationsValues().getDisplayBadgesOnProfile(), - hasSeenGroupStoryEducationSheet = SignalStore.storyValues().userHasSeenGroupStoryEducationSheet + hasSeenGroupStoryEducationSheet = SignalStore.storyValues().userHasSeenGroupStoryEducationSheet, + hasCompletedUsernameOnboarding = SignalStore.uiHints().hasCompletedUsernameOnboarding() ) ) ) @@ -86,7 +88,7 @@ object AccountDataProcessor { TextSecurePreferences.setTypingIndicatorsEnabled(context, settings.typingIndicators) TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, settings.sealedSenderIndicators) SignalStore.settings().isLinkPreviewsEnabled = settings.linkPreviews - SignalStore.phoneNumberPrivacy().phoneNumberListingMode = if (settings.notDiscoverableByPhoneNumber) PhoneNumberPrivacyValues.PhoneNumberListingMode.UNLISTED else PhoneNumberPrivacyValues.PhoneNumberListingMode.LISTED + SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode = if (settings.notDiscoverableByPhoneNumber) PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE else PhoneNumberDiscoverabilityMode.DISCOVERABLE SignalStore.phoneNumberPrivacy().phoneNumberSharingMode = settings.phoneNumberSharingMode.toLocalPhoneNumberMode() SignalStore.settings().isPreferSystemContactPhotos = settings.preferContactAvatars SignalStore.settings().universalExpireTimer = settings.universalExpireTimer @@ -121,6 +123,14 @@ object AccountDataProcessor { ) SignalStore.misc().usernameQrCodeColorScheme = accountData.usernameLink.color.toLocalUsernameColor() } + + if (settings.preferredReactionEmoji.isNotEmpty()) { + SignalStore.emojiValues().reactions = settings.preferredReactionEmoji + } + + if (settings.hasCompletedUsernameOnboarding) { + SignalStore.uiHints().setHasCompletedUsernameOnboarding(true) + } } SignalDatabase.runPostSuccessfulTransaction { ProfileUtil.handleSelfProfileKeyChange() } diff --git a/app/src/main/java/org/tm/archive/backup/v2/processor/ChatBackupProcessor.kt b/app/src/main/java/org/tm/archive/backup/v2/processor/ChatBackupProcessor.kt index 17898efd..b3837e33 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/processor/ChatBackupProcessor.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/processor/ChatBackupProcessor.kt @@ -7,6 +7,7 @@ package org.tm.archive.backup.v2.processor import org.signal.core.util.logging.Log import org.tm.archive.backup.v2.BackupState +import org.tm.archive.backup.v2.ExportState import org.tm.archive.backup.v2.database.getThreadsForBackup import org.tm.archive.backup.v2.database.restoreFromBackup import org.tm.archive.backup.v2.proto.Chat @@ -18,10 +19,15 @@ import org.tm.archive.recipients.RecipientId object ChatBackupProcessor { val TAG = Log.tag(ChatBackupProcessor::class.java) - fun export(emitter: BackupFrameEmitter) { + fun export(exportState: ExportState, emitter: BackupFrameEmitter) { SignalDatabase.threads.getThreadsForBackup().use { reader -> for (chat in reader) { - emitter.emit(Frame(chat = chat)) + if (exportState.recipientIds.contains(chat.recipientId)) { + exportState.threadIds.add(chat.id) + emitter.emit(Frame(chat = chat)) + } else { + Log.w(TAG, "dropping thread for deleted recipient ${chat.recipientId}") + } } } } diff --git a/app/src/main/java/org/tm/archive/backup/v2/processor/ChatItemBackupProcessor.kt b/app/src/main/java/org/tm/archive/backup/v2/processor/ChatItemBackupProcessor.kt index 6335a2c6..9e430fc4 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/processor/ChatItemBackupProcessor.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/processor/ChatItemBackupProcessor.kt @@ -7,6 +7,7 @@ package org.tm.archive.backup.v2.processor import org.signal.core.util.logging.Log import org.tm.archive.backup.v2.BackupState +import org.tm.archive.backup.v2.ExportState import org.tm.archive.backup.v2.database.ChatItemImportInserter import org.tm.archive.backup.v2.database.createChatItemInserter import org.tm.archive.backup.v2.database.getMessagesForBackup @@ -17,10 +18,12 @@ import org.tm.archive.database.SignalDatabase object ChatItemBackupProcessor { val TAG = Log.tag(ChatItemBackupProcessor::class.java) - fun export(emitter: BackupFrameEmitter) { - SignalDatabase.messages.getMessagesForBackup().use { chatItems -> + fun export(exportState: ExportState, emitter: BackupFrameEmitter) { + SignalDatabase.messages.getMessagesForBackup(exportState.backupTime).use { chatItems -> for (chatItem in chatItems) { - emitter.emit(Frame(chatItem = chatItem)) + if (exportState.threadIds.contains(chatItem.chatId)) { + emitter.emit(Frame(chatItem = chatItem)) + } } } } diff --git a/app/src/main/java/org/tm/archive/backup/v2/processor/RecipientBackupProcessor.kt b/app/src/main/java/org/tm/archive/backup/v2/processor/RecipientBackupProcessor.kt index e42df29b..bf810263 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/processor/RecipientBackupProcessor.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/processor/RecipientBackupProcessor.kt @@ -7,13 +7,17 @@ package org.tm.archive.backup.v2.processor import org.signal.core.util.logging.Log import org.tm.archive.backup.v2.BackupState +import org.tm.archive.backup.v2.ExportState +import org.tm.archive.backup.v2.database.BackupRecipient import org.tm.archive.backup.v2.database.getAllForBackup import org.tm.archive.backup.v2.database.getContactsForBackup import org.tm.archive.backup.v2.database.getGroupsForBackup import org.tm.archive.backup.v2.database.restoreRecipientFromBackup import org.tm.archive.backup.v2.proto.Frame +import org.tm.archive.backup.v2.proto.ReleaseNotes import org.tm.archive.backup.v2.stream.BackupFrameEmitter import org.tm.archive.database.SignalDatabase +import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient typealias BackupRecipient = org.tm.archive.backup.v2.proto.Recipient @@ -22,12 +26,24 @@ object RecipientBackupProcessor { val TAG = Log.tag(RecipientBackupProcessor::class.java) - fun export(emitter: BackupFrameEmitter) { + fun export(state: ExportState, emitter: BackupFrameEmitter) { val selfId = Recipient.self().id.toLong() + val releaseChannelId = SignalStore.releaseChannelValues().releaseChannelRecipientId + if (releaseChannelId != null) { + emitter.emit( + Frame( + recipient = BackupRecipient( + id = releaseChannelId.toLong(), + releaseNotes = ReleaseNotes() + ) + ) + ) + } SignalDatabase.recipients.getContactsForBackup(selfId).use { reader -> for (backupRecipient in reader) { if (backupRecipient != null) { + state.recipientIds.add(backupRecipient.id) emitter.emit(Frame(recipient = backupRecipient)) } } @@ -35,11 +51,13 @@ object RecipientBackupProcessor { SignalDatabase.recipients.getGroupsForBackup().use { reader -> for (backupRecipient in reader) { + state.recipientIds.add(backupRecipient.id) emitter.emit(Frame(recipient = backupRecipient)) } } SignalDatabase.distributionLists.getAllForBackup().forEach { + state.recipientIds.add(it.id) emitter.emit(Frame(recipient = it)) } } diff --git a/app/src/main/java/org/tm/archive/backup/v2/stream/BackupExportWriter.kt b/app/src/main/java/org/tm/archive/backup/v2/stream/BackupExportWriter.kt index 21e27362..b820179e 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/stream/BackupExportWriter.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/stream/BackupExportWriter.kt @@ -5,8 +5,10 @@ package org.tm.archive.backup.v2.stream +import org.tm.archive.backup.v2.proto.BackupInfo import org.tm.archive.backup.v2.proto.Frame interface BackupExportWriter : AutoCloseable { + fun write(header: BackupInfo) fun write(frame: Frame) } diff --git a/app/src/main/java/org/tm/archive/backup/v2/stream/BackupImportReader.kt b/app/src/main/java/org/tm/archive/backup/v2/stream/BackupImportReader.kt new file mode 100644 index 00000000..0caa8dd3 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/stream/BackupImportReader.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.stream + +import org.tm.archive.backup.v2.proto.BackupInfo +import org.tm.archive.backup.v2.proto.Frame + +interface BackupImportReader : Iterator, AutoCloseable { + fun getHeader(): BackupInfo? +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupReader.kt b/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupReader.kt index 6e32369f..ce4f766a 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupReader.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupReader.kt @@ -10,6 +10,7 @@ import org.signal.core.util.readNBytesOrThrow import org.signal.core.util.readVarInt32 import org.signal.core.util.stream.MacInputStream import org.signal.core.util.stream.TruncatingInputStream +import org.tm.archive.backup.v2.proto.BackupInfo import org.tm.archive.backup.v2.proto.Frame import org.whispersystems.signalservice.api.backup.BackupKey import org.whispersystems.signalservice.api.push.ServiceId.ACI @@ -33,8 +34,9 @@ class EncryptedBackupReader( aci: ACI, streamLength: Long, dataStream: () -> InputStream -) : Iterator, AutoCloseable { +) : BackupImportReader { + val backupInfo: BackupInfo? var next: Frame? = null val stream: InputStream @@ -56,10 +58,14 @@ class EncryptedBackupReader( cipher ) ) - + backupInfo = readHeader() next = read() } + override fun getHeader(): BackupInfo? { + return backupInfo + } + override fun hasNext(): Boolean { return next != null } @@ -71,6 +77,17 @@ class EncryptedBackupReader( } ?: throw NoSuchElementException() } + private fun readHeader(): BackupInfo? { + try { + val length = stream.readVarInt32().takeIf { it >= 0 } ?: return null + val headerBytes: ByteArray = stream.readNBytesOrThrow(length) + + return BackupInfo.ADAPTER.decode(headerBytes) + } catch (e: EOFException) { + return null + } + } + private fun read(): Frame? { try { val length = stream.readVarInt32().also { if (it < 0) return null } diff --git a/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupWriter.kt b/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupWriter.kt index f8c6f594..c96b403f 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupWriter.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/stream/EncryptedBackupWriter.kt @@ -7,6 +7,7 @@ package org.tm.archive.backup.v2.stream import org.signal.core.util.stream.MacOutputStream import org.signal.core.util.writeVarInt32 +import org.tm.archive.backup.v2.proto.BackupInfo import org.tm.archive.backup.v2.proto.Frame import org.whispersystems.signalservice.api.backup.BackupKey import org.whispersystems.signalservice.api.push.ServiceId.ACI @@ -56,6 +57,13 @@ class EncryptedBackupWriter( ) } + override fun write(header: BackupInfo) { + val headerBytes = header.encode() + + mainStream.writeVarInt32(headerBytes.size) + mainStream.write(headerBytes) + } + @Throws(IOException::class) override fun write(frame: Frame) { val frameBytes: ByteArray = frame.encode() diff --git a/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupReader.kt b/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupReader.kt index 4fbaad04..9381cd86 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupReader.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupReader.kt @@ -7,6 +7,7 @@ package org.tm.archive.backup.v2.stream import org.signal.core.util.readNBytesOrThrow import org.signal.core.util.readVarInt32 +import org.tm.archive.backup.v2.proto.BackupInfo import org.tm.archive.backup.v2.proto.Frame import java.io.EOFException import java.io.InputStream @@ -14,14 +15,20 @@ import java.io.InputStream /** * Reads a plaintext backup import stream one frame at a time. */ -class PlainTextBackupReader(val inputStream: InputStream) : Iterator { +class PlainTextBackupReader(val inputStream: InputStream) : BackupImportReader { + val backupInfo: BackupInfo? var next: Frame? = null init { + backupInfo = readHeader() next = read() } + override fun getHeader(): BackupInfo? { + return backupInfo + } + override fun hasNext(): Boolean { return next != null } @@ -33,6 +40,21 @@ class PlainTextBackupReader(val inputStream: InputStream) : Iterator { } ?: throw NoSuchElementException() } + override fun close() { + inputStream.close() + } + + private fun readHeader(): BackupInfo? { + try { + val length = inputStream.readVarInt32().takeIf { it >= 0 } ?: return null + val headerBytes: ByteArray = inputStream.readNBytesOrThrow(length) + + return BackupInfo.ADAPTER.decode(headerBytes) + } catch (e: EOFException) { + return null + } + } + private fun read(): Frame? { try { val length = inputStream.readVarInt32().also { if (it < 0) return null } diff --git a/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupWriter.kt b/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupWriter.kt index 9acb5c7d..466c32fd 100644 --- a/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupWriter.kt +++ b/app/src/main/java/org/tm/archive/backup/v2/stream/PlainTextBackupWriter.kt @@ -6,6 +6,7 @@ package org.tm.archive.backup.v2.stream import org.signal.core.util.writeVarInt32 +import org.tm.archive.backup.v2.proto.BackupInfo import org.tm.archive.backup.v2.proto.Frame import java.io.IOException import java.io.OutputStream @@ -15,6 +16,14 @@ import java.io.OutputStream */ class PlainTextBackupWriter(private val outputStream: OutputStream) : BackupExportWriter { + @Throws(IOException::class) + override fun write(header: BackupInfo) { + val headerBytes: ByteArray = header.encode() + + outputStream.writeVarInt32(headerBytes.size) + outputStream.write(headerBytes) + } + @Throws(IOException::class) override fun write(frame: Frame) { val frameBytes: ByteArray = frame.encode() diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsCheckoutSheet.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsCheckoutSheet.kt new file mode 100644 index 00000000..0e01a63d --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsCheckoutSheet.kt @@ -0,0 +1,261 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.view.updateLayoutParams +import kotlinx.collections.immutable.persistentListOf +import org.signal.core.ui.BottomSheets +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.util.money.FiatMoney +import org.tm.archive.R +import org.tm.archive.components.settings.app.subscription.donate.gateway.GatewayResponse +import org.tm.archive.components.settings.app.subscription.models.GooglePayButton +import org.tm.archive.databinding.PaypalButtonBinding +import org.tm.archive.payments.FiatMoneyUtil +import java.math.BigDecimal +import java.util.Currency + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MessageBackupsCheckoutSheet( + messageBackupsType: MessageBackupsType, + availablePaymentGateways: List, + onDismissRequest: () -> Unit, + onPaymentGatewaySelected: (GatewayResponse.Gateway) -> Unit +) { + ModalBottomSheet( + onDismissRequest = onDismissRequest, + dragHandle = { BottomSheets.Handle() }, + modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + SheetContent( + messageBackupsType = messageBackupsType, + availablePaymentGateways = availablePaymentGateways, + onPaymentGatewaySelected = onPaymentGatewaySelected + ) + } +} + +@Composable +private fun SheetContent( + messageBackupsType: MessageBackupsType, + availablePaymentGateways: List, + onPaymentGatewaySelected: (GatewayResponse.Gateway) -> Unit +) { + val resources = LocalContext.current.resources + val formattedPrice = remember(messageBackupsType.pricePerMonth) { + FiatMoneyUtil.format(resources, messageBackupsType.pricePerMonth, FiatMoneyUtil.formatOptions().trimZerosAfterDecimal()) + } + + Text( + text = "Pay $formattedPrice/month to Signal", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.padding(top = 48.dp) + ) + + Text( + text = "You'll get:", // TODO [message-backups] Finalized copy + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 5.dp) + ) + + MessageBackupsTypeBlock( + messageBackupsType = messageBackupsType, + isSelected = false, + onSelected = {}, + enabled = false, + modifier = Modifier.padding(top = 24.dp) + ) + + Column( + verticalArrangement = spacedBy(12.dp), + modifier = Modifier.padding(top = 48.dp, bottom = 24.dp) + ) { + availablePaymentGateways.forEach { + when (it) { + GatewayResponse.Gateway.GOOGLE_PAY -> GooglePayButton { + onPaymentGatewaySelected(GatewayResponse.Gateway.GOOGLE_PAY) + } + + GatewayResponse.Gateway.PAYPAL -> PayPalButton { + onPaymentGatewaySelected(GatewayResponse.Gateway.PAYPAL) + } + + GatewayResponse.Gateway.CREDIT_CARD -> CreditOrDebitCardButton { + onPaymentGatewaySelected(GatewayResponse.Gateway.CREDIT_CARD) + } + + GatewayResponse.Gateway.SEPA_DEBIT -> SepaButton { + onPaymentGatewaySelected(GatewayResponse.Gateway.SEPA_DEBIT) + } + + GatewayResponse.Gateway.IDEAL -> IdealButton { + onPaymentGatewaySelected(GatewayResponse.Gateway.IDEAL) + } + } + } + } +} + +@Composable +private fun PayPalButton( + onClick: () -> Unit +) { + AndroidView(factory = { + val view = LayoutInflater.from(it).inflate(R.layout.paypal_button, null) + view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + view + }) { + val binding = PaypalButtonBinding.bind(it) + binding.paypalButton.updateLayoutParams { + marginStart = 0 + marginEnd = 0 + } + + binding.paypalButton.setOnClickListener { + onClick() + } + } +} + +@Composable +private fun GooglePayButton( + onClick: () -> Unit +) { + val model = GooglePayButton.Model(onClick, true) + + AndroidView(factory = { + LayoutInflater.from(it).inflate(R.layout.google_pay_button_pref, null) + }) { + val holder = GooglePayButton.ViewHolder(it) + holder.bind(model) + } +} + +@Composable +private fun SepaButton( + onClick: () -> Unit +) { + Buttons.LargeTonal( + onClick = onClick, + modifier = Modifier.fillMaxWidth() + ) { + Icon( + painter = painterResource(id = R.drawable.bank_transfer), + contentDescription = null, + modifier = Modifier.padding(end = 8.dp) + ) + + Text(text = stringResource(id = R.string.GatewaySelectorBottomSheet__bank_transfer)) + } +} + +@Composable +private fun IdealButton( + onClick: () -> Unit +) { + Buttons.LargeTonal( + onClick = onClick, + modifier = Modifier.fillMaxWidth() + ) { + Image( + painter = painterResource(id = R.drawable.logo_ideal), + contentDescription = null, + modifier = Modifier + .size(32.dp) + .padding(end = 8.dp) + ) + + Text(text = stringResource(id = R.string.GatewaySelectorBottomSheet__ideal)) + } +} + +@Composable +private fun CreditOrDebitCardButton( + onClick: () -> Unit +) { + Buttons.LargePrimary( + onClick = onClick, + modifier = Modifier.fillMaxWidth() + ) { + Icon( + painter = painterResource(id = R.drawable.credit_card), + contentDescription = null, + modifier = Modifier.padding(end = 8.dp) + ) + + Text( + text = stringResource(id = R.string.GatewaySelectorBottomSheet__credit_or_debit_card) + ) + } +} + +@Preview +@Composable +private fun MessageBackupsCheckoutSheetPreview() { + val paidTier = MessageBackupsType( + pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("USD")), + title = "Text + All your media", + features = persistentListOf( + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_thread_compact_bold_16, + label = "Full text message backup" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_album_compact_bold_16, + label = "Full media backup" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_thread_compact_bold_16, + label = "1TB of storage (~250K photos)" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_heart_compact_bold_16, + label = "Thanks for supporting Signal!" + ) + ) + ) + + val availablePaymentGateways = GatewayResponse.Gateway.values().toList() + + Previews.Preview { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + SheetContent( + messageBackupsType = paidTier, + availablePaymentGateways = availablePaymentGateways, + onPaymentGatewaySelected = {} + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsEducationScreen.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsEducationScreen.kt new file mode 100644 index 00000000..969b409c --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsEducationScreen.kt @@ -0,0 +1,187 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.ui.Scaffolds +import org.signal.core.ui.theme.SignalTheme +import org.tm.archive.R + +/** + * Educational content which allows user to proceed to set up automatic backups + * or navigate to a support page to learn more. + */ +@Composable +fun MessageBackupsEducationScreen( + onNavigationClick: () -> Unit, + onEnableBackups: () -> Unit, + onLearnMore: () -> Unit +) { + Scaffolds.Settings( + onNavigationClick = onNavigationClick, + navigationIconPainter = painterResource(id = R.drawable.symbol_x_24), + title = "Chat backups" // TODO [message-backups] Finalized copy + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(it) + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + LazyColumn( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + item { + Image( + painter = painterResource(id = R.drawable.ic_signal_logo_large), // TODO [message-backups] Final image asset + contentDescription = null, + modifier = Modifier + .padding(top = 48.dp) + .size(88.dp) + ) + } + + item { + Text( + text = "Chat Backups", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(top = 15.dp) + ) + } + + item { + Text( + text = "Back up your messages and media and using Signal’s secure, end-to-end encrypted storage service. Never lose a message when you get a new phone or reinstall Signal.", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 12.dp) + ) + } + + item { + Column( + modifier = Modifier.padding(top = 32.dp), + verticalArrangement = Arrangement.spacedBy(20.dp) + ) { + NotableFeatureRow( + painter = painterResource(id = R.drawable.symbol_lock_compact_20), + text = "End-to-end Encrypted" // TODO [message-backups] Finalized copy + ) + + NotableFeatureRow( + painter = painterResource(id = R.drawable.symbol_check_square_compact_20), + text = "Optional, always" // TODO [message-backups] Finalized copy + ) + + NotableFeatureRow( + painter = painterResource(id = R.drawable.symbol_trash_compact_20), + text = "Delete your backup anytime" // TODO [message-backups] Finalized copy + ) + } + } + } + + Buttons.LargePrimary( + onClick = onEnableBackups, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "Enable backups" // TODO [message-backups] Finalized copy + ) + } + + TextButton( + onClick = onLearnMore, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp) + ) { + Text( + text = "Learn more" // TODO [message-backups] Finalized copy + ) + } + } + } +} + +@Preview +@Composable +private fun MessageBackupsEducationSheetPreview() { + Previews.Preview { + MessageBackupsEducationScreen( + onNavigationClick = {}, + onEnableBackups = {}, + onLearnMore = {} + ) + } +} + +@Preview +@Composable +private fun NotableFeatureRowPreview() { + Previews.Preview { + NotableFeatureRow( + painter = painterResource(id = R.drawable.symbol_lock_compact_20), + text = "Notable feature information" + ) + } +} + +@Composable +private fun NotableFeatureRow( + painter: Painter, + text: String +) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painter, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .padding(end = 8.dp) + .size(32.dp) + .background(color = SignalTheme.colors.colorSurface2, shape = CircleShape) + .padding(6.dp) + ) + + Text( + text = text, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowActivity.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowActivity.kt new file mode 100644 index 00000000..b7c2456b --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowActivity.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.dialog +import androidx.navigation.compose.rememberNavController +import org.signal.core.ui.theme.SignalTheme +import org.tm.archive.PassphraseRequiredActivity +import org.tm.archive.util.viewModel + +class MessageBackupsFlowActivity : PassphraseRequiredActivity() { + + private val viewModel: MessageBackupsFlowViewModel by viewModel { MessageBackupsFlowViewModel() } + + override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { + setContent { + SignalTheme { + val state by viewModel.state + val navController = rememberNavController() + + fun MessageBackupsScreen.next() { + val nextScreen = viewModel.goToNextScreen(this) + if (nextScreen != this) { + navController.navigate(nextScreen.name) + } + } + + fun NavController.popOrFinish() { + if (popBackStack()) { + return + } + + finishAfterTransition() + } + + LaunchedEffect(Unit) { + navController.setLifecycleOwner(this@MessageBackupsFlowActivity) + navController.setOnBackPressedDispatcher(this@MessageBackupsFlowActivity.onBackPressedDispatcher) + navController.enableOnBackPressed(true) + } + + NavHost( + navController = navController, + startDestination = MessageBackupsScreen.EDUCATION.name, + enterTransition = { slideInHorizontally(initialOffsetX = { it }) }, + exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) }, + popEnterTransition = { slideInHorizontally(initialOffsetX = { -it }) }, + popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) } + ) { + composable(route = MessageBackupsScreen.EDUCATION.name) { + MessageBackupsEducationScreen( + onNavigationClick = navController::popOrFinish, + onEnableBackups = { MessageBackupsScreen.EDUCATION.next() }, + onLearnMore = {} + ) + } + + composable(route = MessageBackupsScreen.PIN_EDUCATION.name) { + MessageBackupsPinEducationScreen( + onNavigationClick = navController::popOrFinish, + onGeneratePinClick = {}, + onUseCurrentPinClick = { MessageBackupsScreen.PIN_EDUCATION.next() }, + recommendedPinSize = 16 // TODO [message-backups] This value should come from some kind of config + ) + } + + composable(route = MessageBackupsScreen.PIN_CONFIRMATION.name) { + MessageBackupsPinConfirmationScreen( + pin = state.pin, + onPinChanged = viewModel::onPinEntryUpdated, + pinKeyboardType = state.pinKeyboardType, + onPinKeyboardTypeSelected = viewModel::onPinKeyboardTypeUpdated, + onNextClick = { MessageBackupsScreen.PIN_CONFIRMATION.next() } + ) + } + + composable(route = MessageBackupsScreen.TYPE_SELECTION.name) { + MessageBackupsTypeSelectionScreen( + selectedBackupsType = state.selectedMessageBackupsType, + availableBackupsTypes = state.availableBackupsTypes, + onMessageBackupsTypeSelected = viewModel::onMessageBackupsTypeUpdated, + onNavigationClick = navController::popOrFinish, + onReadMoreClicked = {}, + onNextClicked = { MessageBackupsScreen.TYPE_SELECTION.next() } + ) + } + + dialog(route = MessageBackupsScreen.CHECKOUT_SHEET.name) { + MessageBackupsCheckoutSheet( + messageBackupsType = state.selectedMessageBackupsType!!, + availablePaymentGateways = state.availablePaymentGateways, + onDismissRequest = navController::popOrFinish, + onPaymentGatewaySelected = { + viewModel.onPaymentGatewayUpdated(it) + MessageBackupsScreen.CHECKOUT_SHEET.next() + } + ) + } + } + } + } + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowRepository.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowRepository.kt new file mode 100644 index 00000000..b5de6714 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowRepository.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +class MessageBackupsFlowRepository diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowState.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowState.kt new file mode 100644 index 00000000..a3c67561 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowState.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import org.tm.archive.components.settings.app.subscription.donate.gateway.GatewayResponse +import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.lock.v2.PinKeyboardType + +data class MessageBackupsFlowState( + val selectedMessageBackupsType: MessageBackupsType? = null, + val availableBackupsTypes: List = emptyList(), + val selectedPaymentGateway: GatewayResponse.Gateway? = null, + val availablePaymentGateways: List = emptyList(), + val pin: String = "", + val pinKeyboardType: PinKeyboardType = SignalStore.pinValues().keyboardType +) diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowViewModel.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowViewModel.kt new file mode 100644 index 00000000..3785f986 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsFlowViewModel.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import org.tm.archive.components.settings.app.subscription.donate.gateway.GatewayResponse +import org.tm.archive.lock.v2.PinKeyboardType + +class MessageBackupsFlowViewModel : ViewModel() { + private val internalState = mutableStateOf(MessageBackupsFlowState()) + + val state: State = internalState + + fun goToNextScreen(currentScreen: MessageBackupsScreen): MessageBackupsScreen { + return when (currentScreen) { + MessageBackupsScreen.EDUCATION -> MessageBackupsScreen.PIN_EDUCATION + MessageBackupsScreen.PIN_EDUCATION -> MessageBackupsScreen.PIN_CONFIRMATION + MessageBackupsScreen.PIN_CONFIRMATION -> validatePinAndUpdateState() + MessageBackupsScreen.TYPE_SELECTION -> validateTypeAndUpdateState() + MessageBackupsScreen.CHECKOUT_SHEET -> validateGatewayAndUpdateState() + MessageBackupsScreen.PROCESS_PAYMENT -> MessageBackupsScreen.COMPLETED + MessageBackupsScreen.COMPLETED -> error("Unsupported state transition from terminal state COMPLETED") + } + } + + fun onPinEntryUpdated(pin: String) { + internalState.value = state.value.copy(pin = pin) + } + + fun onPinKeyboardTypeUpdated(pinKeyboardType: PinKeyboardType) { + internalState.value = state.value.copy(pinKeyboardType = pinKeyboardType) + } + + fun onPaymentGatewayUpdated(gateway: GatewayResponse.Gateway) { + internalState.value = state.value.copy(selectedPaymentGateway = gateway) + } + + fun onMessageBackupsTypeUpdated(messageBackupsType: MessageBackupsType) { + internalState.value = state.value.copy(selectedMessageBackupsType = messageBackupsType) + } + + private fun validatePinAndUpdateState(): MessageBackupsScreen { + return MessageBackupsScreen.TYPE_SELECTION + } + + private fun validateTypeAndUpdateState(): MessageBackupsScreen { + return MessageBackupsScreen.CHECKOUT_SHEET + } + + private fun validateGatewayAndUpdateState(): MessageBackupsScreen { + return MessageBackupsScreen.PROCESS_PAYMENT + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsPinConfirmationScreen.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsPinConfirmationScreen.kt new file mode 100644 index 00000000..57662030 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsPinConfirmationScreen.kt @@ -0,0 +1,198 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.tm.archive.R +import org.tm.archive.lock.v2.PinKeyboardType + +/** + * Screen which requires the user to enter their pin before enabling backups. + */ +@Composable +fun MessageBackupsPinConfirmationScreen( + pin: String, + onPinChanged: (String) -> Unit, + pinKeyboardType: PinKeyboardType, + onPinKeyboardTypeSelected: (PinKeyboardType) -> Unit, + onNextClick: () -> Unit +) { + val focusRequester = remember { FocusRequester() } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + item { + Text( + text = "Enter your PIN", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(top = 40.dp) + ) + } + + item { + Text( + text = "Enter your Signal PIN to enable backups", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 16.dp) + ) + } + + item { + // TODO [message-backups] Confirm default focus state + val keyboardType = remember(pinKeyboardType) { + when (pinKeyboardType) { + PinKeyboardType.NUMERIC -> KeyboardType.NumberPassword + PinKeyboardType.ALPHA_NUMERIC -> KeyboardType.Password + } + } + + TextField( + value = pin, + onValueChange = onPinChanged, + textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center), + keyboardActions = KeyboardActions( + onDone = { onNextClick() } + ), + keyboardOptions = KeyboardOptions( + keyboardType = keyboardType + ), + modifier = Modifier + .padding(top = 72.dp) + .fillMaxWidth() + .focusRequester(focusRequester) + ) + } + + item { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .padding(top = 48.dp) + ) { + PinKeyboardTypeToggle( + pinKeyboardType = pinKeyboardType, + onPinKeyboardTypeSelected = onPinKeyboardTypeSelected + ) + } + } + } + + Box( + contentAlignment = Alignment.BottomEnd, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Buttons.LargeTonal( + onClick = onNextClick + ) { + Text( + text = "Next" // TODO [message-backups] Finalized copy + ) + } + } + + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } + } +} + +@Preview +@Composable +private fun MessageBackupsPinConfirmationScreenPreview() { + Previews.Preview { + MessageBackupsPinConfirmationScreen( + pin = "", + onPinChanged = {}, + pinKeyboardType = PinKeyboardType.ALPHA_NUMERIC, + onPinKeyboardTypeSelected = {}, + onNextClick = {} + ) + } +} + +@Preview +@Composable +private fun PinKeyboardTypeTogglePreview() { + Previews.Preview { + var type by remember { mutableStateOf(PinKeyboardType.ALPHA_NUMERIC) } + PinKeyboardTypeToggle( + pinKeyboardType = type, + onPinKeyboardTypeSelected = { type = it } + ) + } +} + +@Composable +private fun PinKeyboardTypeToggle( + pinKeyboardType: PinKeyboardType, + onPinKeyboardTypeSelected: (PinKeyboardType) -> Unit +) { + val callback = remember(pinKeyboardType) { + { onPinKeyboardTypeSelected(pinKeyboardType.other) } + } + + val iconRes = remember(pinKeyboardType) { + when (pinKeyboardType) { + PinKeyboardType.NUMERIC -> R.drawable.symbol_keyboard_24 + PinKeyboardType.ALPHA_NUMERIC -> R.drawable.symbol_number_pad_24 + } + } + + TextButton(onClick = callback) { + Icon( + painter = painterResource(id = iconRes), + tint = MaterialTheme.colorScheme.primary, + contentDescription = null, + modifier = Modifier.padding(end = 8.dp) + ) + Text( + text = "Switch keyboard" // TODO [message-backups] Finalized copy + ) + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsPinEducationScreen.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsPinEducationScreen.kt new file mode 100644 index 00000000..23cab97e --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsPinEducationScreen.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.ui.Scaffolds +import org.tm.archive.R + +/** + * Explanation screen that details how the user's pin is utilized with backups, + * and how long they should make their pin. + */ +@Composable +fun MessageBackupsPinEducationScreen( + onNavigationClick: () -> Unit, + onGeneratePinClick: () -> Unit, + onUseCurrentPinClick: () -> Unit, + recommendedPinSize: Int +) { + Scaffolds.Settings( + title = "Backup type", // TODO [message-backups] Finalized copy + onNavigationClick = onNavigationClick, + navigationIconPainter = painterResource(id = R.drawable.symbol_arrow_left_24) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(it) + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + LazyColumn( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + item { + Image( + painter = painterResource(id = R.drawable.ic_signal_logo_large), // TODO [message-backups] Finalized image + contentDescription = null, + modifier = Modifier + .padding(top = 48.dp) + .size(88.dp) + ) + } + + item { + Text( + text = "PINs protect your backup", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(top = 16.dp) + ) + } + + item { + Text( + text = "Your Signal PIN lets you restore your backup when you re-install Signal. For increased security, we recommend updating to a new $recommendedPinSize-digit PIN.", // TODO [message-backups] Finalized copy + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(top = 16.dp) + ) + } + + item { + Text( + text = "If you forget your PIN, you will not be able to restore your backup. You can change your PIN at any time in settings.", // TODO [message-backups] Finalized copy + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(top = 16.dp) + ) + } + } + + Buttons.LargePrimary( + onClick = onGeneratePinClick, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "Generate a new $recommendedPinSize-digit PIN" // TODO [message-backups] Finalized copy + ) + } + + TextButton( + onClick = onUseCurrentPinClick, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp) + ) { + Text( + text = "Use current Signal PIN" // TODO [message-backups] Finalized copy + ) + } + } + } +} + +@Preview +@Composable +private fun MessageBackupsPinScreenPreview() { + Previews.Preview { + MessageBackupsPinEducationScreen( + onNavigationClick = {}, + onGeneratePinClick = {}, + onUseCurrentPinClick = {}, + recommendedPinSize = 16 + ) + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsScreen.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsScreen.kt new file mode 100644 index 00000000..979bafb8 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsScreen.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +enum class MessageBackupsScreen { + EDUCATION, + PIN_EDUCATION, + PIN_CONFIRMATION, + TYPE_SELECTION, + CHECKOUT_SHEET, + PROCESS_PAYMENT, + COMPLETED +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTestRestoreActivity.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTestRestoreActivity.kt new file mode 100644 index 00000000..94d00d2a --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTestRestoreActivity.kt @@ -0,0 +1,148 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.activity.compose.setContent +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import org.signal.core.ui.Buttons +import org.signal.core.ui.Dividers +import org.signal.core.util.getLength +import org.tm.archive.BaseActivity +import org.tm.archive.MainActivity +import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.jobs.ProfileUploadJob +import org.tm.archive.profiles.AvatarHelper +import org.tm.archive.profiles.edit.CreateProfileActivity +import org.tm.archive.recipients.Recipient +import org.tm.archive.registration.RegistrationUtil + +class MessageBackupsTestRestoreActivity : BaseActivity() { + companion object { + fun getIntent(context: Context): Intent { + return Intent(context, MessageBackupsTestRestoreActivity::class.java) + } + } + + private val viewModel: MessageBackupsTestRestoreViewModel by viewModels() + private lateinit var importFileLauncher: ActivityResultLauncher + + private fun onPlaintextClicked() { + viewModel.onPlaintextToggled() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + importFileLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + result.data?.data?.let { uri -> + contentResolver.getLength(uri)?.let { length -> + viewModel.import(length) { contentResolver.openInputStream(uri)!! } + } + } ?: Toast.makeText(this, "No URI selected", Toast.LENGTH_SHORT).show() + } + } + + setContent { + val state by viewModel.state + Surface { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + StateLabel(text = "Plaintext?") + Spacer(modifier = Modifier.width(8.dp)) + Switch( + checked = state.plaintext, + onCheckedChange = { onPlaintextClicked() } + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + Buttons.LargePrimary( + onClick = { + val intent = Intent().apply { + action = Intent.ACTION_GET_CONTENT + type = "application/octet-stream" + addCategory(Intent.CATEGORY_OPENABLE) + } + + importFileLauncher.launch(intent) + }, + enabled = !state.importState.inProgress + ) { + Text("Import from file") + } + + Spacer(modifier = Modifier.height(8.dp)) + + Dividers.Default() + + Buttons.LargeTonal( + onClick = { continueRegistration() }, + enabled = !state.importState.inProgress + ) { + Text("Continue Reg Flow") + } + } + } + } + } + + private fun continueRegistration() { + if (Recipient.self().profileName.isEmpty || !AvatarHelper.hasAvatar(this, Recipient.self().id)) { + val main = MainActivity.clearTop(this) + val profile = CreateProfileActivity.getIntentForUserProfile(this) + profile.putExtra("next_intent", main) + startActivity(profile) + } else { + RegistrationUtil.maybeMarkRegistrationComplete() + ApplicationDependencies.getJobManager().add(ProfileUploadJob()) + startActivity(MainActivity.clearTop(this)) + } + finish() + } + + @Composable + private fun StateLabel(text: String) { + Text( + text = text, + style = MaterialTheme.typography.labelSmall, + textAlign = TextAlign.Center + ) + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTestRestoreViewModel.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTestRestoreViewModel.kt new file mode 100644 index 00000000..3ac4efa0 --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTestRestoreViewModel.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.kotlin.plusAssign +import io.reactivex.rxjava3.kotlin.subscribeBy +import io.reactivex.rxjava3.schedulers.Schedulers +import org.signal.libsignal.zkgroup.profiles.ProfileKey +import org.tm.archive.backup.v2.BackupRepository +import org.tm.archive.recipients.Recipient +import java.io.InputStream + +class MessageBackupsTestRestoreViewModel : ViewModel() { + val disposables = CompositeDisposable() + + private val _state: MutableState = mutableStateOf(ScreenState(importState = ImportState.NONE, plaintext = false)) + val state: State = _state + + fun import(length: Long, inputStreamFactory: () -> InputStream) { + _state.value = _state.value.copy(importState = ImportState.IN_PROGRESS) + + val self = Recipient.self() + val selfData = BackupRepository.SelfData(self.aci.get(), self.pni.get(), self.e164.get(), ProfileKey(self.profileKey)) + + disposables += Single.fromCallable { BackupRepository.import(length, inputStreamFactory, selfData, plaintext = _state.value.plaintext) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy { + _state.value = _state.value.copy(importState = ImportState.NONE) + } + } + + fun onPlaintextToggled() { + _state.value = _state.value.copy(plaintext = !_state.value.plaintext) + } + + override fun onCleared() { + disposables.clear() + } + + data class ScreenState( + val importState: ImportState, + val plaintext: Boolean + ) + + enum class ImportState(val inProgress: Boolean = false) { + NONE, IN_PROGRESS(true) + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTypeFeature.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTypeFeature.kt new file mode 100644 index 00000000..62c5c64d --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTypeFeature.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp + +/** + * Represents a "Feature" included for a specify tier of message backups + */ +data class MessageBackupsTypeFeature( + val iconResourceId: Int, + val label: String +) + +/** + * Renders a "feature row" for a given feature. + */ +@Composable +fun MessageBackupsTypeFeatureRow( + messageBackupsTypeFeature: MessageBackupsTypeFeature, + iconTint: Color = LocalContentColor.current, + modifier: Modifier = Modifier +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = modifier.fillMaxWidth() + ) { + Icon( + painter = painterResource(id = messageBackupsTypeFeature.iconResourceId), + contentDescription = null, + tint = iconTint, + modifier = Modifier.padding(end = 8.dp) + ) + + Text( + text = messageBackupsTypeFeature.label, + style = MaterialTheme.typography.bodyLarge + ) + } +} diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTypeSelectionScreen.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTypeSelectionScreen.kt new file mode 100644 index 00000000..be754e3e --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/MessageBackupsTypeSelectionScreen.kt @@ -0,0 +1,276 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ +package org.tm.archive.backup.v2.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.ClickableText +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.ExperimentalTextApi +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.withAnnotation +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.ui.Scaffolds +import org.signal.core.ui.theme.SignalTheme +import org.signal.core.util.money.FiatMoney +import org.tm.archive.R +import org.tm.archive.payments.FiatMoneyUtil +import java.math.BigDecimal +import java.util.Currency + +/** + * Screen which allows the user to select their preferred backup type. + */ +@OptIn(ExperimentalTextApi::class) +@Composable +fun MessageBackupsTypeSelectionScreen( + selectedBackupsType: MessageBackupsType?, + availableBackupsTypes: List, + onMessageBackupsTypeSelected: (MessageBackupsType) -> Unit, + onNavigationClick: () -> Unit, + onReadMoreClicked: () -> Unit, + onNextClicked: () -> Unit +) { + Scaffolds.Settings( + title = "", + onNavigationClick = onNavigationClick, + navigationIconPainter = painterResource(id = R.drawable.symbol_arrow_left_24) + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + .fillMaxSize() + ) { + LazyColumn( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + item { + Image( + painter = painterResource(id = R.drawable.ic_signal_logo_large), // TODO [message-backups] Finalized art asset + contentDescription = null, + modifier = Modifier.size(88.dp) + ) + } + + item { + Text( + text = "Choose your backup type", // TODO [message-backups] Finalized copy + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(top = 12.dp) + ) + } + + item { + // TODO [message-backups] Finalized copy + val primaryColor = MaterialTheme.colorScheme.primary + val readMoreString = buildAnnotatedString { + append("All backups are end-to-end encrypted. Signal is a non-profit—paying for backups helps support our mission. ") + withAnnotation(tag = "URL", annotation = "read-more") { + withStyle( + style = SpanStyle( + color = primaryColor + ) + ) { + append("Read more") + } + } + } + + ClickableText( + text = readMoreString, + style = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.Center), + onClick = { offset -> + readMoreString + .getStringAnnotations(tag = "URL", start = offset, end = offset) + .firstOrNull()?.let { onReadMoreClicked() } + }, + modifier = Modifier.padding(top = 8.dp) + ) + } + + itemsIndexed( + availableBackupsTypes, + { _, item -> item.title } + ) { index, item -> + MessageBackupsTypeBlock( + messageBackupsType = item, + isSelected = item == selectedBackupsType, + onSelected = { onMessageBackupsTypeSelected(item) }, + modifier = Modifier.padding(top = if (index == 0) 20.dp else 18.dp) + ) + } + } + + Buttons.LargePrimary( + onClick = onNextClicked, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Text( + text = "Next" // TODO [message-backups] Finalized copy + ) + } + } + } +} + +@Preview +@Composable +private fun MessageBackupsTypeSelectionScreenPreview() { + val freeTier = MessageBackupsType( + pricePerMonth = FiatMoney(BigDecimal.ZERO, Currency.getInstance("USD")), + title = "Text + 30 days of media", + features = persistentListOf( + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_thread_compact_bold_16, + label = "Full text message backup" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_album_compact_bold_16, + label = "Last 30 days of media" + ) + ) + ) + + val paidTier = MessageBackupsType( + pricePerMonth = FiatMoney(BigDecimal.valueOf(3), Currency.getInstance("USD")), + title = "Text + All your media", + features = persistentListOf( + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_thread_compact_bold_16, + label = "Full text message backup" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_album_compact_bold_16, + label = "Full media backup" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_thread_compact_bold_16, + label = "1TB of storage (~250K photos)" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_heart_compact_bold_16, + label = "Thanks for supporting Signal!" + ) + ) + ) + + var selectedBackupsType by remember { mutableStateOf(freeTier) } + + Previews.Preview { + MessageBackupsTypeSelectionScreen( + selectedBackupsType = selectedBackupsType, + availableBackupsTypes = listOf(freeTier, paidTier), + onMessageBackupsTypeSelected = { selectedBackupsType = it }, + onNavigationClick = {}, + onReadMoreClicked = {}, + onNextClicked = {} + ) + } +} + +@Composable +fun MessageBackupsTypeBlock( + messageBackupsType: MessageBackupsType, + isSelected: Boolean, + onSelected: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true +) { + val borderColor = if (isSelected) { + MaterialTheme.colorScheme.primary + } else { + Color.Transparent + } + + val background = if (isSelected) { + MaterialTheme.colorScheme.secondaryContainer + } else { + SignalTheme.colors.colorSurface2 + } + + Column( + modifier = modifier + .fillMaxWidth() + .background(color = background, shape = RoundedCornerShape(18.dp)) + .border(width = 2.dp, color = borderColor, shape = RoundedCornerShape(18.dp)) + .clip(shape = RoundedCornerShape(18.dp)) + .clickable(onClick = onSelected, enabled = enabled) + .padding(vertical = 16.dp, horizontal = 20.dp) + ) { + Text( + text = formatCostPerMonth(messageBackupsType.pricePerMonth), + style = MaterialTheme.typography.titleSmall + ) + + Text( + text = messageBackupsType.title, + style = MaterialTheme.typography.titleMedium + ) + + Column( + verticalArrangement = spacedBy(4.dp), + modifier = Modifier + .padding(top = 8.dp) + .padding(horizontal = 16.dp) + ) { + messageBackupsType.features.forEach { + MessageBackupsTypeFeatureRow(messageBackupsTypeFeature = it) + } + } + } +} + +@Composable +private fun formatCostPerMonth(pricePerMonth: FiatMoney): String { + return if (pricePerMonth.amount == BigDecimal.ZERO) { + "Free" + } else { + "${FiatMoneyUtil.format(LocalContext.current.resources, pricePerMonth, FiatMoneyUtil.formatOptions().trimZerosAfterDecimal())}/month" + } +} + +data class MessageBackupsType( + val pricePerMonth: FiatMoney, + val title: String, + val features: ImmutableList +) diff --git a/app/src/main/java/org/tm/archive/backup/v2/ui/restore/RestoreFromBackupFragment.kt b/app/src/main/java/org/tm/archive/backup/v2/ui/restore/RestoreFromBackupFragment.kt new file mode 100644 index 00000000..b76f6fec --- /dev/null +++ b/app/src/main/java/org/tm/archive/backup/v2/ui/restore/RestoreFromBackupFragment.kt @@ -0,0 +1,179 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.backup.v2.ui.restore + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.ui.theme.SignalTheme +import org.tm.archive.R +import org.tm.archive.backup.v2.ui.MessageBackupsTypeFeature +import org.tm.archive.backup.v2.ui.MessageBackupsTypeFeatureRow +import org.tm.archive.compose.ComposeFragment +import org.tm.archive.devicetransfer.moreoptions.MoreTransferOrRestoreOptionsMode +import org.tm.archive.util.navigation.safeNavigate + +/** + * Fragment which facilitates restoring from a backup during + * registration. + */ +class RestoreFromBackupFragment : ComposeFragment() { + + private val navArgs: RestoreFromBackupFragmentArgs by navArgs() + + @Composable + override fun FragmentContent() { + RestoreFromBackupContent( + features = persistentListOf(), + onRestoreBackupClick = { + // TODO [message-backups] Restore backup. + }, + onCancelClick = { + findNavController() + .popBackStack() + }, + onMoreOptionsClick = { + findNavController() + .safeNavigate(RestoreFromBackupFragmentDirections.actionRestoreFromBacakupFragmentToMoreOptions(MoreTransferOrRestoreOptionsMode.SELECTION)) + }, + cancelable = navArgs.cancelable + ) + } +} + +@Preview +@Composable +private fun RestoreFromBackupContentPreview() { + Previews.Preview { + RestoreFromBackupContent( + features = persistentListOf( + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_thread_compact_bold_16, + label = "Your last 30 days of media" + ), + MessageBackupsTypeFeature( + iconResourceId = R.drawable.symbol_recent_compact_bold_16, + label = "All of your text messages" + ) + ), + onRestoreBackupClick = {}, + onCancelClick = {}, + onMoreOptionsClick = {}, + true + ) + } +} + +@Composable +private fun RestoreFromBackupContent( + features: ImmutableList, + onRestoreBackupClick: () -> Unit, + onCancelClick: () -> Unit, + onMoreOptionsClick: () -> Unit, + cancelable: Boolean +) { + Column( + modifier = Modifier + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + .padding(top = 40.dp, bottom = 24.dp) + ) { + Text( + text = "Restore from backup", // TODO [message-backups] Finalized copy. + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(bottom = 12.dp) + ) + + val yourLastBackupText = buildAnnotatedString { + append("Your last backup was made on March 5, 2024 at 9:00am.") // TODO [message-backups] Finalized copy. + append(" ") + withStyle(SpanStyle(fontWeight = FontWeight.SemiBold)) { + append("Only media sent or received in the past 30 days is included.") // TODO [message-backups] Finalized copy. + } + } + + Text( + text = yourLastBackupText, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(bottom = 28.dp) + ) + + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = SignalTheme.colors.colorSurface2, shape = RoundedCornerShape(18.dp)) + .padding(horizontal = 20.dp) + .padding(top = 20.dp, bottom = 18.dp) + ) { + Text( + text = "Your backup includes:", // TODO [message-backups] Finalized copy. + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(bottom = 6.dp) + ) + + features.forEach { + MessageBackupsTypeFeatureRow( + messageBackupsTypeFeature = it, + iconTint = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(start = 16.dp, top = 6.dp) + ) + } + } + + Spacer(modifier = Modifier.weight(1f)) + + Buttons.LargeTonal( + onClick = onRestoreBackupClick, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "Restore backup" // TODO [message-backups] Finalized copy. + ) + } + + if (cancelable) { + TextButton( + onClick = onCancelClick, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = stringResource(id = android.R.string.cancel) + ) + } + } else { + TextButton( + onClick = onMoreOptionsClick, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = stringResource(id = R.string.TransferOrRestoreFragment__more_options) + ) + } + } + } +} diff --git a/app/src/main/java/org/tm/archive/badges/BadgeImageView.kt b/app/src/main/java/org/tm/archive/badges/BadgeImageView.kt index aeeef039..18481608 100644 --- a/app/src/main/java/org/tm/archive/badges/BadgeImageView.kt +++ b/app/src/main/java/org/tm/archive/badges/BadgeImageView.kt @@ -4,6 +4,8 @@ import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatImageView import androidx.core.content.res.use +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy import org.tm.archive.R import org.tm.archive.badges.glide.BadgeSpriteTransformation @@ -11,11 +13,10 @@ import org.tm.archive.badges.models.Badge import org.tm.archive.components.settings.app.subscription.BadgeImageSize import org.tm.archive.database.model.databaseprotos.GiftBadge import org.tm.archive.glide.GiftBadgeModel -import org.tm.archive.mms.GlideApp -import org.tm.archive.mms.GlideRequests import org.tm.archive.recipients.Recipient import org.tm.archive.util.ScreenDensity import org.tm.archive.util.ThemeUtil +import org.tm.archive.util.visible class BadgeImageView @JvmOverloads constructor( context: Context, @@ -43,35 +44,35 @@ class BadgeImageView @JvmOverloads constructor( } fun setBadgeFromRecipient(recipient: Recipient?) { - getGlideRequests()?.let { + getGlideRequestManager()?.let { setBadgeFromRecipient(recipient, it) } ?: clearDrawable() } - fun setBadgeFromRecipient(recipient: Recipient?, glideRequests: GlideRequests) { + fun setBadgeFromRecipient(recipient: Recipient?, requestManager: RequestManager) { if (recipient == null || recipient.badges.isEmpty()) { - setBadge(null, glideRequests) + setBadge(null, requestManager) } else if (recipient.isSelf) { val badge = recipient.featuredBadge if (badge == null || !badge.visible || badge.isExpired()) { - setBadge(null, glideRequests) + setBadge(null, requestManager) } else { - setBadge(badge, glideRequests) + setBadge(badge, requestManager) } } else { - setBadge(recipient.featuredBadge, glideRequests) + setBadge(recipient.featuredBadge, requestManager) } } fun setBadge(badge: Badge?) { - getGlideRequests()?.let { + getGlideRequestManager()?.let { setBadge(badge, it) } ?: clearDrawable() } - fun setBadge(badge: Badge?, glideRequests: GlideRequests) { + fun setBadge(badge: Badge?, requestManager: RequestManager) { if (badge != null) { - glideRequests + requestManager .load(badge) .downsample(DownsampleStrategy.NONE) .transform(BadgeSpriteTransformation(BadgeSpriteTransformation.Size.fromInteger(badgeSize), badge.imageDensity, ThemeUtil.isDarkTheme(context))) @@ -79,26 +80,30 @@ class BadgeImageView @JvmOverloads constructor( isClickable = true } else { - glideRequests + requestManager .clear(this) clearDrawable() } } - fun setGiftBadge(badge: GiftBadge?, glideRequests: GlideRequests) { + fun setGiftBadge(badge: GiftBadge?, requestManager: RequestManager) { if (badge != null) { - glideRequests + requestManager .load(GiftBadgeModel(badge)) .downsample(DownsampleStrategy.NONE) .transform(BadgeSpriteTransformation(BadgeSpriteTransformation.Size.fromInteger(badgeSize), ScreenDensity.getBestDensityBucketForDevice(), ThemeUtil.isDarkTheme(context))) .into(this) } else { - glideRequests + requestManager .clear(this) clearDrawable() } } + fun isShowingBadge(): Boolean { + return drawable != null + } + private fun clearDrawable() { if (drawable != null) { setImageDrawable(null) @@ -106,9 +111,9 @@ class BadgeImageView @JvmOverloads constructor( } } - private fun getGlideRequests(): GlideRequests? { + private fun getGlideRequestManager(): RequestManager? { return try { - GlideApp.with(this) + Glide.with(this) } catch (e: IllegalArgumentException) { // View not attached to an activity or activity destroyed null diff --git a/app/src/main/java/org/tm/archive/badges/gifts/GiftMessageView.kt b/app/src/main/java/org/tm/archive/badges/gifts/GiftMessageView.kt index fbee2a28..efe0671c 100644 --- a/app/src/main/java/org/tm/archive/badges/gifts/GiftMessageView.kt +++ b/app/src/main/java/org/tm/archive/badges/gifts/GiftMessageView.kt @@ -9,13 +9,13 @@ import android.widget.TextView import androidx.core.content.ContextCompat import androidx.core.content.res.use import androidx.swiperefreshlayout.widget.CircularProgressDrawable +import com.bumptech.glide.RequestManager import com.google.android.material.button.MaterialButton import org.signal.core.util.DimensionUnit import org.tm.archive.R import org.tm.archive.badges.BadgeImageView import org.tm.archive.badges.gifts.Gifts.formatExpiry import org.tm.archive.database.model.databaseprotos.GiftBadge -import org.tm.archive.mms.GlideRequests import org.tm.archive.recipients.Recipient /** @@ -50,7 +50,7 @@ class GiftMessageView @JvmOverloads constructor( } } - fun setGiftBadge(glideRequests: GlideRequests, giftBadge: GiftBadge, isOutgoing: Boolean, callback: Callback, fromRecipient: Recipient, toRecipient: Recipient) { + fun setGiftBadge(requestManager: RequestManager, giftBadge: GiftBadge, isOutgoing: Boolean, callback: Callback, fromRecipient: Recipient, toRecipient: Recipient) { descriptionView.text = giftBadge.formatExpiry(context) actionView.icon = null actionView.setOnClickListener { callback.onViewGiftBadgeClicked() } @@ -88,7 +88,7 @@ class GiftMessageView @JvmOverloads constructor( ) } - badgeView.setGiftBadge(giftBadge, glideRequests) + badgeView.setGiftBadge(giftBadge, requestManager) } fun onGiftNotOpened() { diff --git a/app/src/main/java/org/tm/archive/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt b/app/src/main/java/org/tm/archive/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt index bf811a92..6d7a4434 100644 --- a/app/src/main/java/org/tm/archive/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt +++ b/app/src/main/java/org/tm/archive/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt @@ -38,7 +38,6 @@ class GiftFlowRecipientSelectionFragment : Fragment(R.layout.gift_flow_recipient R.id.multiselect_container, MultiselectForwardFragment.create( MultiselectForwardFragmentArgs( - canSendToNonPush = false, multiShareArgs = emptyList(), forceDisableAddMessage = true, selectSingleRecipient = true diff --git a/app/src/main/java/org/tm/archive/badges/models/Badge.kt b/app/src/main/java/org/tm/archive/badges/models/Badge.kt index 2042312d..4616d9b3 100644 --- a/app/src/main/java/org/tm/archive/badges/models/Badge.kt +++ b/app/src/main/java/org/tm/archive/badges/models/Badge.kt @@ -7,6 +7,7 @@ import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.compose.runtime.Stable +import com.bumptech.glide.Glide import com.bumptech.glide.load.Key import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy @@ -14,7 +15,6 @@ import kotlinx.parcelize.Parcelize import org.tm.archive.R import org.tm.archive.badges.glide.BadgeSpriteTransformation import org.tm.archive.components.settings.PreferenceModel -import org.tm.archive.mms.GlideApp import org.tm.archive.util.ThemeUtil import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter @@ -130,7 +130,7 @@ data class Badge( badge.alpha = if (model.badge.isExpired() || model.isFaded) 0.5f else 1f - GlideApp.with(badge) + Glide.with(badge) .load(model.badge) .downsample(DownsampleStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE) diff --git a/app/src/main/java/org/tm/archive/badges/models/BadgeDisplay112.kt b/app/src/main/java/org/tm/archive/badges/models/BadgeDisplay112.kt index d089370c..f3066d6d 100644 --- a/app/src/main/java/org/tm/archive/badges/models/BadgeDisplay112.kt +++ b/app/src/main/java/org/tm/archive/badges/models/BadgeDisplay112.kt @@ -2,10 +2,10 @@ package org.tm.archive.badges.models import android.view.View import android.widget.TextView +import com.bumptech.glide.Glide import org.tm.archive.R import org.tm.archive.badges.BadgeImageView import org.tm.archive.database.model.databaseprotos.GiftBadge -import org.tm.archive.mms.GlideApp import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingModel @@ -49,7 +49,7 @@ object BadgeDisplay112 { override fun bind(model: GiftModel) { titleView.visible = false - badgeImageView.setGiftBadge(model.giftBadge, GlideApp.with(badgeImageView)) + badgeImageView.setGiftBadge(model.giftBadge, Glide.with(badgeImageView)) } } } diff --git a/app/src/main/java/org/tm/archive/calls/links/CallLinks.kt b/app/src/main/java/org/tm/archive/calls/links/CallLinks.kt index a723846e..6bb09149 100644 --- a/app/src/main/java/org/tm/archive/calls/links/CallLinks.kt +++ b/app/src/main/java/org/tm/archive/calls/links/CallLinks.kt @@ -58,7 +58,7 @@ object CallLinks { return false } - if (!url.startsWith(HTTPS_LINK_PREFIX) || !url.startsWith(SNGL_LINK_PREFIX)) { + if (!url.startsWith(HTTPS_LINK_PREFIX) && !url.startsWith(SNGL_LINK_PREFIX)) { return false } diff --git a/app/src/main/java/org/tm/archive/calls/links/UpdateCallLinkRepository.kt b/app/src/main/java/org/tm/archive/calls/links/UpdateCallLinkRepository.kt index 97fbaf09..989d55f6 100644 --- a/app/src/main/java/org/tm/archive/calls/links/UpdateCallLinkRepository.kt +++ b/app/src/main/java/org/tm/archive/calls/links/UpdateCallLinkRepository.kt @@ -48,18 +48,25 @@ class UpdateCallLinkRepository( .subscribeOn(Schedulers.io()) } - fun revokeCallLink(credentials: CallLinkCredentials): Single { + fun deleteCallLink(credentials: CallLinkCredentials): Single { return callLinkManager - .updateCallLinkRevoked(credentials, true) + .deleteCallLink(credentials) .doOnSuccess(updateState(credentials)) .subscribeOn(Schedulers.io()) } private fun updateState(credentials: CallLinkCredentials): (UpdateCallLinkResult) -> Unit { return { result -> - if (result is UpdateCallLinkResult.Success) { - SignalDatabase.callLinks.updateCallLinkState(credentials.roomId, result.state) - ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId)) + when (result) { + is UpdateCallLinkResult.Update -> { + SignalDatabase.callLinks.updateCallLinkState(credentials.roomId, result.state) + ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId)) + } + is UpdateCallLinkResult.Delete -> { + SignalDatabase.callLinks.markRevoked(credentials.roomId) + ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId)) + } + else -> {} } } } diff --git a/app/src/main/java/org/tm/archive/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt b/app/src/main/java/org/tm/archive/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt index 5260f7d8..64f40e9e 100644 --- a/app/src/main/java/org/tm/archive/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/tm/archive/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt @@ -159,7 +159,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment private fun setCallName(callName: String) { lifecycleDisposable += viewModel.setCallName(callName).subscribeBy(onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to update call link name") toastFailure() } @@ -168,7 +168,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment private fun setApproveAllMembers(approveAllMembers: Boolean) { lifecycleDisposable += viewModel.setApproveAllMembers(approveAllMembers).subscribeBy(onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to update call link restrictions") toastFailure() } @@ -177,7 +177,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment private fun toggleApproveAllMembers() { lifecycleDisposable += viewModel.toggleApproveAllMembers().subscribeBy(onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to update call link restrictions") toastFailure() } diff --git a/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsFragment.kt b/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsFragment.kt index 9767852d..6fb66379 100644 --- a/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsFragment.kt +++ b/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsFragment.kt @@ -49,7 +49,9 @@ import org.tm.archive.recipients.RecipientId import org.tm.archive.service.webrtc.links.CallLinkCredentials import org.tm.archive.service.webrtc.links.SignalCallLinkState import org.tm.archive.service.webrtc.links.UpdateCallLinkResult +import org.tm.archive.sharing.v2.ShareActivity import org.tm.archive.util.CommunicationActions +import org.tm.archive.util.Util import java.time.Instant /** @@ -119,15 +121,29 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback { } } + override fun onCopyClicked() { + Util.copyToClipboard(requireContext(), CallLinks.url(viewModel.rootKeySnapshot)) + Toast.makeText(requireContext(), R.string.CreateCallLinkBottomSheetDialogFragment__copied_to_clipboard, Toast.LENGTH_LONG).show() + } + + override fun onShareLinkViaSignalClicked() { + startActivity( + ShareActivity.sendSimpleText( + requireContext(), + getString(R.string.CreateCallLink__use_this_link_to_join_a_signal_call, CallLinks.url(viewModel.rootKeySnapshot)) + ) + ) + } + override fun onDeleteClicked() { viewModel.setDisplayRevocationDialog(true) } override fun onDeleteConfirmed() { viewModel.setDisplayRevocationDialog(false) - lifecycleDisposable += viewModel.revoke().observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = { + lifecycleDisposable += viewModel.delete().observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = { when (it) { - is UpdateCallLinkResult.Success -> ActivityCompat.finishAfterTransition(requireActivity()) + is UpdateCallLinkResult.Update -> ActivityCompat.finishAfterTransition(requireActivity()) else -> { Log.w(TAG, "Failed to revoke. $it") toastFailure() @@ -142,7 +158,7 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback { override fun onApproveAllMembersChanged(checked: Boolean) { lifecycleDisposable += viewModel.setApproveAllMembers(checked).observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to change restrictions. $it") toastFailure() } @@ -151,7 +167,7 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback { private fun setName(name: String) { lifecycleDisposable += viewModel.setName(name).observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to set name. $it") toastFailure() } @@ -175,6 +191,8 @@ private interface CallLinkDetailsCallback { fun onJoinClicked() fun onEditNameClicked() fun onShareClicked() + fun onCopyClicked() + fun onShareLinkViaSignalClicked() fun onDeleteClicked() fun onDeleteConfirmed() fun onDeleteCanceled() @@ -216,6 +234,8 @@ private fun CallLinkDetailsPreview() { override fun onJoinClicked() = Unit override fun onEditNameClicked() = Unit override fun onShareClicked() = Unit + override fun onCopyClicked() = Unit + override fun onShareLinkViaSignalClicked() = Unit override fun onDeleteClicked() = Unit override fun onApproveAllMembersChanged(checked: Boolean) = Unit } @@ -265,6 +285,18 @@ private fun CallLinkDetails( Dividers.Default() } + Rows.TextRow( + text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__share_link_via_signal), + icon = ImageVector.vectorResource(id = R.drawable.symbol_forward_24), + onClick = callback::onShareLinkViaSignalClicked + ) + + Rows.TextRow( + text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__copy_link), + icon = ImageVector.vectorResource(id = R.drawable.symbol_copy_android_24), + onClick = callback::onCopyClicked + ) + Rows.TextRow( text = stringResource(id = R.string.CallLinkDetailsFragment__share_link), icon = ImageVector.vectorResource(id = R.drawable.symbol_link_24), diff --git a/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsViewModel.kt b/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsViewModel.kt index d0d46a58..f31b1a31 100644 --- a/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsViewModel.kt +++ b/app/src/main/java/org/tm/archive/calls/links/details/CallLinkDetailsViewModel.kt @@ -71,9 +71,9 @@ class CallLinkDetailsViewModel( return mutationRepository.setCallName(credentials, name) } - fun revoke(): Single { + fun delete(): Single { val credentials = _state.value.callLink?.credentials ?: error("User cannot change the name of this call.") - return mutationRepository.revokeCallLink(credentials) + return mutationRepository.deleteCallLink(credentials) } class Factory(private val callLinkRoomId: CallLinkRoomId) : ViewModelProvider.Factory { diff --git a/app/src/main/java/org/tm/archive/calls/log/CallLogAdapter.kt b/app/src/main/java/org/tm/archive/calls/log/CallLogAdapter.kt index 8d53270b..386967c2 100644 --- a/app/src/main/java/org/tm/archive/calls/log/CallLogAdapter.kt +++ b/app/src/main/java/org/tm/archive/calls/log/CallLogAdapter.kt @@ -7,13 +7,13 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.core.content.ContextCompat import androidx.core.widget.TextViewCompat +import com.bumptech.glide.Glide import org.tm.archive.R import org.tm.archive.database.CallTable import org.tm.archive.database.MessageTypes import org.tm.archive.databinding.CallLogAdapterItemBinding import org.tm.archive.databinding.CallLogCreateCallLinkItemBinding import org.tm.archive.databinding.ConversationListItemClearFilterBinding -import org.tm.archive.mms.GlideApp import org.tm.archive.recipients.Recipient import org.tm.archive.util.DateUtils import org.tm.archive.util.SearchUtil @@ -182,7 +182,7 @@ class CallLogAdapter( binding: CallLogAdapterItemBinding, private val onCallLinkClicked: (CallLogRow.CallLink) -> Unit, private val onCallLinkLongClicked: (View, CallLogRow.CallLink) -> Boolean, - private val onStartVideoCallClicked: (Recipient) -> Unit + private val onStartVideoCallClicked: (Recipient, Boolean) -> Unit ) : BindingViewHolder(binding) { override fun bind(model: CallLinkModel) { if (payload.size == 1 && payload.contains(PAYLOAD_TIMESTAMP)) { @@ -231,7 +231,7 @@ class CallLogAdapter( binding.callType.setImageResource(R.drawable.symbol_video_24) binding.callType.contentDescription = context.getString(R.string.CallLogAdapter__start_a_video_call) binding.callType.setOnClickListener { - onStartVideoCallClicked(model.callLink.recipient) + onStartVideoCallClicked(model.callLink.recipient, true) } binding.callType.visible = true binding.groupCallButton.visible = false @@ -243,7 +243,7 @@ class CallLogAdapter( private val onCallClicked: (CallLogRow.Call) -> Unit, private val onCallLongClicked: (View, CallLogRow.Call) -> Boolean, private val onStartAudioCallClicked: (Recipient) -> Unit, - private val onStartVideoCallClicked: (Recipient) -> Unit + private val onStartVideoCallClicked: (Recipient, Boolean) -> Unit ) : BindingViewHolder(binding) { override fun bind(model: CallModel) { itemView.setOnClickListener { @@ -272,7 +272,7 @@ class CallLogAdapter( } private fun presentRecipientDetails(recipient: Recipient, searchQuery: String?) { - binding.callRecipientAvatar.setAvatar(GlideApp.with(binding.callRecipientAvatar), recipient, true) + binding.callRecipientAvatar.setAvatar(Glide.with(binding.callRecipientAvatar), recipient, true) binding.callRecipientBadge.setBadgeFromRecipient(recipient) binding.callRecipientName.text = if (searchQuery != null) { SearchUtil.getHighlightedSpan( @@ -333,7 +333,7 @@ class CallLogAdapter( CallTable.Type.VIDEO_CALL -> { binding.callType.setImageResource(R.drawable.symbol_video_24) binding.callType.contentDescription = context.getString(R.string.CallLogAdapter__start_a_video_call) - binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer) } + binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer, true) } binding.callType.visible = true binding.groupCallButton.visible = false } @@ -341,8 +341,8 @@ class CallLogAdapter( CallTable.Type.GROUP_CALL, CallTable.Type.AD_HOC_CALL -> { binding.callType.setImageResource(R.drawable.symbol_video_24) binding.callType.contentDescription = context.getString(R.string.CallLogAdapter__start_a_video_call) - binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer) } - binding.groupCallButton.setOnClickListener { onStartVideoCallClicked(model.call.peer) } + binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer, model.call.canUserBeginCall) } + binding.groupCallButton.setOnClickListener { onStartVideoCallClicked(model.call.peer, model.call.canUserBeginCall) } when (model.call.groupCallState) { CallLogRow.GroupCallState.NONE, CallLogRow.GroupCallState.FULL -> { @@ -472,6 +472,6 @@ class CallLogAdapter( /** * Invoked when user presses the video icon */ - fun onStartVideoCallClicked(recipient: Recipient) + fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: Boolean) } } diff --git a/app/src/main/java/org/tm/archive/calls/log/CallLogFragment.kt b/app/src/main/java/org/tm/archive/calls/log/CallLogFragment.kt index d589c45d..9d7dbe27 100644 --- a/app/src/main/java/org/tm/archive/calls/log/CallLogFragment.kt +++ b/app/src/main/java/org/tm/archive/calls/log/CallLogFragment.kt @@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionInflater import com.google.android.material.appbar.AppBarLayout import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -32,6 +33,7 @@ import org.signal.core.util.DimensionUnit import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.concurrent.addTo import org.signal.core.util.logging.Log +import org.tm.archive.MainActivity import org.tm.archive.R import org.tm.archive.calls.links.details.CallLinkDetailsActivity import org.tm.archive.calls.new.NewCallActivity @@ -45,6 +47,7 @@ import org.tm.archive.components.settings.app.notifications.manual.NotificationP import org.tm.archive.components.settings.conversation.ConversationSettingsActivity import org.tm.archive.conversation.ConversationUpdateTick import org.tm.archive.conversation.SignalBottomActionBarController +import org.tm.archive.conversation.v2.ConversationDialogs import org.tm.archive.conversationlist.ConversationFilterBehavior import org.tm.archive.conversationlist.chatfilter.ConversationFilterSource import org.tm.archive.conversationlist.chatfilter.ConversationListFilterPullView.OnCloseClicked @@ -123,6 +126,12 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal val callLogAdapter = CallLogAdapter(this) disposables.bindTo(viewLifecycleOwner) callLogAdapter.setPagingController(viewModel.controller) + callLogAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + (requireActivity() as? MainActivity)?.onFirstRender() + callLogAdapter.unregisterAdapterDataObserver(this) + } + }) val scrollToPositionDelegate = ScrollToPositionDelegate( recyclerView = binding.recycler, @@ -376,8 +385,12 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal CommunicationActions.startVoiceCall(this, recipient) } - override fun onStartVideoCallClicked(recipient: Recipient) { - CommunicationActions.startVideoCall(this, recipient) + override fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: Boolean) { + if (canUserBeginCall) { + CommunicationActions.startVideoCall(this, recipient) + } else { + ConversationDialogs.displayCannotStartGroupCallDueToPermissionsDialog(requireContext()) + } } override fun startSelection(call: CallLogRow) { @@ -467,7 +480,7 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal is CallLogDeletionResult.FailedToRevoke -> { errorDialog = MaterialAlertDialogBuilder(requireContext()) .setMessage(resources.getQuantityString(R.plurals.CallLogFragment__cant_delete_call_link, it.failedRevocations)) - .setPositiveButton(R.string.ok, null) + .setPositiveButton(android.R.string.ok, null) .show() } CallLogDeletionResult.Success -> { diff --git a/app/src/main/java/org/tm/archive/calls/log/CallLogRepository.kt b/app/src/main/java/org/tm/archive/calls/log/CallLogRepository.kt index 0a13f3f4..724cb1bf 100644 --- a/app/src/main/java/org/tm/archive/calls/log/CallLogRepository.kt +++ b/app/src/main/java/org/tm/archive/calls/log/CallLogRepository.kt @@ -43,7 +43,9 @@ class CallLogRepository( fun markAllCallEventsRead() { SignalExecutors.BOUNDED_IO.execute { - SignalDatabase.messages.markAllCallEventsRead() + val latestCall = SignalDatabase.calls.getLatestCall() ?: return@execute + SignalDatabase.calls.markAllCallEventsRead() + ApplicationDependencies.getJobManager().add(CallLogEventSendJob.forMarkedAsRead(latestCall)) } } @@ -94,14 +96,14 @@ class CallLogRepository( fun deleteAllCallLogsOnOrBeforeNow(): Single { return Single.fromCallable { SignalDatabase.rawDatabase.withinTransaction { - val latestTimestamp = SignalDatabase.calls.getLatestTimestamp() - SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(latestTimestamp) - SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(latestTimestamp) - ApplicationDependencies.getJobManager().add(CallLogEventSendJob.forClearHistory(latestTimestamp)) + val latestCall = SignalDatabase.calls.getLatestCall() ?: return@withinTransaction + SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(latestCall.timestamp) + SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(latestCall.timestamp) + ApplicationDependencies.getJobManager().add(CallLogEventSendJob.forClearHistory(latestCall)) } SignalDatabase.callLinks.getAllAdminCallLinksExcept(emptySet()) - }.flatMap(this::revokeAndCollectResults).map { 0 }.subscribeOn(Schedulers.io()) + }.flatMap(this::deleteAndCollectResults).map { 0 }.subscribeOn(Schedulers.io()) } /** @@ -117,7 +119,7 @@ class CallLogRepository( val allCallLinkIds = SignalDatabase.calls.getCallLinkRoomIdsFromCallRowIds(selectedCallRowIds) + selectedRoomIds SignalDatabase.callLinks.deleteNonAdminCallLinks(allCallLinkIds) SignalDatabase.callLinks.getAdminCallLinks(allCallLinkIds) - }.flatMap(this::revokeAndCollectResults).subscribeOn(Schedulers.io()) + }.flatMap(this::deleteAndCollectResults).subscribeOn(Schedulers.io()) } /** @@ -133,16 +135,16 @@ class CallLogRepository( val allCallLinkIds = SignalDatabase.calls.getCallLinkRoomIdsFromCallRowIds(selectedCallRowIds) + selectedRoomIds SignalDatabase.callLinks.deleteAllNonAdminCallLinksExcept(allCallLinkIds) SignalDatabase.callLinks.getAllAdminCallLinksExcept(allCallLinkIds) - }.flatMap(this::revokeAndCollectResults).subscribeOn(Schedulers.io()) + }.flatMap(this::deleteAndCollectResults).subscribeOn(Schedulers.io()) } - private fun revokeAndCollectResults(callLinksToRevoke: Set): Single { + private fun deleteAndCollectResults(callLinksToRevoke: Set): Single { return Single.merge( callLinksToRevoke.map { - updateCallLinkRepository.revokeCallLink(it.credentials!!) + updateCallLinkRepository.deleteCallLink(it.credentials!!) } ).reduce(0) { acc, current -> - acc + (if (current is UpdateCallLinkResult.Success) 0 else 1) + acc + (if (current is UpdateCallLinkResult.Update) 0 else 1) }.doOnTerminate { SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps() }.doOnDispose { diff --git a/app/src/main/java/org/tm/archive/calls/log/CallLogRow.kt b/app/src/main/java/org/tm/archive/calls/log/CallLogRow.kt index 9381082d..568a398d 100644 --- a/app/src/main/java/org/tm/archive/calls/log/CallLogRow.kt +++ b/app/src/main/java/org/tm/archive/calls/log/CallLogRow.kt @@ -41,6 +41,7 @@ sealed class CallLogRow { val children: Set, val searchQuery: String?, val callLinkPeekInfo: CallLinkPeekInfo?, + val canUserBeginCall: Boolean, override val id: Id = Id.Call(children) ) : CallLogRow() diff --git a/app/src/main/java/org/tm/archive/calls/new/NewCallActivity.kt b/app/src/main/java/org/tm/archive/calls/new/NewCallActivity.kt index fc0192b1..d4aa9e5e 100644 --- a/app/src/main/java/org/tm/archive/calls/new/NewCallActivity.kt +++ b/app/src/main/java/org/tm/archive/calls/new/NewCallActivity.kt @@ -16,16 +16,14 @@ import org.tm.archive.ContactSelectionListFragment import org.tm.archive.InviteActivity import org.tm.archive.R import org.tm.archive.contacts.ContactSelectionDisplayMode -import org.tm.archive.contacts.sync.ContactDiscovery.refresh import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId +import org.tm.archive.recipients.RecipientRepository import org.tm.archive.util.CommunicationActions import org.tm.archive.util.views.SimpleProgressDialog -import java.io.IOException import java.util.Optional import java.util.function.Consumer -import kotlin.time.Duration.Companion.seconds class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment.NewCallCallback { @@ -40,42 +38,42 @@ class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment override fun onSelectionChanged() = Unit override fun onBeforeContactSelected(isFromUnknownSearchKey: Boolean, recipientId: Optional, number: String?, callback: Consumer) { - if (isFromUnknownSearchKey) { + if (recipientId.isPresent) { + launch(Recipient.resolved(recipientId.get())) + } else { Log.i(TAG, "[onContactSelected] Maybe creating a new recipient.") if (SignalStore.account().isRegistered) { Log.i(TAG, "[onContactSelected] Doing contact refresh.") + val progress = SimpleProgressDialog.show(this) - SimpleTask.run(lifecycle, { - var resolved = Recipient.external(this, number!!) - if (!resolved.isRegistered || !resolved.hasServiceId()) { - Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.") - resolved = try { - refresh(this, resolved, false, 10.seconds.inWholeMilliseconds) - Recipient.resolved(resolved.id) - } catch (e: IOException) { - Log.w(TAG, "[onContactSelected] Failed to refresh directory for new contact.") - return@run null - } - } - resolved - }) { resolved: Recipient? -> + + SimpleTask.run(lifecycle, { RecipientRepository.lookupNewE164(this, number!!) }, { result -> progress.dismiss() - if (resolved != null) { - if (resolved.isRegistered && resolved.hasServiceId()) { - launch(resolved) - } else { + + when (result) { + is RecipientRepository.LookupResult.Success -> { + val resolved = Recipient.resolved(result.recipientId) + if (resolved.isRegistered && resolved.hasServiceId()) { + launch(resolved) + } + } + + is RecipientRepository.LookupResult.NotFound, + is RecipientRepository.LookupResult.InvalidEntry -> { MaterialAlertDialogBuilder(this) - .setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, resolved.getDisplayName(this))) + .setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number)) + .setPositiveButton(android.R.string.ok, null) + .show() + } + + else -> { + MaterialAlertDialogBuilder(this) + .setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again) .setPositiveButton(android.R.string.ok, null) .show() } - } else { - MaterialAlertDialogBuilder(this) - .setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again) - .setPositiveButton(android.R.string.ok, null) - .show() } - } + }) } } callback.accept(true) diff --git a/app/src/main/java/org/tm/archive/components/AlbumThumbnailView.java b/app/src/main/java/org/tm/archive/components/AlbumThumbnailView.java index f149bac1..59aa69f1 100644 --- a/app/src/main/java/org/tm/archive/components/AlbumThumbnailView.java +++ b/app/src/main/java/org/tm/archive/components/AlbumThumbnailView.java @@ -16,9 +16,10 @@ import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; import org.tm.archive.components.transfercontrols.TransferControlView; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideClickListener; import org.tm.archive.mms.SlidesClickedListener; @@ -65,7 +66,7 @@ public class AlbumThumbnailView extends FrameLayout { transferControlsStub = new Stub<>(findViewById(R.id.album_transfer_controls_stub)); } - public void setSlides(@NonNull GlideRequests glideRequests, @NonNull List slides, boolean showControls) { + public void setSlides(@NonNull RequestManager requestManager, @NonNull List slides, boolean showControls) { if (slides.size() < 2) { throw new IllegalStateException("Provided less than two slides."); } @@ -98,7 +99,7 @@ public class AlbumThumbnailView extends FrameLayout { currentSizeClass = sizeClass; } - showSlides(glideRequests, slides); + showSlides(requestManager, slides); applyCorners(); forceLayout(); } @@ -261,21 +262,21 @@ public class AlbumThumbnailView extends FrameLayout { applyCornersForSizeClass5(); } - private void showSlides(@NonNull GlideRequests glideRequests, @NonNull List slides) { + private void showSlides(@NonNull RequestManager requestManager, @NonNull List slides) { boolean showControls = TransferControlView.containsPlayableSlides(slides); - setSlide(glideRequests, slides.get(0), R.id.album_cell_1, showControls); - setSlide(glideRequests, slides.get(1), R.id.album_cell_2, showControls); + setSlide(requestManager, slides.get(0), R.id.album_cell_1, showControls); + setSlide(requestManager, slides.get(1), R.id.album_cell_2, showControls); if (slides.size() >= 3) { - setSlide(glideRequests, slides.get(2), R.id.album_cell_3, showControls); + setSlide(requestManager, slides.get(2), R.id.album_cell_3, showControls); } if (slides.size() >= 4) { - setSlide(glideRequests, slides.get(3), R.id.album_cell_4, showControls); + setSlide(requestManager, slides.get(3), R.id.album_cell_4, showControls); } if (slides.size() >= 5) { - setSlide(glideRequests, slides.get(4), R.id.album_cell_5, showControls && slides.size() == 5); + setSlide(requestManager, slides.get(4), R.id.album_cell_5, showControls && slides.size() == 5); } if (slides.size() > 5) { @@ -284,7 +285,7 @@ public class AlbumThumbnailView extends FrameLayout { } } - private void setSlide(@NonNull GlideRequests glideRequests, @NonNull Slide slide, @IdRes int id, boolean showControls) { + private void setSlide(@NonNull RequestManager requestManager, @NonNull Slide slide, @IdRes int id, boolean showControls) { ThumbnailView cell = findViewById(id); cell.showSecondaryText(false); cell.setThumbnailClickListener(defaultThumbnailClickListener); @@ -294,7 +295,7 @@ public class AlbumThumbnailView extends FrameLayout { cell.setPlayVideoClickListener(playVideoClickListener); } cell.setOnLongClickListener(defaultLongClickListener); - cell.setImageResource(glideRequests, slide, showControls, false); + cell.setImageResource(requestManager, slide, showControls, false); } private int sizeClass(int size) { diff --git a/app/src/main/java/org/tm/archive/components/AvatarImageView.java b/app/src/main/java/org/tm/archive/components/AvatarImageView.java index 9874f438..c8452033 100644 --- a/app/src/main/java/org/tm/archive/components/AvatarImageView.java +++ b/app/src/main/java/org/tm/archive/components/AvatarImageView.java @@ -15,6 +15,9 @@ import androidx.annotation.Px; import androidx.appcompat.widget.AppCompatImageView; import androidx.fragment.app.FragmentActivity; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.MultiTransformation; import com.bumptech.glide.load.Transformation; @@ -31,15 +34,13 @@ import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.components.settings.conversation.ConversationSettingsActivity; import org.tm.archive.contacts.avatars.ContactPhoto; +import org.tm.archive.contacts.avatars.FallbackContactPhoto; import org.tm.archive.contacts.avatars.ProfileContactPhoto; import org.tm.archive.contacts.avatars.ResourceContactPhoto; import org.tm.archive.conversation.colors.AvatarColor; import org.tm.archive.conversation.colors.ChatColors; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobs.RetrieveProfileAvatarJob; -import org.tm.archive.mms.GlideApp; -import org.tm.archive.mms.GlideRequest; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment; import org.tm.archive.util.AvatarUtil; @@ -129,10 +130,10 @@ public final class AvatarImageView extends AppCompatImageView { */ public void setRecipient(@NonNull Recipient recipient, boolean quickContactEnabled) { if (recipient.isSelf()) { - setAvatar(GlideApp.with(this), null, quickContactEnabled); + setAvatar(Glide.with(this), null, quickContactEnabled); AvatarUtil.loadIconIntoImageView(recipient, this); } else { - setAvatar(GlideApp.with(this), recipient, quickContactEnabled); + setAvatar(Glide.with(this), recipient, quickContactEnabled); } } @@ -144,21 +145,21 @@ public final class AvatarImageView extends AppCompatImageView { * Shows self as the note to self icon. */ public void setAvatar(@Nullable Recipient recipient) { - setAvatar(GlideApp.with(this), recipient, false); + setAvatar(Glide.with(this), recipient, false); } /** * Shows self as the profile avatar. */ public void setAvatarUsingProfile(@Nullable Recipient recipient) { - setAvatar(GlideApp.with(this), recipient, false, true); + setAvatar(Glide.with(this), recipient, false, true); } - public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) { + public void setAvatar(@NonNull RequestManager requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) { setAvatar(requestManager, recipient, quickContactEnabled, false); } - public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled, boolean useSelfProfileAvatar) { + public void setAvatar(@NonNull RequestManager requestManager, @Nullable Recipient recipient, boolean quickContactEnabled, boolean useSelfProfileAvatar) { setAvatar(requestManager, recipient, new AvatarOptions.Builder(this) .withUseSelfProfileAvatar(useSelfProfileAvatar) .withQuickContactEnabled(quickContactEnabled) @@ -166,10 +167,10 @@ public final class AvatarImageView extends AppCompatImageView { } private void setAvatar(@Nullable Recipient recipient, @NonNull AvatarOptions avatarOptions) { - setAvatar(GlideApp.with(this), recipient, avatarOptions); + setAvatar(Glide.with(this), recipient, avatarOptions); } - private void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, @NonNull AvatarOptions avatarOptions) { + private void setAvatar(@NonNull RequestManager requestManager, @Nullable Recipient recipient, @NonNull AvatarOptions avatarOptions) { if (recipient != null) { RecipientContactPhoto photo = (recipient.isSelf() && avatarOptions.useSelfProfileAvatar) ? new RecipientContactPhoto(recipient, new ProfileContactPhoto(Recipient.self())) @@ -183,8 +184,18 @@ public final class AvatarImageView extends AppCompatImageView { this.chatColors = chatColors; recipientContactPhoto = photo; - Drawable fallbackContactPhotoDrawable = size == SIZE_SMALL ? photo.recipient.getSmallFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider, ViewUtil.getWidth(this)) - : photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider, ViewUtil.getWidth(this)); + Recipient.FallbackPhotoProvider activeFallbackPhotoProvider = this.fallbackPhotoProvider; + if (recipient.isSelf() && avatarOptions.useSelfProfileAvatar) { + activeFallbackPhotoProvider = new Recipient.FallbackPhotoProvider() { + @Override + public @NonNull FallbackContactPhoto getPhotoForLocalNumber() { + return super.getPhotoForRecipientWithName(recipient.getDisplayName(getContext()), ViewUtil.getWidth(AvatarImageView.this)); + } + }; + } + + Drawable fallbackContactPhotoDrawable = size == SIZE_SMALL ? photo.recipient.getSmallFallbackContactPhotoDrawable(getContext(), inverted, activeFallbackPhotoProvider, ViewUtil.getWidth(this)) + : photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted, activeFallbackPhotoProvider, ViewUtil.getWidth(this)); if (fixedSizeTarget != null) { requestManager.clear(fixedSizeTarget); @@ -199,7 +210,7 @@ public final class AvatarImageView extends AppCompatImageView { transforms.add(new CircleCrop()); blurred = shouldBlur; - GlideRequest request = requestManager.load(photo.contactPhoto) + RequestBuilder request = requestManager.load(photo.contactPhoto) .dontAnimate() .fallback(fallbackContactPhotoDrawable) .error(fallbackContactPhotoDrawable) @@ -244,8 +255,7 @@ public final class AvatarImageView extends AppCompatImageView { ConversationSettingsActivity.createTransitionBundle(context, this)); } else { if (context instanceof FragmentActivity) { - RecipientBottomSheetDialogFragment.create(recipient.getId(), null) - .show(((FragmentActivity) context).getSupportFragmentManager(), "BOTTOM"); + RecipientBottomSheetDialogFragment.show(((FragmentActivity) context).getSupportFragmentManager(), recipient.getId(), null); } else { context.startActivity(ConversationSettingsActivity.forRecipient(context, recipient.getId()), ConversationSettingsActivity.createTransitionBundle(context, this)); @@ -265,7 +275,7 @@ public final class AvatarImageView extends AppCompatImageView { .getPhotoForGroup() .asDrawable(getContext(), color); - GlideApp.with(this) + Glide.with(this) .load(avatarBytes) .dontAnimate() .fallback(fallback) diff --git a/app/src/main/java/org/tm/archive/components/BorderlessImageView.java b/app/src/main/java/org/tm/archive/components/BorderlessImageView.java index c517175c..9d96c0f3 100644 --- a/app/src/main/java/org/tm/archive/components/BorderlessImageView.java +++ b/app/src/main/java/org/tm/archive/components/BorderlessImageView.java @@ -9,8 +9,9 @@ import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideClickListener; import org.tm.archive.mms.SlidesClickedListener; @@ -52,15 +53,15 @@ public class BorderlessImageView extends FrameLayout { image.setOnLongClickListener(l); } - public void setSlide(@NonNull GlideRequests glideRequests, @NonNull Slide slide) { + public void setSlide(@NonNull RequestManager requestManager, @NonNull Slide slide) { boolean showControls = slide.asAttachment().getUri() == null; if (slide.hasSticker()) { image.setScaleType(ImageView.ScaleType.FIT_CENTER); - image.setImageResource(glideRequests, slide, showControls, false); + image.setImageResource(requestManager, slide, showControls, false); } else { image.setScaleType(ImageView.ScaleType.CENTER_CROP); - image.setImageResource(glideRequests, slide, showControls, false, slide.asAttachment().width, slide.asAttachment().height); + image.setImageResource(requestManager, slide, showControls, false, slide.asAttachment().width, slide.asAttachment().height); } missingShade.setVisibility(showControls ? View.VISIBLE : View.GONE); diff --git a/app/src/main/java/org/tm/archive/components/ContactFilterView.java b/app/src/main/java/org/tm/archive/components/ContactFilterView.java index 4427507d..378f2c72 100644 --- a/app/src/main/java/org/tm/archive/components/ContactFilterView.java +++ b/app/src/main/java/org/tm/archive/components/ContactFilterView.java @@ -114,23 +114,23 @@ public final class ContactFilterView extends FrameLayout { int defStyle) { final TypedArray attributes = context.obtainStyledAttributes(attrs, - R.styleable.ContactFilterToolbar, + R.styleable.ContactFilterView, defStyle, 0); - int styleResource = attributes.getResourceId(R.styleable.ContactFilterToolbar_searchTextStyle, -1); + int styleResource = attributes.getResourceId(R.styleable.ContactFilterView_searchTextStyle, -1); if (styleResource != -1) { TextViewCompat.setTextAppearance(searchText, styleResource); } - if (!attributes.getBoolean(R.styleable.ContactFilterToolbar_showDialpad, true)) { + if (!attributes.getBoolean(R.styleable.ContactFilterView_showDialpad, true)) { dialpadToggle.setVisibility(GONE); } - if (attributes.getBoolean(R.styleable.ContactFilterToolbar_cfv_autoFocus, true)) { + if (attributes.getBoolean(R.styleable.ContactFilterView_cfv_autoFocus, true)) { searchText.requestFocus(); } - int backgroundRes = attributes.getResourceId(R.styleable.ContactFilterToolbar_cfv_background, -1); + int backgroundRes = attributes.getResourceId(R.styleable.ContactFilterView_cfv_background, -1); if (backgroundRes != -1) { findViewById(R.id.background_holder).setBackgroundResource(backgroundRes); } diff --git a/app/src/main/java/org/tm/archive/components/ConversationItemThumbnail.kt b/app/src/main/java/org/tm/archive/components/ConversationItemThumbnail.kt index 6ccc7374..e23e6570 100644 --- a/app/src/main/java/org/tm/archive/components/ConversationItemThumbnail.kt +++ b/app/src/main/java/org/tm/archive/components/ConversationItemThumbnail.kt @@ -16,10 +16,10 @@ import androidx.annotation.ColorInt import androidx.annotation.Px import androidx.annotation.UiThread import androidx.core.os.bundleOf +import com.bumptech.glide.RequestManager import org.signal.core.util.dp import org.signal.core.util.getParcelableCompat import org.tm.archive.R -import org.tm.archive.mms.GlideRequests import org.tm.archive.mms.Slide import org.tm.archive.mms.SlideClickListener import org.tm.archive.mms.SlidesClickedListener @@ -192,7 +192,7 @@ class ConversationItemThumbnail @JvmOverloads constructor( @UiThread fun setImageResource( - glideRequests: GlideRequests, + requestManager: RequestManager, slides: List, showControls: Boolean, isPreview: Boolean @@ -223,7 +223,7 @@ class ConversationItemThumbnail @JvmOverloads constructor( val attachment = slides[0].asAttachment() - thumbnail.get().setImageResource(glideRequests, slides[0], showControls, isPreview, attachment.width, attachment.height) + thumbnail.get().setImageResource(requestManager, slides[0], showControls, isPreview, attachment.width, attachment.height) touchDelegate = thumbnail.get().touchDelegate } else { state = state.copy( @@ -232,7 +232,7 @@ class ConversationItemThumbnail @JvmOverloads constructor( ) state.applyState(thumbnail, album) - album.get().setSlides(glideRequests, slides, showControls) + album.get().setSlides(requestManager, slides, showControls) touchDelegate = album.get().touchDelegate } } diff --git a/app/src/main/java/org/tm/archive/components/ConversationTypingView.java b/app/src/main/java/org/tm/archive/components/ConversationTypingView.java index 3fbddc91..17319935 100644 --- a/app/src/main/java/org/tm/archive/components/ConversationTypingView.java +++ b/app/src/main/java/org/tm/archive/components/ConversationTypingView.java @@ -11,9 +11,10 @@ import androidx.annotation.Nullable; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; import org.tm.archive.badges.BadgeImageView; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.Recipient; import java.util.List; @@ -49,7 +50,7 @@ public class ConversationTypingView extends ConstraintLayout { indicator = findViewById(R.id.typing_indicator); } - public void setTypists(@NonNull GlideRequests glideRequests, @NonNull List typists, boolean isGroupThread, boolean hasWallpaper) { + public void setTypists(@NonNull RequestManager requestManager, @NonNull List typists, boolean isGroupThread, boolean hasWallpaper) { if (typists.isEmpty()) { indicator.stopAnimation(); return; @@ -64,7 +65,7 @@ public class ConversationTypingView extends ConstraintLayout { typistCount.setVisibility(GONE); if (isGroupThread) { - presentGroupThreadAvatars(glideRequests, typists); + presentGroupThreadAvatars(requestManager, typists); } if (hasWallpaper) { @@ -84,23 +85,23 @@ public class ConversationTypingView extends ConstraintLayout { return indicator.isActive(); } - private void presentGroupThreadAvatars(@NonNull GlideRequests glideRequests, @NonNull List typists) { - avatar1.setAvatar(glideRequests, typists.get(0), typists.size() == 1); + private void presentGroupThreadAvatars(@NonNull RequestManager requestManager, @NonNull List typists) { + avatar1.setAvatar(requestManager, typists.get(0), typists.size() == 1); avatar1.setVisibility(VISIBLE); - badge1.setBadgeFromRecipient(typists.get(0), glideRequests); + badge1.setBadgeFromRecipient(typists.get(0), requestManager); badge1.setVisibility(VISIBLE); if (typists.size() > 1) { - avatar2.setAvatar(glideRequests, typists.get(1), false); + avatar2.setAvatar(requestManager, typists.get(1), false); avatar2.setVisibility(VISIBLE); - badge2.setBadgeFromRecipient(typists.get(1), glideRequests); + badge2.setBadgeFromRecipient(typists.get(1), requestManager); badge2.setVisibility(VISIBLE); } if (typists.size() == 3) { - avatar3.setAvatar(glideRequests, typists.get(2), false); + avatar3.setAvatar(requestManager, typists.get(2), false); avatar3.setVisibility(VISIBLE); - badge3.setBadgeFromRecipient(typists.get(2), glideRequests); + badge3.setBadgeFromRecipient(typists.get(2), requestManager); badge3.setVisibility(VISIBLE); } diff --git a/app/src/main/java/org/tm/archive/components/DeliveryStatusView.java b/app/src/main/java/org/tm/archive/components/DeliveryStatusView.java index 7567a3b1..61e5b1d3 100644 --- a/app/src/main/java/org/tm/archive/components/DeliveryStatusView.java +++ b/app/src/main/java/org/tm/archive/components/DeliveryStatusView.java @@ -3,6 +3,7 @@ package org.tm.archive.components; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; +import android.graphics.PorterDuff; import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; @@ -146,7 +147,7 @@ public class DeliveryStatusView extends AppCompatImageView { setVisibility(View.VISIBLE); ViewUtil.setPaddingStart(this, 0); ViewUtil.setPaddingEnd(this, horizontalPadding); - setImageResource(R.drawable.ic_delivery_status_sending); + setImageResource(R.drawable.symbol_messagestatus_sending_24); updateContentDescription(); } @@ -156,7 +157,7 @@ public class DeliveryStatusView extends AppCompatImageView { ViewUtil.setPaddingStart(this, horizontalPadding); ViewUtil.setPaddingEnd(this, 0); clearAnimation(); - setImageResource(R.drawable.ic_delivery_status_sent); + setImageResource(R.drawable.symbol_messagestatus_sent_24); updateContentDescription(); } @@ -166,7 +167,7 @@ public class DeliveryStatusView extends AppCompatImageView { ViewUtil.setPaddingStart(this, horizontalPadding); ViewUtil.setPaddingEnd(this, 0); clearAnimation(); - setImageResource(R.drawable.ic_delivery_status_delivered); + setImageResource(R.drawable.symbol_messagestatus_delivered_24); updateContentDescription(); } @@ -176,12 +177,12 @@ public class DeliveryStatusView extends AppCompatImageView { ViewUtil.setPaddingStart(this, horizontalPadding); ViewUtil.setPaddingEnd(this, 0); clearAnimation(); - setImageResource(R.drawable.ic_delivery_status_read); + setImageResource(R.drawable.symbol_messagestatus_read_24); updateContentDescription(); } public void setTint(int color) { - setColorFilter(color); + setColorFilter(color, PorterDuff.Mode.SRC_IN); } private void updateContentDescription() { diff --git a/app/src/main/java/org/tm/archive/components/FromTextView.java b/app/src/main/java/org/tm/archive/components/FromTextView.java index 07d18209..a8d0f713 100644 --- a/app/src/main/java/org/tm/archive/components/FromTextView.java +++ b/app/src/main/java/org/tm/archive/components/FromTextView.java @@ -1,29 +1,24 @@ package org.tm.archive.components; import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.text.SpannableStringBuilder; import android.util.AttributeSet; +import androidx.annotation.DrawableRes; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; -import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.components.emoji.SimpleEmojiTextView; import org.tm.archive.recipients.Recipient; import org.tm.archive.util.ContextUtil; +import org.tm.archive.util.DrawableUtil; import org.tm.archive.util.SpanUtil; import org.tm.archive.util.ViewUtil; -import java.util.Objects; - public class FromTextView extends SimpleEmojiTextView { - private static final String TAG = Log.tag(FromTextView.class); - public FromTextView(Context context) { super(context); } @@ -33,22 +28,18 @@ public class FromTextView extends SimpleEmojiTextView { } public void setText(Recipient recipient) { - setText(recipient, true); + setText(recipient, null); } - public void setText(Recipient recipient, boolean read) { - setText(recipient, read, null); + public void setText(Recipient recipient, @Nullable CharSequence suffix) { + setText(recipient, recipient.getDisplayName(getContext()), suffix); } - public void setText(Recipient recipient, boolean read, @Nullable String suffix) { - setText(recipient, recipient.getDisplayNameOrUsername(getContext()), read, suffix); + public void setText(Recipient recipient, @Nullable CharSequence fromString, @Nullable CharSequence suffix) { + setText(recipient, fromString, suffix, true); } - public void setText(Recipient recipient, @Nullable CharSequence fromString, boolean read, @Nullable String suffix) { - setText(recipient, fromString, read, suffix, true); - } - - public void setText(Recipient recipient, @Nullable CharSequence fromString, boolean read, @Nullable String suffix, boolean asThread) { + public void setText(Recipient recipient, @Nullable CharSequence fromString, @Nullable CharSequence suffix, boolean asThread) { SpannableStringBuilder builder = new SpannableStringBuilder(); if (asThread && recipient.isSelf()) { @@ -71,17 +62,23 @@ public class FromTextView extends SimpleEmojiTextView { setText(builder); - if (recipient.isBlocked()) setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_block_grey600_18dp, 0, 0, 0); + if (recipient.isBlocked()) setCompoundDrawablesRelativeWithIntrinsicBounds(getBlocked(), null, null, null); else if (recipient.isMuted()) setCompoundDrawablesRelativeWithIntrinsicBounds(getMuted(), null, null, null); else setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0); } + private Drawable getBlocked() { + return getDrawable(R.drawable.symbol_block_16); + } + private Drawable getMuted() { - Drawable mutedDrawable = Objects.requireNonNull(ContextCompat.getDrawable(getContext(), R.drawable.ic_bell_disabled_16)); + return getDrawable(R.drawable.ic_bell_disabled_16); + } + private Drawable getDrawable(@DrawableRes int drawable) { + Drawable mutedDrawable = ContextUtil.requireDrawable(getContext(), drawable); mutedDrawable.setBounds(0, 0, ViewUtil.dpToPx(18), ViewUtil.dpToPx(18)); - mutedDrawable.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(getContext(), R.color.signal_icon_tint_secondary), PorterDuff.Mode.SRC_IN)); - + DrawableUtil.tint(mutedDrawable, ContextCompat.getColor(getContext(), R.color.signal_icon_tint_secondary)); return mutedDrawable; } } diff --git a/app/src/main/java/org/tm/archive/components/GlideBitmapListeningTarget.java b/app/src/main/java/org/tm/archive/components/GlideBitmapListeningTarget.java index 8552ae80..d57799ec 100644 --- a/app/src/main/java/org/tm/archive/components/GlideBitmapListeningTarget.java +++ b/app/src/main/java/org/tm/archive/components/GlideBitmapListeningTarget.java @@ -9,7 +9,7 @@ import androidx.annotation.Nullable; import com.bumptech.glide.request.target.BitmapImageViewTarget; -import org.tm.archive.util.concurrent.SettableFuture; +import org.signal.core.util.concurrent.SettableFuture; public class GlideBitmapListeningTarget extends BitmapImageViewTarget { diff --git a/app/src/main/java/org/tm/archive/components/GlideDrawableListeningTarget.java b/app/src/main/java/org/tm/archive/components/GlideDrawableListeningTarget.java index d49dcf35..6b340847 100644 --- a/app/src/main/java/org/tm/archive/components/GlideDrawableListeningTarget.java +++ b/app/src/main/java/org/tm/archive/components/GlideDrawableListeningTarget.java @@ -8,8 +8,8 @@ import androidx.annotation.Nullable; import com.bumptech.glide.request.target.DrawableImageViewTarget; +import org.signal.core.util.concurrent.SettableFuture; import org.signal.core.util.logging.Log; -import org.tm.archive.util.concurrent.SettableFuture; public class GlideDrawableListeningTarget extends DrawableImageViewTarget { diff --git a/app/src/main/java/org/tm/archive/components/InputPanel.java b/app/src/main/java/org/tm/archive/components/InputPanel.java index 57084488..7f1b68cc 100644 --- a/app/src/main/java/org/tm/archive/components/InputPanel.java +++ b/app/src/main/java/org/tm/archive/components/InputPanel.java @@ -32,9 +32,13 @@ import androidx.lifecycle.Observer; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.signal.core.util.ThreadUtil; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.SettableFuture; import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.animation.AnimationCompleteListener; @@ -49,9 +53,9 @@ import org.tm.archive.conversation.ConversationStickerSuggestionAdapter; import org.tm.archive.conversation.MessageStyler; import org.tm.archive.conversation.VoiceNoteDraftView; import org.tm.archive.database.DraftTable; -import org.tm.archive.database.model.MmsMessageRecord; import org.tm.archive.database.model.MessageId; import org.tm.archive.database.model.MessageRecord; +import org.tm.archive.database.model.MmsMessageRecord; import org.tm.archive.database.model.Quote; import org.tm.archive.database.model.StickerRecord; import org.tm.archive.keyboard.KeyboardPage; @@ -59,8 +63,6 @@ import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.linkpreview.LinkPreview; import org.tm.archive.linkpreview.LinkPreviewRepository; import org.tm.archive.mms.DecryptableStreamUriLoader; -import org.tm.archive.mms.GlideApp; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.QuoteModel; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideDeck; @@ -69,8 +71,6 @@ import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.MessageRecordUtil; import org.tm.archive.util.ViewUtil; import org.tm.archive.util.concurrent.AssertedSuccessListener; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.tm.archive.util.concurrent.SettableFuture; import java.util.Arrays; import java.util.List; @@ -184,7 +184,7 @@ public class InputPanel extends ConstraintLayout } }); - stickerSuggestionAdapter = new ConversationStickerSuggestionAdapter(GlideApp.with(this), this); + stickerSuggestionAdapter = new ConversationStickerSuggestionAdapter(Glide.with(this), this); stickerSuggestion.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); stickerSuggestion.setAdapter(stickerSuggestionAdapter); @@ -212,14 +212,14 @@ public class InputPanel extends ConstraintLayout composeText.setMediaListener(listener); } - public void setQuote(@NonNull GlideRequests glideRequests, + public void setQuote(@NonNull RequestManager requestManager, long id, @NonNull Recipient author, @Nullable CharSequence body, @NonNull SlideDeck attachments, @NonNull QuoteModel.Type quoteType) { - this.quoteView.setQuote(glideRequests, id, author, body, false, attachments, null, quoteType); + this.quoteView.setQuote(requestManager, id, author, body, false, attachments, null, quoteType); int originalHeight = this.quoteView.getVisibility() == VISIBLE ? this.quoteView.getMeasuredHeight() : 0; @@ -325,10 +325,10 @@ public class InputPanel extends ConstraintLayout this.linkPreview.setNoPreview(customError); } - public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull Optional preview) { + public void setLinkPreview(@NonNull RequestManager requestManager, @NonNull Optional preview) { if (preview.isPresent()) { this.linkPreview.setVisibility(View.VISIBLE); - this.linkPreview.setLinkPreview(glideRequests, preview.get(), true); + this.linkPreview.setLinkPreview(requestManager, preview.get(), true); } else { this.linkPreview.setVisibility(View.GONE); } @@ -404,7 +404,7 @@ public class InputPanel extends ConstraintLayout quoteView.setWallpaperEnabled(enabled); } - public void enterEditMessageMode(@NonNull GlideRequests glideRequests, @NonNull ConversationMessage conversationMessageToEdit, boolean fromDraft) { + public void enterEditMessageMode(@NonNull RequestManager requestManager, @NonNull ConversationMessage conversationMessageToEdit, boolean fromDraft) { SpannableString textToEdit = conversationMessageToEdit.getDisplayBody(getContext()); if (!fromDraft) { MessageStyler.convertSpoilersToComposeMode(textToEdit); @@ -415,14 +415,14 @@ public class InputPanel extends ConstraintLayout if (quote == null) { clearQuote(); } else { - setQuote(glideRequests, quote.getId(), Recipient.resolved(quote.getAuthor()), quote.getDisplayText(), quote.getAttachment(), quote.getQuoteType()); + setQuote(requestManager, quote.getId(), Recipient.resolved(quote.getAuthor()), quote.getDisplayText(), quote.getAttachment(), quote.getQuoteType()); } this.messageToEdit = conversationMessageToEdit.getMessageRecord(); - updateEditModeThumbnail(glideRequests); + updateEditModeThumbnail(requestManager); updateEditModeUi(); } - private void updateEditModeThumbnail(@NonNull GlideRequests glideRequests) { + private void updateEditModeThumbnail(@NonNull RequestManager requestManager) { if (messageToEdit instanceof MmsMessageRecord) { MmsMessageRecord mediaEditMessage = (MmsMessageRecord) messageToEdit; SlideDeck slideDeck = mediaEditMessage.getSlideDeck(); @@ -430,7 +430,7 @@ public class InputPanel extends ConstraintLayout if (imageVideoSlide != null && imageVideoSlide.getUri() != null) { editMessageThumbnail.setVisibility(VISIBLE); - glideRequests.load(new DecryptableStreamUriLoader.DecryptableUri(imageVideoSlide.getUri())) + requestManager.load(new DecryptableStreamUriLoader.DecryptableUri(imageVideoSlide.getUri())) .centerCrop() .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .into(editMessageThumbnail); diff --git a/app/src/main/java/org/tm/archive/components/InsetAwareConstraintLayout.kt b/app/src/main/java/org/tm/archive/components/InsetAwareConstraintLayout.kt index 97ea8bda..bc19f9a2 100644 --- a/app/src/main/java/org/tm/archive/components/InsetAwareConstraintLayout.kt +++ b/app/src/main/java/org/tm/archive/components/InsetAwareConstraintLayout.kt @@ -130,9 +130,9 @@ open class InsetAwareConstraintLayout @JvmOverloads constructor( if (previousKeyboardHeight != keyboardInsets.bottom) { keyboardStateListeners.forEach { - if (previousKeyboardHeight <= 0) { + if (previousKeyboardHeight <= 0 && keyboardInsets.bottom > 0) { it.onKeyboardShown() - } else { + } else if (previousKeyboardHeight > 0 && keyboardInsets.bottom <= 0) { it.onKeyboardHidden() } } diff --git a/app/src/main/java/org/tm/archive/components/LinkPreviewView.java b/app/src/main/java/org/tm/archive/components/LinkPreviewView.java index 2bf24bc9..69ca1fe6 100644 --- a/app/src/main/java/org/tm/archive/components/LinkPreviewView.java +++ b/app/src/main/java/org/tm/archive/components/LinkPreviewView.java @@ -16,13 +16,14 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import com.bumptech.glide.RequestManager; + import org.signal.ringrtc.CallLinkRootKey; import org.tm.archive.R; import org.tm.archive.calls.links.CallLinks; import org.tm.archive.conversation.colors.AvatarColorHash; import org.tm.archive.linkpreview.LinkPreview; import org.tm.archive.linkpreview.LinkPreviewRepository; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.ImageSlide; import org.tm.archive.mms.SlidesClickedListener; import org.tm.archive.recipients.Recipient; @@ -162,11 +163,11 @@ public class LinkPreviewView extends FrameLayout { noPreview.setText(getLinkPreviewErrorString(customError)); } - public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull LinkPreview linkPreview, boolean showThumbnail) { - setLinkPreview(glideRequests, linkPreview, showThumbnail, true, false); + public void setLinkPreview(@NonNull RequestManager requestManager, @NonNull LinkPreview linkPreview, boolean showThumbnail) { + setLinkPreview(requestManager, linkPreview, showThumbnail, true, false); } - public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull LinkPreview linkPreview, boolean showThumbnail, boolean showDescription, boolean scheduleMessageMode) { + public void setLinkPreview(@NonNull RequestManager requestManager, @NonNull LinkPreview linkPreview, boolean showThumbnail, boolean showDescription, boolean scheduleMessageMode) { spinner.setVisibility(GONE); noPreview.setVisibility(GONE); @@ -216,13 +217,13 @@ public class LinkPreviewView extends FrameLayout { if (showThumbnail && linkPreview.getThumbnail().isPresent()) { thumbnail.setVisibility(VISIBLE); thumbnailState.applyState(thumbnail); - thumbnail.get().setImageResource(glideRequests, new ImageSlide(linkPreview.getThumbnail().get()), type == TYPE_CONVERSATION && !scheduleMessageMode, false); + thumbnail.get().setImageResource(requestManager, new ImageSlide(linkPreview.getThumbnail().get()), type == TYPE_CONVERSATION && !scheduleMessageMode, false); thumbnail.get().showSecondaryText(false); } else if (callLinkRootKey != null) { thumbnail.setVisibility(VISIBLE); thumbnailState.applyState(thumbnail); thumbnail.get().setImageDrawable( - glideRequests, + requestManager, Recipient.DEFAULT_FALLBACK_PHOTO_PROVIDER .getPhotoForCallLink() .asDrawable(getContext(), diff --git a/app/src/main/java/org/tm/archive/components/PromptBatterySaverDialogFragment.kt b/app/src/main/java/org/tm/archive/components/PromptBatterySaverDialogFragment.kt index bed77506..e2f18567 100644 --- a/app/src/main/java/org/tm/archive/components/PromptBatterySaverDialogFragment.kt +++ b/app/src/main/java/org/tm/archive/components/PromptBatterySaverDialogFragment.kt @@ -13,16 +13,19 @@ import androidx.annotation.RequiresApi import androidx.core.os.bundleOf import androidx.fragment.app.FragmentManager import org.signal.core.util.concurrent.LifecycleDisposable +import org.signal.core.util.logging.Log import org.tm.archive.R import org.tm.archive.databinding.PromptBatterySaverBottomSheetBinding import org.tm.archive.keyvalue.SignalStore import org.tm.archive.util.BottomSheetUtil +import org.tm.archive.util.LocalMetrics import org.tm.archive.util.PowerManagerCompat @RequiresApi(23) class PromptBatterySaverDialogFragment : FixedRoundedCornerBottomSheetDialogFragment() { companion object { + private val TAG = Log.tag(PromptBatterySaverDialogFragment::class.java) @JvmStatic fun show(fragmentManager: FragmentManager) { @@ -51,8 +54,11 @@ class PromptBatterySaverDialogFragment : FixedRoundedCornerBottomSheetDialogFrag binding.continueButton.setOnClickListener { PowerManagerCompat.requestIgnoreBatteryOptimizations(requireContext()) + Log.i(TAG, "Requested to ignore battery optimizations, clearing local metrics.") + LocalMetrics.clear() } binding.dismissButton.setOnClickListener { + Log.i(TAG, "User denied request to ignore battery optimizations.") SignalStore.uiHints().markDismissedBatterySaverPrompt() dismiss() } diff --git a/app/src/main/java/org/tm/archive/components/QuoteView.java b/app/src/main/java/org/tm/archive/components/QuoteView.java index 7158ec81..c983af91 100644 --- a/app/src/main/java/org/tm/archive/components/QuoteView.java +++ b/app/src/main/java/org/tm/archive/components/QuoteView.java @@ -15,6 +15,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.constraintlayout.widget.ConstraintLayout; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.google.android.material.imageview.ShapeableImageView; import com.google.android.material.shape.CornerFamily; @@ -32,7 +33,6 @@ import org.tm.archive.conversation.MessageStyler; import org.tm.archive.database.model.Mention; import org.tm.archive.database.model.databaseprotos.BodyRangeList; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.QuoteModel; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideDeck; @@ -193,7 +193,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser } } - public void setQuote(GlideRequests glideRequests, + public void setQuote(RequestManager requestManager, long id, @NonNull Recipient author, @Nullable CharSequence body, @@ -213,7 +213,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser this.author.observeForever(this); setQuoteAuthor(author); setQuoteText(resolveBody(body, quoteType), attachments, originalMissing, storyReaction); - setQuoteAttachment(glideRequests, body, attachments, originalMissing); + setQuoteAttachment(requestManager, body, attachments, originalMissing); setQuoteMissingFooter(originalMissing); applyColorTheme(); } @@ -347,10 +347,17 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser } } - private void setQuoteAttachment(@NonNull GlideRequests glideRequests, @NonNull CharSequence body, @NonNull SlideDeck slideDeck, boolean originalMissing) { + private void setQuoteAttachment(@NonNull RequestManager requestManager, @NonNull CharSequence body, @NonNull SlideDeck slideDeck, boolean originalMissing) { boolean outgoing = messageType != MessageType.INCOMING && messageType != MessageType.STORY_REPLY_INCOMING; boolean preview = messageType == MessageType.PREVIEW || messageType == MessageType.STORY_REPLY_PREVIEW; + if (isStoryReply() && originalMissing) { + thumbnailView.setVisibility(GONE); + attachmentVideoOVerlayStub.setVisibility(GONE); + attachmentNameViewStub.setVisibility(GONE); + return; + } + // TODO [alex] -- do we need this? mainView.setMinimumHeight(isStoryReply() && originalMissing ? 0 : thumbHeight); thumbnailView.setPadding(0, 0, 0, 0); @@ -359,7 +366,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser attachmentVideoOVerlayStub.setVisibility(GONE); attachmentNameViewStub.setVisibility(GONE); thumbnailView.setVisibility(VISIBLE); - glideRequests.load(model) + requestManager.load(model) .centerCrop() .override(thumbWidth, thumbHeight) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) @@ -377,7 +384,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser attachmentVideoOVerlayStub.setVisibility(GONE); attachmentNameViewStub.setVisibility(GONE); thumbnailView.setVisibility(VISIBLE); - glideRequests.load(R.drawable.ic_gift_thumbnail) + requestManager.load(R.drawable.ic_gift_thumbnail) .centerCrop() .override(thumbWidth, thumbHeight) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) @@ -404,7 +411,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser if (imageVideoSlide.hasVideo() && !imageVideoSlide.isVideoGif()) { attachmentVideoOVerlayStub.setVisibility(VISIBLE); } - glideRequests.load(new DecryptableUri(imageVideoSlide.getUri())) + requestManager.load(new DecryptableUri(imageVideoSlide.getUri())) .centerCrop() .override(thumbWidth, thumbHeight) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) diff --git a/app/src/main/java/org/tm/archive/components/RecentPhotoViewRail.java b/app/src/main/java/org/tm/archive/components/RecentPhotoViewRail.java index 6fb57d08..649e52cf 100644 --- a/app/src/main/java/org/tm/archive/components/RecentPhotoViewRail.java +++ b/app/src/main/java/org/tm/archive/components/RecentPhotoViewRail.java @@ -22,6 +22,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; @@ -31,7 +32,6 @@ import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.database.CursorRecyclerViewAdapter; import org.tm.archive.database.loaders.RecentPhotosLoader; -import org.tm.archive.mms.GlideApp; public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.LoaderCallbacks { @@ -119,7 +119,7 @@ public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.Lo Key signature = new MediaStoreSignature(mimeType, dateModified, orientation); - GlideApp.with(getContext().getApplicationContext()) + Glide.with(getContext().getApplicationContext()) .load(uri) .signature(signature) .diskCacheStrategy(DiskCacheStrategy.NONE) diff --git a/app/src/main/java/org/tm/archive/components/SharedContactView.java b/app/src/main/java/org/tm/archive/components/SharedContactView.java index 54871d14..b168b543 100644 --- a/app/src/main/java/org/tm/archive/components/SharedContactView.java +++ b/app/src/main/java/org/tm/archive/components/SharedContactView.java @@ -17,6 +17,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.annimon.stream.Stream; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.tm.archive.R; @@ -24,7 +25,6 @@ import org.tm.archive.contactshare.Contact; import org.tm.archive.contactshare.ContactUtil; import org.tm.archive.database.RecipientTable; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.LiveRecipient; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientForeverObserver; @@ -45,13 +45,13 @@ public class SharedContactView extends LinearLayout implements RecipientForeverO private TextView actionButtonView; private ConversationItemFooter footer; - private Contact contact; - private Locale locale; - private GlideRequests glideRequests; - private EventListener eventListener; - private CornerMask cornerMask; - private int bigCornerRadius; - private int smallCornerRadius; + private Contact contact; + private Locale locale; + private RequestManager requestManager; + private EventListener eventListener; + private CornerMask cornerMask; + private int bigCornerRadius; + private int smallCornerRadius; private final Map activeRecipients = new HashMap<>(); @@ -111,10 +111,10 @@ public class SharedContactView extends LinearLayout implements RecipientForeverO cornerMask.mask(canvas); } - public void setContact(@NonNull Contact contact, @NonNull GlideRequests glideRequests, @NonNull Locale locale) { - this.glideRequests = glideRequests; - this.locale = locale; - this.contact = contact; + public void setContact(@NonNull Contact contact, @NonNull RequestManager requestManager, @NonNull Locale locale) { + this.requestManager = requestManager; + this.locale = locale; + this.contact = contact; Stream.of(activeRecipients.values()).forEach(recipient -> recipient.removeForeverObserver(this)); this.activeRecipients.clear(); @@ -172,17 +172,17 @@ public class SharedContactView extends LinearLayout implements RecipientForeverO private void presentAvatar(@Nullable Uri uri) { if (uri != null) { - glideRequests.load(new DecryptableUri(uri)) - .fallback(R.drawable.ic_contact_picture) - .circleCrop() - .diskCacheStrategy(DiskCacheStrategy.ALL) - .dontAnimate() - .into(avatarView); + requestManager.load(new DecryptableUri(uri)) + .fallback(R.drawable.symbol_person_display_40) + .circleCrop() + .diskCacheStrategy(DiskCacheStrategy.ALL) + .dontAnimate() + .into(avatarView); } else { - glideRequests.load(R.drawable.ic_contact_picture) - .circleCrop() - .diskCacheStrategy(DiskCacheStrategy.ALL) - .into(avatarView); + requestManager.load(R.drawable.symbol_person_display_40) + .circleCrop() + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(avatarView); } } diff --git a/app/src/main/java/org/tm/archive/components/ThreadPhotoRailView.java b/app/src/main/java/org/tm/archive/components/ThreadPhotoRailView.java index 3e809cf2..fec8a698 100644 --- a/app/src/main/java/org/tm/archive/components/ThreadPhotoRailView.java +++ b/app/src/main/java/org/tm/archive/components/ThreadPhotoRailView.java @@ -2,7 +2,6 @@ package org.tm.archive.components; import android.content.Context; -import android.database.Cursor; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -15,11 +14,12 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; + import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.database.MediaTable; import org.tm.archive.mediapreview.MediaPreviewCache; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.Slide; import org.tm.archive.util.MediaUtil; @@ -58,8 +58,8 @@ public class ThreadPhotoRailView extends FrameLayout { } } - public void setMediaRecords(@NonNull GlideRequests glideRequests, @NonNull List mediaRecords) { - this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), glideRequests, mediaRecords, this.listener)); + public void setMediaRecords(@NonNull RequestManager requestManager, @NonNull List mediaRecords) { + this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), requestManager, mediaRecords, this.listener)); } private static class ThreadPhotoRailAdapter extends RecyclerView.Adapter { @@ -67,18 +67,18 @@ public class ThreadPhotoRailView extends FrameLayout { @SuppressWarnings("unused") private static final String TAG = Log.tag(ThreadPhotoRailAdapter.class); - @NonNull private final GlideRequests glideRequests; + @NonNull private final RequestManager requestManager; @Nullable private OnItemClickedListener clickedListener; private final List mediaRecords = new ArrayList<>(); private ThreadPhotoRailAdapter(@NonNull Context context, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull List mediaRecords, @Nullable OnItemClickedListener listener) { - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.clickedListener = listener; this.mediaRecords.clear(); @@ -103,7 +103,7 @@ public class ThreadPhotoRailView extends FrameLayout { MediaTable.MediaRecord mediaRecord = mediaRecords.get(position); Slide slide = MediaUtil.getSlideForAttachment(mediaRecord.getAttachment()); - viewHolder.imageView.setImageResource(glideRequests, slide, false, false); + viewHolder.imageView.setImageResource(requestManager, slide, false, false); viewHolder.imageView.setOnClickListener(v -> { MediaPreviewCache.INSTANCE.setDrawable(viewHolder.imageView.getImageDrawable()); if (clickedListener != null) clickedListener.onItemClicked(viewHolder.imageView, mediaRecord); diff --git a/app/src/main/java/org/tm/archive/components/ThumbnailView.java b/app/src/main/java/org/tm/archive/components/ThumbnailView.java index 088268d9..1fb27edb 100644 --- a/app/src/main/java/org/tm/archive/components/ThumbnailView.java +++ b/app/src/main/java/org/tm/archive/components/ThumbnailView.java @@ -27,11 +27,14 @@ import androidx.annotation.UiThread; import androidx.appcompat.widget.AppCompatImageView; import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.Request; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.SettableFuture; import org.signal.core.util.logging.Log; import org.signal.glide.transforms.SignalDownsampleStrategy; import org.tm.archive.R; @@ -39,8 +42,6 @@ import org.tm.archive.blurhash.BlurHash; import org.tm.archive.components.transfercontrols.TransferControlView; import org.tm.archive.database.AttachmentTable; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideRequest; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.ImageSlide; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideClickListener; @@ -49,8 +50,6 @@ import org.tm.archive.mms.VideoSlide; import org.tm.archive.stories.StoryTextPostModel; import org.tm.archive.util.MediaUtil; import org.tm.archive.util.Util; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.tm.archive.util.concurrent.SettableFuture; import org.tm.archive.util.views.Stub; import java.util.Arrays; @@ -314,23 +313,23 @@ public class ThumbnailView extends FrameLayout { } } - public void setImageDrawable(@NonNull GlideRequests glideRequests, @Nullable Drawable drawable) { - glideRequests.clear(image); - glideRequests.clear(blurHash); + public void setImageDrawable(@NonNull RequestManager requestManager, @Nullable Drawable drawable) { + requestManager.clear(image); + requestManager.clear(blurHash); image.setImageDrawable(drawable); blurHash.setImageDrawable(null); } @UiThread - public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide, + public ListenableFuture setImageResource(@NonNull RequestManager requestManager, @NonNull Slide slide, boolean showControls, boolean isPreview) { - return setImageResource(glideRequests, slide, showControls, isPreview, 0, 0); + return setImageResource(requestManager, slide, showControls, isPreview, 0, 0); } @UiThread - public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide, + public ListenableFuture setImageResource(@NonNull RequestManager requestManager, @NonNull Slide slide, boolean showControls, boolean isPreview, int naturalWidth, int naturalHeight) { @@ -340,10 +339,10 @@ public class ThumbnailView extends FrameLayout { transferControlViewStub.setVisibility(View.GONE); playOverlay.setVisibility(View.GONE); - glideRequests.clear(blurHash); + requestManager.clear(blurHash); blurHash.setImageDrawable(null); - glideRequests.clear(image); + requestManager.clear(image); image.setImageDrawable(null); int errorImageResource; @@ -414,10 +413,10 @@ public class ThumbnailView extends FrameLayout { boolean resultHandled = false; if (slide.hasPlaceholder() && (previousBlurHash == null || !Objects.equals(slide.getPlaceholderBlur(), previousBlurHash))) { - buildPlaceholderGlideRequest(glideRequests, slide).into(new GlideBitmapListeningTarget(blurHash, result)); + buildPlaceholderRequestBuilder(requestManager, slide).into(new GlideBitmapListeningTarget(blurHash, result)); resultHandled = true; } else if (!slide.hasPlaceholder()) { - glideRequests.clear(blurHash); + requestManager.clear(blurHash); blurHash.setImageDrawable(null); } @@ -425,14 +424,14 @@ public class ThumbnailView extends FrameLayout { if (!MediaUtil.isJpegType(slide.getContentType()) && !MediaUtil.isVideoType(slide.getContentType())) { SettableFuture thumbnailFuture = new SettableFuture<>(); thumbnailFuture.deferTo(result); - thumbnailFuture.addListener(new BlurHashClearListener(glideRequests, blurHash)); + thumbnailFuture.addListener(new BlurHashClearListener(requestManager, blurHash)); } - buildThumbnailGlideRequest(glideRequests, slide).into(new GlideDrawableListeningTarget(image, result)); + buildThumbnailRequestBuilder(requestManager, slide).into(new GlideDrawableListeningTarget(image, result)); resultHandled = true; } else { - glideRequests.clear(image); + requestManager.clear(image); image.setImageDrawable(null); } @@ -443,20 +442,20 @@ public class ThumbnailView extends FrameLayout { return result; } - public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri) { - return setImageResource(glideRequests, uri, 0, 0); + public ListenableFuture setImageResource(@NonNull RequestManager requestManager, @NonNull Uri uri) { + return setImageResource(requestManager, uri, 0, 0); } - public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri, int width, int height) { - return setImageResource(glideRequests, uri, width, height, true, null); + public ListenableFuture setImageResource(@NonNull RequestManager requestManager, @NonNull Uri uri, int width, int height) { + return setImageResource(requestManager, uri, width, height, true, null); } - public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri, int width, int height, boolean animate, @Nullable ThumbnailRequestListener listener) { + public ListenableFuture setImageResource(@NonNull RequestManager requestManager, @NonNull Uri uri, int width, int height, boolean animate, @Nullable ThumbnailRequestListener listener) { SettableFuture future = new SettableFuture<>(); transferControlViewStub.setVisibility(View.GONE); - GlideRequest request = glideRequests.load(new DecryptableUri(uri)) + RequestBuilder request = requestManager.load(new DecryptableUri(uri)) .diskCacheStrategy(DiskCacheStrategy.NONE) .downsample(SignalDownsampleStrategy.CENTER_OUTSIDE_NO_UPSCALE) .listener(listener); @@ -483,12 +482,12 @@ public class ThumbnailView extends FrameLayout { return future; } - public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull StoryTextPostModel model, int width, int height) { + public ListenableFuture setImageResource(@NonNull RequestManager requestManager, @NonNull StoryTextPostModel model, int width, int height) { SettableFuture future = new SettableFuture<>(); transferControlViewStub.setVisibility(View.GONE); - GlideRequest request = glideRequests.load(model) + RequestBuilder request = requestManager.load(model) .diskCacheStrategy(DiskCacheStrategy.NONE) .placeholder(model.getPlaceholder()) .downsample(SignalDownsampleStrategy.CENTER_OUTSIDE_NO_UPSCALE) @@ -502,7 +501,7 @@ public class ThumbnailView extends FrameLayout { return future; } - private GlideRequest override(@NonNull GlideRequest request, int width, int height) { + private RequestBuilder override(@NonNull RequestBuilder request, int width, int height) { if (width > 0 && height > 0) { Log.d(TAG, "override: apply w" + width + "xh" + height); return request.override(width, height); @@ -542,8 +541,8 @@ public class ThumbnailView extends FrameLayout { return false; } - private GlideRequest buildThumbnailGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) { - GlideRequest request = applySizing(glideRequests.load(new DecryptableUri(Objects.requireNonNull(slide.getUri()))) + private RequestBuilder buildThumbnailRequestBuilder(@NonNull RequestManager requestManager, @NonNull Slide slide) { + RequestBuilder requestBuilder = applySizing(requestManager.load(new DecryptableUri(Objects.requireNonNull(slide.getUri()))) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .downsample(SignalDownsampleStrategy.CENTER_OUTSIDE_NO_UPSCALE) .transition(withCrossFade())); @@ -551,21 +550,21 @@ public class ThumbnailView extends FrameLayout { boolean doNotShowMissingThumbnailImage = Build.VERSION.SDK_INT < 23; if (slide.isInProgress() || doNotShowMissingThumbnailImage) { - return request; + return requestBuilder; } else { - return request.apply(RequestOptions.errorOf(R.drawable.ic_missing_thumbnail_picture)); + return requestBuilder.apply(RequestOptions.errorOf(R.drawable.missing_thumbnail)); } } - public void clear(GlideRequests glideRequests) { - glideRequests.clear(image); + public void clear(RequestManager requestManager) { + requestManager.clear(image); image.setImageDrawable(null); if (transferControlViewStub.resolved()) { transferControlViewStub.get().clear(); } - glideRequests.clear(blurHash); + requestManager.clear(blurHash); blurHash.setImageDrawable(null); slide = null; @@ -594,9 +593,9 @@ public class ThumbnailView extends FrameLayout { } - private RequestBuilder buildPlaceholderGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) { - GlideRequest bitmap = glideRequests.asBitmap(); - BlurHash placeholderBlur = slide.getPlaceholderBlur(); + private RequestBuilder buildPlaceholderRequestBuilder(@NonNull RequestManager requestManager, @NonNull Slide slide) { + RequestBuilder bitmap = requestManager.asBitmap(); + BlurHash placeholderBlur = slide.getPlaceholderBlur(); if (placeholderBlur != null) { bitmap = bitmap.load(placeholderBlur); @@ -604,7 +603,7 @@ public class ThumbnailView extends FrameLayout { bitmap = bitmap.load(slide.getPlaceholderRes(getContext().getTheme())); } - final GlideRequest resizedRequest = applySizing(bitmap.diskCacheStrategy(DiskCacheStrategy.NONE)); + final RequestBuilder resizedRequest = applySizing(bitmap.diskCacheStrategy(DiskCacheStrategy.NONE)); if (placeholderBlur != null) { return resizedRequest.centerCrop(); } else { @@ -612,7 +611,7 @@ public class ThumbnailView extends FrameLayout { } } - private GlideRequest applySizing(@NonNull GlideRequest request) { + private RequestBuilder applySizing(@NonNull RequestBuilder request) { int[] size = new int[2]; fillTargetDimensions(size, dimens, bounds); if (size[WIDTH] == 0 && size[HEIGHT] == 0) { @@ -701,23 +700,23 @@ public class ThumbnailView extends FrameLayout { private static class BlurHashClearListener implements ListenableFuture.Listener { - private final GlideRequests glideRequests; - private final ImageView blurHash; + private final RequestManager requestManager; + private final ImageView blurHash; - private BlurHashClearListener(@NonNull GlideRequests glideRequests, @NonNull ImageView blurHash) { - this.glideRequests = glideRequests; - this.blurHash = blurHash; + private BlurHashClearListener(@NonNull RequestManager requestManager, @NonNull ImageView blurHash) { + this.requestManager = requestManager; + this.blurHash = blurHash; } @Override public void onSuccess(Boolean result) { - glideRequests.clear(blurHash); + requestManager.clear(blurHash); blurHash.setImageDrawable(null); } @Override public void onFailure(ExecutionException e) { - glideRequests.clear(blurHash); + requestManager.clear(blurHash); blurHash.setImageDrawable(null); } } diff --git a/app/src/main/java/org/tm/archive/components/TooltipPopup.java b/app/src/main/java/org/tm/archive/components/TooltipPopup.java index ed6e1907..bb6a7320 100644 --- a/app/src/main/java/org/tm/archive/components/TooltipPopup.java +++ b/app/src/main/java/org/tm/archive/components/TooltipPopup.java @@ -18,13 +18,13 @@ import androidx.annotation.Px; import androidx.annotation.StringRes; import androidx.core.content.ContextCompat; +import com.bumptech.glide.Glide; import com.google.android.material.shape.MaterialShapeDrawable; import com.google.android.material.shape.ShapeAppearanceModel; import org.signal.core.util.DimensionUnit; import org.signal.core.util.logging.Log; import org.tm.archive.R; -import org.tm.archive.mms.GlideApp; /** * Class for creating simple tooltips to show throughout the app. Utilizes a popup window so you @@ -101,7 +101,7 @@ public class TooltipPopup extends PopupWindow { if (iconGlideModel != null) { ImageView iconView = getContentView().findViewById(R.id.tooltip_icon); iconView.setVisibility(View.VISIBLE); - GlideApp.with(anchor.getContext()).load(iconGlideModel).into(iconView); + Glide.with(anchor.getContext()).load(iconGlideModel).into(iconView); } setElevation(10); diff --git a/app/src/main/java/org/tm/archive/components/ZoomingImageView.java b/app/src/main/java/org/tm/archive/components/ZoomingImageView.java index 74db08ea..7ef9f2ab 100644 --- a/app/src/main/java/org/tm/archive/components/ZoomingImageView.java +++ b/app/src/main/java/org/tm/archive/components/ZoomingImageView.java @@ -11,6 +11,7 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.exifinterface.media.ExifInterface; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.Target; import com.davemorrissey.labs.subscaleview.ImageSource; @@ -23,7 +24,6 @@ import org.tm.archive.R; import org.tm.archive.components.subsampling.AttachmentBitmapDecoder; import org.tm.archive.components.subsampling.AttachmentRegionDecoder; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.PartAuthority; import org.tm.archive.util.ActionRequestListener; import org.tm.archive.util.BitmapDecodingException; @@ -81,7 +81,7 @@ public class ZoomingImageView extends FrameLayout { } @SuppressLint("StaticFieldLeak") - public void setImageUri(@NonNull GlideRequests glideRequests, @NonNull Uri uri, @NonNull String contentType, @NonNull Runnable onMediaReady) + public void setImageUri(@NonNull RequestManager requestManager, @NonNull Uri uri, @NonNull String contentType, @NonNull Runnable onMediaReady) { final Context context = getContext(); final int maxTextureSize = BitmapUtil.getMaxTextureSize(); @@ -103,7 +103,7 @@ public class ZoomingImageView extends FrameLayout { if (dimensions == null || (dimensions.first <= maxTextureSize && dimensions.second <= maxTextureSize)) { Log.i(TAG, "Loading in standard image view..."); - setImageViewUri(glideRequests, uri, onMediaReady); + setImageViewUri(requestManager, uri, onMediaReady); } else { Log.i(TAG, "Loading in subsampling image view..."); setSubsamplingImageViewUri(uri); @@ -112,11 +112,11 @@ public class ZoomingImageView extends FrameLayout { }); } - private void setImageViewUri(@NonNull GlideRequests glideRequests, @NonNull Uri uri, @NonNull Runnable onMediaReady) { + private void setImageViewUri(@NonNull RequestManager requestManager, @NonNull Uri uri, @NonNull Runnable onMediaReady) { photoView.setVisibility(View.VISIBLE); subsamplingImageView.setVisibility(View.GONE); - glideRequests.load(new DecryptableUri(uri)) + requestManager.load(new DecryptableUri(uri)) .diskCacheStrategy(DiskCacheStrategy.NONE) .dontTransform() .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) diff --git a/app/src/main/java/org/tm/archive/components/emoji/EmojiImageView.java b/app/src/main/java/org/tm/archive/components/emoji/EmojiImageView.java index d0a0ee2e..a77cb729 100644 --- a/app/src/main/java/org/tm/archive/components/emoji/EmojiImageView.java +++ b/app/src/main/java/org/tm/archive/components/emoji/EmojiImageView.java @@ -34,6 +34,7 @@ public class EmojiImageView extends AppCompatImageView { setImageResource(R.drawable.ic_emoji); } else { setImageDrawable(EmojiProvider.getEmojiDrawable(getContext(), emoji, forceJumboEmoji)); + setContentDescription(emoji); } } } diff --git a/app/src/main/java/org/tm/archive/components/emoji/EmojiTextView.java b/app/src/main/java/org/tm/archive/components/emoji/EmojiTextView.java index de4edf07..2eda2c35 100644 --- a/app/src/main/java/org/tm/archive/components/emoji/EmojiTextView.java +++ b/app/src/main/java/org/tm/archive/components/emoji/EmojiTextView.java @@ -32,6 +32,7 @@ import androidx.core.view.GestureDetectorCompat; import androidx.core.view.ViewKt; import androidx.core.widget.TextViewCompat; +import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.components.emoji.parsing.EmojiParser; import org.tm.archive.components.mention.MentionAnnotation; @@ -73,6 +74,7 @@ public class EmojiTextView extends AppCompatTextView { private boolean isJumbomoji; private boolean forceJumboEmoji; private boolean renderSpoilers; + private boolean shrinkWrap; private MentionRendererDelegate mentionRendererDelegate; private SpoilerRendererDelegate spoilerRendererDelegate; @@ -96,6 +98,7 @@ public class EmojiTextView extends AppCompatTextView { measureLastLine = a.getBoolean(R.styleable.EmojiTextView_measureLastLine, false); forceJumboEmoji = a.getBoolean(R.styleable.EmojiTextView_emoji_forceJumbo, false); renderSpoilers = a.getBoolean(R.styleable.EmojiTextView_emoji_renderSpoilers, false); + shrinkWrap = a.getBoolean(R.styleable.EmojiTextView_emoji_shrinkWrap, false); a.recycle(); a = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.textSize }); @@ -224,6 +227,25 @@ public class EmojiTextView extends AppCompatTextView { widthMeasureSpec = applyWidthMeasureRoundingFix(widthMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int mode = MeasureSpec.getMode(widthMeasureSpec); + if (shrinkWrap && getLayout() != null && mode == MeasureSpec.AT_MOST) { + Layout layout = getLayout(); + + float maxLineWidth = 0f; + for (int i = 0; i < layout.getLineCount(); i++) { + if (layout.getLineWidth(i) > maxLineWidth) { + maxLineWidth = layout.getLineWidth(i); + } + } + + int desiredWidth = (int) maxLineWidth + getPaddingLeft() + getPaddingRight(); + if (getMeasuredWidth() > desiredWidth) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(desiredWidth, mode); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + CharSequence text = getText(); if (getLayout() == null || !measureLastLine || text == null || text.length() == 0) { lastLineWidth = -1; diff --git a/app/src/main/java/org/tm/archive/components/identity/UntrustedSendDialog.java b/app/src/main/java/org/tm/archive/components/identity/UntrustedSendDialog.java index ecbe5061..0d1511d1 100644 --- a/app/src/main/java/org/tm/archive/components/identity/UntrustedSendDialog.java +++ b/app/src/main/java/org/tm/archive/components/identity/UntrustedSendDialog.java @@ -32,7 +32,7 @@ public class UntrustedSendDialog extends AlertDialog.Builder implements DialogIn this.resendListener = resendListener; setTitle(R.string.UntrustedSendDialog_send_message); - setIcon(R.drawable.ic_warning); + setIcon(R.drawable.symbol_error_triangle_fill_24); setMessage(message); setPositiveButton(R.string.UntrustedSendDialog_send, this); setNegativeButton(android.R.string.cancel, null); diff --git a/app/src/main/java/org/tm/archive/components/identity/UnverifiedSendDialog.java b/app/src/main/java/org/tm/archive/components/identity/UnverifiedSendDialog.java index ad362910..c131a3f1 100644 --- a/app/src/main/java/org/tm/archive/components/identity/UnverifiedSendDialog.java +++ b/app/src/main/java/org/tm/archive/components/identity/UnverifiedSendDialog.java @@ -31,7 +31,7 @@ public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogI this.resendListener = resendListener; setTitle(R.string.UnverifiedSendDialog_send_message); - setIcon(R.drawable.ic_warning); + setIcon(R.drawable.symbol_error_triangle_fill_24); setMessage(message); setPositiveButton(R.string.UnverifiedSendDialog_send, this); setNegativeButton(android.R.string.cancel, null); diff --git a/app/src/main/java/org/tm/archive/components/location/SignalMapView.java b/app/src/main/java/org/tm/archive/components/location/SignalMapView.java index 3137276b..9501ded7 100644 --- a/app/src/main/java/org/tm/archive/components/location/SignalMapView.java +++ b/app/src/main/java/org/tm/archive/components/location/SignalMapView.java @@ -17,9 +17,9 @@ import com.google.android.gms.maps.MapView; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.SettableFuture; import org.tm.archive.R; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.tm.archive.util.concurrent.SettableFuture; import java.util.concurrent.ExecutionException; diff --git a/app/src/main/java/org/tm/archive/components/registration/VerificationPinKeyboard.java b/app/src/main/java/org/tm/archive/components/registration/VerificationPinKeyboard.java index a61baeb2..fe92c773 100644 --- a/app/src/main/java/org/tm/archive/components/registration/VerificationPinKeyboard.java +++ b/app/src/main/java/org/tm/archive/components/registration/VerificationPinKeyboard.java @@ -18,11 +18,11 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.SettableFuture; import org.tm.archive.R; import org.tm.archive.components.NumericKeyboardView; import org.tm.archive.util.ViewUtil; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.tm.archive.util.concurrent.SettableFuture; public class VerificationPinKeyboard extends FrameLayout { diff --git a/app/src/main/java/org/tm/archive/components/reminder/OutdatedBuildReminder.java b/app/src/main/java/org/tm/archive/components/reminder/OutdatedBuildReminder.java index 58d9a307..49d063f8 100644 --- a/app/src/main/java/org/tm/archive/components/reminder/OutdatedBuildReminder.java +++ b/app/src/main/java/org/tm/archive/components/reminder/OutdatedBuildReminder.java @@ -37,11 +37,9 @@ public class OutdatedBuildReminder extends Reminder { return false; } - //**TM_SA**// start public static boolean isEligible() { - return false;//getDaysUntilExpiry() <= 10; + return getDaysUntilExpiry() <= 10; } - //**TM_SA**// End private static int getDaysUntilExpiry() { return (int) TimeUnit.MILLISECONDS.toDays(Util.getTimeUntilBuildExpiry()); diff --git a/app/src/main/java/org/tm/archive/components/reminder/PushRegistrationReminder.java b/app/src/main/java/org/tm/archive/components/reminder/PushRegistrationReminder.java deleted file mode 100644 index cfa07e5d..00000000 --- a/app/src/main/java/org/tm/archive/components/reminder/PushRegistrationReminder.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.tm.archive.components.reminder; - -import android.content.Context; - -import org.tm.archive.R; -import org.tm.archive.keyvalue.SignalStore; -import org.tm.archive.registration.RegistrationNavigationActivity; - -public class PushRegistrationReminder extends Reminder { - - public PushRegistrationReminder(final Context context) { - super(R.string.reminder_header_push_title, R.string.reminder_header_push_text); - - setOkListener(v -> context.startActivity(RegistrationNavigationActivity.newIntentForReRegistration(context))); - } - - @Override - public boolean isDismissable() { - return false; - } - - public static boolean isEligible() { - return !SignalStore.account().isRegistered(); - } -} diff --git a/app/src/main/java/org/tm/archive/components/reminder/UnauthorizedReminder.java b/app/src/main/java/org/tm/archive/components/reminder/UnauthorizedReminder.java index 5854e63a..bdd11859 100644 --- a/app/src/main/java/org/tm/archive/components/reminder/UnauthorizedReminder.java +++ b/app/src/main/java/org/tm/archive/components/reminder/UnauthorizedReminder.java @@ -5,6 +5,7 @@ import android.content.Context; import androidx.annotation.NonNull; import org.tm.archive.R; +import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.registration.RegistrationNavigationActivity; import org.tm.archive.util.TextSecurePreferences; @@ -26,6 +27,6 @@ public class UnauthorizedReminder extends Reminder { } public static boolean isEligible(Context context) { - return TextSecurePreferences.isUnauthorizedReceived(context); + return TextSecurePreferences.isUnauthorizedReceived(context) || !SignalStore.account().isRegistered(); } } diff --git a/app/src/main/java/org/tm/archive/components/reminder/UsernameOutOfSyncReminder.kt b/app/src/main/java/org/tm/archive/components/reminder/UsernameOutOfSyncReminder.kt index 8c31e969..bf7af500 100644 --- a/app/src/main/java/org/tm/archive/components/reminder/UsernameOutOfSyncReminder.kt +++ b/app/src/main/java/org/tm/archive/components/reminder/UsernameOutOfSyncReminder.kt @@ -4,7 +4,6 @@ import android.content.Context import org.tm.archive.R import org.tm.archive.keyvalue.AccountValues.UsernameSyncState import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.util.FeatureFlags /** * Displays a reminder message when the local username gets out of sync with @@ -42,14 +41,10 @@ class UsernameOutOfSyncReminder : Reminder(NO_RESOURCE) { companion object { @JvmStatic fun isEligible(): Boolean { - return if (FeatureFlags.usernames()) { - when (SignalStore.account().usernameSyncState) { - UsernameSyncState.USERNAME_AND_LINK_CORRUPTED -> true - UsernameSyncState.LINK_CORRUPTED -> true - UsernameSyncState.IN_SYNC -> false - } - } else { - false + return when (SignalStore.account().usernameSyncState) { + UsernameSyncState.USERNAME_AND_LINK_CORRUPTED -> true + UsernameSyncState.LINK_CORRUPTED -> true + UsernameSyncState.IN_SYNC -> false } } } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsActivity.kt b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsActivity.kt index 881b2389..1ae748d0 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsActivity.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsActivity.kt @@ -66,6 +66,7 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { StartLocation.PRIVACY -> AppSettingsFragmentDirections.actionDirectToPrivacy() StartLocation.LINKED_DEVICES -> AppSettingsFragmentDirections.actionDirectToDevices() StartLocation.USERNAME_LINK -> AppSettingsFragmentDirections.actionDirectToUsernameLinkSettings() + StartLocation.RECOVER_USERNAME -> AppSettingsFragmentDirections.actionDirectToUsernameRecovery() } } @@ -119,8 +120,6 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { override fun onWillFinish() { if (wasConfigurationUpdated) { setResult(MainActivity.RESULT_CONFIG_CHANGED) - } else { - setResult(RESULT_OK) } } @@ -192,6 +191,9 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { @JvmStatic fun usernameLinkSettings(context: Context): Intent = getIntentForStartLocation(context, StartLocation.USERNAME_LINK) + @JvmStatic + fun usernameRecovery(context: Context): Intent = getIntentForStartLocation(context, StartLocation.RECOVER_USERNAME) + private fun getIntentForStartLocation(context: Context, startLocation: StartLocation): Intent { return Intent(context, AppSettingsActivity::class.java) .putExtra(ARG_NAV_GRAPH, R.navigation.app_settings) @@ -214,7 +216,8 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { NOTIFICATION_PROFILE_DETAILS(11), PRIVACY(12), LINKED_DEVICES(13), - USERNAME_LINK(14); + USERNAME_LINK(14), + RECOVER_USERNAME(15); companion object { fun fromCode(code: Int?): StartLocation { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsFragment.kt index eb8de4d5..07b9b3a0 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsFragment.kt @@ -9,14 +9,13 @@ import android.widget.Toast import androidx.annotation.IdRes import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController -import com.tm.androidcopysdk.AndroidCopySDK import com.tm.androidcopysdk.ISendLogCallback -import com.tm.androidcopysdk.utils.PrefManager -import org.archiver.ArchivePreferenceConstants +import org.archiver.ArchiveSender import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.selfAuthentication.ProgressDialog +import org.signal.core.util.isNotNullOrBlank import org.signal.core.util.logging.Log import org.tm.archive.R import org.tm.archive.badges.BadgeImageView @@ -35,7 +34,6 @@ import org.tm.archive.components.settings.PreferenceViewHolder import org.tm.archive.components.settings.app.subscription.completed.TerminalDonationDelegate import org.tm.archive.components.settings.configure import org.tm.archive.events.ReminderUpdateEvent -import org.tm.archive.keyvalue.AccountValues import org.tm.archive.keyvalue.SignalStore import org.tm.archive.phonenumbers.PhoneNumberFormatter import org.tm.archive.recipients.Recipient @@ -50,11 +48,12 @@ import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingViewHolder import org.tm.archive.util.navigation.safeNavigate import org.tm.archive.util.views.Stub +import org.tm.archive.util.visible class AppSettingsFragment : DSLSettingsFragment( titleId = R.string.text_secure_normal__menu_settings, layoutId = R.layout.dsl_settings_fragment_with_reminder -) , +) , ISendLogCallback { //**TM_SA**// add ISendLogCallback{ private val viewModel: AppSettingsViewModel by viewModels() @@ -170,10 +169,9 @@ class AppSettingsFragment : DSLSettingsFragment( onClick = { findNavController().safeNavigate(R.id.action_appSettingsFragment_to_deviceActivity) }, - isEnabled = state.isDeprecatedOrUnregistered() + isEnabled = state.isRegisteredAndUpToDate() ) - - //**TM_SA**// Start - Comment all the Signal mention and put our about and sending logs logic. +//**TM_SA**// Start - Comment all the Signal mention and put our about and sending logs logic. if (false/*state.allowUserToGoToDonationManagementScreen*/) { /*clickPref( title = DSLSettingsText.from(R.string.preferences__donate_to_signal), @@ -225,7 +223,7 @@ class AppSettingsFragment : DSLSettingsFragment( onClick = { findNavController().safeNavigate(R.id.action_appSettingsFragment_to_chatsSettingsFragment) }, - isEnabled = state.isDeprecatedOrUnregistered() + isEnabled = state.isRegisteredAndUpToDate() ) clickPref( @@ -234,7 +232,7 @@ class AppSettingsFragment : DSLSettingsFragment( onClick = { findNavController().safeNavigate(AppSettingsFragmentDirections.actionAppSettingsFragmentToStoryPrivacySettings(R.string.preferences__stories)) }, - isEnabled = state.isDeprecatedOrUnregistered() + isEnabled = state.isRegisteredAndUpToDate() ) clickPref( @@ -243,16 +241,16 @@ class AppSettingsFragment : DSLSettingsFragment( onClick = { findNavController().safeNavigate(R.id.action_appSettingsFragment_to_notificationsSettingsFragment) }, - isEnabled = state.isDeprecatedOrUnregistered() + isEnabled = state.isRegisteredAndUpToDate() ) clickPref( title = DSLSettingsText.from(R.string.preferences__privacy), - icon = DSLSettingsIcon.from(R.drawable.symbol_lock_24), + icon = DSLSettingsIcon.from(R.drawable.symbol_lock_white_48), onClick = { findNavController().safeNavigate(R.id.action_appSettingsFragment_to_privacySettingsFragment) }, - isEnabled = state.isDeprecatedOrUnregistered() + isEnabled = state.isRegisteredAndUpToDate() ) clickPref( @@ -274,8 +272,7 @@ class AppSettingsFragment : DSLSettingsFragment( } dividerPref() - - //**TM_SA**// Mark this part +//**TM_SA**// Mark this part /*if (SignalStore.paymentsValues().paymentsAvailability.showPaymentsMenu()) { customPref( PaymentsPreference( @@ -295,7 +292,6 @@ class AppSettingsFragment : DSLSettingsFragment( findNavController().safeNavigate(R.id.action_appSettingsFragment_to_helpSettingsFragment) } )*/ -//**TM_SA**//end clickPref( title = DSLSettingsText.from(R.string.AppSettingsFragment__invite_your_friends), @@ -317,55 +313,40 @@ class AppSettingsFragment : DSLSettingsFragment( } } } - } - - //**TM_SA**// start + //**TM_SA**// start - override fun sendLogSucceed() { - mProgressDialog.hide() - Log.d("sendLog", "sendLogSucceed") - } - - override fun sendLogFailure() { - mProgressDialog.hide() - Log.d("sendLog", "sendLogFailure") - } - - - private fun doSendLogsClicked() { - - val builder = AlertDialog.Builder(context) - - mProgressDialog = ProgressDialog.progressDialog(requireContext()) - - builder.setTitle(R.string.issue_report_list_title) - builder.setMessage(getString(R.string.issue_report_list_summery) + "?") - - builder.setPositiveButton(R.string.ShareActivity__send) { dialog, which -> - - mProgressDialog.show() - AndroidCopySDK.getInstance(context).sentLogs( - activity, - this, - PrefManager.getStringPref(context, ArchivePreferenceConstants.PREF_KEY_DEVICE_PHONE_NUMBER, ""), - "Signal Archiver logs", - PrefManager.getStringPref(context, ArchivePreferenceConstants.PREF_KEY_DEVICE_NAME, ""), - "", - "", - "", - "", - ArchivePreferenceConstants.GENERATE_TOK_NAME, - ArchivePreferenceConstants.GENERATE_TOK_PASS - ) + override fun sendLogSucceed() { + mProgressDialog.hide() + Log.d("sendLog", "sendLogSucceed") } - builder.setNegativeButton(R.string.CommunicationActions_cancel, null) - builder.show() - } + override fun sendLogFailure() { + mProgressDialog.hide() + Log.d("sendLog", "sendLogFailure") + } - //**TM_SA**// End + + private fun doSendLogsClicked() { + + val builder = AlertDialog.Builder(context) + + mProgressDialog = ProgressDialog.progressDialog(requireContext()) + + builder.setTitle(R.string.issue_report_list_title) + builder.setMessage(getString(R.string.issue_report_list_summery) + "?") + + builder.setPositiveButton(R.string.ShareActivity__send) { dialog, which -> + mProgressDialog.show() + ArchiveSender.sendLogs(requireActivity(), this) + } + builder.setNegativeButton(R.string.CommunicationActions_cancel, null) + builder.show() + + } + + //**TM_SA**// End private fun copySubscriberIdToClipboard(): Boolean { val subscriber = SignalStore.donationsValues().getSubscriber() @@ -420,6 +401,7 @@ class AppSettingsFragment : DSLSettingsFragment( private val aboutView: EmojiTextView = itemView.findViewById(R.id.about) private val badgeView: BadgeImageView = itemView.findViewById(R.id.badge) private val qrButton: View = itemView.findViewById(R.id.qr_button) + private val usernameView: TextView = itemView.findViewById(R.id.username) init { aboutView.setOverflowText(" ") @@ -432,6 +414,8 @@ class AppSettingsFragment : DSLSettingsFragment( titleView.text = model.recipient.profileName.toString() summaryView.text = PhoneNumberFormatter.prettyPrint(model.recipient.requireE164()) + usernameView.text = model.recipient.username.orElse("") + usernameView.visible = model.recipient.username.isPresent avatarView.setRecipient(Recipient.self()) badgeView.setBadgeFromRecipient(Recipient.self()) @@ -439,7 +423,7 @@ class AppSettingsFragment : DSLSettingsFragment( summaryView.visibility = View.VISIBLE avatarView.visibility = View.VISIBLE - if (FeatureFlags.usernames() && SignalStore.account().usernameSyncState == AccountValues.UsernameSyncState.IN_SYNC) { + if (SignalStore.account().username.isNotNullOrBlank()) { qrButton.visibility = View.VISIBLE qrButton.isClickable = true qrButton.setOnClickListener { model.onQrButtonClicked() } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsState.kt b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsState.kt index cb0ad1af..941fe860 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsState.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsState.kt @@ -10,7 +10,7 @@ data class AppSettingsState( val userUnregistered: Boolean, val clientDeprecated: Boolean ) { - fun isDeprecatedOrUnregistered(): Boolean { - return !(userUnregistered || clientDeprecated) + fun isRegisteredAndUpToDate(): Boolean { + return !userUnregistered && !clientDeprecated } } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsViewModel.kt index 9c9a8193..25a9145a 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/AppSettingsViewModel.kt @@ -24,7 +24,7 @@ class AppSettingsViewModel( 0, SignalStore.donationsValues().getExpiredGiftBadge() != null, SignalStore.donationsValues().isLikelyASustainer() || InAppDonations.hasAtLeastOnePaymentMethodAvailable(), - TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()), + TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()) || !SignalStore.account().isRegistered, SignalStore.misc().isClientDeprecated ) ) @@ -54,7 +54,12 @@ class AppSettingsViewModel( } fun refreshDeprecatedOrUnregistered() { - store.update { it.copy(clientDeprecated = SignalStore.misc().isClientDeprecated, userUnregistered = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication())) } + store.update { + it.copy( + clientDeprecated = SignalStore.misc().isClientDeprecated, + userUnregistered = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()) || !SignalStore.account().isRegistered + ) + } } fun refreshExpiredGiftBadge() { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberLockActivity.kt b/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberLockActivity.kt index 02fe7522..a819501f 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberLockActivity.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberLockActivity.kt @@ -1,5 +1,6 @@ package org.tm.archive.components.settings.app.changenumber +import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.os.Bundle @@ -47,6 +48,7 @@ class ChangeNumberLockActivity : PassphraseRequiredActivity() { dynamicTheme.onResume(this) } + @SuppressLint("MissingSuperCall") override fun onBackPressed() = Unit private fun checkWhoAmI() { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberRepository.kt b/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberRepository.kt index efb07475..e57e039a 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberRepository.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberRepository.kt @@ -216,7 +216,7 @@ class ChangeNumberRepository( @WorkerThread fun changeLocalNumber(e164: String, pni: PNI): Single { val oldStorageId: ByteArray? = Recipient.self().storageServiceId - SignalDatabase.recipients.updateSelfPhone(e164, pni) + SignalDatabase.recipients.updateSelfE164(e164, pni) val newStorageId: ByteArray? = Recipient.self().storageServiceId if (e164 != SignalStore.account().requireE164() && MessageDigest.isEqual(oldStorageId, newStorageId)) { @@ -233,6 +233,7 @@ class ChangeNumberRepository( SignalStore.account().setE164(e164) SignalStore.account().setPni(pni) + ApplicationDependencies.resetProtocolStores() ApplicationDependencies.getGroupsV2Authorization().clear() @@ -250,6 +251,7 @@ class ChangeNumberRepository( val pniIdentityKeyPair = IdentityKeyPair(metadata.pniIdentityKeyPair.toByteArray()) val pniRegistrationId = metadata.pniRegistrationId val pniSignedPreyKeyId = metadata.pniSignedPreKeyId + val pniLastResortKyberPreKeyId = metadata.pniLastResortKyberPreKeyId val pniProtocolStore = ApplicationDependencies.getProtocolStore().pni() val pniMetadataStore = SignalStore.account().pniPreKeys @@ -258,19 +260,26 @@ class ChangeNumberRepository( SignalStore.account().setPniIdentityKeyAfterChangeNumber(pniIdentityKeyPair) val signedPreKey = pniProtocolStore.loadSignedPreKey(pniSignedPreyKeyId) - val oneTimePreKeys = PreKeyUtil.generateAndStoreOneTimeEcPreKeys(pniProtocolStore, pniMetadataStore) + val oneTimeEcPreKeys = PreKeyUtil.generateAndStoreOneTimeEcPreKeys(pniProtocolStore, pniMetadataStore) + val lastResortKyberPreKey = pniProtocolStore.loadLastResortKyberPreKeys().firstOrNull { it.id == pniLastResortKyberPreKeyId } + val oneTimeKyberPreKeys = PreKeyUtil.generateAndStoreOneTimeKyberPreKeys(pniProtocolStore, pniMetadataStore) + + if (lastResortKyberPreKey == null) { + Log.w(TAG, "Last-resort kyber prekey is missing!") + } pniMetadataStore.activeSignedPreKeyId = signedPreKey.id accountManager.setPreKeys( PreKeyUpload( serviceIdType = ServiceIdType.PNI, signedPreKey = signedPreKey, - oneTimeEcPreKeys = oneTimePreKeys, - lastResortKyberPreKey = null, - oneTimeKyberPreKeys = null + oneTimeEcPreKeys = oneTimeEcPreKeys, + lastResortKyberPreKey = lastResortKyberPreKey, + oneTimeKyberPreKeys = oneTimeKyberPreKeys ) ) pniMetadataStore.isSignedPreKeyRegistered = true + pniMetadataStore.lastResortKyberPreKeyId = pniLastResortKyberPreKeyId pniProtocolStore.identities().saveIdentityWithoutSideEffects( Recipient.self().id, @@ -282,7 +291,7 @@ class ChangeNumberRepository( true ) - SignalStore.misc().setPniInitializedDevices(true) + SignalStore.misc().hasPniInitializedDevices = true ApplicationDependencies.getGroupsV2Authorization().clear() } @@ -352,7 +361,7 @@ class ChangeNumberRepository( val lastResortKyberPreKeyRecord: KyberPreKeyRecord = if (deviceId == primaryDeviceId) { PreKeyUtil.generateAndStoreLastResortKyberPreKey(ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys, pniIdentity.privateKey) } else { - PreKeyUtil.generateLastRestortKyberPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) + PreKeyUtil.generateLastResortKyberPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) } devicePniLastResortKyberPreKeys[deviceId] = KyberPreKeyEntity(lastResortKyberPreKeyRecord.id, lastResortKyberPreKeyRecord.keyPair.publicKey, lastResortKyberPreKeyRecord.signature) @@ -394,7 +403,8 @@ class ChangeNumberRepository( previousPni = SignalStore.account().pni!!.toByteString(), pniIdentityKeyPair = pniIdentity.serialize().toByteString(), pniRegistrationId = pniRegistrationIds[primaryDeviceId]!!, - pniSignedPreKeyId = devicePniSignedPreKeys[primaryDeviceId]!!.keyId + pniSignedPreKeyId = devicePniSignedPreKeys[primaryDeviceId]!!.keyId, + pniLastResortKyberPreKeyId = devicePniLastResortKyberPreKeys[primaryDeviceId]!!.keyId ) return ChangeNumberRequestData(request, metadata) diff --git a/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberVerifyFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberVerifyFragment.kt index 37c2ab3b..65023e96 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberVerifyFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/changenumber/ChangeNumberVerifyFragment.kt @@ -99,7 +99,7 @@ class ChangeNumberVerifyFragment : LoggingFragment(R.layout.fragment_change_phon } private fun showErrorDialog(context: Context, @StringRes message: Int, onPositiveButtonClickListener: OnClickListener?) { - MaterialAlertDialogBuilder(context).setMessage(message).setPositiveButton(R.string.ok, onPositiveButtonClickListener).show() + MaterialAlertDialogBuilder(context).setMessage(message).setPositiveButton(android.R.string.ok, onPositiveButtonClickListener).show() } private sealed interface RequestCodeResult { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsFragment.kt index a2601630..0d33d12e 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsFragment.kt @@ -1,26 +1,18 @@ package org.tm.archive.components.settings.app.chats -import android.app.Activity -import android.content.Intent -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.ViewModelProvider import androidx.navigation.Navigation import org.tm.archive.R import org.tm.archive.components.settings.DSLConfiguration import org.tm.archive.components.settings.DSLSettingsFragment import org.tm.archive.components.settings.DSLSettingsText -import org.tm.archive.components.settings.app.chats.sms.SmsExportState import org.tm.archive.components.settings.configure -import org.tm.archive.exporter.flow.SmsExportActivity -import org.tm.archive.exporter.flow.SmsExportDialogs import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.navigation.safeNavigate class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__chats) { private lateinit var viewModel: ChatsSettingsViewModel - private lateinit var smsExportLauncher: ActivityResultLauncher override fun onResume() { super.onResume() @@ -29,12 +21,6 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch @Suppress("ReplaceGetOrSet") override fun bindAdapter(adapter: MappingAdapter) { - smsExportLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - SmsExportDialogs.showSmsRemovalDialog(requireContext(), requireView()) - } - } - viewModel = ViewModelProvider(this).get(ChatsSettingsViewModel::class.java) viewModel.state.observe(viewLifecycleOwner) { @@ -44,55 +30,6 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch private fun getConfiguration(state: ChatsSettingsState): DSLConfiguration { return configure { - if (!state.useAsDefaultSmsApp) { - when (state.smsExportState) { - SmsExportState.FETCHING -> Unit - SmsExportState.HAS_UNEXPORTED_MESSAGES -> { - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__export_sms_messages), - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__you_can_export_your_sms_messages_to_your_phones_sms_database), - onClick = { - smsExportLauncher.launch(SmsExportActivity.createIntent(requireContext())) - } - ) - - dividerPref() - } - SmsExportState.ALL_MESSAGES_EXPORTED -> { - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__remove_sms_messages), - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__remove_sms_messages_from_signal_to_clear_up_storage_space), - onClick = { - SmsExportDialogs.showSmsRemovalDialog(requireContext(), requireView()) - } - ) - - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__export_sms_messages_again), - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__exporting_again_can_result_in_duplicate_messages), - onClick = { - SmsExportDialogs.showSmsReExportDialog(requireContext()) { - smsExportLauncher.launch(SmsExportActivity.createIntent(requireContext(), isReExport = true)) - } - } - ) - - dividerPref() - } - SmsExportState.NO_SMS_MESSAGES_IN_DATABASE -> Unit - SmsExportState.NOT_AVAILABLE -> Unit - } - } else { - clickPref( - title = DSLSettingsText.from(R.string.preferences__sms_mms), - onClick = { - Navigation.findNavController(requireView()).safeNavigate(R.id.action_chatsSettingsFragment_to_smsSettingsFragment) - } - ) - - dividerPref() - } - switchPref( title = DSLSettingsText.from(R.string.preferences__generate_link_previews), summary = DSLSettingsText.from(R.string.preferences__retrieve_link_previews_from_websites_for_messages), diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsState.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsState.kt index da506809..4e17795e 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsState.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsState.kt @@ -1,14 +1,10 @@ package org.tm.archive.components.settings.app.chats -import org.tm.archive.components.settings.app.chats.sms.SmsExportState - data class ChatsSettingsState( val generateLinkPreviews: Boolean, val useAddressBook: Boolean, val keepMutedChatsArchived: Boolean, val useSystemEmoji: Boolean, val enterKeySends: Boolean, - val chatBackupsEnabled: Boolean, - val useAsDefaultSmsApp: Boolean, - val smsExportState: SmsExportState = SmsExportState.FETCHING + val chatBackupsEnabled: Boolean ) diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsViewModel.kt index 52e25806..b3e342e5 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/chats/ChatsSettingsViewModel.kt @@ -2,24 +2,18 @@ package org.tm.archive.components.settings.app.chats import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel -import io.reactivex.rxjava3.disposables.CompositeDisposable -import io.reactivex.rxjava3.kotlin.plusAssign -import org.tm.archive.components.settings.app.chats.sms.SmsSettingsRepository import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.keyvalue.SignalStore import org.tm.archive.util.BackupUtil import org.tm.archive.util.ConversationUtil import org.tm.archive.util.ThrottledDebouncer -import org.tm.archive.util.Util import org.tm.archive.util.livedata.Store class ChatsSettingsViewModel @JvmOverloads constructor( - private val repository: ChatsSettingsRepository = ChatsSettingsRepository(), - smsSettingsRepository: SmsSettingsRepository = SmsSettingsRepository() + private val repository: ChatsSettingsRepository = ChatsSettingsRepository() ) : ViewModel() { private val refreshDebouncer = ThrottledDebouncer(500L) - private val disposables = CompositeDisposable() private val store: Store = Store( ChatsSettingsState( @@ -28,23 +22,12 @@ class ChatsSettingsViewModel @JvmOverloads constructor( keepMutedChatsArchived = SignalStore.settings().shouldKeepMutedChatsArchived(), useSystemEmoji = SignalStore.settings().isPreferSystemEmoji, enterKeySends = SignalStore.settings().isEnterKeySends, - chatBackupsEnabled = SignalStore.settings().isBackupEnabled && BackupUtil.canUserAccessBackupDirectory(ApplicationDependencies.getApplication()), - useAsDefaultSmsApp = Util.isDefaultSmsProvider(ApplicationDependencies.getApplication()) + chatBackupsEnabled = SignalStore.settings().isBackupEnabled && BackupUtil.canUserAccessBackupDirectory(ApplicationDependencies.getApplication()) ) ) val state: LiveData = store.stateLiveData - init { - disposables += smsSettingsRepository.getSmsExportState().subscribe { state -> - store.update { it.copy(smsExportState = state) } - } - } - - override fun onCleared() { - disposables.clear() - } - fun setGenerateLinkPreviewsEnabled(enabled: Boolean) { store.update { it.copy(generateLinkPreviews = enabled) } SignalStore.settings().isLinkPreviewsEnabled = enabled diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsExportState.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsExportState.kt deleted file mode 100644 index 0c330149..00000000 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsExportState.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.tm.archive.components.settings.app.chats.sms - -enum class SmsExportState { - FETCHING, - HAS_UNEXPORTED_MESSAGES, - ALL_MESSAGES_EXPORTED, - NO_SMS_MESSAGES_IN_DATABASE, - NOT_AVAILABLE -} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsFragment.kt deleted file mode 100644 index 1b8a1bd9..00000000 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsFragment.kt +++ /dev/null @@ -1,153 +0,0 @@ -package org.tm.archive.components.settings.app.chats.sms - -import android.annotation.SuppressLint -import android.app.Activity -import android.content.Intent -import android.os.Build -import android.provider.Settings -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import androidx.lifecycle.ViewModelProvider -import androidx.navigation.fragment.findNavController -import org.tm.archive.R -import org.tm.archive.components.settings.DSLConfiguration -import org.tm.archive.components.settings.DSLSettingsFragment -import org.tm.archive.components.settings.DSLSettingsText -import org.tm.archive.components.settings.configure -import org.tm.archive.components.settings.models.OutlinedLearnMore -import org.tm.archive.exporter.flow.SmsExportActivity -import org.tm.archive.exporter.flow.SmsExportDialogs -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.util.Util -import org.tm.archive.util.adapter.mapping.MappingAdapter - -private const val SMS_REQUEST_CODE: Short = 1234 - -class SmsSettingsFragment : DSLSettingsFragment(R.string.preferences__sms_mms) { - - private lateinit var viewModel: SmsSettingsViewModel - private lateinit var smsExportLauncher: ActivityResultLauncher - - override fun onResume() { - super.onResume() - viewModel.checkSmsEnabled() - } - - override fun bindAdapter(adapter: MappingAdapter) { - OutlinedLearnMore.register(adapter) - - smsExportLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - SmsExportDialogs.showSmsRemovalDialog(requireContext(), requireView()) - } - } - - viewModel = ViewModelProvider(this)[SmsSettingsViewModel::class.java] - - viewModel.state.observe(viewLifecycleOwner) { - adapter.submitList(getConfiguration(it).toMappingModelList()) - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (Util.isDefaultSmsProvider(requireContext())) { - SignalStore.settings().setDefaultSms(true) - } else { - SignalStore.settings().setDefaultSms(false) - findNavController().navigateUp() - } - } - - private fun getConfiguration(state: SmsSettingsState): DSLConfiguration { - return configure { - if (state.useAsDefaultSmsApp) { - customPref( - OutlinedLearnMore.Model( - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__sms_support_will_be_removed_soon_to_focus_on_encrypted_messaging), - learnMoreUrl = getString(R.string.sms_export_url) - ) - ) - } - - when (state.smsExportState) { - SmsExportState.FETCHING -> Unit - SmsExportState.HAS_UNEXPORTED_MESSAGES -> { - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__export_sms_messages), - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__you_can_export_your_sms_messages_to_your_phones_sms_database), - onClick = { - smsExportLauncher.launch(SmsExportActivity.createIntent(requireContext())) - } - ) - - dividerPref() - } - SmsExportState.ALL_MESSAGES_EXPORTED -> { - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__remove_sms_messages), - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__remove_sms_messages_from_signal_to_clear_up_storage_space), - onClick = { - SmsExportDialogs.showSmsRemovalDialog(requireContext(), requireView()) - } - ) - - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__export_sms_messages_again), - summary = DSLSettingsText.from(R.string.SmsSettingsFragment__exporting_again_can_result_in_duplicate_messages), - onClick = { - SmsExportDialogs.showSmsReExportDialog(requireContext()) { - smsExportLauncher.launch(SmsExportActivity.createIntent(requireContext(), isReExport = true)) - } - } - ) - - dividerPref() - } - SmsExportState.NO_SMS_MESSAGES_IN_DATABASE -> Unit - SmsExportState.NOT_AVAILABLE -> Unit - } - - if (state.useAsDefaultSmsApp) { - @Suppress("DEPRECATION") - clickPref( - title = DSLSettingsText.from(R.string.SmsSettingsFragment__use_as_default_sms_app), - summary = DSLSettingsText.from(R.string.arrays__enabled), - onClick = { - startDefaultAppSelectionIntent() - } - ) - } - - switchPref( - title = DSLSettingsText.from(R.string.preferences__sms_delivery_reports), - summary = DSLSettingsText.from(R.string.preferences__request_a_delivery_report_for_each_sms_message_you_send), - isChecked = state.smsDeliveryReportsEnabled, - onClick = { - viewModel.setSmsDeliveryReportsEnabled(!state.smsDeliveryReportsEnabled) - } - ) - - switchPref( - title = DSLSettingsText.from(R.string.preferences__support_wifi_calling), - summary = DSLSettingsText.from(R.string.preferences__enable_if_your_device_supports_sms_mms_delivery_over_wifi), - isChecked = state.wifiCallingCompatibilityEnabled, - onClick = { - viewModel.setWifiCallingCompatibilityEnabled(!state.wifiCallingCompatibilityEnabled) - } - ) - } - } - - // Linter isn't smart enough to figure out the else only happens if API >= 24 - @SuppressLint("InlinedApi") - @Suppress("DEPRECATION") - private fun startDefaultAppSelectionIntent() { - val intent: Intent = when { - Build.VERSION.SDK_INT < 23 -> Intent(Settings.ACTION_WIRELESS_SETTINGS) - Build.VERSION.SDK_INT < 24 -> Intent(Settings.ACTION_SETTINGS) - else -> Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) - } - - startActivityForResult(intent, SMS_REQUEST_CODE.toInt()) - } -} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsRepository.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsRepository.kt deleted file mode 100644 index 2a316433..00000000 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsRepository.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.tm.archive.components.settings.app.chats.sms - -import androidx.annotation.WorkerThread -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers -import org.tm.archive.database.MessageTable -import org.tm.archive.database.SignalDatabase - -class SmsSettingsRepository( - private val smsDatabase: MessageTable = SignalDatabase.messages, - private val mmsDatabase: MessageTable = SignalDatabase.messages -) { - fun getSmsExportState(): Single { - return Single.fromCallable { - checkInsecureMessageCount() ?: checkUnexportedInsecureMessageCount() - }.subscribeOn(Schedulers.io()) - } - - @WorkerThread - private fun checkInsecureMessageCount(): SmsExportState? { - val totalSmsMmsCount = smsDatabase.getInsecureMessageCount() + mmsDatabase.getInsecureMessageCount() - - return if (totalSmsMmsCount == 0) { - SmsExportState.NO_SMS_MESSAGES_IN_DATABASE - } else { - null - } - } - - @WorkerThread - private fun checkUnexportedInsecureMessageCount(): SmsExportState { - val totalUnexportedCount = smsDatabase.getUnexportedInsecureMessagesCount() + mmsDatabase.getUnexportedInsecureMessagesCount() - - return if (totalUnexportedCount > 0) { - SmsExportState.HAS_UNEXPORTED_MESSAGES - } else { - SmsExportState.ALL_MESSAGES_EXPORTED - } - } -} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsState.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsState.kt deleted file mode 100644 index 485c6582..00000000 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.tm.archive.components.settings.app.chats.sms - -data class SmsSettingsState( - val useAsDefaultSmsApp: Boolean, - val smsDeliveryReportsEnabled: Boolean, - val wifiCallingCompatibilityEnabled: Boolean, - val smsExportState: SmsExportState = SmsExportState.FETCHING -) diff --git a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsViewModel.kt deleted file mode 100644 index 9706c42f..00000000 --- a/app/src/main/java/org/tm/archive/components/settings/app/chats/sms/SmsSettingsViewModel.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.tm.archive.components.settings.app.chats.sms - -import androidx.lifecycle.LiveData -import androidx.lifecycle.ViewModel -import io.reactivex.rxjava3.disposables.CompositeDisposable -import io.reactivex.rxjava3.kotlin.plusAssign -import org.tm.archive.dependencies.ApplicationDependencies -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.util.Util -import org.tm.archive.util.livedata.Store - -class SmsSettingsViewModel : ViewModel() { - - private val repository = SmsSettingsRepository() - - private val disposables = CompositeDisposable() - private val store = Store( - SmsSettingsState( - useAsDefaultSmsApp = Util.isDefaultSmsProvider(ApplicationDependencies.getApplication()), - smsDeliveryReportsEnabled = SignalStore.settings().isSmsDeliveryReportsEnabled, - wifiCallingCompatibilityEnabled = SignalStore.settings().isWifiCallingCompatibilityModeEnabled - ) - ) - - val state: LiveData = store.stateLiveData - - init { - disposables += repository.getSmsExportState().subscribe { state -> - store.update { it.copy(smsExportState = state) } - } - } - - override fun onCleared() { - disposables.clear() - } - - fun setSmsDeliveryReportsEnabled(enabled: Boolean) { - store.update { it.copy(smsDeliveryReportsEnabled = enabled) } - SignalStore.settings().isSmsDeliveryReportsEnabled = enabled - } - - fun setWifiCallingCompatibilityEnabled(enabled: Boolean) { - store.update { it.copy(wifiCallingCompatibilityEnabled = enabled) } - SignalStore.settings().isWifiCallingCompatibilityModeEnabled = enabled - } - - fun checkSmsEnabled() { - store.update { it.copy(useAsDefaultSmsApp = Util.isDefaultSmsProvider(ApplicationDependencies.getApplication())) } - } -} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/help/HelpSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/help/HelpSettingsFragment.kt index 9ea6c21d..acbcf41b 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/help/HelpSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/help/HelpSettingsFragment.kt @@ -36,16 +36,14 @@ class HelpSettingsFragment : DSLSettingsFragment(R.string.preferences__help) { title = DSLSettingsText.from(R.string.HelpSettingsFragment__version), summary = DSLSettingsText.from(BuildConfig.VERSION_NAME) ) - - //**TM_SA**//s +//**TM_SA**//s /*clickPref( title = DSLSettingsText.from(R.string.HelpSettingsFragment__debug_log), onClick = { Navigation.findNavController(requireView()).safeNavigate(R.id.action_helpSettingsFragment_to_submitDebugLogActivity) } )*/ - //**TM_SA**//e - +//**TM_SA**//e clickPref( title = DSLSettingsText.from(R.string.HelpSettingsFragment__licenses), onClick = { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsFragment.kt index dbc4bbf9..6b71fa00 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsFragment.kt @@ -12,6 +12,7 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.signal.core.util.AppUtil +import org.signal.core.util.ThreadUtil import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.concurrent.SimpleTask import org.signal.core.util.logging.Log @@ -24,6 +25,7 @@ import org.tm.archive.R import org.tm.archive.components.settings.DSLConfiguration import org.tm.archive.components.settings.DSLSettingsFragment import org.tm.archive.components.settings.DSLSettingsText +import org.tm.archive.components.settings.app.privacy.advanced.AdvancedPrivacySettingsRepository import org.tm.archive.components.settings.configure import org.tm.archive.database.JobDatabase import org.tm.archive.database.LocalMetricsDatabase @@ -140,6 +142,14 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter } ) + clickPref( + title = DSLSettingsText.from("Unregister"), + summary = DSLSettingsText.from("This will unregister your account without deleting it."), + onClick = { + onUnregisterClicked() + } + ) + dividerPref() sectionHeaderPref(DSLSettingsText.from("Miscellaneous")) @@ -186,6 +196,48 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter } ) + clickPref( + title = DSLSettingsText.from("Log dump PreKey ServiceId-KeyIds"), + onClick = { + logPreKeyIds() + } + ) + + clickPref( + title = DSLSettingsText.from("Retry all jobs now"), + summary = DSLSettingsText.from("Clear backoff intervals, app will restart"), + onClick = { + SimpleTask.run({ + JobDatabase.getInstance(ApplicationDependencies.getApplication()).debugResetBackoffInterval() + }) { + AppUtil.restart(requireContext()) + } + } + ) + + clickPref( + title = DSLSettingsText.from("Delete all prekeys"), + summary = DSLSettingsText.from("Deletes all signed/last-resort/one-time prekeys for both ACI and PNI accounts. WILL cause problems."), + onClick = { + MaterialAlertDialogBuilder(requireContext()) + .setTitle("Delete all prekeys?") + .setMessage("Are you sure? This will delete all prekeys for both ACI and PNI accounts. This WILL cause problems.") + .setPositiveButton(android.R.string.ok) { _, _ -> + SignalDatabase.signedPreKeys.debugDeleteAll() + SignalDatabase.oneTimePreKeys.debugDeleteAll() + SignalDatabase.kyberPreKeys.debugDeleteAll() + + Toast.makeText(requireContext(), "All prekeys deleted!", Toast.LENGTH_SHORT).show() + } + .setNegativeButton(android.R.string.cancel, null) + .show() + } + ) + + dividerPref() + + sectionHeaderPref(DSLSettingsText.from("Logging")) + clickPref( title = DSLSettingsText.from("Clear all logs"), onClick = { @@ -227,21 +279,10 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter ) clickPref( - title = DSLSettingsText.from("Log dump PreKey ServiceId-KeyIds"), + title = DSLSettingsText.from("Clear local metrics"), + summary = DSLSettingsText.from("Click to clear all local metrics state."), onClick = { - logPreKeyIds() - } - ) - - clickPref( - title = DSLSettingsText.from("Retry all jobs now"), - summary = DSLSettingsText.from("Clear backoff intervals, app will restart"), - onClick = { - SimpleTask.run({ - JobDatabase.getInstance(ApplicationDependencies.getApplication()).debugResetBackoffInterval() - }) { - AppUtil.restart(requireContext()) - } + clearAllLocalMetricsState() } ) @@ -436,18 +477,6 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter dividerPref() - sectionHeaderPref(DSLSettingsText.from("Local Metrics")) - - clickPref( - title = DSLSettingsText.from("Clear local metrics"), - summary = DSLSettingsText.from("Click to clear all local metrics state."), - onClick = { - clearAllLocalMetricsState() - } - ) - - dividerPref() - sectionHeaderPref(DSLSettingsText.from("Group call server")) radioPref( @@ -716,13 +745,6 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter } ) - clickPref( - title = DSLSettingsText.from("Clear Username education ui hint"), - onClick = { - SignalStore.uiHints().clearHasSeenUsernameEducation() - } - ) - clickPref( title = DSLSettingsText.from("Corrupt username"), summary = DSLSettingsText.from("Changes our local username without telling the server so it falls out of sync. Refresh profile afterwards to trigger corruption."), @@ -731,7 +753,7 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter .setTitle("Corrupt your username?") .setMessage("Are you sure? You might not be able to get your original username back.") .setPositiveButton(android.R.string.ok) { _, _ -> - val random = "${(1..5).map { ('a'..'z').random() }.joinToString(separator = "") }.${Random.nextInt(1, 100)}" + val random = "${(1..5).map { ('a'..'z').random() }.joinToString(separator = "") }.${Random.nextInt(10, 100)}" SignalStore.account().username = random SignalDatabase.recipients.setUsername(Recipient.self().id, random) @@ -791,6 +813,32 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter } } + private fun onUnregisterClicked() { + MaterialAlertDialogBuilder(requireContext()) + .setTitle("Unregister?") + .setMessage("Are you sure? You'll have to re-register to use Signal again -- no promises that the process will go smoothly.") + .setPositiveButton(android.R.string.ok) { _, _ -> + AdvancedPrivacySettingsRepository(requireContext()).disablePushMessages { + ThreadUtil.runOnMain { + when (it) { + AdvancedPrivacySettingsRepository.DisablePushMessagesResult.SUCCESS -> { + SignalStore.account().setRegistered(false) + SignalStore.registrationValues().clearRegistrationComplete() + SignalStore.registrationValues().clearHasUploadedProfile() + Toast.makeText(context, "Unregistered!", Toast.LENGTH_SHORT).show() + } + + AdvancedPrivacySettingsRepository.DisablePushMessagesResult.NETWORK_ERROR -> { + Toast.makeText(context, "Network error!", Toast.LENGTH_SHORT).show() + } + } + } + } + } + .setNegativeButton(android.R.string.cancel, null) + .show() + } + private fun copyPaymentsDataToClipboard() { MaterialAlertDialogBuilder(requireContext()) .setMessage( diff --git a/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsViewModel.kt index 76b01da4..6d651261 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/internal/InternalSettingsViewModel.kt @@ -75,7 +75,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito } fun resetPnpInitializedState() { - SignalStore.misc().setPniInitializedDevices(false) + SignalStore.misc().hasPniInitializedDevices = false refresh() } @@ -159,7 +159,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito delayResends = SignalStore.internalValues().delayResends(), disableStorageService = SignalStore.internalValues().storageServiceDisabled(), canClearOnboardingState = SignalStore.storyValues().hasDownloadedOnboardingStory && Stories.isFeatureEnabled(), - pnpInitialized = SignalStore.misc().hasPniInitializedDevices(), + pnpInitialized = SignalStore.misc().hasPniInitializedDevices, useConversationItemV2ForMedia = SignalStore.internalValues().useConversationItemV2Media(), hasPendingOneTimeDonation = SignalStore.donationsValues().getPendingOneTimeDonation() != null ) diff --git a/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt index 37f84304..8e968051 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt @@ -12,7 +12,11 @@ import android.os.Bundle import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -20,12 +24,26 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Switch +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign @@ -34,6 +52,7 @@ import androidx.compose.ui.unit.dp import androidx.fragment.app.viewModels import org.signal.core.ui.Buttons import org.signal.core.ui.Dividers +import org.signal.core.ui.Snackbars import org.signal.core.ui.theme.SignalTheme import org.signal.core.util.bytes import org.signal.core.util.getLength @@ -48,6 +67,7 @@ class InternalBackupPlaygroundFragment : ComposeFragment() { private val viewModel: InternalBackupPlaygroundViewModel by viewModels() private lateinit var exportFileLauncher: ActivityResultLauncher private lateinit var importFileLauncher: ActivityResultLauncher + private lateinit var validateFileLauncher: ActivityResultLauncher override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -72,43 +92,110 @@ class InternalBackupPlaygroundFragment : ComposeFragment() { } ?: Toast.makeText(requireContext(), "No URI selected", Toast.LENGTH_SHORT).show() } } + + validateFileLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + result.data?.data?.let { uri -> + requireContext().contentResolver.getLength(uri)?.let { length -> + viewModel.validate(length) { requireContext().contentResolver.openInputStream(uri)!! } + } + } ?: Toast.makeText(requireContext(), "No URI selected", Toast.LENGTH_SHORT).show() + } + } } @Composable override fun FragmentContent() { val state by viewModel.state + val mediaState by viewModel.mediaState - Screen( - state = state, - onExportClicked = { viewModel.export() }, - onImportMemoryClicked = { viewModel.import() }, - onImportFileClicked = { - val intent = Intent().apply { - action = Intent.ACTION_GET_CONTENT - type = "application/octet-stream" - addCategory(Intent.CATEGORY_OPENABLE) - } + LaunchedEffect(Unit) { + viewModel.loadMedia() + } - importFileLauncher.launch(intent) + Tabs( + mainContent = { + Screen( + state = state, + onExportClicked = { viewModel.export() }, + onImportMemoryClicked = { viewModel.import() }, + onImportFileClicked = { + val intent = Intent().apply { + action = Intent.ACTION_GET_CONTENT + type = "application/octet-stream" + addCategory(Intent.CATEGORY_OPENABLE) + } + + importFileLauncher.launch(intent) + }, + onPlaintextClicked = { viewModel.onPlaintextToggled() }, + onSaveToDiskClicked = { + val intent = Intent().apply { + action = Intent.ACTION_CREATE_DOCUMENT + type = "application/octet-stream" + addCategory(Intent.CATEGORY_OPENABLE) + putExtra(Intent.EXTRA_TITLE, "backup-${if (state.plaintext) "plaintext" else "encrypted"}-${System.currentTimeMillis()}.bin") + } + + exportFileLauncher.launch(intent) + }, + onUploadToRemoteClicked = { viewModel.uploadBackupToRemote() }, + onCheckRemoteBackupStateClicked = { viewModel.checkRemoteBackupState() }, + onValidateFileClicked = { + val intent = Intent().apply { + action = Intent.ACTION_GET_CONTENT + type = "application/octet-stream" + addCategory(Intent.CATEGORY_OPENABLE) + } + + validateFileLauncher.launch(intent) + } + ) }, - onPlaintextClicked = { viewModel.onPlaintextToggled() }, - onSaveToDiskClicked = { - val intent = Intent().apply { - action = Intent.ACTION_CREATE_DOCUMENT - type = "application/octet-stream" - addCategory(Intent.CATEGORY_OPENABLE) - putExtra(Intent.EXTRA_TITLE, "backup-${if (state.plaintext) "plaintext" else "encrypted"}-${System.currentTimeMillis()}.bin") - } - - exportFileLauncher.launch(intent) - }, - onUploadToRemoteClicked = { viewModel.uploadBackupToRemote() }, - onCheckRemoteBackupStateClicked = { viewModel.checkRemoteBackupState() } + mediaContent = { snackbarHostState -> + MediaList( + state = mediaState, + snackbarHostState = snackbarHostState, + backupAttachmentMedia = { viewModel.backupAttachmentMedia(it) }, + deleteBackupAttachmentMedia = { viewModel.deleteBackupAttachmentMedia(it) }, + batchBackupAttachmentMedia = { viewModel.backupAttachmentMedia(it) }, + batchDeleteBackupAttachmentMedia = { viewModel.deleteBackupAttachmentMedia(it) } + ) + } ) } +} - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) +@Composable +fun Tabs( + mainContent: @Composable () -> Unit, + mediaContent: @Composable (snackbarHostState: SnackbarHostState) -> Unit +) { + val tabs = listOf("Main", "Media") + var tabIndex by remember { mutableIntStateOf(0) } + + val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } + + Scaffold( + snackbarHost = { Snackbars.Host(snackbarHostState) }, + topBar = { + TabRow(selectedTabIndex = tabIndex) { + tabs.forEachIndexed { index, tab -> + Tab( + text = { Text(tab) }, + selected = index == tabIndex, + onClick = { tabIndex = index } + ) + } + } + } + ) { + Surface(modifier = Modifier.padding(it)) { + when (tabIndex) { + 0 -> mainContent() + 1 -> mediaContent(snackbarHostState) + } + } } } @@ -120,6 +207,7 @@ fun Screen( onImportFileClicked: () -> Unit = {}, onPlaintextClicked: () -> Unit = {}, onSaveToDiskClicked: () -> Unit = {}, + onValidateFileClicked: () -> Unit = {}, onUploadToRemoteClicked: () -> Unit = {}, onCheckRemoteBackupStateClicked: () -> Unit = {} ) { @@ -165,15 +253,23 @@ fun Screen( Text("Import from file") } + Buttons.LargeTonal( + onClick = onValidateFileClicked + ) { + Text("Validate file") + } + Spacer(modifier = Modifier.height(16.dp)) when (state.backupState) { BackupState.NONE -> { StateLabel("") } + BackupState.EXPORT_IN_PROGRESS -> { StateLabel("Export in progress...") } + BackupState.EXPORT_DONE -> { StateLabel("Export complete. Sitting in memory. You can click 'Import' to import that data, save it to a file, or upload it to remote.") @@ -183,6 +279,7 @@ fun Screen( Text("Save to file") } } + BackupState.IMPORT_IN_PROGRESS -> { StateLabel("Import in progress...") } @@ -200,14 +297,17 @@ fun Screen( when (state.remoteBackupState) { is InternalBackupPlaygroundViewModel.RemoteBackupState.Available -> { - StateLabel("Exists/allocated. Space used by media: ${state.remoteBackupState.response.usedSpace ?: 0} bytes (${state.remoteBackupState.response.usedSpace?.bytes?.inMebiBytes?.roundedString(3) ?: 0} MiB)") + StateLabel("Exists/allocated. ${state.remoteBackupState.response.mediaCount} media items, using ${state.remoteBackupState.response.usedSpace} bytes (${state.remoteBackupState.response.usedSpace.bytes.inMebiBytes.roundedString(3)} MiB)") } + InternalBackupPlaygroundViewModel.RemoteBackupState.GeneralError -> { StateLabel("Hit an unknown error. Check the logs.") } + InternalBackupPlaygroundViewModel.RemoteBackupState.NotFound -> { StateLabel("Not found.") } + InternalBackupPlaygroundViewModel.RemoteBackupState.Unknown -> { StateLabel("Hit the button above to check the state.") } @@ -228,12 +328,15 @@ fun Screen( BackupUploadState.NONE -> { StateLabel("") } + BackupUploadState.UPLOAD_IN_PROGRESS -> { StateLabel("Upload in progress...") } + BackupUploadState.UPLOAD_DONE -> { StateLabel("Upload complete.") } + BackupUploadState.UPLOAD_FAILED -> { StateLabel("Upload failed.") } @@ -251,6 +354,124 @@ private fun StateLabel(text: String) { ) } +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun MediaList( + state: InternalBackupPlaygroundViewModel.MediaState, + snackbarHostState: SnackbarHostState, + backupAttachmentMedia: (InternalBackupPlaygroundViewModel.BackupAttachment) -> Unit, + deleteBackupAttachmentMedia: (InternalBackupPlaygroundViewModel.BackupAttachment) -> Unit, + batchBackupAttachmentMedia: (Set) -> Unit, + batchDeleteBackupAttachmentMedia: (Set) -> Unit +) { + LaunchedEffect(state.error?.id) { + state.error?.let { + snackbarHostState.showSnackbar(it.errorText) + } + } + + var selectionState by remember { mutableStateOf(MediaMultiSelectState()) } + + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn(modifier = Modifier.fillMaxSize()) { + items( + count = state.attachments.size, + key = { index -> state.attachments[index].id } + ) { index -> + val attachment = state.attachments[index] + Row( + modifier = Modifier + .combinedClickable( + onClick = { + if (selectionState.selecting) { + selectionState = selectionState.copy(selected = if (selectionState.selected.contains(attachment.mediaId)) selectionState.selected - attachment.mediaId else selectionState.selected + attachment.mediaId) + } + }, + onLongClick = { + selectionState = if (selectionState.selecting) MediaMultiSelectState() else MediaMultiSelectState(selecting = true, selected = setOf(attachment.mediaId)) + } + ) + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + if (selectionState.selecting) { + Checkbox( + checked = selectionState.selected.contains(attachment.mediaId), + onCheckedChange = { selected -> + selectionState = selectionState.copy(selected = if (selected) selectionState.selected + attachment.mediaId else selectionState.selected - attachment.mediaId) + } + ) + } + + Column(modifier = Modifier.weight(1f, true)) { + Text(text = "Attachment ${attachment.title}") + Text(text = "State: ${attachment.state}") + } + + if (attachment.state == InternalBackupPlaygroundViewModel.BackupAttachment.State.INIT || + attachment.state == InternalBackupPlaygroundViewModel.BackupAttachment.State.IN_PROGRESS + ) { + CircularProgressIndicator() + } else { + Button( + enabled = !selectionState.selecting, + onClick = { + when (attachment.state) { + InternalBackupPlaygroundViewModel.BackupAttachment.State.LOCAL_ONLY -> backupAttachmentMedia(attachment) + InternalBackupPlaygroundViewModel.BackupAttachment.State.UPLOADED -> deleteBackupAttachmentMedia(attachment) + else -> throw AssertionError("Unsupported state: ${attachment.state}") + } + } + ) { + Text( + text = when (attachment.state) { + InternalBackupPlaygroundViewModel.BackupAttachment.State.LOCAL_ONLY -> "Backup" + InternalBackupPlaygroundViewModel.BackupAttachment.State.UPLOADED -> "Remote Delete" + else -> throw AssertionError("Unsupported state: ${attachment.state}") + } + ) + } + } + } + } + } + + if (selectionState.selecting) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 24.dp) + .background( + color = MaterialTheme.colorScheme.secondaryContainer, + shape = RoundedCornerShape(8.dp) + ) + .padding(8.dp) + ) { + Button(onClick = { selectionState = MediaMultiSelectState() }) { + Text("Cancel") + } + Button(onClick = { + batchBackupAttachmentMedia(selectionState.selected) + selectionState = MediaMultiSelectState() + }) { + Text("Backup") + } + Button(onClick = { + batchDeleteBackupAttachmentMedia(selectionState.selected) + selectionState = MediaMultiSelectState() + }) { + Text("Delete") + } + } + } + } +} + +private data class MediaMultiSelectState( + val selecting: Boolean = false, + val selected: Set = emptySet() +) + @Preview(name = "Light Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(name = "Dark Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt index a09eeaf4..ab315f66 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt @@ -13,17 +13,27 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign +import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.schedulers.Schedulers +import org.signal.core.util.Base64 import org.signal.libsignal.zkgroup.profiles.ProfileKey +import org.tm.archive.attachments.DatabaseAttachment +import org.tm.archive.backup.v2.BackupMetadata import org.tm.archive.backup.v2.BackupRepository +import org.tm.archive.database.SignalDatabase +import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient import org.whispersystems.signalservice.api.NetworkResult -import org.whispersystems.signalservice.api.archive.ArchiveGetBackupInfoResponse +import org.whispersystems.signalservice.api.backup.BackupKey import java.io.ByteArrayInputStream import java.io.InputStream +import java.util.UUID +import kotlin.random.Random class InternalBackupPlaygroundViewModel : ViewModel() { + private val backupKey = SignalStore.svr().getOrCreateMasterKey().deriveBackupKey() + var backupData: ByteArray? = null val disposables = CompositeDisposable() @@ -31,6 +41,9 @@ class InternalBackupPlaygroundViewModel : ViewModel() { private val _state: MutableState = mutableStateOf(ScreenState(backupState = BackupState.NONE, uploadState = BackupUploadState.NONE, plaintext = false)) val state: State = _state + private val _mediaState: MutableState = mutableStateOf(MediaState()) + val mediaState: State = _mediaState + fun export() { _state.value = _state.value.copy(backupState = BackupState.EXPORT_IN_PROGRESS) val plaintext = _state.value.plaintext @@ -78,6 +91,19 @@ class InternalBackupPlaygroundViewModel : ViewModel() { } } + fun validate(length: Long, inputStreamFactory: () -> InputStream) { + val self = Recipient.self() + val selfData = BackupRepository.SelfData(self.aci.get(), self.pni.get(), self.e164.get(), ProfileKey(self.profileKey)) + + disposables += Single.fromCallable { BackupRepository.validate(length, inputStreamFactory, selfData) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { nothing -> + backupData = null + _state.value = _state.value.copy(backupState = BackupState.NONE) + } + } + fun onPlaintextToggled() { _state.value = _state.value.copy(plaintext = !_state.value.plaintext) } @@ -104,9 +130,11 @@ class InternalBackupPlaygroundViewModel : ViewModel() { result is NetworkResult.Success -> { _state.value = _state.value.copy(remoteBackupState = RemoteBackupState.Available(result.result)) } + result is NetworkResult.StatusCodeError && result.code == 404 -> { _state.value = _state.value.copy(remoteBackupState = RemoteBackupState.NotFound) } + else -> { _state.value = _state.value.copy(remoteBackupState = RemoteBackupState.GeneralError) } @@ -114,6 +142,98 @@ class InternalBackupPlaygroundViewModel : ViewModel() { } } + fun loadMedia() { + disposables += Single + .fromCallable { SignalDatabase.attachments.debugGetLatestAttachments() } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.single()) + .subscribeBy { + _mediaState.set { update(attachments = it.map { a -> BackupAttachment.from(backupKey, a) }) } + } + + disposables += Single + .fromCallable { BackupRepository.debugGetArchivedMediaState() } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.single()) + .subscribeBy { result -> + when (result) { + is NetworkResult.Success -> _mediaState.set { update(archiveStateLoaded = true, backedUpMediaIds = result.result.map { it.mediaId }.toSet()) } + else -> _mediaState.set { copy(error = MediaStateError(errorText = "$result")) } + } + } + } + + fun backupAttachmentMedia(mediaIds: Set) { + disposables += Single.fromCallable { mediaIds.mapNotNull { mediaState.value.idToAttachment[it]?.dbAttachment }.toList() } + .map { BackupRepository.archiveMedia(it) } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.single()) + .doOnSubscribe { _mediaState.set { update(inProgressMediaIds = inProgressMediaIds + mediaIds) } } + .doOnTerminate { _mediaState.set { update(inProgressMediaIds = inProgressMediaIds - mediaIds) } } + .subscribeBy { result -> + when (result) { + is NetworkResult.Success -> { + val response = result.result + val successes = response.responses.filter { it.status == 200 } + val failures = response.responses - successes.toSet() + + _mediaState.set { + var updated = update(backedUpMediaIds = backedUpMediaIds + successes.map { it.mediaId }) + if (failures.isNotEmpty()) { + updated = updated.copy(error = MediaStateError(errorText = failures.toString())) + } + updated + } + } + + else -> _mediaState.set { copy(error = MediaStateError(errorText = "$result")) } + } + } + } + + fun backupAttachmentMedia(attachment: BackupAttachment) { + disposables += Single.fromCallable { BackupRepository.archiveMedia(attachment.dbAttachment) } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.single()) + .doOnSubscribe { _mediaState.set { update(inProgressMediaIds = inProgressMediaIds + attachment.mediaId) } } + .doOnTerminate { _mediaState.set { update(inProgressMediaIds = inProgressMediaIds - attachment.mediaId) } } + .subscribeBy { + when (it) { + is NetworkResult.Success -> { + _mediaState.set { update(backedUpMediaIds = backedUpMediaIds + attachment.mediaId) } + } + + else -> _mediaState.set { copy(error = MediaStateError(errorText = "$it")) } + } + } + } + + fun deleteBackupAttachmentMedia(mediaIds: Set) { + deleteBackupAttachmentMedia(mediaIds.mapNotNull { mediaState.value.idToAttachment[it] }.toList()) + } + + fun deleteBackupAttachmentMedia(attachment: BackupAttachment) { + deleteBackupAttachmentMedia(listOf(attachment)) + } + + private fun deleteBackupAttachmentMedia(attachments: List) { + val ids = attachments.map { it.mediaId }.toSet() + disposables += Single.fromCallable { BackupRepository.deleteArchivedMedia(attachments.map { it.dbAttachment }) } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.single()) + .doOnSubscribe { _mediaState.set { update(inProgressMediaIds = inProgressMediaIds + ids) } } + .doOnTerminate { _mediaState.set { update(inProgressMediaIds = inProgressMediaIds - ids) } } + .subscribeBy { + when (it) { + is NetworkResult.Success -> { + _mediaState.set { update(backedUpMediaIds = backedUpMediaIds - ids) } + } + + else -> _mediaState.set { copy(error = MediaStateError(errorText = "$it")) } + } + } + } + override fun onCleared() { disposables.clear() } @@ -137,6 +257,79 @@ class InternalBackupPlaygroundViewModel : ViewModel() { object Unknown : RemoteBackupState() object NotFound : RemoteBackupState() object GeneralError : RemoteBackupState() - data class Available(val response: ArchiveGetBackupInfoResponse) : RemoteBackupState() + data class Available(val response: BackupMetadata) : RemoteBackupState() + } + + data class MediaState( + val backupStateLoaded: Boolean = false, + val attachments: List = emptyList(), + val backedUpMediaIds: Set = emptySet(), + val inProgressMediaIds: Set = emptySet(), + val error: MediaStateError? = null + ) { + val idToAttachment: Map = attachments.associateBy { it.mediaId } + + fun update( + archiveStateLoaded: Boolean = this.backupStateLoaded, + attachments: List = this.attachments, + backedUpMediaIds: Set = this.backedUpMediaIds, + inProgressMediaIds: Set = this.inProgressMediaIds + ): MediaState { + val updatedAttachments = if (archiveStateLoaded) { + attachments.map { + val state = if (inProgressMediaIds.contains(it.mediaId)) { + BackupAttachment.State.IN_PROGRESS + } else if (backedUpMediaIds.contains(it.mediaId)) { + BackupAttachment.State.UPLOADED + } else { + BackupAttachment.State.LOCAL_ONLY + } + + it.copy(state = state) + } + } else { + attachments + } + + return copy( + backupStateLoaded = archiveStateLoaded, + attachments = updatedAttachments, + backedUpMediaIds = backedUpMediaIds + ) + } + } + + data class BackupAttachment( + val dbAttachment: DatabaseAttachment, + val state: State = State.INIT, + val mediaId: String = Base64.encodeUrlSafeWithPadding(Random.nextBytes(15)) + ) { + val id: Any = dbAttachment.attachmentId + val title: String = dbAttachment.attachmentId.toString() + + enum class State { + INIT, + LOCAL_ONLY, + UPLOADED, + IN_PROGRESS + } + + companion object { + fun from(backupKey: BackupKey, dbAttachment: DatabaseAttachment): BackupAttachment { + return BackupAttachment( + dbAttachment = dbAttachment, + mediaId = backupKey.deriveMediaId(Base64.decode(dbAttachment.dataHash!!)).toString() + ) + } + } + } + + data class MediaStateError( + val id: UUID = UUID.randomUUID(), + val errorText: String + ) + + fun MutableState.set(update: T.() -> T) { + this.value = this.value.update() } } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/internal/search/InternalSearchFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/internal/search/InternalSearchFragment.kt index 1a281cc4..12ffcbed 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/internal/search/InternalSearchFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/internal/search/InternalSearchFragment.kt @@ -95,8 +95,7 @@ fun ResultItem(result: InternalSearchResult, modifier: Modifier = Modifier) { .clickable { if (activity != null) { RecipientBottomSheetDialogFragment - .create(result.id, result.groupId) - .show(activity.supportFragmentManager, "TAG") + .show(activity.supportFragmentManager, result.id, result.groupId) } } .padding(8.dp) diff --git a/app/src/main/java/org/tm/archive/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt index 4b358210..e3de82bb 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt @@ -16,9 +16,7 @@ import org.tm.archive.R import org.tm.archive.components.ContactFilterView import org.tm.archive.contacts.ContactSelectionDisplayMode import org.tm.archive.groups.SelectionLimits -import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.RecipientId -import org.tm.archive.util.Util import org.tm.archive.util.ViewUtil import org.tm.archive.util.views.CircularProgressMaterialButton import java.util.Optional @@ -100,17 +98,12 @@ class SelectRecipientsFragment : LoggingFragment(), ContactSelectionListFragment } private fun getDefaultDisplayMode(): Int { - var mode = ContactSelectionDisplayMode.FLAG_PUSH or + return ContactSelectionDisplayMode.FLAG_PUSH or ContactSelectionDisplayMode.FLAG_ACTIVE_GROUPS or ContactSelectionDisplayMode.FLAG_HIDE_NEW or ContactSelectionDisplayMode.FLAG_HIDE_RECENT_HEADER or - ContactSelectionDisplayMode.FLAG_GROUPS_AFTER_CONTACTS - - if (Util.isDefaultSmsProvider(requireContext()) && SignalStore.misc().smsExportPhase.allowSmsFeatures()) { - mode = mode or ContactSelectionDisplayMode.FLAG_SMS - } - - return mode or ContactSelectionDisplayMode.FLAG_HIDE_GROUPS_V1 + ContactSelectionDisplayMode.FLAG_GROUPS_AFTER_CONTACTS or + ContactSelectionDisplayMode.FLAG_HIDE_GROUPS_V1 } override fun onBeforeContactSelected(isFromUnknownSearchKey: Boolean, recipientId: Optional, number: String?, callback: Consumer) { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/privacy/PrivacySettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/privacy/PrivacySettingsFragment.kt index dea79db4..af99d1c4 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/privacy/PrivacySettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/privacy/PrivacySettingsFragment.kt @@ -40,7 +40,6 @@ import org.tm.archive.service.KeyCachingService import org.tm.archive.util.CommunicationActions import org.tm.archive.util.ConversationUtil import org.tm.archive.util.ExpirationUtil -import org.tm.archive.util.FeatureFlags import org.tm.archive.util.ServiceUtil import org.tm.archive.util.SpanUtil import org.tm.archive.util.TextSecurePreferences @@ -119,18 +118,16 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac private fun getConfiguration(state: PrivacySettingsState): DSLConfiguration { return configure { - if (FeatureFlags.phoneNumberPrivacy()) { - clickPref( - title = DSLSettingsText.from(R.string.preferences_app_protection__phone_number), - summary = DSLSettingsText.from(R.string.preferences_app_protection__choose_who_can_see), - onClick = { - Navigation.findNavController(requireView()) - .safeNavigate(R.id.action_privacySettingsFragment_to_phoneNumberPrivacySettingsFragment) - } - ) + clickPref( + title = DSLSettingsText.from(R.string.preferences_app_protection__phone_number), + summary = DSLSettingsText.from(R.string.preferences_app_protection__choose_who_can_see), + onClick = { + Navigation.findNavController(requireView()) + .safeNavigate(R.id.action_privacySettingsFragment_to_phoneNumberPrivacySettingsFragment) + } + ) - dividerPref() - } + dividerPref() clickPref( title = DSLSettingsText.from(R.string.PrivacySettingsFragment__blocked), @@ -193,7 +190,7 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac MaterialAlertDialogBuilder(requireContext()).apply { setTitle(R.string.ApplicationPreferencesActivity_disable_passphrase) setMessage(R.string.ApplicationPreferencesActivity_this_will_permanently_unlock_signal_and_message_notifications) - setIcon(R.drawable.ic_warning) + setIcon(R.drawable.symbol_error_triangle_fill_24) setPositiveButton(R.string.ApplicationPreferencesActivity_disable) { _, _ -> MasterSecretUtil.changeMasterSecretPassphrase( activity, @@ -330,7 +327,6 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac } )*/ //**TM_SA**//end - dividerPref() clickPref( diff --git a/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt index 7900772d..9c92f250 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt @@ -6,16 +6,12 @@ import android.content.Intent import android.content.IntentFilter import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter -import android.graphics.drawable.Drawable import android.net.ConnectivityManager import android.text.SpannableStringBuilder -import android.widget.TextView import android.widget.Toast import androidx.core.content.ContextCompat -import androidx.core.widget.TextViewCompat import androidx.lifecycle.ViewModelProvider import androidx.preference.PreferenceManager -import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.tm.archive.R import org.tm.archive.components.SignalProgressDialog import org.tm.archive.components.settings.DSLConfiguration @@ -24,7 +20,6 @@ import org.tm.archive.components.settings.DSLSettingsText import org.tm.archive.components.settings.configure import org.tm.archive.keyvalue.SignalStore import org.tm.archive.phonenumbers.PhoneNumberFormatter -import org.tm.archive.registration.RegistrationNavigationActivity import org.tm.archive.util.CommunicationActions import org.tm.archive.util.SpanUtil import org.tm.archive.util.ViewUtil @@ -107,40 +102,6 @@ class AdvancedPrivacySettingsFragment : DSLSettingsFragment(R.string.preferences private fun getConfiguration(state: AdvancedPrivacySettingsState): DSLConfiguration { return configure { - switchPref( - title = DSLSettingsText.from(R.string.preferences__signal_messages_and_calls), - summary = DSLSettingsText.from(getPushToggleSummary(state.isPushEnabled)), - isChecked = state.isPushEnabled - ) { - if (state.isPushEnabled) { - val builder = MaterialAlertDialogBuilder(requireContext()).apply { - setMessage(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls_by_unregistering) - setNegativeButton(android.R.string.cancel, null) - setPositiveButton( - android.R.string.ok - ) { _, _ -> viewModel.disablePushMessages() } - } - - val icon: Drawable = requireNotNull(ContextCompat.getDrawable(builder.context, R.drawable.symbol_info_24)) - icon.setBounds(0, 0, ViewUtil.dpToPx(32), ViewUtil.dpToPx(32)) - - val title = TextView(builder.context) - val padding = ViewUtil.dpToPx(16) - title.setText(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls) - title.setPadding(padding, padding, padding, padding) - title.compoundDrawablePadding = padding / 2 - TextViewCompat.setTextAppearance(title, R.style.TextAppearance_Signal_Title2_MaterialDialog) - TextViewCompat.setCompoundDrawablesRelative(title, icon, null, null, null) - - builder - .setCustomTitle(title) - .setOnDismissListener { viewModel.refresh() } - .show() - } else { - startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext())) - } - } - switchPref( title = DSLSettingsText.from(R.string.preferences_advanced__always_relay_calls), summary = DSLSettingsText.from(R.string.preferences_advanced__relay_all_calls_through_the_signal_server_to_avoid_revealing_your_ip_address), diff --git a/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt index cc4ed571..bcf569c9 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt @@ -38,25 +38,6 @@ class AdvancedPrivacySettingsViewModel( ) } - fun disablePushMessages() { - store.update { getState().copy(showProgressSpinner = true) } - - repository.disablePushMessages { - when (it) { - AdvancedPrivacySettingsRepository.DisablePushMessagesResult.SUCCESS -> { - SignalStore.account().setRegistered(false) - SignalStore.registrationValues().clearRegistrationComplete() - SignalStore.registrationValues().clearHasUploadedProfile() - } - AdvancedPrivacySettingsRepository.DisablePushMessagesResult.NETWORK_ERROR -> { - singleEvents.postValue(Event.DISABLE_PUSH_FAILED) - } - } - - store.update { getState().copy(showProgressSpinner = false) } - } - } - fun setAlwaysRelayCalls(enabled: Boolean) { sharedPreferences.edit().putBoolean(TextSecurePreferences.ALWAYS_RELAY_CALLS_PREF, enabled).apply() refresh() diff --git a/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsFragment.kt index 81f5e0ff..fcce735a 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsFragment.kt @@ -1,11 +1,15 @@ package org.tm.archive.components.settings.app.privacy.pnp +import android.content.res.Configuration import android.os.Bundle import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -15,13 +19,18 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.launch import org.signal.core.ui.Dividers import org.signal.core.ui.Rows import org.signal.core.ui.Scaffolds import org.signal.core.ui.Texts +import org.signal.core.ui.theme.SignalTheme import org.tm.archive.R import org.tm.archive.compose.ComposeFragment import org.tm.archive.compose.StatusBarColorNestedScrollConnection @@ -44,98 +53,188 @@ class PhoneNumberPrivacySettingsFragment : ComposeFragment() { @Composable override fun FragmentContent() { val state: PhoneNumberPrivacySettingsState by viewModel.state - val onNavigationClick: () -> Unit = remember { - { findNavController().popBackStack() } - } + val snackbarHostState = remember { SnackbarHostState() } + val snackbarMessage = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment__to_change_this_setting) - Scaffolds.Settings( - title = stringResource(id = R.string.preferences_app_protection__phone_number), - onNavigationClick = onNavigationClick, - navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24), - navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close), - modifier = Modifier.nestedScroll(statusBarNestedScrollConnection) - ) { contentPadding -> - Box(modifier = Modifier.padding(contentPadding)) { - LazyColumn { - item { - Texts.SectionHeader( - text = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment__who_can_see_my_number) + Screen( + state = state, + snackbarHostState = snackbarHostState, + onNavigationClick = { findNavController().popBackStack() }, + statusBarNestedScrollConnection = statusBarNestedScrollConnection, + onEveryoneCanSeeMyNumberClicked = viewModel::setEveryoneCanSeeMyNumber, + onNobodyCanSeeMyNumberClicked = viewModel::setNobodyCanSeeMyNumber, + onEveryoneCanFindMeByNumberClicked = viewModel::setEveryoneCanFindMeByMyNumber, + onNobodyCanFindMeByNumberClicked = { + if (!state.phoneNumberSharing) { + onNobodyCanFindMeByNumberClicked() + } else { + lifecycleScope.launch { + snackbarHostState.showSnackbar( + message = snackbarMessage, + duration = SnackbarDuration.Short ) } + } + } + ) + } - item { - Rows.RadioRow( - selected = state.phoneNumberSharing, - text = stringResource(id = R.string.PhoneNumberPrivacy_everyone), - modifier = Modifier.clickable(onClick = viewModel::setEveryoneCanSeeMyNumber) - ) - } + private fun onNobodyCanFindMeByNumberClicked() { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.PhoneNumberPrivacySettingsFragment__nobody_can_find_me_warning_title) + .setMessage(getString(R.string.PhoneNumberPrivacySettingsFragment__nobody_can_find_me_warning_message)) + .setNegativeButton(getString(R.string.PhoneNumberPrivacySettingsFragment__cancel), null) + .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.setNobodyCanFindMeByMyNumber() } + .show() + } +} - item { - Rows.RadioRow( - selected = !state.phoneNumberSharing, - text = stringResource(id = R.string.PhoneNumberPrivacy_nobody), - modifier = Modifier.clickable(onClick = viewModel::setNobodyCanSeeMyNumber) - ) - } +@Composable +private fun Screen( + state: PhoneNumberPrivacySettingsState, + snackbarHostState: SnackbarHostState = SnackbarHostState(), + onNavigationClick: () -> Unit = {}, + statusBarNestedScrollConnection: StatusBarColorNestedScrollConnection? = null, + onEveryoneCanSeeMyNumberClicked: () -> Unit = {}, + onNobodyCanSeeMyNumberClicked: () -> Unit = {}, + onEveryoneCanFindMeByNumberClicked: () -> Unit = {}, + onNobodyCanFindMeByNumberClicked: () -> Unit = {} +) { + Scaffolds.Settings( + title = stringResource(id = R.string.preferences_app_protection__phone_number), + onNavigationClick = onNavigationClick, + navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24), + navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close), + snackbarHost = { + SnackbarHost(snackbarHostState) + }, + modifier = statusBarNestedScrollConnection?.let { Modifier.nestedScroll(it) } ?: Modifier + ) { contentPadding -> + Box(modifier = Modifier.padding(contentPadding)) { + LazyColumn { + item { + Texts.SectionHeader( + text = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment_who_can_see_my_number_heading) + ) + } - item { - Text( - text = stringResource( - id = if (state.phoneNumberSharing) { - R.string.PhoneNumberPrivacySettingsFragment__your_phone_number + item { + Rows.RadioRow( + selected = state.phoneNumberSharing, + text = stringResource(id = R.string.PhoneNumberPrivacy_everyone), + modifier = Modifier.clickable(onClick = onEveryoneCanSeeMyNumberClicked) + ) + } + + item { + Rows.RadioRow( + selected = !state.phoneNumberSharing, + text = stringResource(id = R.string.PhoneNumberPrivacy_nobody), + modifier = Modifier.clickable(onClick = onNobodyCanSeeMyNumberClicked) + ) + } + + item { + Text( + text = stringResource( + id = if (state.phoneNumberSharing) { + R.string.PhoneNumberPrivacySettingsFragment_sharing_on_description + } else { + if (state.discoverableByPhoneNumber) { + R.string.PhoneNumberPrivacySettingsFragment_sharing_off_discovery_on_description } else { - R.string.PhoneNumberPrivacySettingsFragment__nobody_will_see + R.string.PhoneNumberPrivacySettingsFragment_sharing_off_discovery_off_description } - ), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp) - ) - } + } + ), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp) + ) + } - item { - Dividers.Default() - } + item { + Dividers.Default() + } - item { - Texts.SectionHeader(text = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment__who_can_find_me_by_number)) - } + item { + Texts.SectionHeader(text = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment_who_can_find_me_by_number_heading)) + } - item { - Rows.RadioRow( - selected = state.discoverableByPhoneNumber, - text = stringResource(id = R.string.PhoneNumberPrivacy_everyone), - modifier = Modifier.clickable(onClick = viewModel::setEveryoneCanFindMeByMyNumber) - ) - } + item { + Rows.RadioRow( + selected = state.discoverableByPhoneNumber, + text = stringResource(id = R.string.PhoneNumberPrivacy_everyone), + modifier = Modifier.clickable(onClick = onEveryoneCanFindMeByNumberClicked) + ) + } - if (!state.phoneNumberSharing) { - item { - Rows.RadioRow( - selected = !state.discoverableByPhoneNumber, - text = stringResource(id = R.string.PhoneNumberPrivacy_nobody), - modifier = Modifier.clickable(onClick = viewModel::setNobodyCanFindMeByMyNumber) - ) - } - } + item { + Rows.RadioRow( + enabled = !state.phoneNumberSharing, + selected = !state.discoverableByPhoneNumber, + text = stringResource(id = R.string.PhoneNumberPrivacy_nobody), + modifier = Modifier.clickable(onClick = onNobodyCanFindMeByNumberClicked) + ) + } - item { - Text( - text = stringResource( - id = if (state.discoverableByPhoneNumber) { - R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has - } else { - R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal - } - ), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp) - ) - } + item { + Text( + text = stringResource( + id = if (state.discoverableByPhoneNumber) { + R.string.PhoneNumberPrivacySettingsFragment_discovery_on_description + } else { + R.string.PhoneNumberPrivacySettingsFragment_discovery_off_description + } + ), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp) + ) } } } } } + +@Preview(name = "Light Theme", group = "Screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "Screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewSharingAndDiscoverable() { + SignalTheme { + Screen( + state = PhoneNumberPrivacySettingsState( + phoneNumberSharing = true, + discoverableByPhoneNumber = true + ) + ) + } +} + +@Preview(name = "Light Theme", group = "Screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "Screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewNotSharingDiscoverable() { + SignalTheme { + Screen( + state = PhoneNumberPrivacySettingsState( + phoneNumberSharing = false, + discoverableByPhoneNumber = true + ) + ) + } +} + +@Preview(name = "Light Theme", group = "Screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "Screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewNotSharingNotDiscoverable() { + SignalTheme { + Screen( + state = PhoneNumberPrivacySettingsState( + phoneNumberSharing = false, + discoverableByPhoneNumber = false + ) + ) + } +} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsViewModel.kt index 8993dd32..484f3180 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/privacy/pnp/PhoneNumberPrivacySettingsViewModel.kt @@ -8,7 +8,7 @@ import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.jobs.ProfileUploadJob import org.tm.archive.jobs.RefreshAttributesJob import org.tm.archive.jobs.RefreshOwnProfileJob -import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberSharingMode import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient @@ -19,7 +19,7 @@ class PhoneNumberPrivacySettingsViewModel : ViewModel() { private val _state = mutableStateOf( PhoneNumberPrivacySettingsState( phoneNumberSharing = SignalStore.phoneNumberPrivacy().isPhoneNumberSharingEnabled, - discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().isDiscoverableByPhoneNumber + discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode != PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE ) ) @@ -51,7 +51,7 @@ class PhoneNumberPrivacySettingsViewModel : ViewModel() { } private fun setDiscoverableByPhoneNumber(discoverable: Boolean) { - SignalStore.phoneNumberPrivacy().phoneNumberListingMode = if (discoverable) PhoneNumberListingMode.LISTED else PhoneNumberListingMode.UNLISTED + SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode = if (discoverable) PhoneNumberDiscoverabilityMode.DISCOVERABLE else PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE StorageSyncHelper.scheduleSyncForDataChange() ApplicationDependencies.getJobManager().startChain(RefreshAttributesJob()).then(RefreshOwnProfileJob()).enqueue() refresh() @@ -60,7 +60,7 @@ class PhoneNumberPrivacySettingsViewModel : ViewModel() { fun refresh() { _state.value = PhoneNumberPrivacySettingsState( phoneNumberSharing = SignalStore.phoneNumberPrivacy().isPhoneNumberSharingEnabled, - discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().isDiscoverableByPhoneNumber + discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode != PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE ) } } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/subscription/OneTimeDonationRepository.kt b/app/src/main/java/org/tm/archive/components/settings/app/subscription/OneTimeDonationRepository.kt index e818b350..a0a29791 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/subscription/OneTimeDonationRepository.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/subscription/OneTimeDonationRepository.kt @@ -21,11 +21,8 @@ import org.tm.archive.jobs.BoostReceiptRequestResponseJob import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId -import org.tm.archive.util.ProfileUtil -import org.whispersystems.signalservice.api.profiles.SignalServiceProfile import org.whispersystems.signalservice.api.services.DonationsService import org.whispersystems.signalservice.internal.push.DonationProcessor -import java.io.IOException import java.util.Currency import java.util.Locale import java.util.concurrent.CountDownLatch @@ -60,19 +57,6 @@ class OneTimeDonationRepository(private val donationsService: DonationsService) Log.w(TAG, "Invalid badge recipient $badgeRecipient. Verification failed.", true) throw DonationError.GiftRecipientVerificationError.SelectedRecipientIsInvalid } - - try { - val profile = ProfileUtil.retrieveProfileSync(ApplicationDependencies.getApplication(), recipient, SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) - if (!profile.profile.capabilities.isGiftBadges) { - Log.w(TAG, "Badge recipient does not support gifting. Verification failed.", true) - throw DonationError.GiftRecipientVerificationError.SelectedRecipientDoesNotSupportGifts - } else { - Log.d(TAG, "Badge recipient supports gifting. Verification successful.", true) - } - } catch (e: IOException) { - Log.w(TAG, "Failed to retrieve profile for recipient.", e, true) - throw DonationError.GiftRecipientVerificationError.FailedToFetchProfile(e) - } }.subscribeOn(Schedulers.io()) } } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalConfirmationResult.kt b/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalConfirmationResult.kt index f88f7ddf..d24699a6 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalConfirmationResult.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalConfirmationResult.kt @@ -7,19 +7,18 @@ import kotlinx.parcelize.Parcelize @Parcelize data class PayPalConfirmationResult( val payerId: String, - val paymentId: String, + val paymentId: String?, val paymentToken: String ) : Parcelable { companion object { private const val KEY_PAYER_ID = "PayerID" - private const val KEY_PAYMENT_ID = "paymentId" private const val KEY_PAYMENT_TOKEN = "token" fun fromUrl(url: String): PayPalConfirmationResult? { val uri = Uri.parse(url) return PayPalConfirmationResult( payerId = uri.getQueryParameter(KEY_PAYER_ID) ?: return null, - paymentId = uri.getQueryParameter(KEY_PAYMENT_ID) ?: return null, + paymentId = null, paymentToken = uri.getQueryParameter(KEY_PAYMENT_TOKEN) ?: return null ) } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalPaymentInProgressFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalPaymentInProgressFragment.kt index 25c029ac..d4674717 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalPaymentInProgressFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/paypal/PayPalPaymentInProgressFragment.kt @@ -126,7 +126,7 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog val listener = FragmentResultListener { _, bundle -> val result: PayPalConfirmationResult? = bundle.getParcelableCompat(PayPalConfirmationDialogFragment.REQUEST_KEY, PayPalConfirmationResult::class.java) if (result != null) { - emitter.onSuccess(result) + emitter.onSuccess(result.copy(paymentId = createPaymentIntentResponse.paymentId)) } else { emitter.onError(DonationError.UserCancelledPaymentError(args.request.donateToSignalType.toErrorSource())) } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/transfer/ideal/IdealTransferDetailsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/transfer/ideal/IdealTransferDetailsFragment.kt index 87b04c2d..6abc7903 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/transfer/ideal/IdealTransferDetailsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/subscription/donate/transfer/ideal/IdealTransferDetailsFragment.kt @@ -49,6 +49,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.navigation.navGraphViewModels +import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.signal.core.ui.Buttons import org.signal.core.ui.Scaffolds import org.signal.core.ui.Texts @@ -156,13 +157,30 @@ class IdealTransferDetailsFragment : ComposeFragment(), DonationCheckoutDelegate } private fun onDonateClick() { - stripePaymentViewModel.provideIDEALData(viewModel.state.value.asIDEALData()) - findNavController().safeNavigate( - IdealTransferDetailsFragmentDirections.actionBankTransferDetailsFragmentToStripePaymentInProgressFragment( - DonationProcessorAction.PROCESS_NEW_DONATION, - args.request + val state = viewModel.state.value + + val continueTransfer = { + stripePaymentViewModel.provideIDEALData(state.asIDEALData()) + findNavController().safeNavigate( + IdealTransferDetailsFragmentDirections.actionBankTransferDetailsFragmentToStripePaymentInProgressFragment( + DonationProcessorAction.PROCESS_NEW_DONATION, + args.request + ) ) - ) + } + + if (args.request.donateToSignalType == DonateToSignalType.MONTHLY) { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.IdealTransferDetailsFragment__confirm_your_donation_with_s, getString(state.idealBank!!.getUIValues().name))) + .setMessage(R.string.IdealTransferDetailsFragment__monthly_ideal_warning) + .setPositiveButton(R.string.IdealTransferDetailsFragment__continue) { _, _ -> + continueTransfer() + } + .setNegativeButton(android.R.string.cancel, null) + .show() + } else { + continueTransfer() + } } override fun onUserLaunchedAnExternalApplication() { diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/UsernameQrCodeColorScheme.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/UsernameQrCodeColorScheme.kt index 01a96936..44804001 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/UsernameQrCodeColorScheme.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/UsernameQrCodeColorScheme.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.graphics.Color enum class UsernameQrCodeColorScheme( val borderColor: Color, val foregroundColor: Color, + val backgroundColor: Color, val textColor: Color = Color.White, val outlineColor: Color = Color.Transparent, private val key: String @@ -15,11 +16,13 @@ enum class UsernameQrCodeColorScheme( Blue( borderColor = Color(0xFF506ECD), foregroundColor = Color(0xFF2449C0), + backgroundColor = Color(0xFFEDF0FA), key = "blue" ), White( borderColor = Color(0xFFFFFFFF), foregroundColor = Color(0xFF000000), + backgroundColor = Color(0xFFF5F5F5), textColor = Color.Black, outlineColor = Color(0xFFE9E9E9), key = "white" @@ -27,31 +30,37 @@ enum class UsernameQrCodeColorScheme( Grey( borderColor = Color(0xFF6A6C74), foregroundColor = Color(0xFF464852), + backgroundColor = Color(0xFFF0F0F1), key = "grey" ), Tan( borderColor = Color(0xFFBBB29A), foregroundColor = Color(0xFF73694F), + backgroundColor = Color(0xFFF6F5F2), key = "tan" ), Green( borderColor = Color(0xFF97AA89), foregroundColor = Color(0xFF55733F), + backgroundColor = Color(0xFFF2F5F0), key = "green" ), Orange( borderColor = Color(0xFFDE7134), foregroundColor = Color(0xFFDA6C2E), + backgroundColor = Color(0xFFFCF1EB), key = "orange" ), Pink( borderColor = Color(0xFFEA7B9D), foregroundColor = Color(0xFFBB617B), + backgroundColor = Color(0xFFFCF1F5), key = "pink" ), Purple( borderColor = Color(0xFF9E7BE9), foregroundColor = Color(0xFF7651C5), + backgroundColor = Color(0xFFF5F3FA), key = "purple" ); diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/QrScanResult.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/QrScanResult.kt index 8ad3da08..63d25625 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/QrScanResult.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/QrScanResult.kt @@ -13,4 +13,6 @@ sealed class QrScanResult { object InvalidData : QrScanResult() object NetworkError : QrScanResult() + + object QrNotFound : QrScanResult() } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt index 0c41c655..f49b865c 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt @@ -1,16 +1,20 @@ -@file:OptIn(ExperimentalMaterial3Api::class) +@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class) package org.tm.archive.components.settings.app.usernamelinks.main +import android.app.Activity import android.content.Intent import android.content.res.Configuration import android.graphics.Bitmap import android.os.Bundle import android.view.View +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth @@ -23,7 +27,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -39,29 +42,43 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.app.ShareCompat +import androidx.core.app.TaskStackBuilder import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.MultiplePermissionsState import com.google.accompanist.permissions.PermissionState import com.google.accompanist.permissions.PermissionStatus import com.google.accompanist.permissions.isGranted +import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.accompanist.permissions.rememberPermissionState +import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.CoroutineScope import org.signal.core.ui.Buttons import org.signal.core.ui.Dialogs +import org.signal.core.ui.Snackbars import org.signal.core.ui.theme.SignalTheme import org.signal.core.util.concurrent.LifecycleDisposable +import org.tm.archive.MainActivity import org.tm.archive.R +import org.tm.archive.components.settings.app.usernamelinks.QrCodeData +import org.tm.archive.components.settings.app.usernamelinks.QrCodeState +import org.tm.archive.components.settings.app.usernamelinks.UsernameQrCodeColorScheme import org.tm.archive.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab import org.tm.archive.compose.ComposeFragment +import org.tm.archive.permissions.PermissionCompat import org.tm.archive.providers.BlobProvider +import org.tm.archive.util.CommunicationActions import java.io.ByteArrayOutputStream import java.util.UUID @@ -71,6 +88,18 @@ class UsernameLinkSettingsFragment : ComposeFragment() { private val viewModel: UsernameLinkSettingsViewModel by viewModels() private val disposables: LifecycleDisposable = LifecycleDisposable() + private lateinit var galleryLauncher: ActivityResultLauncher + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + galleryLauncher = registerForActivityResult(UsernameQrImageSelectionActivity.Contract()) { uri -> + if (uri != null) { + viewModel.scanImage(requireContext(), uri) + } + } + } + override fun onStart() { super.onStart() setFragmentResultListener(UsernameLinkShareBottomSheet.REQUEST_KEY) { key, bundle -> @@ -80,88 +109,48 @@ class UsernameLinkSettingsFragment : ComposeFragment() { } } - @OptIn(ExperimentalMaterial3Api::class) @Composable override fun FragmentContent() { val state by viewModel.state - val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } - val scope: CoroutineScope = rememberCoroutineScope() val navController: NavController by remember { mutableStateOf(findNavController()) } - var showResetDialog: Boolean by remember { mutableStateOf(false) } - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() - val cameraPermissionState: PermissionState = rememberPermissionState(permission = android.Manifest.permission.CAMERA) val linkCopiedEvent: UUID? by viewModel.linkCopiedEvent + val helpText = stringResource(id = R.string.UsernameLinkSettings_scan_this_qr_code) - val linkCopiedString = stringResource(R.string.UsernameLinkSettings_link_copied_toast) + val cameraPermissionState: PermissionState = rememberPermissionState(permission = android.Manifest.permission.CAMERA) { + viewModel.onTabSelected(ActiveTab.Scan) + } - LaunchedEffect(linkCopiedEvent) { - if (linkCopiedEvent != null) { - snackbarHostState.showSnackbar(linkCopiedString) + val galleryPermissionState: MultiplePermissionsState = rememberMultiplePermissionsState(permissions = PermissionCompat.forImages().toList()) { grants -> + if (grants.values.all { it }) { + galleryLauncher.launch(Unit) + } else { + Toast.makeText(requireContext(), R.string.ChatWallpaperPreviewActivity__viewing_your_gallery_requires_the_storage_permission, Toast.LENGTH_SHORT).show() } } - Scaffold( - snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - topBar = { - TopAppBarContent( - activeTab = state.activeTab, - scrollBehavior = scrollBehavior, - onCodeTabSelected = { viewModel.onTabSelected(ActiveTab.Code) }, - onScanTabSelected = { viewModel.onTabSelected(ActiveTab.Scan) }, - cameraPermissionState = cameraPermissionState - ) + MainScreen( + state = state, + navController = navController, + lifecycleOwner = viewLifecycleOwner, + disposables = disposables.disposables, + cameraPermissionState = cameraPermissionState, + onCodeTabSelected = { viewModel.onTabSelected(ActiveTab.Code) }, + onScanTabSelected = { viewModel.onTabSelected(ActiveTab.Scan) }, + onUsernameLinkResetResultHandled = { viewModel.onUsernameLinkResetResultHandled() }, + onShareBadge = { shareQrBadge(requireActivity(), viewModel.generateQrCodeImage(helpText)) }, + onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) }, + onQrResultHandled = { viewModel.onQrResultHandled() }, + onOpenGalleryClicked = { + if (galleryPermissionState.allPermissionsGranted) { + galleryLauncher.launch(Unit) + } else { + galleryPermissionState.launchMultiplePermissionRequest() + } }, - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) - ) { contentPadding -> - - if (state.indeterminateProgress) { - Dialogs.IndeterminateProgressDialog() - } - - AnimatedVisibility( - visible = state.activeTab == ActiveTab.Code, - enter = slideInHorizontally(initialOffsetX = { fullWidth -> -fullWidth }), - exit = slideOutHorizontally(targetOffsetX = { fullWidth -> -fullWidth }) - ) { - UsernameLinkShareScreen( - state = state, - snackbarHostState = snackbarHostState, - scope = scope, - modifier = Modifier.padding(contentPadding), - navController = navController, - onShareBadge = { - shareQrBadge(viewModel.generateQrCodeImage()) - }, - onResetClicked = { showResetDialog = true }, - onLinkResultHandled = { viewModel.onUsernameLinkResetResultHandled() } - ) - } - - AnimatedVisibility( - visible = state.activeTab == ActiveTab.Scan, - enter = slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }), - exit = slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth }) - ) { - UsernameQrScanScreen( - lifecycleOwner = viewLifecycleOwner, - disposables = disposables.disposables, - qrScanResult = state.qrScanResult, - onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) }, - onQrResultHandled = { viewModel.onQrResultHandled() }, - modifier = Modifier.padding(contentPadding) - ) - } - } - - if (showResetDialog) { - ResetDialog( - onConfirm = { - viewModel.onUsernameLinkReset() - showResetDialog = false - }, - onDismiss = { showResetDialog = false } - ) - } + onLinkReset = { viewModel.onUsernameLinkReset() }, + onBackNavigationPressed = { requireActivity().onBackPressed() }, + linkCopiedEvent = linkCopiedEvent + ) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -172,153 +161,278 @@ class UsernameLinkSettingsFragment : ComposeFragment() { super.onResume() viewModel.onResume() } +} - @OptIn(ExperimentalMaterial3Api::class) - @Composable - private fun TopAppBarContent( - activeTab: ActiveTab, - scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), - onCodeTabSelected: () -> Unit = {}, - onScanTabSelected: () -> Unit = {}, - cameraPermissionState: PermissionState = previewPermissionState() - ) { - CenterAlignedTopAppBar( - modifier = Modifier - .fillMaxWidth(), - title = { - Row( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - TabButton( - label = stringResource(R.string.UsernameLinkSettings_code_tab_name), - active = activeTab == ActiveTab.Code, - onClick = onCodeTabSelected, - modifier = Modifier.padding(end = 8.dp) - ) - TabButton( - label = stringResource(R.string.UsernameLinkSettings_scan_tab_name), - active = activeTab == ActiveTab.Scan, - onClick = { - if (cameraPermissionState.status.isGranted) { - onScanTabSelected() - } else { - cameraPermissionState.launchPermissionRequest() - } - }, - modifier = Modifier.padding(end = 8.dp) - ) - } - }, - navigationIcon = { - IconButton( - onClick = { requireActivity().onBackPressed() } - ) { - Icon( - painter = painterResource(R.drawable.symbol_x_24), - contentDescription = stringResource(android.R.string.cancel) - ) - } - }, - scrollBehavior = scrollBehavior - ) +@OptIn(ExperimentalPermissionsApi::class) +@Composable +private fun MainScreen( + state: UsernameLinkSettingsState, + navController: NavController? = null, + lifecycleOwner: LifecycleOwner = previewLifecycleOwner, + disposables: CompositeDisposable = CompositeDisposable(), + cameraPermissionState: PermissionState = previewPermissionState(), + onCodeTabSelected: () -> Unit = {}, + onScanTabSelected: () -> Unit = {}, + onUsernameLinkResetResultHandled: () -> Unit = {}, + onShareBadge: () -> Unit = {}, + onQrCodeScanned: (String) -> Unit = {}, + onQrResultHandled: () -> Unit = {}, + onOpenGalleryClicked: () -> Unit = {}, + onLinkReset: () -> Unit = {}, + onBackNavigationPressed: () -> Unit = {}, + linkCopiedEvent: UUID? = null +) { + val context = LocalContext.current + + val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } + val scope: CoroutineScope = rememberCoroutineScope() + var showResetDialog: Boolean by remember { mutableStateOf(false) } + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + + val linkCopiedString = stringResource(R.string.UsernameLinkSettings_link_copied_toast) + + LaunchedEffect(linkCopiedEvent) { + if (linkCopiedEvent != null) { + snackbarHostState.showSnackbar(linkCopiedString) + } } - @Composable - private fun TabButton(label: String, active: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { - val colors = if (active) { - ButtonDefaults.filledTonalButtonColors() - } else { - ButtonDefaults.buttonColors( - containerColor = SignalTheme.colors.colorSurface2, - contentColor = MaterialTheme.colorScheme.onSurface + Scaffold( + snackbarHost = { Snackbars.Host(snackbarHostState) }, + topBar = { + TopAppBarContent( + activeTab = state.activeTab, + scrollBehavior = scrollBehavior, + onCodeTabSelected = onCodeTabSelected, + onScanTabSelected = onScanTabSelected, + cameraPermissionState = cameraPermissionState, + onBackNavigationPressed = onBackNavigationPressed + ) + }, + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) + ) { contentPadding -> + + if (state.indeterminateProgress) { + Dialogs.IndeterminateProgressDialog() + } + + AnimatedVisibility( + visible = state.activeTab == ActiveTab.Code, + enter = slideInHorizontally(initialOffsetX = { fullWidth -> -fullWidth }), + exit = slideOutHorizontally(targetOffsetX = { fullWidth -> -fullWidth }) + ) { + UsernameLinkShareScreen( + state = state, + snackbarHostState = snackbarHostState, + scope = scope, + modifier = Modifier.padding(contentPadding), + navController = navController, + onShareBadge = onShareBadge, + onResetClicked = { showResetDialog = true }, + onLinkResultHandled = onUsernameLinkResetResultHandled ) } - Buttons.Small( - onClick = onClick, - modifier = modifier.defaultMinSize(minWidth = 100.dp), - shape = RoundedCornerShape(12.dp), - colors = colors + + AnimatedVisibility( + visible = state.activeTab == ActiveTab.Scan, + enter = slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }), + exit = slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth }) ) { - Text(label) + UsernameQrScanScreen( + lifecycleOwner = lifecycleOwner, + disposables = disposables, + qrScanResult = state.qrScanResult, + onQrCodeScanned = onQrCodeScanned, + onQrResultHandled = onQrResultHandled, + onOpenGalleryClicked = onOpenGalleryClicked, + modifier = Modifier.padding(contentPadding), + onRecipientFound = { recipient -> + val taskStack = TaskStackBuilder + .create(context) + .addNextIntent(MainActivity.clearTop(context)) + + CommunicationActions.startConversation(context, recipient, null, taskStack) + } + ) } } - @Composable - private fun ResetDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) { - Dialogs.SimpleAlertDialog( - title = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_title), - body = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_body), - confirm = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_confirm_button), - dismiss = stringResource(id = android.R.string.cancel), - onConfirm = onConfirm, - onDismiss = onDismiss + if (showResetDialog) { + ResetDialog( + onConfirm = { + onLinkReset() + showResetDialog = false + }, + onDismiss = { showResetDialog = false } ) } +} - @Preview - @Composable - private fun PreviewAppBar() { - SignalTheme { - Surface { +@Composable +private fun TopAppBarContent( + activeTab: ActiveTab, + scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), + onCodeTabSelected: () -> Unit = {}, + onScanTabSelected: () -> Unit = {}, + cameraPermissionState: PermissionState = previewPermissionState(), + onBackNavigationPressed: () -> Unit = {} +) { + CenterAlignedTopAppBar( + modifier = Modifier + .fillMaxWidth(), + title = { + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + TabButton( + label = stringResource(R.string.UsernameLinkSettings_code_tab_name), + active = activeTab == ActiveTab.Code, + onClick = onCodeTabSelected, + modifier = Modifier.padding(end = 8.dp) + ) + TabButton( + label = stringResource(R.string.UsernameLinkSettings_scan_tab_name), + active = activeTab == ActiveTab.Scan, + onClick = { + if (cameraPermissionState.status.isGranted) { + onScanTabSelected() + } else { + cameraPermissionState.launchPermissionRequest() + } + }, + modifier = Modifier.padding(end = 8.dp) + ) + } + }, + navigationIcon = { + IconButton( + onClick = onBackNavigationPressed + ) { + Icon( + painter = painterResource(R.drawable.symbol_x_24), + contentDescription = stringResource(android.R.string.cancel) + ) + } + }, + scrollBehavior = scrollBehavior + ) +} + +@Composable +private fun TabButton(label: String, active: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { + val colors = if (active) { + ButtonDefaults.filledTonalButtonColors() + } else { + ButtonDefaults.buttonColors( + containerColor = SignalTheme.colors.colorSurface2, + contentColor = MaterialTheme.colorScheme.onSurface + ) + } + Buttons.Small( + onClick = onClick, + modifier = modifier.defaultMinSize(minWidth = 100.dp), + shape = RoundedCornerShape(12.dp), + colors = colors + ) { + Text(label) + } +} + +@Composable +private fun ResetDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) { + Dialogs.SimpleAlertDialog( + title = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_title), + body = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_body), + confirm = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_confirm_button), + dismiss = stringResource(id = android.R.string.cancel), + onConfirm = onConfirm, + onDismiss = onDismiss + ) +} + +@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun AppBarPreview() { + SignalTheme { + Surface { + Column { TopAppBarContent(activeTab = ActiveTab.Code) + TopAppBarContent(activeTab = ActiveTab.Scan) } } } - - @Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO) - @Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) - @Composable - private fun PreviewAll() { - FragmentContent() - } - - @Preview - @Composable - private fun PreviewResetDialog() { - SignalTheme { - Surface { - ResetDialog(onConfirm = {}, onDismiss = {}) - } - } - } - - private fun previewPermissionState(): PermissionState { - return object : PermissionState { - override val permission: String = "" - override val status: PermissionStatus = PermissionStatus.Granted - override fun launchPermissionRequest() = Unit - } - } - - private fun shareQrBadge(badge: Bitmap?) { - if (badge == null) { - return - } - - try { - ByteArrayOutputStream().use { byteArrayOutputStream -> - badge.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) - byteArrayOutputStream.flush() - val bytes = byteArrayOutputStream.toByteArray() - val shareUri = BlobProvider.getInstance() - .forData(bytes) - .withMimeType("image/png") - .withFileName("SignalGroupQr.png") - .createForSingleSessionInMemory() - - val intent = ShareCompat.IntentBuilder.from(requireActivity()) - .setType("image/png") - .setStream(shareUri) - .createChooserIntent() - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - - startActivity(intent) - } - } finally { - badge.recycle() - } - } +} + +@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun MainScreenPreview() { + SignalTheme { + MainScreen( + state = UsernameLinkSettingsState( + activeTab = ActiveTab.Code, + username = "PeterParker.42", + usernameLinkState = UsernameLinkState.Present("https://signal.org"), + qrCodeState = QrCodeState.Present(QrCodeData.forData("PeterParker.42", 64)), + qrCodeColorScheme = UsernameQrCodeColorScheme.Orange + ) + ) + } +} + +@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ResetDialogPreview() { + SignalTheme { + Surface { + ResetDialog(onConfirm = {}, onDismiss = {}) + } + } +} + +private fun previewPermissionState(): PermissionState { + return object : PermissionState { + override val permission: String = "" + override val status: PermissionStatus = PermissionStatus.Granted + override fun launchPermissionRequest() = Unit + } +} + +private val previewLifecycleOwner: LifecycleOwner = object : LifecycleOwner { + override val lifecycle: Lifecycle + get() = throw UnsupportedOperationException("Only for tests") +} + +private fun shareQrBadge(activity: Activity, badge: Bitmap?) { + if (badge == null) { + return + } + + try { + ByteArrayOutputStream().use { byteArrayOutputStream -> + badge.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) + byteArrayOutputStream.flush() + val bytes = byteArrayOutputStream.toByteArray() + val shareUri = BlobProvider.getInstance() + .forData(bytes) + .withMimeType("image/png") + .withFileName("SignalGroupQr.png") + .createForSingleSessionInMemory() + + val intent = ShareCompat.IntentBuilder(activity) + .setType("image/png") + .setStream(shareUri) + .createChooserIntent() + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + + activity.startActivity(intent) + } + } finally { + badge.recycle() + } } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt index 16f2ade6..f1e9f331 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt @@ -1,5 +1,6 @@ package org.tm.archive.components.settings.app.usernamelinks.main +import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Color @@ -9,7 +10,11 @@ import android.graphics.PorterDuffColorFilter import android.graphics.Rect import android.graphics.RectF import android.graphics.Typeface +import android.net.Uri import android.os.Build +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf @@ -17,13 +22,16 @@ import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Canvas import androidx.compose.ui.graphics.drawscope.CanvasDrawScope import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.graphics.withSave import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.LayoutDirection +import androidx.core.graphics.withTranslation import androidx.lifecycle.ViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign +import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.subjects.BehaviorSubject import org.signal.core.util.logging.Log @@ -36,7 +44,6 @@ import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.keyvalue.SignalStore import org.tm.archive.profiles.manage.UsernameRepository import org.tm.archive.profiles.manage.UsernameRepository.toLink -import org.tm.archive.recipients.Recipient import org.tm.archive.util.NetworkUtil import org.whispersystems.signalservice.api.push.UsernameLinkComponents import java.util.Optional @@ -122,7 +129,9 @@ class UsernameLinkSettingsViewModel : ViewModel() { val components: Optional = when (result) { is UsernameLinkResetResult.Success -> Optional.of(result.components) is UsernameLinkResetResult.NetworkError -> Optional.empty() - else -> { usernameLink.value ?: Optional.empty() } + else -> { + usernameLink.value ?: Optional.empty() + } } _state.value = _state.value.copy( @@ -157,16 +166,7 @@ class UsernameLinkSettingsViewModel : ViewModel() { indeterminateProgress = true ) - disposable += UsernameRepository.fetchUsernameAndAciFromLink(url) - .map { result -> - when (result) { - is UsernameRepository.UsernameLinkConversionResult.Success -> QrScanResult.Success(Recipient.externalUsername(result.aci, result.username.toString())) - is UsernameRepository.UsernameLinkConversionResult.Invalid -> QrScanResult.InvalidData - is UsernameRepository.UsernameLinkConversionResult.NotFound -> QrScanResult.NotFound(result.username?.toString()) - is UsernameRepository.UsernameLinkConversionResult.NetworkError -> QrScanResult.NetworkError - } - } - .subscribeOn(Schedulers.io()) + disposable += UsernameQrScanRepository.lookupUsernameUrl(url) .observeOn(AndroidSchedulers.mainThread()) .subscribe { result -> _state.value = _state.value.copy( @@ -186,6 +186,21 @@ class UsernameLinkSettingsViewModel : ViewModel() { _linkCopiedEvent.value = UUID.randomUUID() } + fun scanImage(context: Context, uri: Uri) { + _state.value = _state.value.copy( + indeterminateProgress = true + ) + + disposable += UsernameQrScanRepository.scanImageUriForQrCode(context, uri) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy { result -> + _state.value = _state.value.copy( + qrScanResult = result, + indeterminateProgress = false + ) + } + } + private fun generateQrCodeData(url: Optional): Single> { return Single.fromCallable { url.map { QrCodeData.forData(it, 64) } @@ -200,7 +215,7 @@ class UsernameLinkSettingsViewModel : ViewModel() { * * I hate this as much as you do. */ - fun generateQrCodeImage(): Bitmap? { + fun generateQrCodeImage(helpText: String): Bitmap? { val state: UsernameLinkSettingsState = _state.value if (state.qrCodeState !is QrCodeState.Present) { @@ -210,12 +225,23 @@ class UsernameLinkSettingsViewModel : ViewModel() { val qrCodeData: QrCodeData = state.qrCodeState.data - val width = 480 - val height = 525 - val qrSize = 300f - val qrPadding = 25f - val borderSizeX = 64f - val borderSizeY = 52f + val scaleFactor = 2 + val width = 424 * scaleFactor + val height = 576 * scaleFactor + val backgroundPadHorizontal = 64f * scaleFactor + val backgroundPadVertical = 80f * scaleFactor + val qrBorderWidth = width - (backgroundPadHorizontal * 2) + val qrBorderHeight = 324f * scaleFactor + val qrBorderRadius = 30f * scaleFactor + val qrSize = 184f * scaleFactor + val qrPadding = 16f * scaleFactor + val borderSizeX = 40f * scaleFactor + val borderSizeY = 32f * scaleFactor + val helpTextHorizontalPad = 72 * scaleFactor + val helpTextVerticalPad = 444f * scaleFactor + val helpTextSize = 14f * scaleFactor + val usernameVerticalPad = 348f * scaleFactor + val usernameTextSize = 20f * scaleFactor val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).apply { eraseColor(Color.TRANSPARENT) @@ -225,43 +251,51 @@ class UsernameLinkSettingsViewModel : ViewModel() { val composeCanvas = Canvas(androidCanvas) val canvasDrawScope = CanvasDrawScope() - // Draw the background - androidCanvas.drawRoundRect(0f, 0f, width.toFloat(), height.toFloat(), 30f, 30f, Paint().apply { color = state.qrCodeColorScheme.borderColor.toArgb() }) - androidCanvas.drawRoundRect(borderSizeX, borderSizeY, borderSizeX + qrSize + qrPadding * 2, borderSizeY + qrSize + qrPadding * 2, 15f, 15f, Paint().apply { color = Color.WHITE }) - androidCanvas.drawRoundRect( - borderSizeX, - borderSizeY, - borderSizeX + qrSize + qrPadding * 2, - borderSizeY + qrSize + qrPadding * 2, - 15f, - 15f, - Paint().apply { - color = state.qrCodeColorScheme.outlineColor.toArgb() - style = Paint.Style.STROKE - strokeWidth = 4f - } - ) + // Background + androidCanvas.drawColor(state.qrCodeColorScheme.backgroundColor.toArgb()) - // Draw the QR code - composeCanvas.translate((width / 2) - (qrSize / 2), 80f) - canvasDrawScope.draw( - density = object : Density { - override val density: Float = 1f - override val fontScale: Float = 1f - }, - layoutDirection = LayoutDirection.Ltr, - canvas = composeCanvas, - size = Size(qrSize, qrSize) - ) { - drawQr( - data = qrCodeData, - foregroundColor = state.qrCodeColorScheme.foregroundColor, - backgroundColor = state.qrCodeColorScheme.borderColor, - deadzonePercent = 0.35f, - logo = null + // QR Border + androidCanvas.withTranslation(x = backgroundPadHorizontal, y = backgroundPadVertical) { + drawRoundRect(0f, 0f, qrBorderWidth, qrBorderHeight, qrBorderRadius, qrBorderRadius, Paint().apply { color = state.qrCodeColorScheme.borderColor.toArgb() }) + + drawRoundRect(borderSizeX, borderSizeY, borderSizeX + qrSize + qrPadding * 2, borderSizeY + qrSize + qrPadding * 2, 15f, 15f, Paint().apply { color = Color.WHITE }) + drawRoundRect( + borderSizeX, + borderSizeY, + borderSizeX + qrSize + qrPadding * 2, + borderSizeY + qrSize + qrPadding * 2, + 15f * scaleFactor, + 15f * scaleFactor, + Paint().apply { + color = state.qrCodeColorScheme.outlineColor.toArgb() + style = Paint.Style.STROKE + strokeWidth = 4f + } ) + + // Draw the QR code + composeCanvas.withSave { + composeCanvas.translate((qrBorderWidth / 2) - (qrSize / 2), borderSizeY + qrPadding) + + canvasDrawScope.draw( + density = object : Density { + override val density: Float = 1f + override val fontScale: Float = 1f + }, + layoutDirection = LayoutDirection.Ltr, + canvas = composeCanvas, + size = Size(qrSize, qrSize) + ) { + drawQr( + data = qrCodeData, + foregroundColor = state.qrCodeColorScheme.foregroundColor, + backgroundColor = state.qrCodeColorScheme.borderColor, + deadzonePercent = 0.35f, + logo = null + ) + } + } } - composeCanvas.translate(-90f, -80f) // Draw the signal logo -- unfortunately can't have the normal QR code drawing handle it because it requires a composable ImageBitmap BitmapFactory.decodeResource(ApplicationDependencies.getApplication().resources, R.drawable.qrcode_logo).also { logoBitmap -> @@ -269,14 +303,18 @@ class UsernameLinkSettingsViewModel : ViewModel() { colorFilter = PorterDuffColorFilter(state.qrCodeColorScheme.foregroundColor.toArgb(), PorterDuff.Mode.SRC_IN) } val sourceRect = Rect(0, 0, logoBitmap.width, logoBitmap.height) - val destRect = RectF(210f, 200f, 270f, 260f) + + val logoSize = 36f * scaleFactor + val destLeft = (width / 2f) - (logoSize / 2f) + val destTop = destLeft - (10f * scaleFactor) + (logoSize / 2f) + val destRect = RectF(destLeft, destTop, destLeft + logoSize, destTop + logoSize) androidCanvas.drawBitmap(logoBitmap, sourceRect, destRect, tintedPaint) } - // Draw the text - val textPaint = Paint().apply { + // Draw the username + val usernamePaint = TextPaint().apply { color = state.qrCodeColorScheme.textColor.toArgb() - textSize = 34f + textSize = usernameTextSize typeface = if (Build.VERSION.SDK_INT < 26) { Typeface.DEFAULT_BOLD } else { @@ -286,10 +324,40 @@ class UsernameLinkSettingsViewModel : ViewModel() { .build() } } - val textBounds = Rect() - textPaint.getTextBounds(state.username, 0, state.username.length, textBounds) - androidCanvas.drawText(state.username, (width / 2f) - (textBounds.width() / 2f), 465f, textPaint) + val usernameMaxWidth = qrBorderWidth - borderSizeX * 2f + val usernameLayout = StaticLayout(state.username, usernamePaint, usernameMaxWidth.toInt(), Layout.Alignment.ALIGN_CENTER, 1f, 0f, true) + val usernameVerticalOffset = when (usernameLayout.lineCount) { + 1 -> 0f + 2 -> usernameTextSize / 2f + else -> usernameTextSize + } + + androidCanvas.withTranslation(x = backgroundPadHorizontal + borderSizeX, y = usernameVerticalPad - usernameVerticalOffset) { + usernameLayout.draw(this) + } + + // Draw the help text + val helpTextPaint = TextPaint().apply { + isAntiAlias = true + color = 0xFF3C3C43.toInt() + textSize = helpTextSize + typeface = if (Build.VERSION.SDK_INT < 26) { + Typeface.DEFAULT + } else { + Typeface.Builder("") + .setFallback("sans-serif") + .setWeight(400) + .build() + } + } + + val maxWidth = width - helpTextHorizontalPad * 2 + val helpTextLayout = StaticLayout(helpText, helpTextPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1f, 0f, true) + + androidCanvas.withTranslation(x = helpTextHorizontalPad.toFloat(), y = helpTextVerticalPad) { + helpTextLayout.draw(androidCanvas) + } return bitmap } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkShareScreen.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkShareScreen.kt index 58c44234..64a6fc2e 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkShareScreen.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameLinkShareScreen.kt @@ -44,6 +44,8 @@ import org.tm.archive.components.settings.app.usernamelinks.UsernameQrCodeColorS import org.tm.archive.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab import org.tm.archive.util.Util import org.tm.archive.util.navigation.safeNavigate +import org.whispersystems.signalservice.api.push.UsernameLinkComponents +import java.util.UUID /** * A screen that shows all the data around your username link and how to share it, including a QR code. @@ -54,7 +56,7 @@ fun UsernameLinkShareScreen( onLinkResultHandled: () -> Unit, snackbarHostState: SnackbarHostState, scope: CoroutineScope, - navController: NavController, + navController: NavController?, onShareBadge: () -> Unit, modifier: Modifier = Modifier, onResetClicked: () -> Unit @@ -68,6 +70,12 @@ fun UsernameLinkShareScreen( UsernameLinkResetResult.NetworkError -> { ResetLinkResultDialog(stringResource(R.string.UsernameLinkSettings_reset_link_result_network_error), onDismiss = onLinkResultHandled) } + UsernameLinkResetResult.UnexpectedError -> { + ResetLinkResultDialog(stringResource(R.string.UsernameLinkSettings_reset_link_result_unknown_error), onDismiss = onLinkResultHandled) + } + is UsernameLinkResetResult.Success -> { + ResetLinkResultDialog(stringResource(R.string.UsernameLinkSettings_reset_link_result_success), onDismiss = onLinkResultHandled) + } else -> {} } @@ -93,21 +101,18 @@ fun UsernameLinkShareScreen( ButtonBar( onShareClicked = onShareBadge, - onColorClicked = { navController.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkQrColorPickerFragment()) } - ) - - LinkRow( - linkState = state.usernameLinkState, - onClick = { - navController.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkShareBottomSheet()) - } + onColorClicked = { navController?.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkQrColorPickerFragment()) }, + onLinkClicked = { + navController?.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkShareBottomSheet()) + }, + linkState = state.usernameLinkState ) Text( text = stringResource(id = R.string.UsernameLinkSettings_qr_description), textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyMedium, - modifier = Modifier.padding(bottom = 19.dp, start = 43.dp, end = 43.dp), + modifier = Modifier.padding(top = 42.dp, bottom = 19.dp, start = 43.dp, end = 43.dp), color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -127,11 +132,22 @@ fun UsernameLinkShareScreen( } @Composable -private fun ButtonBar(onShareClicked: () -> Unit, onColorClicked: () -> Unit) { +private fun ButtonBar( + linkState: UsernameLinkState, + onLinkClicked: () -> Unit, + onShareClicked: () -> Unit, + onColorClicked: () -> Unit +) { Row( horizontalArrangement = Arrangement.spacedBy(space = 32.dp, alignment = Alignment.CenterHorizontally), modifier = Modifier.fillMaxWidth() ) { + Buttons.ActionButton( + enabled = linkState is UsernameLinkState.Present, + onClick = onLinkClicked, + iconResId = R.drawable.symbol_link_24, + labelResId = R.string.UsernameLinkSettings_link_button_label + ) Buttons.ActionButton( onClick = onShareClicked, iconResId = R.drawable.symbol_share_android_24, @@ -215,6 +231,82 @@ private fun ScreenPreview() { } } +@Preview(name = "Light Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewResetSuccess() { + SignalTheme { + Surface { + UsernameLinkShareScreen( + state = previewState().copy(usernameLinkResetResult = UsernameLinkResetResult.Success(UsernameLinkComponents(Util.getSecretBytes(32), UUID.randomUUID()))), + snackbarHostState = SnackbarHostState(), + scope = rememberCoroutineScope(), + navController = NavController(LocalContext.current), + onShareBadge = {}, + onResetClicked = {}, + onLinkResultHandled = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewResetNetworkError() { + SignalTheme { + Surface { + UsernameLinkShareScreen( + state = previewState().copy(usernameLinkResetResult = UsernameLinkResetResult.NetworkError), + snackbarHostState = SnackbarHostState(), + scope = rememberCoroutineScope(), + navController = NavController(LocalContext.current), + onShareBadge = {}, + onResetClicked = {}, + onLinkResultHandled = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewResetNetworkUnavailable() { + SignalTheme { + Surface { + UsernameLinkShareScreen( + state = previewState().copy(usernameLinkResetResult = UsernameLinkResetResult.NetworkUnavailable), + snackbarHostState = SnackbarHostState(), + scope = rememberCoroutineScope(), + navController = NavController(LocalContext.current), + onShareBadge = {}, + onResetClicked = {}, + onLinkResultHandled = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ScreenPreviewResetUnexpectedError() { + SignalTheme { + Surface { + UsernameLinkShareScreen( + state = previewState().copy(usernameLinkResetResult = UsernameLinkResetResult.UnexpectedError), + snackbarHostState = SnackbarHostState(), + scope = rememberCoroutineScope(), + navController = NavController(LocalContext.current), + onShareBadge = {}, + onResetClicked = {}, + onLinkResultHandled = {} + ) + } + } +} + @Preview(name = "Light Theme", group = "LinkRow", uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(name = "Dark Theme", group = "LinkRow", uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrImageSelectionActivity.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrImageSelectionActivity.kt new file mode 100644 index 00000000..dac932fe --- /dev/null +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrImageSelectionActivity.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.components.settings.app.usernamelinks.main + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.view.WindowManager +import androidx.activity.result.contract.ActivityResultContract +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDelegate +import org.tm.archive.R +import org.tm.archive.mediasend.Media +import org.tm.archive.mediasend.v2.gallery.MediaGalleryFragment + +/** + * Select username qr code from gallery instead of using camera. + */ +class UsernameQrImageSelectionActivity : AppCompatActivity(), MediaGalleryFragment.Callbacks { + + override fun attachBaseContext(newBase: Context) { + delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES + super.attachBaseContext(newBase) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN) + setContentView(R.layout.username_qr_image_selection_activity) + } + + @SuppressLint("LogTagInlined") + override fun onMediaSelected(media: Media) { + setResult(RESULT_OK, Intent().setData(media.uri)) + finish() + } + + override fun onToolbarNavigationClicked() { + setResult(RESULT_CANCELED) + finish() + } + + override fun isCameraEnabled() = false + override fun isMultiselectEnabled() = false + + class Contract : ActivityResultContract() { + override fun createIntent(context: Context, input: Unit): Intent { + return Intent(context, UsernameQrImageSelectionActivity::class.java) + } + + override fun parseResult(resultCode: Int, intent: Intent?): Uri? { + return if (resultCode == RESULT_OK) { + intent?.data + } else { + null + } + } + } +} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt new file mode 100644 index 00000000..173e6cf5 --- /dev/null +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.components.settings.app.usernamelinks.main + +import android.content.Context +import android.net.Uri +import com.bumptech.glide.Glide +import com.bumptech.glide.load.DecodeFormat +import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.kotlin.plusAssign +import io.reactivex.rxjava3.schedulers.Schedulers +import org.signal.core.util.toOptional +import org.signal.qr.QrProcessor +import org.tm.archive.profiles.manage.UsernameRepository +import org.tm.archive.recipients.Recipient + +/** + * A collection of functions to help with scanning QR codes for usernames. + */ +object UsernameQrScanRepository { + + /** + * Given a URL, will attempt to lookup the username, coercing it to a standard set of [QrScanResult]s. + */ + fun lookupUsernameUrl(url: String): Single { + return UsernameRepository.fetchUsernameAndAciFromLink(url) + .map { result -> + when (result) { + is UsernameRepository.UsernameLinkConversionResult.Success -> QrScanResult.Success(Recipient.externalUsername(result.aci, result.username.toString())) + is UsernameRepository.UsernameLinkConversionResult.Invalid -> QrScanResult.InvalidData + is UsernameRepository.UsernameLinkConversionResult.NotFound -> QrScanResult.NotFound(result.username?.toString()) + is UsernameRepository.UsernameLinkConversionResult.NetworkError -> QrScanResult.NetworkError + } + } + .subscribeOn(Schedulers.io()) + } + + /** + * Given a URI pointing to an image that may contain a username QR code, this will attempt to lookup the username, coercing it to a standard set of [QrScanResult]s. + */ + fun scanImageUriForQrCode(context: Context, uri: Uri): Single { + val loadBitmap = Glide.with(context) + .asBitmap() + .format(DecodeFormat.PREFER_ARGB_8888) + .load(uri) + .submit() + + return Single.fromFuture(loadBitmap) + .map { QrProcessor().getScannedData(it).toOptional() } + .flatMap { + if (it.isPresent) { + lookupUsernameUrl(it.get()) + } else { + Single.just(QrScanResult.QrNotFound) + } + } + .subscribeOn(Schedulers.io()) + } +} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanScreen.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanScreen.kt index 95317706..b074d3a1 100644 --- a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanScreen.kt +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScanScreen.kt @@ -1,26 +1,30 @@ package org.tm.archive.components.settings.app.usernamelinks.main +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.DrawScope -import androidx.compose.ui.graphics.drawscope.Fill import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -28,10 +32,11 @@ import androidx.lifecycle.LifecycleOwner import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import org.signal.core.ui.Dialogs +import org.signal.core.ui.theme.SignalTheme import org.signal.qr.QrScannerView import org.tm.archive.R import org.tm.archive.mediasend.camerax.CameraXModelBlocklist -import org.tm.archive.util.CommunicationActions +import org.tm.archive.recipients.Recipient import java.util.concurrent.TimeUnit /** @@ -44,26 +49,41 @@ fun UsernameQrScanScreen( qrScanResult: QrScanResult?, onQrCodeScanned: (String) -> Unit, onQrResultHandled: () -> Unit, + onOpenGalleryClicked: () -> Unit, + onRecipientFound: (Recipient) -> Unit, modifier: Modifier = Modifier ) { + val path = remember { Path() } + when (qrScanResult) { QrScanResult.InvalidData -> { - QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_invalid), onDismiss = onQrResultHandled) + QrScanResultDialog(message = stringResource(R.string.UsernameLinkSettings_qr_result_invalid), onDismiss = onQrResultHandled) } + QrScanResult.NetworkError -> { - QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_network_error), onDismiss = onQrResultHandled) + QrScanResultDialog(message = stringResource(R.string.UsernameLinkSettings_qr_result_network_error), onDismiss = onQrResultHandled) } + + QrScanResult.QrNotFound -> { + QrScanResultDialog( + title = stringResource(R.string.UsernameLinkSettings_qr_code_not_found), + message = stringResource(R.string.UsernameLinkSettings_try_scanning_another_image_containing_a_signal_qr_code), + onDismiss = onQrResultHandled + ) + } + is QrScanResult.NotFound -> { if (qrScanResult.username != null) { - QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_not_found, qrScanResult.username), onDismiss = onQrResultHandled) + QrScanResultDialog(message = stringResource(R.string.UsernameLinkSettings_qr_result_not_found, qrScanResult.username), onDismiss = onQrResultHandled) } else { - QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_not_found_no_username), onDismiss = onQrResultHandled) + QrScanResultDialog(message = stringResource(R.string.UsernameLinkSettings_qr_result_not_found_no_username), onDismiss = onQrResultHandled) } } + is QrScanResult.Success -> { - CommunicationActions.startConversation(LocalContext.current, qrScanResult.recipient, null) - onQrResultHandled() + onRecipientFound(qrScanResult.recipient) } + null -> {} } @@ -72,25 +92,46 @@ fun UsernameQrScanScreen( .fillMaxWidth() .fillMaxHeight() ) { - AndroidView( - factory = { context -> - val view = QrScannerView(context) - disposables += view.qrData.throttleFirst(3000, TimeUnit.MILLISECONDS).subscribe { data -> - onQrCodeScanned(data) - } - view - }, - update = { view -> - view.start(lifecycleOwner = lifecycleOwner, forceLegacy = CameraXModelBlocklist.isBlocklisted()) - }, + Box( modifier = Modifier .fillMaxWidth() .weight(1f, true) - .drawWithContent { - drawContent() - drawQrCrosshair() - } - ) + ) { + AndroidView( + factory = { context -> + val view = QrScannerView(context) + disposables += view.qrData.throttleFirst(3000, TimeUnit.MILLISECONDS).subscribe { data -> + onQrCodeScanned(data) + } + view + }, + update = { view -> + view.start(lifecycleOwner = lifecycleOwner, forceLegacy = CameraXModelBlocklist.isBlocklisted()) + }, + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + .drawWithContent { + drawContent() + drawQrCrosshair(path) + } + ) + + FloatingActionButton( + shape = CircleShape, + containerColor = SignalTheme.colors.colorSurface1, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 24.dp), + onClick = onOpenGalleryClicked + ) { + Image( + painter = painterResource(id = R.drawable.symbol_album_24), + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface) + ) + } + } Row( modifier = Modifier @@ -109,41 +150,48 @@ fun UsernameQrScanScreen( } @Composable -private fun QrScanResultDialog(message: String, onDismiss: () -> Unit) { +private fun QrScanResultDialog(title: String? = null, message: String, onDismiss: () -> Unit) { Dialogs.SimpleMessageDialog( + title = title, message = message, dismiss = stringResource(id = android.R.string.ok), onDismiss = onDismiss ) } -private fun DrawScope.drawQrCrosshair() { +private fun DrawScope.drawQrCrosshair(path: Path) { val crosshairWidth: Float = size.minDimension * 0.6f - val clearWidth: Float = crosshairWidth * 0.75f + val crosshairLineLength = crosshairWidth * 0.125f - // Draw a full white rounded rect... - drawRoundRect( - color = Color.White, - topLeft = center - Offset(crosshairWidth / 2, crosshairWidth / 2), - style = Stroke(width = 3.dp.toPx()), - size = Size(crosshairWidth, crosshairWidth), - cornerRadius = CornerRadius(10.dp.toPx(), 10.dp.toPx()) - ) + val topLeft = center - Offset(crosshairWidth / 2, crosshairWidth / 2) + val topRight = center + Offset(crosshairWidth / 2, -crosshairWidth / 2) + val bottomRight = center + Offset(crosshairWidth / 2, crosshairWidth / 2) + val bottomLeft = center + Offset(-crosshairWidth / 2, crosshairWidth / 2) - // ...then cut out the middle parts with BlendMode.Clear to leave us with just the corners - drawRect( - color = Color.White, - topLeft = Offset(center.x - clearWidth / 2, 0f), - style = Fill, - size = Size(clearWidth, size.height), - blendMode = BlendMode.Clear - ) + path.reset() - drawRect( + drawPath( + path = path.apply { + moveTo(topLeft.x, topLeft.y + crosshairLineLength) + lineTo(topLeft.x, topLeft.y) + lineTo(topLeft.x + crosshairLineLength, topLeft.y) + + moveTo(topRight.x - crosshairLineLength, topRight.y) + lineTo(topRight.x, topRight.y) + lineTo(topRight.x, topRight.y + crosshairLineLength) + + moveTo(bottomRight.x, bottomRight.y - crosshairLineLength) + lineTo(bottomRight.x, bottomRight.y) + lineTo(bottomRight.x - crosshairLineLength, bottomRight.y) + + moveTo(bottomLeft.x + crosshairLineLength, bottomLeft.y) + lineTo(bottomLeft.x, bottomLeft.y) + lineTo(bottomLeft.x, bottomLeft.y - crosshairLineLength) + }, color = Color.White, - topLeft = Offset(0f, center.y - clearWidth / 2), - style = Fill, - size = Size(size.width, clearWidth), - blendMode = BlendMode.Clear + style = Stroke( + width = 3.dp.toPx(), + pathEffect = PathEffect.cornerPathEffect(10.dp.toPx()) + ) ) } diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScannerActivity.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScannerActivity.kt new file mode 100644 index 00000000..f11c35ec --- /dev/null +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScannerActivity.kt @@ -0,0 +1,167 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +@file:OptIn(ExperimentalPermissionsApi::class) + +package org.tm.archive.components.settings.app.usernamelinks.main + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContract +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.LifecycleOwner +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.MultiplePermissionsState +import com.google.accompanist.permissions.rememberMultiplePermissionsState +import io.reactivex.rxjava3.disposables.CompositeDisposable +import org.signal.core.ui.Dialogs +import org.signal.core.ui.theme.SignalTheme +import org.signal.core.util.concurrent.LifecycleDisposable +import org.signal.core.util.getParcelableExtraCompat +import org.tm.archive.R +import org.tm.archive.permissions.PermissionCompat +import org.tm.archive.recipients.Recipient +import org.tm.archive.recipients.RecipientId +import org.tm.archive.util.DynamicTheme + +/** + * Prompts the user to scan a username QR code. Uses the activity result to communicate the recipient that was found, or null if no valid usernames were scanned. + * See [Contract]. + */ +class UsernameQrScannerActivity : AppCompatActivity() { + + companion object { + private const val KEY_RECIPIENT_ID = "recipient_id" + } + + private val viewModel: UsernameQrScannerViewModel by viewModels() + private val disposables = LifecycleDisposable() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + disposables.bindTo(this) + + val galleryLauncher = registerForActivityResult(UsernameQrImageSelectionActivity.Contract()) { uri -> + if (uri != null) { + viewModel.onQrImageSelected(this, uri) + } + } + + setContent { + val galleryPermissionState: MultiplePermissionsState = rememberMultiplePermissionsState(permissions = PermissionCompat.forImages().toList()) { grants -> + if (grants.values.all { it }) { + galleryLauncher.launch(Unit) + } else { + Toast.makeText(this, R.string.ChatWallpaperPreviewActivity__viewing_your_gallery_requires_the_storage_permission, Toast.LENGTH_SHORT).show() + } + } + + val state by viewModel.state + + SignalTheme(isDarkMode = DynamicTheme.isDarkTheme(LocalContext.current)) { + Content( + lifecycleOwner = this, + diposables = disposables.disposables, + state = state, + galleryPermissionsState = galleryPermissionState, + onQrScanned = { url -> viewModel.onQrScanned(url) }, + onQrResultHandled = { + finish() + }, + onOpenGalleryClicked = { + if (galleryPermissionState.allPermissionsGranted) { + galleryLauncher.launch(Unit) + } else { + galleryPermissionState.launchMultiplePermissionRequest() + } + }, + onRecipientFound = { recipient -> + val intent = Intent().apply { + putExtra(KEY_RECIPIENT_ID, recipient.id) + } + setResult(RESULT_OK, intent) + finish() + }, + onBackNavigationPressed = { + finish() + } + ) + } + } + } + + class Contract : ActivityResultContract() { + override fun createIntent(context: Context, input: Unit): Intent { + return Intent(context, UsernameQrScannerActivity::class.java) + } + + override fun parseResult(resultCode: Int, intent: Intent?): RecipientId? { + return intent?.getParcelableExtraCompat(KEY_RECIPIENT_ID, RecipientId::class.java) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun Content( + lifecycleOwner: LifecycleOwner, + diposables: CompositeDisposable, + state: UsernameQrScannerViewModel.ScannerState, + galleryPermissionsState: MultiplePermissionsState, + onQrScanned: (String) -> Unit, + onQrResultHandled: () -> Unit, + onOpenGalleryClicked: () -> Unit, + onRecipientFound: (Recipient) -> Unit, + onBackNavigationPressed: () -> Unit +) { + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = {}, + navigationIcon = { + IconButton( + onClick = onBackNavigationPressed + ) { + Icon( + painter = painterResource(R.drawable.symbol_x_24), + contentDescription = stringResource(android.R.string.cancel) + ) + } + } + ) + } + ) { contentPadding -> + UsernameQrScanScreen( + lifecycleOwner = lifecycleOwner, + disposables = diposables, + qrScanResult = state.qrScanResult, + onQrCodeScanned = onQrScanned, + onQrResultHandled = onQrResultHandled, + onOpenGalleryClicked = onOpenGalleryClicked, + onRecipientFound = onRecipientFound, + modifier = Modifier.padding(contentPadding) + ) + + if (state.indeterminateProgress) { + Dialogs.IndeterminateProgressDialog() + } + } +} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScannerViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScannerViewModel.kt new file mode 100644 index 00000000..cd650108 --- /dev/null +++ b/app/src/main/java/org/tm/archive/components/settings/app/usernamelinks/main/UsernameQrScannerViewModel.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.components.settings.app.usernamelinks.main + +import android.content.Context +import android.net.Uri +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.kotlin.plusAssign +import io.reactivex.rxjava3.kotlin.subscribeBy + +class UsernameQrScannerViewModel : ViewModel() { + + private val _state = mutableStateOf(ScannerState(qrScanResult = null, indeterminateProgress = false)) + val state: State = _state + + private val disposables = CompositeDisposable() + + fun onQrScanned(url: String) { + _state.value = state.value.copy(indeterminateProgress = true) + + disposables += UsernameQrScanRepository.lookupUsernameUrl(url) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { result -> + _state.value = _state.value.copy( + qrScanResult = result, + indeterminateProgress = false + ) + } + } + + fun onQrImageSelected(context: Context, uri: Uri) { + _state.value = state.value.copy(indeterminateProgress = true) + + disposables += UsernameQrScanRepository.scanImageUriForQrCode(context, uri) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy { result -> + _state.value = _state.value.copy( + qrScanResult = result, + indeterminateProgress = false + ) + } + } + + override fun onCleared() { + disposables.clear() + } + + data class ScannerState( + val qrScanResult: QrScanResult?, + val indeterminateProgress: Boolean + ) +} diff --git a/app/src/main/java/org/tm/archive/components/settings/app/wrapped/WrappedMmsPreferencesFragment.kt b/app/src/main/java/org/tm/archive/components/settings/app/wrapped/WrappedMmsPreferencesFragment.kt deleted file mode 100644 index 7390f9fe..00000000 --- a/app/src/main/java/org/tm/archive/components/settings/app/wrapped/WrappedMmsPreferencesFragment.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.tm.archive.components.settings.app.wrapped - -import androidx.fragment.app.Fragment -import org.tm.archive.R -import org.tm.archive.preferences.MmsPreferencesFragment - -class WrappedMmsPreferencesFragment : SettingsWrapperFragment() { - override fun getFragment(): Fragment { - toolbar.setTitle(R.string.preferences__advanced_mms_access_point_names) - return MmsPreferencesFragment() - } -} diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsFragment.kt index d5c96889..7056af49 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsFragment.kt @@ -14,6 +14,7 @@ import android.view.ViewGroup import android.widget.FrameLayout import android.widget.TextView import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.core.view.doOnPreDraw @@ -28,7 +29,9 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import io.reactivex.rxjava3.kotlin.subscribeBy import org.signal.core.util.DimensionUnit +import org.signal.core.util.Result import org.signal.core.util.concurrent.LifecycleDisposable +import org.signal.core.util.concurrent.addTo import org.signal.core.util.getParcelableArrayListExtraCompat import org.tm.archive.AvatarPreviewActivity import org.tm.archive.BlockUnblockDialog @@ -74,6 +77,8 @@ import org.tm.archive.groups.ui.managegroup.dialogs.GroupInviteSentDialog import org.tm.archive.groups.ui.managegroup.dialogs.GroupsLearnMoreBottomSheetDialogFragment import org.tm.archive.mediaoverview.MediaOverviewActivity import org.tm.archive.mediapreview.MediaIntentFactory +import org.tm.archive.messagerequests.MessageRequestRepository +import org.tm.archive.nicknames.NicknameActivity import org.tm.archive.profiles.edit.CreateProfileActivity import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientExporter @@ -89,6 +94,7 @@ import org.tm.archive.util.CommunicationActions import org.tm.archive.util.ContextUtil import org.tm.archive.util.DateUtils import org.tm.archive.util.ExpirationUtil +import org.tm.archive.util.FeatureFlags import org.tm.archive.util.Material3OnScrollHelper import org.tm.archive.util.ViewUtil import org.tm.archive.util.adapter.mapping.MappingAdapter @@ -112,17 +118,13 @@ class ConversationSettingsFragment : DSLSettingsFragment( private val alertTint by lazy { ContextCompat.getColor(requireContext(), R.color.signal_alert_primary) } private val alertDisabledTint by lazy { ContextCompat.getColor(requireContext(), R.color.signal_alert_primary_50) } private val blockIcon by lazy { - ContextUtil.requireDrawable(requireContext(), R.drawable.ic_block_tinted_24).apply { + ContextUtil.requireDrawable(requireContext(), R.drawable.symbol_block_24).apply { colorFilter = PorterDuffColorFilter(alertTint, PorterDuff.Mode.SRC_IN) } } - private val unblockIcon by lazy { - ContextUtil.requireDrawable(requireContext(), R.drawable.ic_block_tinted_24) - } - private val leaveIcon by lazy { - ContextUtil.requireDrawable(requireContext(), R.drawable.ic_leave_tinted_24).apply { + ContextUtil.requireDrawable(requireContext(), R.drawable.symbol_leave_24).apply { colorFilter = PorterDuffColorFilter(alertTint, PorterDuff.Mode.SRC_IN) } } @@ -135,7 +137,8 @@ class ConversationSettingsFragment : DSLSettingsFragment( recipientId = args.recipientId, groupId = ParcelableGroupId.get(groupId), callMessageIds = args.callMessageIds ?: longArrayOf(), - repository = ConversationSettingsRepository(requireContext()) + repository = ConversationSettingsRepository(requireContext()), + messageRequestRepository = MessageRequestRepository(requireContext()) ) } ) @@ -149,6 +152,7 @@ class ConversationSettingsFragment : DSLSettingsFragment( private lateinit var toolbarTitle: TextView private lateinit var toolbarBackground: View private lateinit var addToGroupStoryDelegate: AddToGroupStoryDelegate + private lateinit var nicknameLauncher: ActivityResultLauncher private val navController get() = Navigation.findNavController(requireView()) private val lifecycleDisposable = LifecycleDisposable() @@ -216,6 +220,10 @@ class ConversationSettingsFragment : DSLSettingsFragment( } override fun bindAdapter(adapter: MappingAdapter) { + nicknameLauncher = registerForActivityResult(NicknameActivity.Contract()) { + // Intentionally left blank + } + val args = ConversationSettingsFragmentArgs.fromBundle(requireArguments()) BioTextPreference.register(adapter) @@ -323,9 +331,14 @@ class ConversationSettingsFragment : DSLSettingsFragment( state.withRecipientSettingsState { customPref( - BioTextPreference.RecipientModel(recipient = state.recipient, onHeadlineClickListener = { - AboutSheet.create(state.recipient).show(parentFragmentManager, null) - }) + BioTextPreference.RecipientModel( + recipient = state.recipient, + onHeadlineClickListener = if (state.recipient.isSelf || !state.recipient.isIndividual) { + null + } else { + { AboutSheet.create(state.recipient).show(parentFragmentManager, null) } + } + ) ) } @@ -463,9 +476,9 @@ class ConversationSettingsFragment : DSLSettingsFragment( val summary = DSLSettingsText.from(formatDisappearingMessagesLifespan(state.disappearingMessagesLifespan)) val icon = if (state.disappearingMessagesLifespan <= 0 || state.recipient.isBlocked) { - R.drawable.ic_update_timer_disabled_16 + R.drawable.symbol_timer_slash_24 } else { - R.drawable.ic_update_timer_16 + R.drawable.symbol_timer_24 } var enabled = !state.recipient.isBlocked @@ -490,10 +503,25 @@ class ConversationSettingsFragment : DSLSettingsFragment( ) } + if (FeatureFlags.nicknames() && state.recipient.isIndividual && !state.recipient.isSelf) { + clickPref( + title = DSLSettingsText.from(R.string.NicknameActivity__nickname), + icon = DSLSettingsIcon.from(R.drawable.symbol_edit_24), + onClick = { + nicknameLauncher.launch( + NicknameActivity.Args( + state.recipient.id, + false + ) + ) + } + ) + } + if (!state.recipient.isReleaseNotes) { clickPref( title = DSLSettingsText.from(R.string.preferences__chat_color_and_wallpaper), - icon = DSLSettingsIcon.from(R.drawable.ic_color_24), + icon = DSLSettingsIcon.from(R.drawable.symbol_color_24), onClick = { startActivity(ChatWallpaperActivity.createIntent(requireContext(), state.recipient.id)) } @@ -503,7 +531,7 @@ class ConversationSettingsFragment : DSLSettingsFragment( if (!state.recipient.isSelf) { clickPref( title = DSLSettingsText.from(R.string.ConversationSettingsFragment__sounds_and_notifications), - icon = DSLSettingsIcon.from(R.drawable.ic_speaker_24), + icon = DSLSettingsIcon.from(R.drawable.symbol_speaker_24), isEnabled = !state.isDeprecatedOrUnregistered, onClick = { val action = ConversationSettingsFragmentDirections.actionConversationSettingsFragmentToSoundsAndNotificationsSettingsFragment(state.recipient.id) @@ -548,7 +576,7 @@ class ConversationSettingsFragment : DSLSettingsFragment( if (!state.recipient.isReleaseNotes && !state.recipient.isSelf) { clickPref( title = DSLSettingsText.from(R.string.ConversationSettingsFragment__view_safety_number), - icon = DSLSettingsIcon.from(R.drawable.ic_safety_number_24), + icon = DSLSettingsIcon.from(R.drawable.symbol_safety_number_24), isEnabled = !state.isDeprecatedOrUnregistered, onClick = { VerifyIdentityActivity.startOrShowExchangeMessagesDialog(requireActivity(), recipientState.identityRecord) @@ -686,7 +714,7 @@ class ConversationSettingsFragment : DSLSettingsFragment( recipient = member.member, isAdmin = member.isAdmin, onClick = { - RecipientBottomSheetDialogFragment.create(member.member.id, groupState.groupId).show(parentFragmentManager, "BOTTOM") + RecipientBottomSheetDialogFragment.show(parentFragmentManager, member.member.id, groupState.groupId) } ) ) @@ -775,11 +803,10 @@ class ConversationSettingsFragment : DSLSettingsFragment( } val titleTint = if (isBlocked) null else if (state.isDeprecatedOrUnregistered) alertDisabledTint else alertTint - val blockUnblockIcon = if (isBlocked) unblockIcon else blockIcon clickPref( title = if (titleTint != null) DSLSettingsText.from(title, titleTint) else DSLSettingsText.from(title), - icon = DSLSettingsIcon.from(blockUnblockIcon), + icon = if (isBlocked) DSLSettingsIcon.from(R.drawable.symbol_block_24) else DSLSettingsIcon.from(blockIcon), isEnabled = !state.isDeprecatedOrUnregistered, onClick = { if (state.recipient.isBlocked) { @@ -793,6 +820,49 @@ class ConversationSettingsFragment : DSLSettingsFragment( } } ) + + val reportSpamTint = if (state.isDeprecatedOrUnregistered) R.color.signal_alert_primary_50 else R.color.signal_alert_primary + clickPref( + title = DSLSettingsText.from(R.string.ConversationFragment_report_spam, ContextCompat.getColor(requireContext(), reportSpamTint)), + icon = DSLSettingsIcon.from(R.drawable.symbol_spam_24, reportSpamTint), + isEnabled = !state.isDeprecatedOrUnregistered, + onClick = { + BlockUnblockDialog.showReportSpamFor( + requireContext(), + viewLifecycleOwner.lifecycle, + state.recipient, + { + viewModel + .onReportSpam() + .subscribeBy { + Toast.makeText(requireContext(), R.string.ConversationFragment_reported_as_spam, Toast.LENGTH_SHORT).show() + onToolbarNavigationClicked() + } + .addTo(lifecycleDisposable) + }, + if (state.recipient.isBlocked) { + null + } else { + Runnable { + viewModel + .onBlockAndReportSpam() + .subscribeBy { result -> + when (result) { + is Result.Success -> { + Toast.makeText(requireContext(), R.string.ConversationFragment_reported_as_spam_and_blocked, Toast.LENGTH_SHORT).show() + onToolbarNavigationClicked() + } + is Result.Failure -> { + Toast.makeText(requireContext(), GroupErrors.getUserDisplayMessage(result.failure), Toast.LENGTH_SHORT).show() + } + } + } + .addTo(lifecycleDisposable) + } + } + ) + } + ) } } } diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsViewModel.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsViewModel.kt index f2e3af67..00bca643 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsViewModel.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/ConversationSettingsViewModel.kt @@ -1,6 +1,5 @@ package org.tm.archive.components.settings.conversation -import android.database.Cursor import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -8,11 +7,13 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Maybe import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.subjects.PublishSubject import io.reactivex.rxjava3.subjects.Subject +import org.signal.core.util.Result import org.signal.core.util.ThreadUtil import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.readToList @@ -25,8 +26,10 @@ import org.tm.archive.database.model.StoryViewState import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.groups.GroupId import org.tm.archive.groups.LiveGroup +import org.tm.archive.groups.ui.GroupChangeFailureReason import org.tm.archive.groups.v2.GroupAddMembersResult import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.messagerequests.MessageRequestRepository import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.recipients.RecipientUtil @@ -37,6 +40,7 @@ import org.tm.archive.util.livedata.Store sealed class ConversationSettingsViewModel( private val callMessageIds: LongArray, private val repository: ConversationSettingsRepository, + private val messageRequestRepository: MessageRequestRepository, specificSettingsState: SpecificSettingsState ) : ViewModel() { @@ -90,6 +94,27 @@ sealed class ConversationSettingsViewModel( sharedMediaUpdateTrigger.postValue(Unit) } + fun onReportSpam(): Maybe { + return if (store.state.threadId > 0 && store.state.recipient != Recipient.UNKNOWN) { + messageRequestRepository.reportSpamMessageRequest(store.state.recipient.id, store.state.threadId) + .observeOn(AndroidSchedulers.mainThread()) + .toSingle { Unit } + .toMaybe() + } else { + Maybe.empty() + } + } + + fun onBlockAndReportSpam(): Maybe> { + return if (store.state.threadId > 0 && store.state.recipient != Recipient.UNKNOWN) { + messageRequestRepository.blockAndReportSpamMessageRequest(store.state.recipient.id, store.state.threadId) + .observeOn(AndroidSchedulers.mainThread()) + .toMaybe() + } else { + Maybe.empty() + } + } + open fun refreshRecipient(): Unit = error("This ViewModel does not support this interaction") abstract fun setMuteUntil(muteUntil: Long) @@ -112,19 +137,15 @@ sealed class ConversationSettingsViewModel( disposable.clear() } - private fun Cursor?.ensureClosed() { - if (this != null && !this.isClosed) { - this.close() - } - } - private class RecipientSettingsViewModel( private val recipientId: RecipientId, private val callMessageIds: LongArray, - private val repository: ConversationSettingsRepository + private val repository: ConversationSettingsRepository, + messageRequestRepository: MessageRequestRepository ) : ConversationSettingsViewModel( callMessageIds, repository, + messageRequestRepository, SpecificSettingsState.RecipientSettingsState() ) { @@ -136,7 +157,7 @@ sealed class ConversationSettingsViewModel( } store.update(liveRecipient.liveData) { recipient, state -> - val isAudioAvailable = (recipient.isRegistered || SignalStore.misc().smsExportPhase.allowSmsFeatures()) && + val isAudioAvailable = recipient.isRegistered && !recipient.isGroup && !recipient.isBlocked && !recipient.isSelf && @@ -159,7 +180,7 @@ sealed class ConversationSettingsViewModel( contactLinkState = when { recipient.isSelf || recipient.isReleaseNotes || recipient.isBlocked -> ContactLinkState.NONE recipient.isSystemContact -> ContactLinkState.OPEN - recipient.hasE164() -> ContactLinkState.ADD + recipient.hasE164() && recipient.shouldShowE164() -> ContactLinkState.ADD else -> ContactLinkState.NONE } ) @@ -252,8 +273,9 @@ sealed class ConversationSettingsViewModel( private class GroupSettingsViewModel( private val groupId: GroupId, private val callMessageIds: LongArray, - private val repository: ConversationSettingsRepository - ) : ConversationSettingsViewModel(callMessageIds, repository, SpecificSettingsState.GroupSettingsState(groupId)) { + private val repository: ConversationSettingsRepository, + messageRequestRepository: MessageRequestRepository + ) : ConversationSettingsViewModel(callMessageIds, repository, messageRequestRepository, SpecificSettingsState.GroupSettingsState(groupId)) { private val liveGroup = LiveGroup(groupId) @@ -465,15 +487,16 @@ sealed class ConversationSettingsViewModel( private val recipientId: RecipientId? = null, private val groupId: GroupId? = null, private val callMessageIds: LongArray, - private val repository: ConversationSettingsRepository + private val repository: ConversationSettingsRepository, + private val messageRequestRepository: MessageRequestRepository ) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { return requireNotNull( modelClass.cast( when { - recipientId != null -> RecipientSettingsViewModel(recipientId, callMessageIds, repository) - groupId != null -> GroupSettingsViewModel(groupId, callMessageIds, repository) + recipientId != null -> RecipientSettingsViewModel(recipientId, callMessageIds, repository, messageRequestRepository) + groupId != null -> GroupSettingsViewModel(groupId, callMessageIds, repository, messageRequestRepository) else -> error("One of RecipientId or GroupId required.") } ) diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/InternalConversationSettingsFragment.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/InternalConversationSettingsFragment.kt index 1fe64182..b695b70f 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/InternalConversationSettingsFragment.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/InternalConversationSettingsFragment.kt @@ -28,7 +28,6 @@ import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientForeverObserver import org.tm.archive.recipients.RecipientId import org.tm.archive.subscription.Subscriber -import org.tm.archive.util.FeatureFlags import org.tm.archive.util.SpanUtil import org.tm.archive.util.Util import org.tm.archive.util.adapter.mapping.MappingAdapter @@ -128,6 +127,16 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( title = DSLSettingsText.from("Sealed Sender Mode"), summary = DSLSettingsText.from(recipient.unidentifiedAccessMode.toString()) ) + + textPref( + title = DSLSettingsText.from("Phone Number Sharing"), + summary = DSLSettingsText.from(recipient.phoneNumberSharing.name) + ) + + textPref( + title = DSLSettingsText.from("Phone Number Discoverability"), + summary = DSLSettingsText.from(SignalDatabase.recipients.getPhoneNumberDiscoverability(recipient.id)?.name ?: "null") + ) } textPref( @@ -250,11 +259,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( SignalDatabase.recipients.debugClearE164AndPni(recipient.id) - val splitRecipientId: RecipientId = if (FeatureFlags.phoneNumberPrivacy()) { - SignalDatabase.recipients.getAndPossiblyMergePnpVerified(null, recipient.pni.orElse(null), recipient.requireE164()) - } else { - SignalDatabase.recipients.getAndPossiblyMerge(recipient.pni.orElse(null), recipient.requireE164()) - } + val splitRecipientId: RecipientId = SignalDatabase.recipients.getAndPossiblyMergePnpVerified(null, recipient.pni.orElse(null), recipient.requireE164()) val splitRecipient: Recipient = Recipient.resolved(splitRecipientId) val splitThreadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(splitRecipient) @@ -277,7 +282,6 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( clickPref( title = DSLSettingsText.from("Split without creating threads"), summary = DSLSettingsText.from("Splits this contact into two recipients so you can test merging them together. This will become the PNI-based recipient. Another recipient will be made with this ACI and profile key. Doing a CDS refresh should allow you to see a Session Switchover Event, as long as you had a session with this PNI."), - isEnabled = FeatureFlags.phoneNumberPrivacy(), onClick = { MaterialAlertDialogBuilder(requireContext()) .setTitle("Are you sure?") @@ -321,15 +325,8 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( return if (capabilities != null) { TextUtils.concat( - colorize("GV1Migration", capabilities.groupsV1MigrationCapability), - ", ", - colorize("AnnouncementGroup", capabilities.announcementGroupCapability), - ", ", - colorize("SenderKey", capabilities.senderKeyCapability), - ", ", - colorize("ChangeNumber", capabilities.changeNumberCapability), - ", ", - colorize("Stories", capabilities.storiesCapability) + colorize("PNP/PNI", capabilities.pnpCapability), + colorize("PaymentActivation", capabilities.paymentActivation) ) } else { "Recipient not found!" diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/BioTextPreference.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/BioTextPreference.kt index 75e659ec..2b9aa32d 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/BioTextPreference.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/BioTextPreference.kt @@ -6,9 +6,10 @@ import android.text.SpannableStringBuilder import android.view.View import android.widget.TextView import android.widget.Toast +import androidx.core.content.ContextCompat import org.tm.archive.R import org.tm.archive.components.settings.PreferenceModel -import org.tm.archive.phonenumbers.PhoneNumberFormatter +import org.tm.archive.fonts.SignalSymbols import org.tm.archive.recipients.Recipient import org.tm.archive.util.ContextUtil import org.tm.archive.util.ServiceUtil @@ -32,19 +33,19 @@ object BioTextPreference { abstract fun getSubhead1Text(context: Context): String? abstract fun getSubhead2Text(): String? - open val onHeadlineClickListener: () -> Unit = {} + open val onHeadlineClickListener: (() -> Unit)? = null } class RecipientModel( private val recipient: Recipient, - override val onHeadlineClickListener: () -> Unit + override val onHeadlineClickListener: (() -> Unit)? ) : BioTextPreferenceModel() { override fun getHeadlineText(context: Context): CharSequence { val name = if (recipient.isSelf) { context.getString(R.string.note_to_self) } else { - recipient.getDisplayNameOrUsername(context) + recipient.getDisplayName(context) } if (!recipient.showVerified() && !recipient.isIndividual) { @@ -53,11 +54,34 @@ object BioTextPreference { return SpannableStringBuilder(name).apply { if (recipient.showVerified()) { - SpanUtil.appendCenteredImageSpan(this, ContextUtil.requireDrawable(context, R.drawable.ic_official_28), 28, 28) + SpanUtil.appendSpacer(this, 8) + SpanUtil.appendCenteredImageSpanWithoutSpace(this, ContextUtil.requireDrawable(context, R.drawable.ic_official_28), 28, 28) + } else if (recipient.isSystemContact) { + val systemContactGlyph = SignalSymbols.getSpannedString( + context, + SignalSymbols.Weight.BOLD, + SignalSymbols.Glyph.PERSON_CIRCLE + ).let { + SpanUtil.ofSize(it, 20) + } + + append(" ") + append(systemContactGlyph) } - if (recipient.isIndividual) { - SpanUtil.appendCenteredImageSpan(this, ContextUtil.requireDrawable(context, R.drawable.symbol_chevron_right_24_color_on_secondary_container), 24, 24) + if (recipient.isIndividual && !recipient.isSelf) { + val chevronGlyph = SignalSymbols.getSpannedString( + context, + SignalSymbols.Weight.BOLD, + SignalSymbols.Glyph.CHEVRON_RIGHT + ).let { + SpanUtil.ofSize(it, 24) + }.let { + SpanUtil.color(ContextCompat.getColor(context, R.color.signal_colorOutline), it) + } + + append(" ") + append(chevronGlyph) } } } @@ -70,11 +94,7 @@ object BioTextPreference { } } - override fun getSubhead2Text(): String? = if (recipient.shouldShowE164()) { - recipient.e164.map(PhoneNumberFormatter::prettyPrint).orElse(null) - } else { - null - } + override fun getSubhead2Text(): String? = null override fun areContentsTheSame(newItem: RecipientModel): Boolean { return super.areContentsTheSame(newItem) && newItem.recipient.hasSameContent(recipient) @@ -114,7 +134,11 @@ object BioTextPreference { override fun bind(model: T) { headline.text = model.getHeadlineText(context) - headline.setOnClickListener { model.onHeadlineClickListener() } + + val clickListener = model.onHeadlineClickListener + if (clickListener != null) { + headline.setOnClickListener { clickListener() } + } model.getSubhead1Text(context).let { subhead1.text = it diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/CallPreference.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/CallPreference.kt index cbab5d65..38039329 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/CallPreference.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/CallPreference.kt @@ -61,8 +61,8 @@ object CallPreference { private fun getCallType(call: CallTable.Call): String { val id = when (call.messageType) { - MessageTypes.MISSED_VIDEO_CALL_TYPE -> if (call.event == CallTable.Event.MISSED) R.string.MessageRecord_missed_voice_call else R.string.MessageRecord_missed_voice_call_notification_profile - MessageTypes.MISSED_AUDIO_CALL_TYPE -> if (call.event == CallTable.Event.MISSED) R.string.MessageRecord_missed_video_call else R.string.MessageRecord_missed_video_call_notification_profile + MessageTypes.MISSED_AUDIO_CALL_TYPE -> if (call.event == CallTable.Event.MISSED) R.string.MessageRecord_missed_voice_call else R.string.MessageRecord_missed_voice_call_notification_profile + MessageTypes.MISSED_VIDEO_CALL_TYPE -> if (call.event == CallTable.Event.MISSED) R.string.MessageRecord_missed_video_call else R.string.MessageRecord_missed_video_call_notification_profile MessageTypes.INCOMING_AUDIO_CALL_TYPE -> R.string.MessageRecord_incoming_voice_call MessageTypes.INCOMING_VIDEO_CALL_TYPE -> R.string.MessageRecord_incoming_video_call MessageTypes.OUTGOING_AUDIO_CALL_TYPE -> R.string.MessageRecord_outgoing_voice_call diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/RecipientPreference.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/RecipientPreference.kt index f91ebf4f..a42c7504 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/RecipientPreference.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/RecipientPreference.kt @@ -1,12 +1,16 @@ package org.tm.archive.components.settings.conversation.preferences +import android.text.SpannableStringBuilder import android.view.View import android.widget.TextView +import androidx.core.content.ContextCompat import org.tm.archive.R import org.tm.archive.badges.BadgeImageView import org.tm.archive.components.AvatarImageView import org.tm.archive.components.settings.PreferenceModel import org.tm.archive.recipients.Recipient +import org.tm.archive.util.ContextUtil +import org.tm.archive.util.SpanUtil import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingViewHolder @@ -56,7 +60,16 @@ object RecipientPreference { name.text = if (model.recipient.isSelf) { context.getString(R.string.Recipient_you) } else { - model.recipient.getDisplayName(context) + if (model.recipient.isSystemContact) { + SpannableStringBuilder(model.recipient.getDisplayName(context)).apply { + val drawable = ContextUtil.requireDrawable(context, R.drawable.symbol_person_circle_24).apply { + setTint(ContextCompat.getColor(context, R.color.signal_colorOnSurface)) + } + SpanUtil.appendCenteredImageSpan(this, drawable, 16, 16) + } + } else { + model.recipient.getDisplayName(context) + } } val aboutText = model.recipient.combinedAboutAndEmoji diff --git a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/SharedMediaPreference.kt b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/SharedMediaPreference.kt index 8c02e091..be3a30b5 100644 --- a/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/SharedMediaPreference.kt +++ b/app/src/main/java/org/tm/archive/components/settings/conversation/preferences/SharedMediaPreference.kt @@ -1,11 +1,11 @@ package org.tm.archive.components.settings.conversation.preferences import android.view.View +import com.bumptech.glide.Glide import org.tm.archive.R import org.tm.archive.components.ThreadPhotoRailView import org.tm.archive.components.settings.PreferenceModel import org.tm.archive.database.MediaTable -import org.tm.archive.mms.GlideApp import org.tm.archive.util.ViewUtil import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter @@ -40,7 +40,7 @@ object SharedMediaPreference { private val rail: ThreadPhotoRailView = itemView.findViewById(R.id.rail_view) override fun bind(model: Model) { - rail.setMediaRecords(GlideApp.with(rail), model.mediaRecords) + rail.setMediaRecords(Glide.with(rail), model.mediaRecords) rail.setListener { v, m -> model.onMediaRecordClick(v, m, ViewUtil.isLtr(rail)) } diff --git a/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlView.kt b/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlView.kt index ee194e99..eb57e92e 100644 --- a/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlView.kt +++ b/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlView.kt @@ -20,6 +20,7 @@ import org.greenrobot.eventbus.ThreadMode import org.signal.core.util.logging.Log import org.tm.archive.R import org.tm.archive.attachments.Attachment +import org.tm.archive.attachments.DatabaseAttachment import org.tm.archive.components.RecyclerViewParentTransitionController import org.tm.archive.database.AttachmentTable import org.tm.archive.databinding.TransferControlsViewBinding @@ -108,7 +109,7 @@ class TransferControlView @JvmOverloads constructor(context: Context, attrs: Att if (currentState.slides.size == 1) { val slide = currentState.slides.first() if (slide.hasVideo()) { - if (currentState.isOutgoing) { + if (currentState.isUpload) { return when (slide.transferState) { AttachmentTable.TRANSFER_PROGRESS_STARTED -> { Mode.UPLOADING_SINGLE_ITEM @@ -146,7 +147,7 @@ class TransferControlView @JvmOverloads constructor(context: Context, attrs: Att } } } else { - return if (currentState.isOutgoing) { + return if (currentState.isUpload) { when (slide.transferState) { AttachmentTable.TRANSFER_PROGRESS_FAILED -> { Mode.RETRY_UPLOADING @@ -179,7 +180,7 @@ class TransferControlView @JvmOverloads constructor(context: Context, attrs: Att } else { when (getTransferState(currentState.slides)) { AttachmentTable.TRANSFER_PROGRESS_STARTED -> { - return if (currentState.isOutgoing) { + return if (currentState.isUpload) { Mode.UPLOADING_GALLERY } else { Mode.DOWNLOADING_GALLERY @@ -195,7 +196,7 @@ class TransferControlView @JvmOverloads constructor(context: Context, attrs: Att } AttachmentTable.TRANSFER_PROGRESS_FAILED -> { - return if (currentState.isOutgoing) { + return if (currentState.isUpload) { Mode.RETRY_UPLOADING } else { Mode.RETRY_DOWNLOADING @@ -557,14 +558,14 @@ class TransferControlView @JvmOverloads constructor(context: Context, attrs: Att } } val playableWhileDownloading = allStreamableOrDone - val isOutgoing = slides.any { it.asAttachment().uploadTimestamp == 0L } + val isUpload = slides.any { it.asAttachment().uploadTimestamp == 0L } && slides.all { (it.asAttachment() as? DatabaseAttachment)?.hasData == true } val result = state.copy( slides = slides, networkProgress = networkProgress, compressionProgress = compressionProgress, playableWhileDownloading = playableWhileDownloading, - isOutgoing = isOutgoing + isUpload = isUpload ) verboseLog("New state calculated and being returned for new slides: ${slidesAsListOfTimestamps(slides)}\n$result") return@updateState result diff --git a/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlViewState.kt b/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlViewState.kt index 67e3a318..3c96c152 100644 --- a/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlViewState.kt +++ b/app/src/main/java/org/tm/archive/components/transfercontrols/TransferControlViewState.kt @@ -21,5 +21,5 @@ data class TransferControlViewState( val networkProgress: Map = HashMap(), val compressionProgress: Map = HashMap(), val playableWhileDownloading: Boolean = false, - val isOutgoing: Boolean = false + val isUpload: Boolean = false ) diff --git a/app/src/main/java/org/tm/archive/components/transfercontrols/TransferProgressView.kt b/app/src/main/java/org/tm/archive/components/transfercontrols/TransferProgressView.kt index 8d02a7ed..ac6a2766 100644 --- a/app/src/main/java/org/tm/archive/components/transfercontrols/TransferProgressView.kt +++ b/app/src/main/java/org/tm/archive/components/transfercontrols/TransferProgressView.kt @@ -51,8 +51,8 @@ class TransferProgressView @JvmOverloads constructor( private val progressRect = RectF() private val stopIconRect = RectF() - private val downloadDrawable = ContextCompat.getDrawable(context, R.drawable.ic_arrow_down_24) - private val uploadDrawable = ContextCompat.getDrawable(context, R.drawable.ic_arrow_up_16) + private val downloadDrawable = ContextCompat.getDrawable(context, R.drawable.symbol_arrow_down_24) + private val uploadDrawable = ContextCompat.getDrawable(context, R.drawable.symbol_arrow_up_24) private var progressPercent = 0f private var currentState = State.UNINITIALIZED diff --git a/app/src/main/java/org/tm/archive/components/verify/SafetyNumberQrView.kt b/app/src/main/java/org/tm/archive/components/verify/SafetyNumberQrView.kt index 20661655..f79c272c 100644 --- a/app/src/main/java/org/tm/archive/components/verify/SafetyNumberQrView.kt +++ b/app/src/main/java/org/tm/archive/components/verify/SafetyNumberQrView.kt @@ -9,7 +9,6 @@ import android.animation.ValueAnimator import android.content.Context import android.content.res.ColorStateList import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.Outline import android.graphics.PorterDuff @@ -26,12 +25,14 @@ import android.widget.TextView import androidx.annotation.DrawableRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.toBitmap import androidx.core.widget.ImageViewCompat import androidx.interpolator.view.animation.FastOutSlowInInterpolator import org.signal.core.util.dp import org.signal.libsignal.protocol.fingerprint.Fingerprint import org.tm.archive.R import org.tm.archive.qr.QrCodeUtil +import org.tm.archive.util.ContextUtil import org.tm.archive.util.ViewUtil import org.tm.archive.util.visible import java.nio.charset.Charset @@ -149,7 +150,7 @@ class SafetyNumberQrView : ConstraintLayout { fun animateVerifiedSuccess() { val qrBitmap = (qrCode.drawable as BitmapDrawable).bitmap - val qrSuccess: Bitmap = createVerifiedBitmap(qrBitmap.width, qrBitmap.height, R.drawable.ic_check_white_48dp) + val qrSuccess: Bitmap = createVerifiedBitmap(qrBitmap.width, qrBitmap.height, R.drawable.symbol_check_white_48) qrVerified.setImageBitmap(qrSuccess) qrVerified.background.setColorFilter(resources.getColor(R.color.green_500), PorterDuff.Mode.MULTIPLY) tapLabel.setText(context.getString(R.string.verify_display_fragment__successful_match)) @@ -158,7 +159,7 @@ class SafetyNumberQrView : ConstraintLayout { fun animateVerifiedFailure() { val qrBitmap = (qrCode.drawable as BitmapDrawable).bitmap - val qrSuccess: Bitmap = createVerifiedBitmap(qrBitmap.width, qrBitmap.height, R.drawable.ic_close_white_48dp) + val qrSuccess: Bitmap = createVerifiedBitmap(qrBitmap.width, qrBitmap.height, R.drawable.symbol_x_white_48) qrVerified.setImageBitmap(qrSuccess) qrVerified.background.setColorFilter(resources.getColor(R.color.red_500), PorterDuff.Mode.MULTIPLY) tapLabel.setText(context.getString(R.string.verify_display_fragment__failed_to_verify_safety_number)) @@ -211,7 +212,7 @@ class SafetyNumberQrView : ConstraintLayout { private fun createVerifiedBitmap(width: Int, height: Int, @DrawableRes id: Int): Bitmap { val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) - val check = BitmapFactory.decodeResource(resources, id) + val check = ContextUtil.requireDrawable(context, id).toBitmap() val offset = ((width - check.width) / 2).toFloat() canvas.drawBitmap(check, offset, offset, null) return bitmap diff --git a/app/src/main/java/org/tm/archive/components/voice/RetryableInitAudioSink.kt b/app/src/main/java/org/tm/archive/components/voice/RetryableInitAudioSink.kt index aabaecc0..e1083176 100644 --- a/app/src/main/java/org/tm/archive/components/voice/RetryableInitAudioSink.kt +++ b/app/src/main/java/org/tm/archive/components/voice/RetryableInitAudioSink.kt @@ -3,7 +3,6 @@ package org.tm.archive.components.voice import android.content.Context import androidx.annotation.OptIn import androidx.media3.common.util.UnstableApi -import androidx.media3.exoplayer.audio.AudioCapabilities import androidx.media3.exoplayer.audio.AudioSink import androidx.media3.exoplayer.audio.DefaultAudioSink import org.signal.core.util.logging.Log @@ -19,12 +18,9 @@ class RetryableInitAudioSink( context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, - enableOffload: Boolean, - val delegate: AudioSink = DefaultAudioSink.Builder() - .setAudioCapabilities(AudioCapabilities.getCapabilities(context)) + val delegate: AudioSink = DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) - .setOffloadMode(if (enableOffload) DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED else DefaultAudioSink.OFFLOAD_MODE_DISABLED) .build() ) : AudioSink by delegate { diff --git a/app/src/main/java/org/tm/archive/components/voice/VoiceNotePlayer.kt b/app/src/main/java/org/tm/archive/components/voice/VoiceNotePlayer.kt index 150faf6e..5da4301c 100644 --- a/app/src/main/java/org/tm/archive/components/voice/VoiceNotePlayer.kt +++ b/app/src/main/java/org/tm/archive/components/voice/VoiceNotePlayer.kt @@ -20,7 +20,7 @@ import org.tm.archive.video.exo.SignalMediaSourceFactory @OptIn(UnstableApi::class) class VoiceNotePlayer @JvmOverloads constructor( context: Context, - private val internalPlayer: ExoPlayer = ExoPlayer.Builder(context) + internalPlayer: ExoPlayer = ExoPlayer.Builder(context) .setRenderersFactory(WorkaroundRenderersFactory(context)) .setMediaSourceFactory(SignalMediaSourceFactory(context)) .setLoadControl( @@ -35,13 +35,6 @@ class VoiceNotePlayer @JvmOverloads constructor( setAudioAttributes(AudioAttributes.Builder().setContentType(C.AUDIO_CONTENT_TYPE_MUSIC).setUsage(C.USAGE_MEDIA).build(), true) } - /** - * Required to expose this because this is unique to [ExoPlayer], not the generic [androidx.media3.common.Player] interface. - */ - fun setAudioAttributes(audioAttributes: AudioAttributes, handleAudioFocus: Boolean) { - internalPlayer.setAudioAttributes(audioAttributes, handleAudioFocus) - } - override fun seekTo(windowIndex: Int, positionMs: Long) { super.seekTo(windowIndex, positionMs) @@ -66,7 +59,8 @@ class VoiceNotePlayer @JvmOverloads constructor( */ @OptIn(androidx.media3.common.util.UnstableApi::class) class WorkaroundRenderersFactory(val context: Context) : DefaultRenderersFactory(context) { - override fun buildAudioSink(context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean): AudioSink? { - return RetryableInitAudioSink(context, enableFloatOutput, enableAudioTrackPlaybackParams, enableOffload) + + override fun buildAudioSink(context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean): AudioSink { + return RetryableInitAudioSink(context, enableFloatOutput, enableAudioTrackPlaybackParams) } } diff --git a/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantView.java b/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantView.java index 11f1242d..bd51da08 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantView.java +++ b/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantView.java @@ -19,6 +19,7 @@ import androidx.core.widget.ImageViewCompat; import androidx.transition.Transition; import androidx.transition.TransitionManager; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -33,7 +34,6 @@ import org.tm.archive.contacts.avatars.ProfileContactPhoto; import org.tm.archive.contacts.avatars.ResourceContactPhoto; import org.tm.archive.conversation.colors.ChatColors; import org.tm.archive.events.CallParticipant; -import org.tm.archive.mms.GlideApp; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.AvatarUtil; @@ -61,6 +61,7 @@ public class CallParticipantView extends ConstraintLayout { private boolean infoMode; private boolean raiseHandAllowed; private Runnable missingMediaKeysUpdater; + private boolean shouldRenderInPip; private SelfPipMode selfPipMode = SelfPipMode.NOT_SELF_PIP; @@ -198,6 +199,8 @@ public class CallParticipantView extends ConstraintLayout { pipBadge.setBadgeFromRecipient(participant.getRecipient()); contactPhoto = participant.getRecipient().getContactPhoto(); } + + setRenderInPip(shouldRenderInPip); } private boolean isMissingMediaKeys(@NonNull CallParticipant participant) { @@ -223,10 +226,15 @@ public class CallParticipantView extends ConstraintLayout { } void setRenderInPip(boolean shouldRenderInPip) { + this.shouldRenderInPip = shouldRenderInPip; + if (infoMode) { infoMessage.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE); infoMoreInfo.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE); + infoOverlay.setOnClickListener(shouldRenderInPip ? v -> infoMoreInfo.performClick() : null); return; + } else { + infoOverlay.setOnClickListener(null); } avatar.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE); @@ -243,7 +251,7 @@ public class CallParticipantView extends ConstraintLayout { * Adjust UI elements for the various self PIP positions. If called after a {@link TransitionManager#beginDelayedTransition(ViewGroup, Transition)}, * the changes to the UI elements will animate. */ - void setSelfPipMode(@NonNull SelfPipMode selfPipMode) { + void setSelfPipMode(@NonNull SelfPipMode selfPipMode, boolean isMoreThanOneCameraAvailable) { Preconditions.checkArgument(selfPipMode != SelfPipMode.NOT_SELF_PIP); if (this.selfPipMode == selfPipMode) { @@ -274,26 +282,30 @@ public class CallParticipantView extends ConstraintLayout { ViewUtil.dpToPx(6) ); - constraints.setVisibility(R.id.call_participant_switch_camera, View.VISIBLE); - constraints.setMargin( - R.id.call_participant_switch_camera, - ConstraintSet.END, - ViewUtil.dpToPx(6) - ); - constraints.setMargin( - R.id.call_participant_switch_camera, - ConstraintSet.BOTTOM, - ViewUtil.dpToPx(6) - ); - constraints.constrainWidth(R.id.call_participant_switch_camera, ViewUtil.dpToPx(28)); - constraints.constrainHeight(R.id.call_participant_switch_camera, ViewUtil.dpToPx(28)); + if (isMoreThanOneCameraAvailable) { + constraints.setVisibility(R.id.call_participant_switch_camera, View.VISIBLE); + constraints.setMargin( + R.id.call_participant_switch_camera, + ConstraintSet.END, + ViewUtil.dpToPx(6) + ); + constraints.setMargin( + R.id.call_participant_switch_camera, + ConstraintSet.BOTTOM, + ViewUtil.dpToPx(6) + ); + constraints.constrainWidth(R.id.call_participant_switch_camera, ViewUtil.dpToPx(28)); + constraints.constrainHeight(R.id.call_participant_switch_camera, ViewUtil.dpToPx(28)); - ViewGroup.LayoutParams params = switchCameraIcon.getLayoutParams(); - params.width = params.height = ViewUtil.dpToPx(16); - switchCameraIcon.setLayoutParams(params); + ViewGroup.LayoutParams params = switchCameraIcon.getLayoutParams(); + params.width = params.height = ViewUtil.dpToPx(16); + switchCameraIcon.setLayoutParams(params); - switchCameraIconFrame.setClickable(false); - switchCameraIconFrame.setEnabled(false); + switchCameraIconFrame.setClickable(false); + switchCameraIconFrame.setEnabled(false); + } else { + constraints.setVisibility(R.id.call_participant_switch_camera, View.GONE); + } } case EXPANDED_SELF_PIP -> { constraints.connect( @@ -313,26 +325,30 @@ public class CallParticipantView extends ConstraintLayout { ViewUtil.dpToPx(8) ); - constraints.setVisibility(R.id.call_participant_switch_camera, View.VISIBLE); - constraints.setMargin( - R.id.call_participant_switch_camera, - ConstraintSet.END, - ViewUtil.dpToPx(8) - ); - constraints.setMargin( - R.id.call_participant_switch_camera, - ConstraintSet.BOTTOM, - ViewUtil.dpToPx(8) - ); - constraints.constrainWidth(R.id.call_participant_switch_camera, ViewUtil.dpToPx(48)); - constraints.constrainHeight(R.id.call_participant_switch_camera, ViewUtil.dpToPx(48)); + if (isMoreThanOneCameraAvailable) { + constraints.setVisibility(R.id.call_participant_switch_camera, View.VISIBLE); + constraints.setMargin( + R.id.call_participant_switch_camera, + ConstraintSet.END, + ViewUtil.dpToPx(8) + ); + constraints.setMargin( + R.id.call_participant_switch_camera, + ConstraintSet.BOTTOM, + ViewUtil.dpToPx(8) + ); + constraints.constrainWidth(R.id.call_participant_switch_camera, ViewUtil.dpToPx(48)); + constraints.constrainHeight(R.id.call_participant_switch_camera, ViewUtil.dpToPx(48)); - ViewGroup.LayoutParams params = switchCameraIcon.getLayoutParams(); - params.width = params.height = ViewUtil.dpToPx(24); - switchCameraIcon.setLayoutParams(params); + ViewGroup.LayoutParams params = switchCameraIcon.getLayoutParams(); + params.width = params.height = ViewUtil.dpToPx(24); + switchCameraIcon.setLayoutParams(params); - switchCameraIconFrame.setClickable(true); - switchCameraIconFrame.setEnabled(true); + switchCameraIconFrame.setClickable(true); + switchCameraIconFrame.setEnabled(true); + } else { + constraints.setVisibility(R.id.call_participant_switch_camera, View.GONE); + } } case MINI_SELF_PIP -> { constraints.connect( @@ -408,7 +424,7 @@ public class CallParticipantView extends ConstraintLayout { : recipient.getContactPhoto(); FallbackContactPhoto fallbackPhoto = recipient.getFallbackContactPhoto(FALLBACK_PHOTO_PROVIDER); - GlideApp.with(this) + Glide.with(this) .load(contactPhoto) .fallback(fallbackPhoto.asCallCard(getContext())) .error(fallbackPhoto.asCallCard(getContext())) diff --git a/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantsState.kt b/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantsState.kt index 35a4513d..c94338f3 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantsState.kt +++ b/app/src/main/java/org/tm/archive/components/webrtc/CallParticipantsState.kt @@ -53,7 +53,12 @@ data class CallParticipantsState( val raisedHands: List get() { - val results = allRemoteParticipants.filter { it.isHandRaised }.map { GroupCallRaiseHandEvent(it.recipient, it.handRaisedTimestamp) }.toMutableList() + val results = allRemoteParticipants.asSequence() + .filter { it.isHandRaised } + .distinctBy { it.recipient } + .map { GroupCallRaiseHandEvent(it.recipient, it.handRaisedTimestamp) } + .sortedBy { it.timestamp } + .toMutableList() if (localParticipant.isHandRaised) { results.add(GroupCallRaiseHandEvent(localParticipant.recipient, localParticipant.handRaisedTimestamp)) } diff --git a/app/src/main/java/org/tm/archive/components/webrtc/LayoutPositions.kt b/app/src/main/java/org/tm/archive/components/webrtc/LayoutPositions.kt index c536a0ab..9005c507 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/LayoutPositions.kt +++ b/app/src/main/java/org/tm/archive/components/webrtc/LayoutPositions.kt @@ -20,7 +20,7 @@ enum class LayoutPositions( SMALL_GROUP( participantBottomViewId = ConstraintSet.PARENT_ID, participantBottomMargin = 0, - reactionBottomViewId = R.id.call_screen_above_controls_guideline, + reactionBottomViewId = R.id.call_screen_pending_recipients, reactionBottomMargin = 8 ), @@ -28,7 +28,7 @@ enum class LayoutPositions( LARGE_GROUP( participantBottomViewId = R.id.call_screen_participants_recycler, participantBottomMargin = 16, - reactionBottomViewId = R.id.call_screen_participants_recycler, + reactionBottomViewId = R.id.call_screen_pending_recipients, reactionBottomMargin = 20 ); diff --git a/app/src/main/java/org/tm/archive/components/webrtc/WebRtcCallView.java b/app/src/main/java/org/tm/archive/components/webrtc/WebRtcCallView.java index 73ab6c31..f22d49a5 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/WebRtcCallView.java +++ b/app/src/main/java/org/tm/archive/components/webrtc/WebRtcCallView.java @@ -25,6 +25,7 @@ import androidx.annotation.StringRes; import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.Toolbar; import androidx.compose.ui.platform.ComposeView; +import androidx.constraintlayout.widget.Barrier; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.constraintlayout.widget.Guideline; @@ -35,6 +36,7 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.widget.MarginPageTransformer; import androidx.viewpager2.widget.ViewPager2; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.google.android.material.button.MaterialButton; @@ -51,7 +53,7 @@ import org.tm.archive.contacts.avatars.ContactPhoto; import org.tm.archive.contacts.avatars.ProfileContactPhoto; import org.tm.archive.events.CallParticipant; import org.tm.archive.events.WebRtcViewModel; -import org.tm.archive.mms.GlideApp; +import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.ringrtc.CameraState; @@ -94,7 +96,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { private RecipientId recipientId; private ImageView answer; private TextView answerWithoutVideoLabel; - private ImageView cameraDirectionToggle; private AccessibleToggleButton ringToggle; private PictureInPictureGestureHelper pictureInPictureGestureHelper; private ImageView overflow; @@ -124,6 +125,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { private RecyclerView groupReactionsFeed; private MultiReactionBurstLayout reactionViews; private ComposeView raiseHandSnackbar; + private Barrier pipBottomBoundaryBarrier; @@ -175,7 +177,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { incomingRingStatus = findViewById(R.id.call_screen_incoming_ring_status); answer = findViewById(R.id.call_screen_answer_call); answerWithoutVideoLabel = findViewById(R.id.call_screen_answer_without_video_label); - cameraDirectionToggle = findViewById(R.id.call_screen_camera_direction_toggle); ringToggle = findViewById(R.id.call_screen_audio_ring_toggle); overflow = findViewById(R.id.call_screen_overflow_button); hangup = findViewById(R.id.call_screen_end_call); @@ -203,6 +204,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { groupReactionsFeed = findViewById(R.id.call_screen_reactions_feed); reactionViews = findViewById(R.id.call_screen_reactions_container); raiseHandSnackbar = findViewById(R.id.call_screen_raise_hand_view); + pipBottomBoundaryBarrier = findViewById(R.id.pip_bottom_boundary_barrier); View decline = findViewById(R.id.call_screen_decline_call); View answerLabel = findViewById(R.id.call_screen_answer_call_label); @@ -269,7 +271,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { runIfNonNull(controlsListener, listener -> listener.onRingGroupChanged(isOn, ringToggle.isActivated())); }); - cameraDirectionToggle.setOnClickListener(v -> runIfNonNull(controlsListener, ControlsListener::onCameraDirectionChanged)); smallLocalRender.findViewById(R.id.call_participant_switch_camera).setOnClickListener(v -> runIfNonNull(controlsListener, ControlsListener::onCameraDirectionChanged)); overflow.setOnClickListener(v -> { @@ -351,10 +352,15 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { rotatableControls.add(audioToggle); rotatableControls.add(micToggle); rotatableControls.add(videoToggle); - rotatableControls.add(cameraDirectionToggle); rotatableControls.add(decline); rotatableControls.add(smallLocalAudioIndicator); rotatableControls.add(ringToggle); + + pipBottomBoundaryBarrier.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + if (bottom != oldBottom) { + onBarrierBottomChanged(bottom); + } + }); } @Override @@ -432,7 +438,13 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { if (state.getGroupCallState().isNotIdle()) { if (state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) { - callLinkWarningCard.setVisibility(callParticipantsViewState.isStartedFromCallLink() ? View.VISIBLE : View.GONE); + if (callParticipantsViewState.isStartedFromCallLink()) { + TextView warningTextView = callLinkWarningCard.get().findViewById(R.id.call_screen_call_link_warning_textview); + warningTextView.setText(SignalStore.phoneNumberPrivacy().isPhoneNumberSharingEnabled() ? R.string.WebRtcCallView__anyone_who_joins_pnp_enabled : R.string.WebRtcCallView__anyone_who_joins_pnp_disabled); + callLinkWarningCard.setVisibility(View.VISIBLE); + } else { + callLinkWarningCard.setVisibility(View.GONE); + } setStatus(state.getPreJoinGroupDescription(getContext())); } else if (state.getCallState() == WebRtcViewModel.State.CALL_CONNECTED && state.isInOutgoingRingingMode()) { callLinkWarningCard.setVisibility(View.GONE); @@ -494,11 +506,11 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { if (state == WebRtcLocalRenderState.EXPANDED) { pictureInPictureExpansionHelper.beginExpandTransition(); - smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.EXPANDED_SELF_PIP); + smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.EXPANDED_SELF_PIP, localCallParticipant.isMoreThanOneCameraAvailable()); return; } else if ((state.isAnySmall() || state == WebRtcLocalRenderState.GONE) && pictureInPictureExpansionHelper.isExpandedOrExpanding()) { pictureInPictureExpansionHelper.beginShrinkTransition(); - smallLocalRender.setSelfPipMode(pictureInPictureExpansionHelper.isMiniSize() ? CallParticipantView.SelfPipMode.MINI_SELF_PIP : CallParticipantView.SelfPipMode.NORMAL_SELF_PIP); + smallLocalRender.setSelfPipMode(pictureInPictureExpansionHelper.isMiniSize() ? CallParticipantView.SelfPipMode.MINI_SELF_PIP : CallParticipantView.SelfPipMode.NORMAL_SELF_PIP, localCallParticipant.isMoreThanOneCameraAvailable()); if (state != WebRtcLocalRenderState.GONE) { return; @@ -514,14 +526,14 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { break; case SMALL_RECTANGLE: smallLocalRenderFrame.setVisibility(View.VISIBLE); - animatePipToLargeRectangle(displaySmallSelfPipInLandscape); + animatePipToLargeRectangle(displaySmallSelfPipInLandscape, localCallParticipant.isMoreThanOneCameraAvailable()); largeLocalRender.attachBroadcastVideoSink(null); largeLocalRenderFrame.setVisibility(View.GONE); break; case SMALLER_RECTANGLE: smallLocalRenderFrame.setVisibility(View.VISIBLE); - animatePipToSmallRectangle(); + animatePipToSmallRectangle(localCallParticipant.isMoreThanOneCameraAvailable()); largeLocalRender.attachBroadcastVideoSink(null); largeLocalRenderFrame.setVisibility(View.GONE); @@ -546,7 +558,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { if (!localAvatar.equals(previousLocalAvatar)) { previousLocalAvatar = localAvatar; - GlideApp.with(getContext().getApplicationContext()) + Glide.with(getContext().getApplicationContext()) .load(localAvatar) .transform(new CenterCrop(), new BlurTransformation(getContext(), 0.25f, BlurTransformation.MAX_RADIUS)) .diskCacheStrategy(DiskCacheStrategy.ALL) @@ -773,7 +785,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { } } - private void animatePipToLargeRectangle(boolean isLandscape) { + private void animatePipToLargeRectangle(boolean isLandscape, boolean moreThanOneCameraAvailable) { final Point dimens; if (isLandscape) { dimens = new Point(ViewUtil.dpToPx(PictureInPictureExpansionHelper.NORMAL_PIP_HEIGHT_DP), @@ -790,10 +802,10 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { } }); - smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.NORMAL_SELF_PIP); + smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.NORMAL_SELF_PIP, moreThanOneCameraAvailable); } - private void animatePipToSmallRectangle() { + private void animatePipToSmallRectangle(boolean moreThanOneCameraAvailable) { pictureInPictureExpansionHelper.startDefaultSizeTransition(new Point(ViewUtil.dpToPx(PictureInPictureExpansionHelper.MINI_PIP_WIDTH_DP), ViewUtil.dpToPx(PictureInPictureExpansionHelper.MINI_PIP_HEIGHT_DP)), new PictureInPictureExpansionHelper.Callback() { @@ -803,7 +815,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { } }); - smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.MINI_SELF_PIP); + smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.MINI_SELF_PIP, moreThanOneCameraAvailable); } private void toggleControls() { @@ -826,6 +838,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { previousLayoutPositions = layoutPositions; ConstraintSet constraintSet = new ConstraintSet(); + constraintSet.setForceId(false); constraintSet.clone(this); constraintSet.connect(R.id.call_screen_participants_parent, @@ -851,17 +864,18 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { private void moveSnackbarAboveParticipantRail(boolean aboveRail) { if (aboveRail) { - updateSnackbarBottomConstraint(callParticipantsRecycler); + updatePendingParticipantsBottomConstraint(callParticipantsRecycler); } else { - updateSnackbarBottomConstraint(aboveControlsGuideline); + updatePendingParticipantsBottomConstraint(aboveControlsGuideline); } } - private void updateSnackbarBottomConstraint(View anchor) { + private void updatePendingParticipantsBottomConstraint(View anchor) { ConstraintSet constraintSet = new ConstraintSet(); + constraintSet.setForceId(false); constraintSet.clone(this); - constraintSet.connect(R.id.call_screen_raise_hand_view, + constraintSet.connect(R.id.call_screen_pending_recipients, ConstraintSet.BOTTOM, anchor.getId(), ConstraintSet.TOP, @@ -903,7 +917,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { } private void updateButtonStateForLargeButtons() { - cameraDirectionToggle.setImageResource(R.drawable.webrtc_call_screen_camera_toggle); hangup.setImageResource(R.drawable.webrtc_call_screen_hangup); overflow.setImageResource(R.drawable.webrtc_call_screen_overflow_menu); micToggle.setBackgroundResource(R.drawable.webrtc_call_screen_mic_toggle); @@ -914,7 +927,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { } private void updateButtonStateForSmallButtons() { - cameraDirectionToggle.setImageResource(R.drawable.webrtc_call_screen_camera_toggle_small); hangup.setImageResource(R.drawable.webrtc_call_screen_hangup_small); overflow.setImageResource(R.drawable.webrtc_call_screen_overflow_menu_small); micToggle.setBackgroundResource(R.drawable.webrtc_call_screen_mic_toggle_small); @@ -938,15 +950,12 @@ public class WebRtcCallView extends InsetAwareConstraintLayout { ringToggle.setActivated(enabled); } - public void onControlTopChanged(int guidelineTop, int snackBarHeight) { - int offset = 0; - if (lastState != null) { - CallParticipantsState state = lastState.getCallParticipantsState(); - if (!state.isViewingFocusedParticipant() && !state.isLargeVideoGroup()) { - offset = snackBarHeight; - } - pictureInPictureGestureHelper.setBottomVerticalBoundary(guidelineTop - offset); - } + public void onControlTopChanged() { + onBarrierBottomChanged(pipBottomBoundaryBarrier.getBottom()); + } + + private void onBarrierBottomChanged(int barrierBottom) { + pictureInPictureGestureHelper.setBottomVerticalBoundary(barrierBottom); } public interface ControlsListener { diff --git a/app/src/main/java/org/tm/archive/components/webrtc/WebRtcControls.java b/app/src/main/java/org/tm/archive/components/webrtc/WebRtcControls.java index 6c23e4d3..304c47f9 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/WebRtcControls.java +++ b/app/src/main/java/org/tm/archive/components/webrtc/WebRtcControls.java @@ -101,7 +101,9 @@ public final class WebRtcControls { isCallLink); } - /** This is only true at the very start of a call and will then never be true again */ + /** + * This is only true at the very start of a call and will then never be true again + */ public boolean hideControlsSheetInitially() { return displayIncomingCallButtons() || callState == CallState.NONE; } @@ -157,7 +159,7 @@ public final class WebRtcControls { } public boolean displayOverflow() { - return FeatureFlags.groupCallReactions() && isAtLeastOutgoing() && hasAtLeastOneRemote && isGroupCall(); + return (FeatureFlags.groupCallReactions() || FeatureFlags.groupCallRaiseHand()) && isAtLeastOutgoing() && hasAtLeastOneRemote && isGroupCall(); } public boolean displayMuteAudio() { diff --git a/app/src/main/java/org/tm/archive/components/webrtc/controls/CallInfoView.kt b/app/src/main/java/org/tm/archive/components/webrtc/controls/CallInfoView.kt index 88654387..00888f98 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/controls/CallInfoView.kt +++ b/app/src/main/java/org/tm/archive/components/webrtc/controls/CallInfoView.kt @@ -52,7 +52,6 @@ import org.signal.core.ui.Rows import org.signal.core.ui.theme.SignalTheme import org.signal.ringrtc.CallLinkState import org.tm.archive.R -import org.tm.archive.calls.links.SignalCallRow import org.tm.archive.components.AvatarImageView import org.tm.archive.components.webrtc.WebRtcCallViewModel import org.tm.archive.dependencies.ApplicationDependencies @@ -165,8 +164,16 @@ private fun CallInfo( modifier = modifier ) { item { + val text = if (controlAndInfoState.callLink == null) { + stringResource(id = R.string.CallLinkInfoSheet__call_info) + } else if (controlAndInfoState.callLink.state.name.isNotEmpty()) { + controlAndInfoState.callLink.state.name + } else { + stringResource(id = R.string.Recipient_signal_call) + } + Text( - text = stringResource(id = R.string.CallLinkInfoSheet__call_info), + text = text, style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(bottom = 24.dp) ) @@ -174,8 +181,6 @@ private fun CallInfo( if (controlAndInfoState.callLink != null) { item { - SignalCallRow(callLink = controlAndInfoState.callLink, onJoinClicked = null) - Rows.TextRow( text = stringResource(id = R.string.CallLinkDetailsFragment__share_link), icon = ImageVector.vectorResource(id = R.drawable.symbol_link_24), @@ -224,8 +229,7 @@ private fun CallInfo( } } - var includeAdminControlsDivider = true - if (controlAndInfoState.callLink == null || participantsState.isOngoing()) { + if (!participantsState.inCallLobby || participantsState.isOngoing()) { item { Box( modifier = Modifier @@ -240,13 +244,11 @@ private fun CallInfo( ) } } - } else { - includeAdminControlsDivider = false } if (!participantsState.inCallLobby || participantsState.isOngoing()) { items( - items = participantsState.participantsForList, + items = participantsState.participantsForList.distinctBy { it.callParticipantId }, key = { it.callParticipantId }, contentType = { null } ) { @@ -285,12 +287,16 @@ private fun CallInfo( if (controlAndInfoState.callLink?.credentials?.adminPassBytes != null) { item { - if (includeAdminControlsDivider) { + if (!participantsState.inCallLobby) { Dividers.Default() } Rows.TextRow( - text = stringResource(id = R.string.CallLinkDetailsFragment__add_call_name), + text = if (controlAndInfoState.callLink.state.name.isNotEmpty()) { + stringResource(id = R.string.CallLinkDetailsFragment__edit_call_name) + } else { + stringResource(id = R.string.CallLinkDetailsFragment__add_call_name) + }, onClick = onEditNameClicked ) Rows.ToggleRow( diff --git a/app/src/main/java/org/tm/archive/components/webrtc/controls/ControlsAndInfoController.kt b/app/src/main/java/org/tm/archive/components/webrtc/controls/ControlsAndInfoController.kt index 8d2cda2a..fee91837 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/controls/ControlsAndInfoController.kt +++ b/app/src/main/java/org/tm/archive/components/webrtc/controls/ControlsAndInfoController.kt @@ -97,7 +97,7 @@ class ControlsAndInfoController( private val handler: Handler? get() = webRtcCallView.handler - private var previousCallControlHeight = 0 + private var previousCallControlHeightData = HeightData() private var controlPeakHeight = 0 private var controlState: WebRtcControls = WebRtcControls.NONE @@ -147,13 +147,14 @@ class ControlsAndInfoController( webRtcCallView.post { onControlTopChanged() } } - raiseHandComposeView.addOnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ -> - onControlTopChanged(composeViewSize = bottom - top) + raiseHandComposeView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + onControlTopChanged() } callControls.viewTreeObserver.addOnGlobalLayoutListener { - if (callControls.height > 0 && callControls.height != previousCallControlHeight) { - previousCallControlHeight = callControls.height + if (callControls.height > 0 && previousCallControlHeightData.hasChanged(callControls.height, coordinator.height)) { + previousCallControlHeightData = HeightData(callControls.height, coordinator.height) + controlPeakHeight = callControls.height + callControls.y.toInt() behavior.peekHeight = controlPeakHeight frame.minimumHeight = coordinator.height / 2 @@ -184,8 +185,6 @@ class ControlsAndInfoController( callInfoComposeView.alpha = alphaCallInfo(slideOffset) callInfoComposeView.translationY = infoTranslationDistance - (infoTranslationDistance * callInfoComposeView.alpha) - - onControlTopChanged() } }) @@ -210,10 +209,10 @@ class ControlsAndInfoController( } } - fun onControlTopChanged(composeViewSize: Int = raiseHandComposeView.height) { + private fun onControlTopChanged() { val guidelineTop = max(frame.top, coordinator.height - behavior.peekHeight) aboveControlsGuideline.setGuidelineBegin(guidelineTop) - webRtcCallView.onControlTopChanged(guidelineTop, composeViewSize) + webRtcCallView.onControlTopChanged() } fun addVisibilityListener(listener: BottomSheetVisibilityListener): Boolean { @@ -322,7 +321,6 @@ class ControlsAndInfoController( val margin = if (controlState.displaySmallCallButtons()) 4.dp else 8.dp setControlConstraints(R.id.call_screen_speaker_toggle, controlState.displayAudioToggle(), margin) - setControlConstraints(R.id.call_screen_camera_direction_toggle, controlState.displayCameraToggle(), margin) setControlConstraints(R.id.call_screen_video_toggle, controlState.displayVideoToggle(), margin) setControlConstraints(R.id.call_screen_audio_mic_toggle, controlState.displayMuteAudio(), margin) setControlConstraints(R.id.call_screen_audio_ring_toggle, controlState.displayRingToggle(), margin) @@ -395,7 +393,7 @@ class ControlsAndInfoController( controlsAndInfoViewModel.setApproveAllMembers(checked) .observeOn(AndroidSchedulers.mainThread()) .subscribeBy(onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to change restrictions. $it") toastFailure() } @@ -421,7 +419,7 @@ class ControlsAndInfoController( .observeOn(AndroidSchedulers.mainThread()) .subscribeBy( onSuccess = { - if (it !is UpdateCallLinkResult.Success) { + if (it !is UpdateCallLinkResult.Update) { Log.w(TAG, "Failed to set name. $it") toastFailure() } @@ -458,6 +456,15 @@ class ControlsAndInfoController( displayEndCall() != previousState.displayEndCall() } + private data class HeightData( + val controlHeight: Int = 0, + val coordinatorHeight: Int = 0 + ) { + fun hasChanged(controlHeight: Int, coordinatorHeight: Int): Boolean { + return controlHeight != this.controlHeight || coordinatorHeight != this.coordinatorHeight + } + } + interface BottomSheetVisibilityListener { fun onShown() fun onHidden() diff --git a/app/src/main/java/org/tm/archive/components/webrtc/controls/RaiseHandSnackbar.kt b/app/src/main/java/org/tm/archive/components/webrtc/controls/RaiseHandSnackbar.kt index ce3ac4ba..7969ef17 100644 --- a/app/src/main/java/org/tm/archive/components/webrtc/controls/RaiseHandSnackbar.kt +++ b/app/src/main/java/org/tm/archive/components/webrtc/controls/RaiseHandSnackbar.kt @@ -120,7 +120,7 @@ private fun RaiseHand( modifier = modifier .padding(horizontal = 16.dp) .clip(shape = RoundedCornerShape(16.dp, 16.dp, 16.dp, 16.dp)) - .background(MaterialTheme.colorScheme.surface) + .background(SignalTheme.colors.colorSurface1) .animateContentSize() ) { val boxModifier = modifier diff --git a/app/src/main/java/org/tm/archive/compose/ComposeFullScreenDialogFragment.kt b/app/src/main/java/org/tm/archive/compose/ComposeFullScreenDialogFragment.kt new file mode 100644 index 00000000..42690b1b --- /dev/null +++ b/app/src/main/java/org/tm/archive/compose/ComposeFullScreenDialogFragment.kt @@ -0,0 +1,41 @@ +package org.tm.archive.compose + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.fragment.app.DialogFragment +import org.signal.core.ui.theme.SignalTheme +import org.tm.archive.R +import org.tm.archive.util.DynamicTheme + +/** + * Generic ComposeFragment which can be subclassed to build UI with compose. + */ +abstract class ComposeFullScreenDialogFragment : DialogFragment() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + SignalTheme( + isDarkMode = DynamicTheme.isDarkTheme(LocalContext.current) + ) { + DialogContent() + } + } + } + } + + @Composable + abstract fun DialogContent() +} diff --git a/app/src/main/java/org/tm/archive/contacts/ContactChip.java b/app/src/main/java/org/tm/archive/contacts/ContactChip.java index 22645adf..8ca28807 100644 --- a/app/src/main/java/org/tm/archive/contacts/ContactChip.java +++ b/app/src/main/java/org/tm/archive/contacts/ContactChip.java @@ -11,13 +11,13 @@ import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; import com.google.android.material.chip.Chip; import org.tm.archive.contacts.avatars.ContactPhoto; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.Recipient; public final class ContactChip extends Chip { @@ -44,7 +44,7 @@ public final class ContactChip extends Chip { return contact; } - public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, @Nullable Runnable onAvatarSet) { + public void setAvatar(@NonNull RequestManager requestManager, @Nullable Recipient recipient, @Nullable Runnable onAvatarSet) { if (recipient != null) { requestManager.clear(this); diff --git a/app/src/main/java/org/tm/archive/contacts/ContactRepository.java b/app/src/main/java/org/tm/archive/contacts/ContactRepository.java index a96dd422..d0d2a32f 100644 --- a/app/src/main/java/org/tm/archive/contacts/ContactRepository.java +++ b/app/src/main/java/org/tm/archive/contacts/ContactRepository.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import org.signal.libsignal.protocol.util.Pair; +import org.tm.archive.contacts.paged.ContactSearchSortOrder; import org.tm.archive.database.RecipientTable; import org.tm.archive.database.SignalDatabase; import org.tm.archive.phonenumbers.PhoneNumberFormatter; @@ -108,15 +109,15 @@ public class ContactRepository { @WorkerThread public @NonNull Cursor querySignalContacts(@NonNull String query) { - return querySignalContacts(query, true); + return querySignalContacts(new RecipientTable.ContactSearchQuery(query, true, ContactSearchSortOrder.NATURAL)); } @WorkerThread - public @NonNull Cursor querySignalContacts(@NonNull String query, boolean includeSelf) { - Cursor cursor = TextUtils.isEmpty(query) ? recipientTable.getSignalContacts(includeSelf) - : recipientTable.querySignalContacts(query, includeSelf); + public @NonNull Cursor querySignalContacts(@NonNull RecipientTable.ContactSearchQuery contactSearchQuery) { + Cursor cursor = TextUtils.isEmpty(contactSearchQuery.getQuery()) ? recipientTable.getSignalContacts(contactSearchQuery.getIncludeSelf()) + : recipientTable.querySignalContacts(contactSearchQuery); - cursor = handleNoteToSelfQuery(query, includeSelf, cursor); + cursor = handleNoteToSelfQuery(contactSearchQuery.getQuery(), contactSearchQuery.getIncludeSelf(), cursor); return new SearchCursorWrapper(cursor, SEARCH_CURSOR_MAPPERS); } diff --git a/app/src/main/java/org/tm/archive/contacts/ContactsSyncAdapter.java b/app/src/main/java/org/tm/archive/contacts/ContactsSyncAdapter.java index 03f17043..4428e16f 100644 --- a/app/src/main/java/org/tm/archive/contacts/ContactsSyncAdapter.java +++ b/app/src/main/java/org/tm/archive/contacts/ContactsSyncAdapter.java @@ -79,10 +79,6 @@ public class ContactsSyncAdapter extends AbstractThreadedSyncAdapter { try { ContactDiscovery.refresh(context, recipients, true); - - if (Util.isDefaultSmsProvider(context)) { - ContactDiscovery.syncRecipientInfoWithSystemContacts(context); - } } catch (IOException e) { Log.w(TAG, "Failed to refresh! Scheduling for later.", e); ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(true)); diff --git a/app/src/main/java/org/tm/archive/contacts/SelectedContacts.kt b/app/src/main/java/org/tm/archive/contacts/SelectedContacts.kt index f1b30213..712c46a8 100644 --- a/app/src/main/java/org/tm/archive/contacts/SelectedContacts.kt +++ b/app/src/main/java/org/tm/archive/contacts/SelectedContacts.kt @@ -1,8 +1,8 @@ package org.tm.archive.contacts import android.view.View +import com.bumptech.glide.Glide import org.tm.archive.R -import org.tm.archive.mms.GlideApp import org.tm.archive.recipients.Recipient import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter @@ -30,13 +30,13 @@ object SelectedContacts { private val chip: ContactChip = itemView.findViewById(R.id.contact_chip) override fun bind(model: Model) { - chip.text = model.recipient.getShortDisplayNameIncludingUsername(context) + chip.text = model.recipient.getShortDisplayName(context) chip.setContact(model.selectedContact) chip.isCloseIconVisible = true chip.setOnCloseIconClickListener { onCloseIconClicked(model) } - chip.setAvatar(GlideApp.with(itemView), model.recipient, null) + chip.setAvatar(Glide.with(itemView), model.recipient, null) } } } diff --git a/app/src/main/java/org/tm/archive/contacts/avatars/TransparentContactPhoto.java b/app/src/main/java/org/tm/archive/contacts/avatars/TransparentContactPhoto.java index 26252d7c..aadb7dec 100644 --- a/app/src/main/java/org/tm/archive/contacts/avatars/TransparentContactPhoto.java +++ b/app/src/main/java/org/tm/archive/contacts/avatars/TransparentContactPhoto.java @@ -32,7 +32,7 @@ public class TransparentContactPhoto implements FallbackContactPhoto { @Override public Drawable asCallCard(@NonNull Context context) { - return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large); + return ContextCompat.getDrawable(context, R.drawable.symbol_person_display_40); } } diff --git a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchAdapter.kt b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchAdapter.kt index 1213f17e..67730b3d 100644 --- a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchAdapter.kt +++ b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchAdapter.kt @@ -1,11 +1,13 @@ package org.tm.archive.contacts.paged import android.content.Context +import android.text.SpannableStringBuilder import android.view.View import android.view.ViewGroup import android.widget.CheckBox import android.widget.TextView import androidx.appcompat.widget.AppCompatImageView +import androidx.core.content.ContextCompat import com.google.android.material.button.MaterialButton import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Observable @@ -28,6 +30,8 @@ import org.tm.archive.database.model.DistributionListPrivacyMode import org.tm.archive.database.model.StoryViewState import org.tm.archive.keyvalue.SignalStore import org.tm.archive.recipients.Recipient +import org.tm.archive.util.ContextUtil +import org.tm.archive.util.SpanUtil import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingModel @@ -390,19 +394,41 @@ open class ContactSearchAdapter( private val checkbox: CheckBox = itemView.findViewById(R.id.check_box) private val name: FromTextView = itemView.findViewById(R.id.name) private val number: TextView = itemView.findViewById(R.id.number) + private val headerGroup: View = itemView.findViewById(R.id.contact_header) + private val headerText: TextView = itemView.findViewById(R.id.section_header) override fun bind(model: UnknownRecipientModel) { checkbox.visible = displayCheckBox checkbox.isSelected = false - name.setText( - when (model.data.mode) { - ContactSearchConfiguration.NewRowMode.NEW_CALL -> R.string.contact_selection_list__new_call - ContactSearchConfiguration.NewRowMode.NEW_CONVERSATION -> R.string.contact_selection_list__unknown_contact - ContactSearchConfiguration.NewRowMode.BLOCK -> R.string.contact_selection_list__unknown_contact_block - ContactSearchConfiguration.NewRowMode.ADD_TO_GROUP -> R.string.contact_selection_list__unknown_contact_add_to_group - } - ) - number.text = model.data.query + val nameText = when (model.data.mode) { + ContactSearchConfiguration.NewRowMode.NEW_CALL -> R.string.contact_selection_list__new_call + ContactSearchConfiguration.NewRowMode.NEW_CONVERSATION -> -1 + ContactSearchConfiguration.NewRowMode.BLOCK -> R.string.contact_selection_list__unknown_contact_block + ContactSearchConfiguration.NewRowMode.ADD_TO_GROUP -> R.string.contact_selection_list__unknown_contact_add_to_group + } + + if (nameText > 0) { + name.setText(nameText) + number.text = model.data.query + number.visible = true + } else { + name.text = model.data.query + number.visible = false + } + + if (model.data.mode == ContactSearchConfiguration.NewRowMode.NEW_CONVERSATION) { + headerGroup.visible = true + headerText.setText( + if (model.data.sectionKey == ContactSearchConfiguration.SectionKey.PHONE_NUMBER) { + R.string.FindByActivity__find_by_phone_number + } else { + R.string.FindByActivity__find_by_username + } + ) + } else { + headerGroup.visible = false + } + itemView.setOnClickListener { onClick.onClicked(itemView, model.data, false) } @@ -500,7 +526,19 @@ open class ContactSearchAdapter( return } - name.setText(getRecipient(model)) + val recipient = getRecipient(model) + val suffix: CharSequence? = if (recipient.isSystemContact && !recipient.showVerified()) { + SpannableStringBuilder().apply { + val drawable = ContextUtil.requireDrawable(context, R.drawable.symbol_person_circle_24).apply { + setTint(ContextCompat.getColor(context, R.color.signal_colorOnSurface)) + } + SpanUtil.appendCenteredImageSpan(this, drawable, 16, 16) + } + } else { + null + } + name.setText(recipient, suffix) + badge.setBadgeFromRecipient(getRecipient(model)) bindAvatar(model) diff --git a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchConfiguration.kt b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchConfiguration.kt index 6f68d7e9..f9102fbb 100644 --- a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchConfiguration.kt +++ b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchConfiguration.kt @@ -69,6 +69,8 @@ class ContactSearchConfiguration private constructor( /** * 1:1 Recipients with whom the user has started a conversation. * + * Note that sort order is only respected when returning a query result for signal-only contacts. In all other cases, natural ordering is used. + * * Key: [ContactSearchKey.RecipientSearchKey] * Data: [ContactSearchData.KnownRecipient] * Model: [ContactSearchAdapter.RecipientModel] @@ -78,7 +80,8 @@ class ContactSearchConfiguration private constructor( val transportType: TransportType, override val includeHeader: Boolean, override val expandConfig: ExpandConfig? = null, - val includeLetterHeaders: Boolean = false + val includeLetterHeaders: Boolean = false, + val pushSearchResultsSortOrder: ContactSearchSortOrder = ContactSearchSortOrder.NATURAL ) : Section(SectionKey.INDIVIDUALS) /** diff --git a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSource.kt b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSource.kt index dfd0ae32..1d33bf99 100644 --- a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSource.kt +++ b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSource.kt @@ -9,6 +9,7 @@ import org.tm.archive.contacts.paged.collections.ContactSearchIterator import org.tm.archive.contacts.paged.collections.CursorSearchIterator import org.tm.archive.contacts.paged.collections.StoriesSearchCollection import org.tm.archive.database.GroupTable +import org.tm.archive.database.RecipientTable import org.tm.archive.database.model.DistributionListPrivacyMode import org.tm.archive.database.model.GroupRecord import org.tm.archive.database.model.ThreadRecord @@ -20,7 +21,6 @@ import org.tm.archive.search.MessageResult import org.tm.archive.search.MessageSearchResult import org.tm.archive.search.SearchRepository import org.tm.archive.search.ThreadSearchResult -import org.tm.archive.util.FeatureFlags import org.tm.archive.util.UsernameUtil import java.util.concurrent.TimeUnit @@ -189,14 +189,10 @@ class ContactSearchPagedDataSource( return false } - return if (FeatureFlags.usernames()) { - NumberUtil.isVisuallyValidNumberOrEmail(query) - } else { - NumberUtil.isValidSmsOrEmail(query) - } + return NumberUtil.isVisuallyValidNumberOrEmail(query) } private fun isPossiblyUsername(query: String?): Boolean { - return query != null && FeatureFlags.usernames() && UsernameUtil.isValidUsernameForSearch(query) + return query != null && UsernameUtil.isValidUsernameForSearch(query) } private fun getPossiblePhoneNumber(section: ContactSearchConfiguration.Section.PhoneNumber, query: String?): List { return if (isPossiblyPhoneNumber(query)) { @@ -215,7 +211,10 @@ class ContactSearchPagedDataSource( private fun getNonGroupSearchIterator(section: ContactSearchConfiguration.Section.Individuals, query: String?): ContactSearchIterator { return when (section.transportType) { - ContactSearchConfiguration.TransportType.PUSH -> CursorSearchIterator(wrapRecipientCursor(contactSearchPagedDataSourceRepository.querySignalContacts(query, section.includeSelf))) + ContactSearchConfiguration.TransportType.PUSH -> { + val searchQuery = RecipientTable.ContactSearchQuery(query ?: "", section.includeSelf, section.pushSearchResultsSortOrder) + CursorSearchIterator(wrapRecipientCursor(contactSearchPagedDataSourceRepository.querySignalContacts(searchQuery))) + } ContactSearchConfiguration.TransportType.SMS -> CursorSearchIterator(wrapRecipientCursor(contactSearchPagedDataSourceRepository.queryNonSignalContacts(query))) ContactSearchConfiguration.TransportType.ALL -> CursorSearchIterator(wrapRecipientCursor(contactSearchPagedDataSourceRepository.queryNonGroupContacts(query, section.includeSelf))) } diff --git a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSourceRepository.kt b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSourceRepository.kt index e26dda83..3d0ba271 100644 --- a/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSourceRepository.kt +++ b/app/src/main/java/org/tm/archive/contacts/paged/ContactSearchPagedDataSourceRepository.kt @@ -34,8 +34,8 @@ open class ContactSearchPagedDataSourceRepository( .getLatestActiveStorySendTimestamps(System.currentTimeMillis() - activeStoryCutoffDuration) } - open fun querySignalContacts(query: String?, includeSelf: Boolean): Cursor? { - return contactRepository.querySignalContacts(query ?: "", includeSelf) + open fun querySignalContacts(contactsSearchQuery: RecipientTable.ContactSearchQuery): Cursor? { + return contactRepository.querySignalContacts(contactsSearchQuery) } open fun querySignalContactLetterHeaders(query: String?, includeSelf: Boolean, includePush: Boolean, includeSms: Boolean): Map { diff --git a/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscovery.kt b/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscovery.kt index f6ca2375..4dc541e4 100644 --- a/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscovery.kt +++ b/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscovery.kt @@ -25,9 +25,9 @@ import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.registration.RegistrationUtil import org.tm.archive.storage.StorageSyncHelper -import org.tm.archive.util.FeatureFlags import org.tm.archive.util.TextSecurePreferences import org.tm.archive.util.Util +import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.util.UuidUtil import java.io.IOException @@ -70,7 +70,7 @@ object ContactDiscovery { context = context, descriptor = "refresh-all", refresh = { - ContactDiscoveryRefreshV2.refreshAll(context, useCompat = FeatureFlags.cdsCompatMode()) + ContactDiscoveryRefreshV2.refreshAll(context) }, removeSystemContactLinksIfMissing = true, notifyOfNewUsers = notifyOfNewUsers, @@ -87,9 +87,7 @@ object ContactDiscovery { refreshRecipients( context = context, descriptor = "refresh-multiple", - refresh = { - ContactDiscoveryRefreshV2.refresh(context, recipients, useCompat = FeatureFlags.cdsCompatMode()) - }, + refresh = { ContactDiscoveryRefreshV2.refresh(context, recipients) }, removeSystemContactLinksIfMissing = false, notifyOfNewUsers = notifyOfNewUsers ) @@ -103,9 +101,7 @@ object ContactDiscovery { val result: RefreshResult = refreshRecipients( context = context, descriptor = "refresh-single", - refresh = { - ContactDiscoveryRefreshV2.refresh(context, listOf(recipient), useCompat = FeatureFlags.cdsCompatMode(), timeoutMs = timeoutMs) - }, + refresh = { ContactDiscoveryRefreshV2.refresh(context, listOf(recipient), timeoutMs = timeoutMs) }, removeSystemContactLinksIfMissing = false, notifyOfNewUsers = notifyOfNewUsers ) @@ -117,6 +113,19 @@ object ContactDiscovery { } } + /** + * Looks up the PNI/ACI for an E164. Only creates a recipient if the number is in the CDS directory. + * Use sparingly! This will always use up the user's CDS quota. Always prefer other syncing methods for bulk lookups. + * + * Returns a [LookupResult] if the E164 is in the CDS directory, or null if it is not. + * Important: Just because a user is not in the directory does not mean they are not registered. They could have discoverability off. + */ + @Throws(IOException::class) + @WorkerThread + fun lookupE164(e164: String): LookupResult? { + return ContactDiscoveryRefreshV2.lookupE164(e164) + } + @JvmStatic @WorkerThread fun syncRecipientInfoWithSystemContacts(context: Context) { @@ -198,9 +207,12 @@ object ContactDiscovery { if (!SignalStore.settings().isNotifyWhenContactJoinsSignal) return Recipient.resolvedList(newUserIds) - .filter { !it.isSelf && it.hasAUserSetDisplayName(context) && !hasSession(it.id) } - .map { IncomingMessage.contactJoined(it.id, System.currentTimeMillis()) } - .map { SignalDatabase.messages.insertMessageInbox(it) } + .filter { !it.isSelf && it.hasAUserSetDisplayName(context) && !hasSession(it.id) && it.hasE164() } + .map { + Log.i(TAG, "Inserting 'contact joined' message for ${it.id}. E164: ${it.e164}") + val message = IncomingMessage.contactJoined(it.id, System.currentTimeMillis()) + SignalDatabase.messages.insertMessageInbox(message) + } .filter { it.isPresent } .map { it.get() } .forEach { result -> @@ -280,7 +292,7 @@ object ContactDiscovery { /** * Whether or not a session exists with the provided recipient. */ - fun hasSession(id: RecipientId): Boolean { + private fun hasSession(id: RecipientId): Boolean { val recipient = Recipient.resolved(id) if (!recipient.hasServiceId()) { @@ -297,4 +309,10 @@ object ContactDiscovery { val registeredIds: Set, val rewrites: Map ) + + data class LookupResult( + val recipientId: RecipientId, + val pni: ServiceId.PNI, + val aci: ServiceId.ACI? + ) } diff --git a/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscoveryRefreshV2.kt b/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscoveryRefreshV2.kt index 55172b0c..be7c7d53 100644 --- a/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscoveryRefreshV2.kt +++ b/app/src/main/java/org/tm/archive/contacts/sync/ContactDiscoveryRefreshV2.kt @@ -44,7 +44,7 @@ object ContactDiscoveryRefreshV2 { @WorkerThread @Synchronized @JvmStatic - fun refreshAll(context: Context, useCompat: Boolean, timeoutMs: Long? = null): ContactDiscovery.RefreshResult { + fun refreshAll(context: Context, timeoutMs: Long? = null): ContactDiscovery.RefreshResult { val recipientE164s: Set = SignalDatabase.recipients.getAllE164s().sanitize() val systemE164s: Set = SystemContactsRepository.getAllDisplayNumbers(context).toE164s(context).sanitize() @@ -53,7 +53,6 @@ object ContactDiscoveryRefreshV2 { systemE164s = systemE164s, inputPreviousE164s = SignalDatabase.cds.getAllE164s(), isPartialRefresh = false, - useCompat = useCompat, timeoutMs = timeoutMs ) } @@ -62,14 +61,14 @@ object ContactDiscoveryRefreshV2 { @WorkerThread @Synchronized @JvmStatic - fun refresh(context: Context, inputRecipients: List, useCompat: Boolean, timeoutMs: Long? = null): ContactDiscovery.RefreshResult { + fun refresh(context: Context, inputRecipients: List, timeoutMs: Long? = null): ContactDiscovery.RefreshResult { val recipients: List = inputRecipients.map { it.resolve() } val inputE164s: Set = recipients.mapNotNull { it.e164.orElse(null) }.toSet().sanitize() return if (inputE164s.size > MAXIMUM_ONE_OFF_REQUEST_SIZE) { Log.i(TAG, "List of specific recipients to refresh is too large! (Size: ${recipients.size}). Doing a full refresh instead.") - val fullResult: ContactDiscovery.RefreshResult = refreshAll(context, useCompat = useCompat, timeoutMs = timeoutMs) + val fullResult: ContactDiscovery.RefreshResult = refreshAll(context, timeoutMs = timeoutMs) val inputIds: Set = recipients.map { it.id }.toSet() ContactDiscovery.RefreshResult( @@ -82,22 +81,56 @@ object ContactDiscoveryRefreshV2 { systemE164s = inputE164s, inputPreviousE164s = emptySet(), isPartialRefresh = true, - useCompat = useCompat, timeoutMs = timeoutMs ) } } + @Throws(IOException::class) + @WorkerThread + @Synchronized + fun lookupE164(e164: String): ContactDiscovery.LookupResult? { + val response: CdsiV2Service.Response = try { + ApplicationDependencies.getSignalServiceAccountManager().getRegisteredUsersWithCdsi( + emptySet(), + setOf(e164), + SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(), + Optional.empty(), + BuildConfig.CDSI_MRENCLAVE, + 10_000, + if (FeatureFlags.useLibsignalNetForCdsiLookup()) BuildConfig.LIBSIGNAL_NET_ENV else null + ) { + Log.i(TAG, "Ignoring token for one-off lookup.") + } + } catch (e: CdsiResourceExhaustedException) { + Log.w(TAG, "CDS resource exhausted! Can try again in ${e.retryAfterSeconds} seconds.") + SignalStore.misc().cdsBlockedUtil = System.currentTimeMillis() + e.retryAfterSeconds.seconds.inWholeMilliseconds + throw e + } catch (e: CdsiInvalidTokenException) { + Log.w(TAG, "We did not provide a token, but still got a token error! Unexpected, but ignoring.") + throw e + } + + return response.results[e164]?.let { item -> + val id = SignalDatabase.recipients.processIndividualCdsLookup(e164 = e164, aci = item.aci.orElse(null), pni = item.pni) + + ContactDiscovery.LookupResult( + recipientId = id, + pni = item.pni, + aci = item.aci?.orElse(null) + ) + } + } + @Throws(IOException::class) private fun refreshInternal( recipientE164s: Set, systemE164s: Set, inputPreviousE164s: Set, isPartialRefresh: Boolean, - useCompat: Boolean, timeoutMs: Long? = null ): ContactDiscovery.RefreshResult { - val tag = "refreshInternal-${if (useCompat) "compat" else "v2"}" + val tag = "refreshInternal-v2" val stopwatch = Stopwatch(tag) val previousE164s: Set = if (SignalStore.misc().cdsToken != null && !isPartialRefresh) inputPreviousE164s else emptySet() @@ -127,10 +160,10 @@ object ContactDiscoveryRefreshV2 { previousE164s, newE164s, SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(), - useCompat, Optional.ofNullable(token), BuildConfig.CDSI_MRENCLAVE, - timeoutMs + timeoutMs, + if (FeatureFlags.useLibsignalNetForCdsiLookup()) BuildConfig.LIBSIGNAL_NET_ENV else null ) { tokenToSave -> stopwatch.split("network-pre-token") if (!isPartialRefresh) { @@ -165,10 +198,6 @@ object ContactDiscoveryRefreshV2 { val registeredIds: MutableSet = mutableSetOf() val rewrites: MutableMap = mutableMapOf() - if (useCompat && !response.isCompatResponse()) { - Log.w(TAG, "Was told to useCompat, but the server responded with a non-compat response! Assuming the server has shut off compat mode.") - } - val transformed: Map = response.results.mapValues { entry -> CdsV2Result(entry.value.pni, entry.value.aci.orElse(null)) } val fuzzyOutput: OutputResult = FuzzyPhoneNumberHelper.generateOutput(transformed, fuzzyInput) @@ -182,9 +211,12 @@ object ContactDiscoveryRefreshV2 { val existingIds: Set = SignalDatabase.recipients.getAllPossiblyRegisteredByE164(recipientE164s + rewrites.values) stopwatch.split("get-ids") - val inactiveIds: Set = (existingIds - registeredIds).removePossiblyRegisteredButUnlisted() + val inactiveIds: Set = (existingIds - registeredIds).removePossiblyRegisteredButUndiscoverable() stopwatch.split("registered-but-unlisted") + val missingFromCds: Set = existingIds - registeredIds + SignalDatabase.recipients.updatePhoneNumberDiscoverability(registeredIds, missingFromCds) + SignalDatabase.recipients.bulkUpdatedRegisteredStatus(registeredIds, inactiveIds) stopwatch.split("update-registered") @@ -195,17 +227,17 @@ object ContactDiscoveryRefreshV2 { private fun hasCommunicatedWith(recipient: Recipient): Boolean { val localAci = SignalStore.account().requireAci() - return SignalDatabase.threads.hasThread(recipient.id) || (recipient.hasServiceId() && SignalDatabase.sessions.hasSessionFor(localAci, recipient.requireServiceId().toString())) + return SignalDatabase.threads.hasActiveThread(recipient.id) || (recipient.hasServiceId() && SignalDatabase.sessions.hasSessionFor(localAci, recipient.requireServiceId().toString())) } /** - * If an account is unlisted, it won't come back in the CDS response. So just because we're missing a entry doesn't mean they've become unregistered. + * If an account is undiscoverable, it won't come back in the CDS response. So just because we're missing a entry doesn't mean they've become unregistered. * This function removes people from the list that both have a serviceId and some history of communication. We consider this a good heuristic for * "maybe this person just removed themselves from CDS". We'll rely on profile fetches that occur during chat opens to check registered status and clear * actually-unregistered users out. */ @WorkerThread - private fun Set.removePossiblyRegisteredButUnlisted(): Set { + private fun Set.removePossiblyRegisteredButUndiscoverable(): Set { val selfId = Recipient.self().id return this - Recipient.resolvedList(this) .filter { @@ -235,13 +267,4 @@ object ContactDiscoveryRefreshV2 { val nearestThousand = (this.toDouble() / 1000).roundToInt() return "~${nearestThousand}k" } - - /** - * Responses that respect useCompat will have an ACI for every user. If it doesn't, it means is a PNP response where some accounts may only have PNI's. - * There may come a day when we request compat mode but the server refuses to allow it, so we need to be able to detect when that happens to fallback - * to the PNP behavior. - */ - private fun CdsiV2Service.Response.isCompatResponse(): Boolean { - return this.results.values.all { it.hasAci() } - } } diff --git a/app/src/main/java/org/tm/archive/contactshare/ContactFieldAdapter.java b/app/src/main/java/org/tm/archive/contactshare/ContactFieldAdapter.java index 0110b817..c28aec9a 100644 --- a/app/src/main/java/org/tm/archive/contactshare/ContactFieldAdapter.java +++ b/app/src/main/java/org/tm/archive/contactshare/ContactFieldAdapter.java @@ -15,11 +15,11 @@ import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; import com.annimon.stream.Stream; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.tm.archive.R; import org.tm.archive.contactshare.Contact.Phone; -import org.tm.archive.mms.GlideRequests; import java.util.ArrayList; import java.util.List; @@ -31,16 +31,16 @@ import static org.tm.archive.contactshare.Contact.PostalAddress; class ContactFieldAdapter extends RecyclerView.Adapter { - private final Locale locale; - private final boolean selectable; - private final List fields; - private final GlideRequests glideRequests; + private final Locale locale; + private final boolean selectable; + private final List fields; + private final RequestManager requestManager; - public ContactFieldAdapter(@NonNull Locale locale, @NonNull GlideRequests glideRequests, boolean selectable) { - this.locale = locale; - this.glideRequests = glideRequests; - this.selectable = selectable; - this.fields = new ArrayList<>(); + public ContactFieldAdapter(@NonNull Locale locale, @NonNull RequestManager requestManager, boolean selectable) { + this.locale = locale; + this.requestManager = requestManager; + this.selectable = selectable; + this.fields = new ArrayList<>(); } @Override @@ -50,7 +50,7 @@ class ContactFieldAdapter extends RecyclerView.Adapter { - private final GlideRequests glideRequests; - private final Locale locale; - private final EventListener eventListener; - private final List contacts; + private final RequestManager requestManager; + private final Locale locale; + private final EventListener eventListener; + private final List contacts; - ContactShareEditAdapter(@NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull EventListener eventListener) { - this.glideRequests = glideRequests; - this.locale = locale; - this.eventListener = eventListener; - this.contacts = new ArrayList<>(); + ContactShareEditAdapter(@NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull EventListener eventListener) { + this.requestManager = requestManager; + this.locale = locale; + this.eventListener = eventListener; + this.contacts = new ArrayList<>(); } @Override public @NonNull ContactEditViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ContactEditViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_editable_contact, parent, false), locale, - glideRequests); + requestManager); } @Override @@ -67,12 +68,12 @@ public class ContactShareEditAdapter extends RecyclerView.Adapter { + mediaAdapter = new AttachmentKeyboardMediaAdapter(Glide.with(this), media -> { if (callback != null) { callback.onAttachmentMediaClicked(media); } diff --git a/app/src/main/java/org/tm/archive/conversation/AttachmentKeyboardMediaAdapter.java b/app/src/main/java/org/tm/archive/conversation/AttachmentKeyboardMediaAdapter.java index 93efaae5..c1894a81 100644 --- a/app/src/main/java/org/tm/archive/conversation/AttachmentKeyboardMediaAdapter.java +++ b/app/src/main/java/org/tm/archive/conversation/AttachmentKeyboardMediaAdapter.java @@ -8,10 +8,11 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; import org.tm.archive.components.ThumbnailView; import org.tm.archive.mediasend.Media; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.util.MediaUtil; import org.tm.archive.util.adapter.StableIdGenerator; @@ -22,15 +23,15 @@ import java.util.concurrent.TimeUnit; class AttachmentKeyboardMediaAdapter extends RecyclerView.Adapter { private final List media; - private final GlideRequests glideRequests; + private final RequestManager requestManager; private final Listener listener; private final StableIdGenerator idGenerator; - AttachmentKeyboardMediaAdapter(@NonNull GlideRequests glideRequests, @NonNull Listener listener) { - this.glideRequests = glideRequests; - this.listener = listener; - this.media = new ArrayList<>(); - this.idGenerator = new StableIdGenerator<>(); + AttachmentKeyboardMediaAdapter(@NonNull RequestManager requestManager, @NonNull Listener listener) { + this.requestManager = requestManager; + this.listener = listener; + this.media = new ArrayList<>(); + this.idGenerator = new StableIdGenerator<>(); setHasStableIds(true); } @@ -47,7 +48,7 @@ class AttachmentKeyboardMediaAdapter extends RecyclerView.Adapter listener.onMediaClicked(media)); duration.setVisibility(View.GONE); diff --git a/app/src/main/java/org/tm/archive/conversation/ConversationAdapter.java b/app/src/main/java/org/tm/archive/conversation/ConversationAdapter.java index f50b4290..f474b258 100644 --- a/app/src/main/java/org/tm/archive/conversation/ConversationAdapter.java +++ b/app/src/main/java/org/tm/archive/conversation/ConversationAdapter.java @@ -39,6 +39,8 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.media3.common.MediaItem; +import com.bumptech.glide.RequestManager; + import org.signal.core.util.logging.Log; import org.signal.paging.PagingController; import org.tm.archive.BindableConversationItem; @@ -50,7 +52,6 @@ import org.tm.archive.database.model.MmsMessageRecord; import org.tm.archive.database.model.MessageRecord; import org.tm.archive.giph.mp4.GiphyMp4Playable; import org.tm.archive.giph.mp4.GiphyMp4PlaybackPolicyEnforcer; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.CachedInflater; import org.tm.archive.util.DateUtils; @@ -99,7 +100,7 @@ public class ConversationAdapter private final ItemClickListener clickListener; private final Context context; private final LifecycleOwner lifecycleOwner; - private final GlideRequests glideRequests; + private final RequestManager requestManager; private final Locale locale; private final Set selected; private final Calendar calendar; @@ -119,7 +120,7 @@ public class ConversationAdapter public ConversationAdapter(@NonNull Context context, @NonNull LifecycleOwner lifecycleOwner, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @Nullable ItemClickListener clickListener, boolean hasWallpaper, @@ -137,10 +138,10 @@ public class ConversationAdapter } }); - this.lifecycleOwner = lifecycleOwner; - this.context = context; + this.lifecycleOwner = lifecycleOwner; + this.context = context; - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.locale = locale; this.clickListener = clickListener; this.selected = new HashSet<>(); @@ -276,7 +277,7 @@ public class ConversationAdapter conversationMessage, Optional.ofNullable(previousMessage != null ? previousMessage.getMessageRecord() : null), Optional.ofNullable(nextMessage != null ? nextMessage.getMessageRecord() : null), - glideRequests, + requestManager, locale, selected, conversationMessage.getThreadRecipient(), diff --git a/app/src/main/java/org/tm/archive/conversation/ConversationHeaderView.java b/app/src/main/java/org/tm/archive/conversation/ConversationHeaderView.java index 9bad2b16..aa657a82 100644 --- a/app/src/main/java/org/tm/archive/conversation/ConversationHeaderView.java +++ b/app/src/main/java/org/tm/archive/conversation/ConversationHeaderView.java @@ -15,6 +15,8 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; import androidx.core.view.ViewKt; +import com.bumptech.glide.RequestManager; + import org.signal.core.util.DimensionUnit; import org.signal.core.util.concurrent.SignalExecutors; import org.tm.archive.R; @@ -23,7 +25,6 @@ import org.tm.archive.contacts.avatars.FallbackContactPhoto; import org.tm.archive.contacts.avatars.ResourceContactPhoto; import org.tm.archive.database.SignalDatabase; import org.tm.archive.databinding.ConversationHeaderViewBinding; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.Recipient; import org.tm.archive.util.ContextUtil; import org.tm.archive.util.LongClickMovementMethod; @@ -60,8 +61,8 @@ public class ConversationHeaderView extends ConstraintLayout { } } - public void setAvatar(@NonNull GlideRequests requests, @Nullable Recipient recipient) { - binding.messageRequestAvatar.setAvatar(requests, recipient, false); + public void setAvatar(@NonNull RequestManager requestManager, @Nullable Recipient recipient) { + binding.messageRequestAvatar.setAvatar(requestManager, recipient, false); if (recipient != null && recipient.shouldBlurAvatar() && recipient.getContactPhoto() != null) { binding.messageRequestAvatarTapToView.setVisibility(VISIBLE); @@ -75,7 +76,7 @@ public class ConversationHeaderView extends ConstraintLayout { } public String setTitle(@NonNull Recipient recipient) { - SpannableStringBuilder title = new SpannableStringBuilder(recipient.isSelf() ? getContext().getString(R.string.note_to_self) : recipient.getDisplayNameOrUsername(getContext())); + SpannableStringBuilder title = new SpannableStringBuilder(recipient.isSelf() ? getContext().getString(R.string.note_to_self) : recipient.getDisplayName(getContext())); if (recipient.showVerified()) { SpanUtil.appendCenteredImageSpan(title, ContextUtil.requireDrawable(getContext(), R.drawable.ic_official_28), 28, 28); } @@ -119,54 +120,69 @@ public class ConversationHeaderView extends ConstraintLayout { return binding.messageRequestDescription; } + public void setButton(@NonNull CharSequence button, Runnable onClick) { + binding.messageRequestButton.setText(button); + binding.messageRequestButton.setOnClickListener(v -> onClick.run()); + binding.messageRequestButton.setVisibility(View.VISIBLE); + } + public void showBackgroundBubble(boolean enabled) { if (enabled) { setBackgroundResource(R.drawable.wallpaper_bubble_background_18); - binding.messageRequestInfoOutline.setVisibility(View.INVISIBLE); - binding.messageRequestDivider.setVisibility(View.VISIBLE); } else { setBackground(null); - binding.messageRequestInfoOutline.setVisibility(View.VISIBLE); - binding.messageRequestDivider.setVisibility(View.INVISIBLE); } - hideDecoratorsIfContentIsNotPresent(); + updateOutlineVisibility(); } public void hideSubtitle() { binding.messageRequestSubtitle.setVisibility(View.GONE); + updateOutlineVisibility(); } public void showDescription() { binding.messageRequestDescription.setVisibility(View.VISIBLE); + updateOutlineVisibility(); } public void hideDescription() { binding.messageRequestDescription.setVisibility(View.GONE); + updateOutlineVisibility(); + } + + public void hideButton() { + binding.messageRequestButton.setVisibility(View.GONE); } public void setLinkifyDescription(boolean enable) { binding.messageRequestDescription.setMovementMethod(enable ? LongClickMovementMethod.getInstance(getContext()) : null); } - private void hideDecoratorsIfContentIsNotPresent() { + private void updateOutlineVisibility() { if (ViewKt.isVisible(binding.messageRequestSubtitle) || ViewKt.isVisible(binding.messageRequestDescription)) { - return; + if (getBackground() != null) { + binding.messageRequestInfoOutline.setVisibility(View.GONE); + binding.messageRequestDivider.setVisibility(View.VISIBLE); + } else { + binding.messageRequestInfoOutline.setVisibility(View.VISIBLE); + binding.messageRequestDivider.setVisibility(View.INVISIBLE); + } + } else { + binding.messageRequestInfoOutline.setVisibility(View.GONE); + binding.messageRequestDivider.setVisibility(View.GONE); } - - binding.messageRequestInfoOutline.setVisibility(View.GONE); - binding.messageRequestDivider.setVisibility(View.GONE); } private @NonNull CharSequence prependIcon(@NonNull CharSequence input, @DrawableRes int iconRes) { Drawable drawable = ContextCompat.getDrawable(getContext(), iconRes); Preconditions.checkNotNull(drawable); - drawable.setBounds(0, 0, (int) DimensionUnit.DP.toPixels(20), (int) DimensionUnit.DP.toPixels(20)); + drawable.setBounds(0, 0, (int) DimensionUnit.SP.toPixels(20), (int) DimensionUnit.SP.toPixels(20)); drawable.setColorFilter(ContextCompat.getColor(getContext(), R.color.signal_colorOnSurface), PorterDuff.Mode.SRC_ATOP); return new SpannableStringBuilder() .append(SpanUtil.buildCenteredImageSpan(drawable)) - .append(SpanUtil.space(8, DimensionUnit.DP)) + .append(SpanUtil.space(8, DimensionUnit.SP)) .append(input); } diff --git a/app/src/main/java/org/tm/archive/conversation/ConversationItem.java b/app/src/main/java/org/tm/archive/conversation/ConversationItem.java index a8744761..7d4ddba2 100644 --- a/app/src/main/java/org/tm/archive/conversation/ConversationItem.java +++ b/app/src/main/java/org/tm/archive/conversation/ConversationItem.java @@ -54,12 +54,12 @@ import androidx.annotation.ColorInt; import androidx.annotation.DimenRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.lifecycle.LifecycleOwner; import androidx.media3.common.MediaItem; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.collect.Sets; @@ -72,6 +72,7 @@ import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallLinkRootKey; import org.tm.archive.BindableConversationItem; import org.tm.archive.R; +import org.tm.archive.attachments.Attachment; import org.tm.archive.attachments.AttachmentId; import org.tm.archive.attachments.DatabaseAttachment; import org.tm.archive.badges.BadgeImageView; @@ -105,10 +106,8 @@ import org.tm.archive.conversation.v2.items.InteractiveConversationElement; import org.tm.archive.conversation.v2.items.V2ConversationItemUtils; import org.tm.archive.database.AttachmentTable; import org.tm.archive.database.MediaTable; -import org.tm.archive.database.MessageTable; -import org.tm.archive.database.SignalDatabase; -import org.tm.archive.database.model.MmsMessageRecord; import org.tm.archive.database.model.MessageRecord; +import org.tm.archive.database.model.MmsMessageRecord; import org.tm.archive.database.model.Quote; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.events.PartProgressEvent; @@ -116,18 +115,16 @@ import org.tm.archive.giph.mp4.GiphyMp4PlaybackPolicy; import org.tm.archive.giph.mp4.GiphyMp4PlaybackPolicyEnforcer; import org.tm.archive.jobmanager.JobManager; import org.tm.archive.jobs.AttachmentDownloadJob; -import org.tm.archive.jobs.MmsSendJob; -import org.tm.archive.jobs.SmsSendJob; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.linkpreview.LinkPreview; import org.tm.archive.mediapreview.MediaIntentFactory; import org.tm.archive.mediapreview.MediaPreviewCache; import org.tm.archive.mediapreview.MediaPreviewV2Fragment; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.ImageSlide; import org.tm.archive.mms.PartAuthority; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideClickListener; +import org.tm.archive.mms.SlideDeck; import org.tm.archive.mms.SlidesClickedListener; import org.tm.archive.mms.TextSlide; import org.tm.archive.mms.VideoSlide; @@ -199,7 +196,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private Locale locale; private boolean groupThread; private LiveRecipient author; - private GlideRequests glideRequests; + private RequestManager requestManager; private Optional previousMessage; private ConversationItemDisplayMode displayMode; @@ -364,7 +361,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo @NonNull ConversationMessage conversationMessage, @NonNull Optional previousMessageRecord, @NonNull Optional nextMessageRecord, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull Set batchSelected, @NonNull Recipient conversationRecipient, @@ -386,7 +383,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo this.messageRecord = conversationMessage.getMessageRecord(); this.nextMessageRecord = nextMessageRecord; this.locale = locale; - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.batchSelected = batchSelected; this.conversationRecipient = conversationRecipient.live(); this.groupThread = conversationRecipient.isGroup(); @@ -716,7 +713,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo bodyBubble.setVideoPlayerProjection(null); bodyBubble.setQuoteViewProjection(null); - glideRequests = null; + requestManager = null; } @Override @@ -1085,7 +1082,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo boolean messageRequestAccepted, boolean allowedToPlayInline) { - boolean showControls = messageRecord.isMediaPending() || (!messageRecord.isFailed() && !MessageRecordUtil.isScheduled(messageRecord)); + boolean showControls = !MessageRecordUtil.isScheduled(messageRecord) && (messageRecord.isMediaPending() || !messageRecord.isFailed()); ViewUtil.setTopMargin(bodyText, readDimen(R.dimen.message_bubble_top_padding)); @@ -1131,7 +1128,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE); paymentViewStub.setVisibility(View.GONE); - sharedContactStub.get().setContact(((MmsMessageRecord) messageRecord).getSharedContacts().get(0), glideRequests, locale); + sharedContactStub.get().setContact(((MmsMessageRecord) messageRecord).getSharedContacts().get(0), requestManager, locale); sharedContactStub.get().setEventListener(sharedContactEventListener); sharedContactStub.get().setOnClickListener(sharedContactClickListener); sharedContactStub.get().setOnLongClickListener(passthroughClickListener); @@ -1174,14 +1171,14 @@ public final class ConversationItem extends RelativeLayout implements BindableCo mediaThumbnailStub.require().setVisibility(VISIBLE); mediaThumbnailStub.require().setMinimumThumbnailWidth(readDimen(R.dimen.media_bubble_min_width_with_content)); mediaThumbnailStub.require().setMaximumThumbnailHeight(readDimen(R.dimen.media_bubble_max_height)); - mediaThumbnailStub.require().setImageResource(glideRequests, Collections.singletonList(new ImageSlide(linkPreview.getThumbnail().get())), showControls, false); + mediaThumbnailStub.require().setImageResource(requestManager, Collections.singletonList(new ImageSlide(linkPreview.getThumbnail().get())), showControls, false); mediaThumbnailStub.require().setThumbnailClickListener(new LinkPreviewThumbnailClickListener()); mediaThumbnailStub.require().setStartTransferClickListener(downloadClickListener); mediaThumbnailStub.require().setCancelTransferClickListener(attachmentCancelClickListener); mediaThumbnailStub.require().setPlayVideoClickListener(playVideoClickListener); mediaThumbnailStub.require().setOnLongClickListener(passthroughClickListener); - linkPreviewStub.get().setLinkPreview(glideRequests, linkPreview, false); + linkPreviewStub.get().setLinkPreview(requestManager, linkPreview, false); setThumbnailCorners(messageRecord, previousRecord, nextRecord, isGroupThread); setLinkPreviewCorners(messageRecord, previousRecord, nextRecord, isGroupThread, true); @@ -1190,7 +1187,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo ViewUtil.updateLayoutParamsIfNonNull(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); ViewUtil.setTopMargin(linkPreviewStub.get(), 0); } else { - linkPreviewStub.get().setLinkPreview(glideRequests, linkPreview, true, !isContentCondensed(), displayMode.getScheduleMessageMode()); + linkPreviewStub.get().setLinkPreview(requestManager, linkPreview, true, !isContentCondensed(), displayMode.getScheduleMessageMode()); linkPreviewStub.get().setDownloadClickedListener(downloadClickListener); setLinkPreviewCorners(messageRecord, previousRecord, nextRecord, isGroupThread, false); ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -1277,11 +1274,11 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (hasSticker(messageRecord)) { //noinspection ConstantConditions - stickerStub.get().setSlide(glideRequests, ((MmsMessageRecord) messageRecord).getSlideDeck().getStickerSlide()); + stickerStub.get().setSlide(requestManager, ((MmsMessageRecord) messageRecord).getSlideDeck().getStickerSlide()); stickerStub.get().setThumbnailClickListener(new StickerClickListener()); } else { //noinspection ConstantConditions - stickerStub.get().setSlide(glideRequests, ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlide()); + stickerStub.get().setSlide(requestManager, ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlide()); stickerStub.get().setThumbnailClickListener((v, slide) -> performClick()); } @@ -1307,7 +1304,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE); paymentViewStub.setVisibility(View.GONE); - List thumbnailSlides = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlides(); + final SlideDeck slideDeck = ((MmsMessageRecord) messageRecord).getSlideDeck(); + List thumbnailSlides = slideDeck.getThumbnailSlides(); mediaThumbnailStub.require().setMinimumThumbnailWidth(readDimen(isCaptionlessMms(messageRecord) ? R.dimen.media_bubble_min_width_solo : R.dimen.media_bubble_min_width_with_content)); mediaThumbnailStub.require().setMaximumThumbnailHeight(readDimen(isContentCondensed() ? R.dimen.media_bubble_max_height_condensed @@ -1319,7 +1317,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo mediaThumbnailStub.require().setOnLongClickListener(passthroughClickListener); mediaThumbnailStub.require().setOnClickListener(passthroughClickListener); mediaThumbnailStub.require().showShade(messageRecord.isDisplayBodyEmpty(getContext()) && !hasExtraText(messageRecord)); - mediaThumbnailStub.require().setImageResource(glideRequests, + mediaThumbnailStub.require().setImageResource(requestManager, thumbnailSlides, showControls, false); @@ -1328,7 +1326,11 @@ public final class ConversationItem extends RelativeLayout implements BindableCo mediaThumbnailStub.require().setStartTransferClickListener(downloadClickListener); } else { mediaThumbnailStub.require().setConversationColor(Color.TRANSPARENT); - mediaThumbnailStub.require().setStartTransferClickListener(new ResendClickListener(messageRecord)); + if (doAnySlidesLackData(slideDeck)) { + mediaThumbnailStub.require().setStartTransferClickListener(downloadClickListener); + } else { + mediaThumbnailStub.require().setStartTransferClickListener(new ResendClickListener(messageRecord)); + } } mediaThumbnailStub.require().setBorderless(false); @@ -1366,7 +1368,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo paymentViewStub.setVisibility(View.GONE); MmsMessageRecord mmsMessageRecord = (MmsMessageRecord) messageRecord; - giftViewStub.get().setGiftBadge(glideRequests, Objects.requireNonNull(mmsMessageRecord.getGiftBadge()), messageRecord.isOutgoing(), giftMessageViewCallback, messageRecord.getFromRecipient(), messageRecord.getToRecipient()); + giftViewStub.get().setGiftBadge(requestManager, Objects.requireNonNull(mmsMessageRecord.getGiftBadge()), messageRecord.isOutgoing(), giftMessageViewCallback, messageRecord.getFromRecipient(), messageRecord.getToRecipient()); giftViewStub.get().setVisibility(VISIBLE); footer.setVisibility(VISIBLE); @@ -1537,8 +1539,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } }); - contactPhoto.setAvatar(glideRequests, recipient, false); - badgeImageView.setBadgeFromRecipient(recipient, glideRequests); + contactPhoto.setAvatar(requestManager, recipient, false); + badgeImageView.setBadgeFromRecipient(recipient, requestManager); badgeImageView.setClickable(false); } @@ -1567,7 +1569,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } private void setStatusIcons(MessageRecord messageRecord, boolean hasWallpaper) { - bodyText.setCompoundDrawablesWithIntrinsicBounds(0, 0, messageRecord.isKeyExchange() ? R.drawable.ic_menu_login : 0, 0); + bodyText.setCompoundDrawablesWithIntrinsicBounds(0, 0, messageRecord.isKeyExchange() ? R.drawable.symbol_key_24 : 0, 0); if (!messageRecord.isMediaPending() && messageRecord.isFailed()) { alertView.setFailed(); @@ -1601,7 +1603,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } //noinspection ConstantConditions - quoteView.setQuote(glideRequests, + quoteView.setQuote(requestManager, quote.getId(), Recipient.live(quote.getAuthor()).get(), quote.getDisplayText(), @@ -2017,6 +2019,15 @@ public final class ConversationItem extends RelativeLayout implements BindableCo return context.getResources().getDimensionPixelOffset(dimenId); } + private boolean doAnySlidesLackData(SlideDeck deck) { + for (Attachment attachment : deck.asAttachments()) { + if (attachment instanceof DatabaseAttachment && !((DatabaseAttachment) attachment).hasData) { + return true; + } + } + return false; + } + /// Event handlers private Spannable getLongMessageSpan(@NonNull MessageRecord messageRecord) { @@ -2671,8 +2682,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (eventListener != null) { eventListener.onIncomingIdentityMismatchClicked(messageRecord.getFromRecipient().getId()); } - } else if (messageRecord.isPendingInsecureSmsFallback()) { - handleMessageApproval(); } } } @@ -2766,45 +2775,4 @@ public final class ConversationItem extends RelativeLayout implements BindableCo footer.setAudioDuration(durationMillis, playheadMillis); } } - - private void handleMessageApproval() { - final int title; - final int message; - - if (messageRecord.isMms()) title = R.string.ConversationItem_click_to_approve_unencrypted_mms_dialog_title; - else title = R.string.ConversationItem_click_to_approve_unencrypted_sms_dialog_title; - - message = R.string.ConversationItem_click_to_approve_unencrypted_dialog_message; - - AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context); - builder.setTitle(title); - - if (message > -1) builder.setMessage(message); - - builder.setPositiveButton(R.string.yes, (dialogInterface, i) -> { - MessageTable db = SignalDatabase.messages(); - - db.markAsInsecure(messageRecord.getId()); - db.markAsOutbox(messageRecord.getId()); - db.markAsForcedSms(messageRecord.getId()); - - if (messageRecord.isMms()) { - MmsSendJob.enqueue(context, - ApplicationDependencies.getJobManager(), - messageRecord.getId()); - } else { - ApplicationDependencies.getJobManager().add(new SmsSendJob(messageRecord.getId(), - messageRecord.getToRecipient())); - } - }); - - builder.setNegativeButton(R.string.no, (dialogInterface, i) -> { - if (messageRecord.isMms()) { - SignalDatabase.messages().markAsSentFailed(messageRecord.getId()); - } else { - SignalDatabase.messages().markAsSentFailed(messageRecord.getId()); - } - }); - builder.show(); - } } diff --git a/app/src/main/java/org/tm/archive/conversation/ConversationOptionsMenu.kt b/app/src/main/java/org/tm/archive/conversation/ConversationOptionsMenu.kt index 18058e62..fac50c2b 100644 --- a/app/src/main/java/org/tm/archive/conversation/ConversationOptionsMenu.kt +++ b/app/src/main/java/org/tm/archive/conversation/ConversationOptionsMenu.kt @@ -16,7 +16,7 @@ import io.reactivex.rxjava3.kotlin.subscribeBy import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.logging.Log import org.tm.archive.R -import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.messagerequests.MessageRequestState import org.tm.archive.recipients.Recipient /** @@ -54,7 +54,7 @@ internal object ConversationOptionsMenu { hasActiveGroupCall, distributionType, threadId, - isInMessageRequest, + messageRequestState, isInBubble ) = callback.getSnapshot() @@ -63,6 +63,23 @@ internal object ConversationOptionsMenu { return } + if (!messageRequestState.isAccepted) { + menuInflater.inflate(R.menu.conversation_message_request, menu) + + if (messageRequestState.isBlocked) { + hideMenuItem(menu, R.id.menu_block) + hideMenuItem(menu, R.id.menu_accept) + } else { + hideMenuItem(menu, R.id.menu_unblock) + } + + if (messageRequestState.reportedAsSpam) { + hideMenuItem(menu, R.id.menu_report_spam) + } + + return + } + if (!afterFirstRenderMode) { createdPreRenderMenu = true if (recipient.isSelf) { @@ -84,12 +101,6 @@ internal object ConversationOptionsMenu { return } - if (isInMessageRequest && !recipient.isBlocked) { - if (isActiveGroup) { - menuInflater.inflate(R.menu.conversation_message_requests_group, menu) - } - } - if (isPushAvailable) { if (recipient.expiresInSeconds > 0) { if (!isInActiveGroup) { @@ -107,8 +118,6 @@ internal object ConversationOptionsMenu { if (!recipient.isGroup) { if (isPushAvailable) { menuInflater.inflate(R.menu.conversation_callable_secure, menu) - } else if (!recipient.isReleaseNotes && SignalStore.misc().smsExportPhase.allowSmsFeatures()) { - menuInflater.inflate(R.menu.conversation_callable_insecure, menu) } } else if (recipient.isGroup) { if (isActiveV2Group) { @@ -123,17 +132,13 @@ internal object ConversationOptionsMenu { menuInflater.inflate(R.menu.conversation, menu) - if (isInMessageRequest && !recipient.isBlocked) { - hideMenuItem(menu, R.id.menu_conversation_settings) - } - if (!recipient.isGroup && !isPushAvailable && !recipient.isReleaseNotes) { menuInflater.inflate(R.menu.conversation_insecure, menu) } if (recipient.isMuted) menuInflater.inflate(R.menu.conversation_muted, menu) else menuInflater.inflate(R.menu.conversation_unmuted, menu) - if (!recipient.isGroup && (recipient.contactUri == null) && !recipient.isReleaseNotes && !recipient.isSelf && recipient.hasE164()) { + if (!recipient.isGroup && recipient.contactUri == null && !recipient.isReleaseNotes && !recipient.isSelf && recipient.hasE164() && recipient.shouldShowE164()) { menuInflater.inflate(R.menu.conversation_add_to_contacts, menu) } @@ -141,8 +146,6 @@ internal object ConversationOptionsMenu { if (isPushAvailable) { hideMenuItem(menu, R.id.menu_call_secure) hideMenuItem(menu, R.id.menu_video_secure) - } else { - hideMenuItem(menu, R.id.menu_call_insecure) } hideMenuItem(menu, R.id.menu_mute_notifications) } @@ -153,8 +156,6 @@ internal object ConversationOptionsMenu { hideMenuItem(menu, R.id.menu_video_secure) hideMenuItem(menu, R.id.menu_expiring_messages) hideMenuItem(menu, R.id.menu_expiring_messages_off) - } else { - hideMenuItem(menu, R.id.menu_call_insecure) } hideMenuItem(menu, R.id.menu_mute_notifications) } @@ -199,9 +200,8 @@ internal object ConversationOptionsMenu { override fun onMenuItemSelected(menuItem: MenuItem): Boolean { when (menuItem.itemId) { - R.id.menu_call_secure -> callback.handleDial(true) + R.id.menu_call_secure -> callback.handleDial() R.id.menu_video_secure -> callback.handleVideo() - R.id.menu_call_insecure -> callback.handleDial(false) R.id.menu_view_media -> callback.handleViewMedia() R.id.menu_add_shortcut -> callback.handleAddShortcut() R.id.menu_search -> callback.handleSearch() @@ -216,6 +216,11 @@ internal object ConversationOptionsMenu { R.id.menu_expiring_messages_off, R.id.menu_expiring_messages -> callback.handleSelectMessageExpiration() R.id.menu_create_bubble -> callback.handleCreateBubble() R.id.home -> callback.handleGoHome() + R.id.menu_block -> callback.handleBlock() + R.id.menu_unblock -> callback.handleUnblock() + R.id.menu_report_spam -> callback.handleReportSpam() + R.id.menu_accept -> callback.handleMessageRequestAccept() + R.id.menu_delete_chat -> callback.handleDeleteConversation() R.id.edittext_bold, R.id.edittext_italic, R.id.edittext_strikethrough, @@ -252,7 +257,7 @@ internal object ConversationOptionsMenu { val hasActiveGroupCall: Boolean, val distributionType: Int, val threadId: Long, - val isInMessageRequest: Boolean, + val messageRequestState: MessageRequestState, val isInBubble: Boolean ) @@ -266,7 +271,7 @@ internal object ConversationOptionsMenu { fun onOptionsMenuCreated(menu: Menu) fun handleVideo() - fun handleDial(isSecure: Boolean) + fun handleDial() fun handleViewMedia() fun handleAddShortcut() fun handleSearch() @@ -284,5 +289,10 @@ internal object ConversationOptionsMenu { fun showExpiring(recipient: Recipient) fun clearExpiring() fun handleFormatText(@IdRes id: Int) + fun handleBlock() + fun handleUnblock() + fun handleReportSpam() + fun handleMessageRequestAccept() + fun handleDeleteConversation() } } diff --git a/app/src/main/java/org/tm/archive/conversation/ConversationStickerSuggestionAdapter.java b/app/src/main/java/org/tm/archive/conversation/ConversationStickerSuggestionAdapter.java index 1158d06f..360bed0b 100644 --- a/app/src/main/java/org/tm/archive/conversation/ConversationStickerSuggestionAdapter.java +++ b/app/src/main/java/org/tm/archive/conversation/ConversationStickerSuggestionAdapter.java @@ -8,24 +8,24 @@ import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import org.tm.archive.R; import org.tm.archive.database.model.StickerRecord; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideRequests; import java.util.ArrayList; import java.util.List; public class ConversationStickerSuggestionAdapter extends RecyclerView.Adapter { - private final GlideRequests glideRequests; + private final RequestManager requestManager; private final EventListener eventListener; private final List stickers; - public ConversationStickerSuggestionAdapter(@NonNull GlideRequests glideRequests, @NonNull EventListener eventListener) { - this.glideRequests = glideRequests; + public ConversationStickerSuggestionAdapter(@NonNull RequestManager requestManager, @NonNull EventListener eventListener) { + this.requestManager = requestManager; this.eventListener = eventListener; this.stickers = new ArrayList<>(); } @@ -37,7 +37,7 @@ public class ConversationStickerSuggestionAdapter extends RecyclerView.Adapter previousMessageRecord, @NonNull Optional nextMessageRecord, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull Set batchSelected, @NonNull Recipient conversationRecipient, @@ -566,6 +566,22 @@ public final class ConversationUpdateItem extends FrameLayout eventListener.onSendPaymentClicked(conversationMessage.getMessageRecord().getFromRecipient().getId()); } }); + } else if (conversationMessage.getMessageRecord().isReportedSpam()) { + actionButton.setText(R.string.ConversationUpdateItem_learn_more); + actionButton.setVisibility(VISIBLE); + actionButton.setOnClickListener(v -> { + if (batchSelected.isEmpty() && eventListener != null) { + eventListener.onReportSpamLearnMoreClicked(); + } + }); + } else if (conversationMessage.getMessageRecord().isMessageRequestAccepted()) { + actionButton.setText(R.string.ConversationUpdateItem_options); + actionButton.setVisibility(VISIBLE); + actionButton.setOnClickListener(v -> { + if (batchSelected.isEmpty() && eventListener != null) { + eventListener.onMessageRequestAcceptOptionsClicked(); + } + }); } else{ actionButton.setVisibility(GONE); actionButton.setOnClickListener(null); diff --git a/app/src/main/java/org/tm/archive/conversation/MessageSendType.kt b/app/src/main/java/org/tm/archive/conversation/MessageSendType.kt index 58487972..baf28761 100644 --- a/app/src/main/java/org/tm/archive/conversation/MessageSendType.kt +++ b/app/src/main/java/org/tm/archive/conversation/MessageSendType.kt @@ -8,9 +8,7 @@ import androidx.annotation.StringRes import kotlinx.parcelize.Parcelize import org.tm.archive.R import org.tm.archive.util.CharacterCalculator -import org.tm.archive.util.MmsCharacterCalculator import org.tm.archive.util.PushCharacterCalculator -import org.tm.archive.util.SmsCharacterCalculator import java.lang.IllegalArgumentException /** @@ -29,15 +27,9 @@ sealed class MessageSendType( @ColorRes val backgroundColorRes: Int, val transportType: TransportType, - val characterCalculator: CharacterCalculator, - open val simName: CharSequence? = null, - open val simSubscriptionId: Int? = null + val characterCalculator: CharacterCalculator ) : Parcelable { - @get:JvmName("usesSmsTransport") - val usesSmsTransport - get() = transportType == TransportType.SMS - @get:JvmName("usesSignalTransport") val usesSignalTransport get() = transportType == TransportType.SIGNAL @@ -50,54 +42,6 @@ sealed class MessageSendType( return context.getString(titleRes) } - /** - * A type representing an SMS message, with optional SIM fields for multi-SIM devices. - */ - @Parcelize - data class SmsMessageSendType(override val simName: CharSequence? = null, override val simSubscriptionId: Int? = null) : MessageSendType( - titleRes = R.string.ConversationActivity_transport_insecure_sms, - composeHintRes = R.string.conversation_activity__type_message_sms_insecure, - buttonDrawableRes = R.drawable.ic_send_unlock_24, - menuDrawableRes = R.drawable.ic_insecure_24, - backgroundColorRes = R.color.core_grey_50, - transportType = TransportType.SMS, - characterCalculator = SmsCharacterCalculator(), - simName = simName, - simSubscriptionId = simSubscriptionId - ) { - override fun getTitle(context: Context): String { - return if (simName == null) { - super.getTitle(context) - } else { - context.getString(R.string.ConversationActivity_transport_insecure_sms_with_sim, simName) - } - } - } - - /** - * A type representing an MMS message, with optional SIM fields for multi-SIM devices. - */ - @Parcelize - data class MmsMessageSendType(override val simName: CharSequence? = null, override val simSubscriptionId: Int? = null) : MessageSendType( - titleRes = R.string.ConversationActivity_transport_insecure_mms, - composeHintRes = R.string.conversation_activity__type_message_mms_insecure, - buttonDrawableRes = R.drawable.ic_send_unlock_24, - menuDrawableRes = R.drawable.ic_insecure_24, - backgroundColorRes = R.color.core_grey_50, - transportType = TransportType.SMS, - characterCalculator = MmsCharacterCalculator(), - simName = simName, - simSubscriptionId = simSubscriptionId - ) { - override fun getTitle(context: Context): String { - return if (simName == null) { - super.getTitle(context) - } else { - context.getString(R.string.ConversationActivity_transport_insecure_sms_with_sim, simName) - } - } - } - /** * A type representing a basic Signal message. */ diff --git a/app/src/main/java/org/tm/archive/conversation/ScheduledMessagesBottomSheet.kt b/app/src/main/java/org/tm/archive/conversation/ScheduledMessagesBottomSheet.kt index 88968cc3..b872cb4e 100644 --- a/app/src/main/java/org/tm/archive/conversation/ScheduledMessagesBottomSheet.kt +++ b/app/src/main/java/org/tm/archive/conversation/ScheduledMessagesBottomSheet.kt @@ -12,6 +12,7 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.signal.core.util.StreamUtil import org.signal.core.util.concurrent.LifecycleDisposable @@ -38,7 +39,6 @@ import org.tm.archive.giph.mp4.GiphyMp4ProjectionPlayerHolder import org.tm.archive.giph.mp4.GiphyMp4ProjectionRecycler import org.tm.archive.groups.GroupId import org.tm.archive.groups.GroupMigrationMembershipChange -import org.tm.archive.mms.GlideApp import org.tm.archive.mms.PartAuthority import org.tm.archive.mms.TextSlide import org.tm.archive.recipients.Recipient @@ -91,7 +91,7 @@ class ScheduledMessagesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment val colorizer = Colorizer() - messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, GlideApp.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper(), colorizer).apply { + messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, Glide.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper(), colorizer).apply { setCondensedMode(ConversationItemDisplayMode.Condensed(scheduleMessageMode = true)) } @@ -274,6 +274,9 @@ class ScheduledMessagesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment override fun onActivatePaymentsClicked() = Unit override fun onSendPaymentClicked(recipientId: RecipientId) = Unit override fun onEditedIndicatorClicked(messageRecord: MessageRecord) = Unit + override fun onShowSafetyTips(forGroup: Boolean) = Unit + override fun onReportSpamLearnMoreClicked() = Unit + override fun onMessageRequestAcceptOptionsClicked() = Unit } companion object { diff --git a/app/src/main/java/org/tm/archive/conversation/SignalBottomActionBarController.kt b/app/src/main/java/org/tm/archive/conversation/SignalBottomActionBarController.kt index e8a8af86..6624119a 100644 --- a/app/src/main/java/org/tm/archive/conversation/SignalBottomActionBarController.kt +++ b/app/src/main/java/org/tm/archive/conversation/SignalBottomActionBarController.kt @@ -5,10 +5,10 @@ import android.view.ViewTreeObserver import androidx.core.view.doOnPreDraw import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView +import org.signal.core.util.concurrent.ListenableFuture.Listener import org.signal.core.util.dp import org.tm.archive.components.menu.SignalBottomActionBar import org.tm.archive.util.ViewUtil -import org.tm.archive.util.concurrent.ListenableFuture.Listener import java.util.concurrent.ExecutionException class SignalBottomActionBarController( diff --git a/app/src/main/java/org/tm/archive/conversation/colors/NameColors.kt b/app/src/main/java/org/tm/archive/conversation/colors/NameColors.kt deleted file mode 100644 index bbe6d94a..00000000 --- a/app/src/main/java/org/tm/archive/conversation/colors/NameColors.kt +++ /dev/null @@ -1,63 +0,0 @@ -package org.tm.archive.conversation.colors - -import androidx.lifecycle.LiveData -import androidx.lifecycle.map -import androidx.lifecycle.switchMap -import com.annimon.stream.Stream -import org.signal.core.util.MapUtil -import org.tm.archive.conversation.colors.ChatColorsPalette.Names.all -import org.tm.archive.groups.GroupId -import org.tm.archive.groups.LiveGroup -import org.tm.archive.groups.ui.GroupMemberEntry.FullMember -import org.tm.archive.recipients.Recipient -import org.tm.archive.recipients.RecipientId -import org.tm.archive.util.DefaultValueLiveData -import java.util.Optional - -object NameColors { - - fun createSessionMembersCache(): MutableMap> { - return mutableMapOf() - } - - fun getNameColorsMapLiveData( - recipientId: LiveData, - sessionMemberCache: MutableMap> - ): LiveData> { - val recipient = recipientId.switchMap { r: RecipientId? -> Recipient.live(r!!).liveData } - val group = recipient.map { obj: Recipient -> obj.groupId } - val groupMembers = group.switchMap { g: Optional -> - g.map { groupId: GroupId -> this.getSessionGroupRecipients(groupId, sessionMemberCache) } - .orElseGet { DefaultValueLiveData(emptySet()) } - } - return groupMembers.map { members: Set? -> - val sorted = Stream.of(members) - .filter { member: Recipient? -> member != Recipient.self() } - .sortBy { obj: Recipient -> obj.requireStringId() } - .toList() - val names = all - val colors: MutableMap = HashMap() - for (i in sorted.indices) { - colors[sorted[i].id] = names[i % names.size] - } - colors - } - } - - private fun getSessionGroupRecipients(groupId: GroupId, sessionMemberCache: MutableMap>): LiveData> { - val fullMembers = LiveGroup(groupId) - .fullMembers - .map { members: List? -> - Stream.of(members) - .map { it.member } - .toList() - } - - return fullMembers.map { currentMembership: List? -> - val cachedMembers: MutableSet = MapUtil.getOrDefault(sessionMemberCache, groupId, HashSet()).toMutableSet() - cachedMembers.addAll(currentMembership!!) - sessionMemberCache[groupId] = cachedMembers - cachedMembers - } - } -} diff --git a/app/src/main/java/org/tm/archive/conversation/drafts/DraftRepository.kt b/app/src/main/java/org/tm/archive/conversation/drafts/DraftRepository.kt index c5eb811f..e38921a1 100644 --- a/app/src/main/java/org/tm/archive/conversation/drafts/DraftRepository.kt +++ b/app/src/main/java/org/tm/archive/conversation/drafts/DraftRepository.kt @@ -4,6 +4,7 @@ import android.content.Context import android.net.Uri import android.text.Spannable import android.text.SpannableString +import com.bumptech.glide.Glide import io.reactivex.rxjava3.core.Maybe import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.Base64 @@ -33,7 +34,6 @@ import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.keyboard.KeyboardUtil import org.tm.archive.mediasend.Media import org.tm.archive.mms.GifSlide -import org.tm.archive.mms.GlideApp import org.tm.archive.mms.ImageSlide import org.tm.archive.mms.PartAuthority import org.tm.archive.mms.QuoteId @@ -97,7 +97,7 @@ class DraftRepository( } if (shareMedia != null && shareContentType != null && borderless) { - val details = KeyboardUtil.getImageDetails(GlideApp.with(context), shareMedia) + val details = KeyboardUtil.getImageDetails(Glide.with(context), shareMedia) if (details == null || !details.hasTransparency) { return ShareOrDraftData.SetMedia(shareMedia, shareMediaType!!, null) to null diff --git a/app/src/main/java/org/tm/archive/conversation/mutiselect/Multiselect.kt b/app/src/main/java/org/tm/archive/conversation/mutiselect/Multiselect.kt index 9fd8f47b..06cfed38 100644 --- a/app/src/main/java/org/tm/archive/conversation/mutiselect/Multiselect.kt +++ b/app/src/main/java/org/tm/archive/conversation/mutiselect/Multiselect.kt @@ -1,20 +1,9 @@ package org.tm.archive.conversation.mutiselect -import android.Manifest -import android.content.Context -import android.content.pm.PackageManager -import android.net.Uri -import androidx.core.content.ContextCompat -import org.tm.archive.attachments.Attachment import org.tm.archive.conversation.ConversationMessage -import org.tm.archive.conversation.MessageSendType -import org.tm.archive.database.model.MessageRecord import org.tm.archive.database.model.MmsMessageRecord -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.mms.MediaConstraints import org.tm.archive.mms.SlideDeck import org.tm.archive.mms.TextSlide -import org.tm.archive.util.Util /** * General helper object for all things multiselect. This is only utilized by @@ -65,51 +54,4 @@ object Multiselect { return parts } - - fun canSendToNonPush(context: Context, multiselectPart: MultiselectPart): Boolean { - return when (multiselectPart) { - is MultiselectPart.Attachments -> canSendAllAttachmentsToNonPush(context, multiselectPart.conversationMessage.messageRecord) - is MultiselectPart.Message -> canSendAllAttachmentsToNonPush(context, multiselectPart.conversationMessage.messageRecord) - is MultiselectPart.Text -> true - is MultiselectPart.Update -> throw AssertionError("Should never get to here.") - } - } - - /** - * Helper function to determine whether a given attachment can be sent via MMS. - */ - fun isMmsSupported(context: Context, mediaUri: Uri, mediaType: String, mediaSize: Long): Boolean { - val canReadPhoneState = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED - if (!Util.isDefaultSmsProvider(context) || !canReadPhoneState || !Util.isMmsCapable(context) || !SignalStore.misc().smsExportPhase.allowSmsFeatures()) { - return false - } - - val sendType: MessageSendType = MessageSendType.getFirstForTransport(MessageSendType.TransportType.SMS) - - val mmsConstraints = MediaConstraints.getMmsMediaConstraints(sendType.simSubscriptionId ?: -1) - return mmsConstraints.isSatisfied(context, mediaUri, mediaType, mediaSize) || mmsConstraints.canResize(mediaType) - } - - private fun canSendAllAttachmentsToNonPush(context: Context, messageRecord: MessageRecord): Boolean { - return if (messageRecord is MmsMessageRecord) { - messageRecord.slideDeck.asAttachments().all { isMmsSupported(context, it) } - } else { - true - } - } - - /** - * Helper function to determine whether a given attachment can be sent via MMS. - */ - private fun isMmsSupported(context: Context, attachment: Attachment): Boolean { - val canReadPhoneState = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED - if (!Util.isDefaultSmsProvider(context) || !canReadPhoneState || !Util.isMmsCapable(context) || !SignalStore.misc().smsExportPhase.allowSmsFeatures()) { - return false - } - - val sendType: MessageSendType = MessageSendType.getFirstForTransport(MessageSendType.TransportType.SMS) - - val mmsConstraints = MediaConstraints.getMmsMediaConstraints(sendType.simSubscriptionId ?: -1) - return mmsConstraints.isSatisfied(context, attachment) || mmsConstraints.canResize(attachment) - } } diff --git a/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragment.kt b/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragment.kt index 5b2514c6..3e90524f 100644 --- a/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragment.kt +++ b/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragment.kt @@ -59,7 +59,6 @@ import org.tm.archive.stories.settings.privacy.ChooseInitialMyStoryMembershipBot import org.tm.archive.util.BottomSheetUtil import org.tm.archive.util.FeatureFlags import org.tm.archive.util.FullscreenHelper -import org.tm.archive.util.Util import org.tm.archive.util.ViewUtil import org.tm.archive.util.fragments.findListener import org.tm.archive.util.fragments.requireListener @@ -470,7 +469,7 @@ class MultiselectForwardFragment : addSection( ContactSearchConfiguration.Section.Individuals( includeHeader = true, - transportType = if (includeSms()) ContactSearchConfiguration.TransportType.ALL else ContactSearchConfiguration.TransportType.PUSH, + transportType = ContactSearchConfiguration.TransportType.PUSH, includeSelf = true ) ) @@ -485,18 +484,13 @@ class MultiselectForwardFragment : addSection( ContactSearchConfiguration.Section.Groups( - includeHeader = true, - includeMms = includeSms() + includeHeader = true ) ) } } } - private fun includeSms(): Boolean { - return Util.isDefaultSmsProvider(requireContext()) && args.canSendToNonPush - } - private fun isSelectedMediaValidForStories(): Boolean { return !args.isViewOnce && args.multiShareArgs.all { it.isValidForStories } } diff --git a/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt b/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt index 117fdcad..b6586adf 100644 --- a/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt +++ b/app/src/main/java/org/tm/archive/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt @@ -15,7 +15,6 @@ import org.tm.archive.attachments.Attachment import org.tm.archive.color.ViewColorSet import org.tm.archive.conversation.ConversationMessage import org.tm.archive.conversation.MessageStyler -import org.tm.archive.conversation.mutiselect.Multiselect import org.tm.archive.conversation.mutiselect.MultiselectPart import org.tm.archive.database.SignalDatabase import org.tm.archive.database.model.MmsMessageRecord @@ -23,7 +22,6 @@ import org.tm.archive.mediasend.Media import org.tm.archive.mms.PartAuthority import org.tm.archive.sharing.MultiShareArgs import org.tm.archive.stories.Stories -import org.tm.archive.util.MediaUtil import org.tm.archive.util.hasSharedContact import java.util.Optional import java.util.function.Consumer @@ -41,7 +39,6 @@ import java.util.function.Consumer */ @Parcelize data class MultiselectForwardFragmentArgs @JvmOverloads constructor( - val canSendToNonPush: Boolean, val multiShareArgs: List = listOf(), @StringRes val title: Int = R.string.MultiselectForwardFragment__forward_to, val forceDisableAddMessage: Boolean = false, @@ -60,8 +57,6 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor( @JvmStatic fun create(context: Context, threadId: Long, mediaUri: Uri, mediaType: String, consumer: Consumer) { SignalExecutors.BOUNDED.execute { - val mediaSize = MediaUtil.getMediaSize(context, mediaUri) - val isMmsSupported = Multiselect.isMmsSupported(context, mediaUri, mediaType, mediaSize) val multiShareArgs = MultiShareArgs.Builder(setOf()) .withDataUri(mediaUri) .withDataType(mediaType) @@ -76,7 +71,6 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor( ThreadUtil.runOnMain { consumer.accept( MultiselectForwardFragmentArgs( - isMmsSupported, listOf(multiShareArgs), storySendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND, sendButtonColors = sendButtonColors ?: ViewColorSet.PRIMARY @@ -97,13 +91,11 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor( throw AssertionError("Cannot forward view once media") } - val canSendToNonPush: Boolean = selectedParts.all { Multiselect.canSendToNonPush(context, it) } val multiShareArgs: List = conversationMessages.map { buildMultiShareArgs(context, it, selectedParts) } ThreadUtil.runOnMain { consumer.accept( MultiselectForwardFragmentArgs( - canSendToNonPush, multiShareArgs, storySendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND ) diff --git a/app/src/main/java/org/tm/archive/conversation/quotes/MessageQuotesBottomSheet.kt b/app/src/main/java/org/tm/archive/conversation/quotes/MessageQuotesBottomSheet.kt index ef584d49..bafeb565 100644 --- a/app/src/main/java/org/tm/archive/conversation/quotes/MessageQuotesBottomSheet.kt +++ b/app/src/main/java/org/tm/archive/conversation/quotes/MessageQuotesBottomSheet.kt @@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import org.signal.core.util.concurrent.LifecycleDisposable @@ -35,7 +36,6 @@ import org.tm.archive.giph.mp4.GiphyMp4ProjectionRecycler import org.tm.archive.groups.GroupId import org.tm.archive.groups.GroupMigrationMembershipChange import org.tm.archive.linkpreview.LinkPreview -import org.tm.archive.mms.GlideApp import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.util.BottomSheetUtil @@ -73,7 +73,7 @@ class MessageQuotesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment() { val colorizer = Colorizer() - messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, GlideApp.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper(), colorizer).apply { + messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, Glide.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper(), colorizer).apply { setCondensedMode(ConversationItemDisplayMode.Condensed(scheduleMessageMode = false)) } @@ -257,6 +257,10 @@ class MessageQuotesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment() { dismiss() getAdapterListener().onEditedIndicatorClicked(messageRecord) } + + override fun onShowSafetyTips(forGroup: Boolean) = Unit + override fun onReportSpamLearnMoreClicked() = Unit + override fun onMessageRequestAcceptOptionsClicked() = Unit } companion object { diff --git a/app/src/main/java/org/tm/archive/conversation/ui/edit/EditMessageHistoryDialog.kt b/app/src/main/java/org/tm/archive/conversation/ui/edit/EditMessageHistoryDialog.kt index 1948fd17..7d2044f5 100644 --- a/app/src/main/java/org/tm/archive/conversation/ui/edit/EditMessageHistoryDialog.kt +++ b/app/src/main/java/org/tm/archive/conversation/ui/edit/EditMessageHistoryDialog.kt @@ -10,6 +10,7 @@ import androidx.core.view.doOnNextLayout import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager +import com.bumptech.glide.Glide import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import io.reactivex.rxjava3.kotlin.subscribeBy @@ -36,7 +37,6 @@ import org.tm.archive.giph.mp4.GiphyMp4ProjectionPlayerHolder import org.tm.archive.giph.mp4.GiphyMp4ProjectionRecycler import org.tm.archive.groups.GroupId import org.tm.archive.groups.GroupMigrationMembershipChange -import org.tm.archive.mms.GlideApp import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.util.BottomSheetUtil @@ -85,7 +85,7 @@ class EditMessageHistoryDialog : FixedRoundedCornerBottomSheetDialogFragment() { val messageAdapter = ConversationAdapter( requireContext(), viewLifecycleOwner, - GlideApp.with(this), + Glide.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper(), @@ -165,6 +165,9 @@ class EditMessageHistoryDialog : FixedRoundedCornerBottomSheetDialogFragment() { override fun onActivatePaymentsClicked() = Unit override fun onSendPaymentClicked(recipientId: RecipientId) = Unit override fun onEditedIndicatorClicked(messageRecord: MessageRecord) = Unit + override fun onShowSafetyTips(forGroup: Boolean) = Unit + override fun onReportSpamLearnMoreClicked() = Unit + override fun onMessageRequestAcceptOptionsClicked() = Unit } companion object { diff --git a/app/src/main/java/org/tm/archive/conversation/ui/error/SafetyNumberChangeAdapter.java b/app/src/main/java/org/tm/archive/conversation/ui/error/SafetyNumberChangeAdapter.java index 46c9c3a9..5d396f1e 100644 --- a/app/src/main/java/org/tm/archive/conversation/ui/error/SafetyNumberChangeAdapter.java +++ b/app/src/main/java/org/tm/archive/conversation/ui/error/SafetyNumberChangeAdapter.java @@ -64,7 +64,7 @@ final class SafetyNumberChangeAdapter extends ListAdapter Unit + private val startExpirationTimeout: (MessageRecord) -> Unit, + private val chatColorsDataProvider: () -> ChatColorsDrawable.ChatColorsData ) : PagingMappingAdapter(), ConversationAdapterBridge, V2ConversationContext { companion object { @@ -183,6 +184,10 @@ class ConversationAdapterV2( override fun getColorizer(): Colorizer = colorizer + override fun getChatColorsData(): ChatColorsDrawable.ChatColorsData { + return chatColorsDataProvider() + } + override fun getNextMessage(adapterPosition: Int): MessageRecord? { return getConversationMessage(adapterPosition - 1)?.messageRecord } @@ -330,7 +335,7 @@ class ConversationAdapterV2( model.conversationMessage, previousMessage, nextMessage, - glideRequests, + requestManager, Locale.getDefault(), _selected, model.conversationMessage.threadRecipient, @@ -358,7 +363,7 @@ class ConversationAdapterV2( model.conversationMessage, previousMessage, nextMessage, - glideRequests, + requestManager, Locale.getDefault(), _selected, model.conversationMessage.threadRecipient, @@ -386,7 +391,7 @@ class ConversationAdapterV2( model.conversationMessage, previousMessage, nextMessage, - glideRequests, + requestManager, Locale.getDefault(), _selected, model.conversationMessage.threadRecipient, @@ -414,7 +419,7 @@ class ConversationAdapterV2( model.conversationMessage, previousMessage, nextMessage, - glideRequests, + requestManager, Locale.getDefault(), _selected, model.conversationMessage.threadRecipient, @@ -442,7 +447,7 @@ class ConversationAdapterV2( model.conversationMessage, previousMessage, nextMessage, - glideRequests, + requestManager, Locale.getDefault(), _selected, model.conversationMessage.threadRecipient, @@ -563,7 +568,7 @@ class ConversationAdapterV2( val (recipient, groupInfo, sharedGroups, messageRequestState) = model.recipientInfo val isSelf = recipient.id == Recipient.self().id - conversationBanner.setAvatar(glideRequests, recipient) + conversationBanner.setAvatar(requestManager, recipient) conversationBanner.showBackgroundBubble(recipient.hasWallpaper()) val title: String = conversationBanner.setTitle(recipient) conversationBanner.setAbout(recipient) @@ -578,7 +583,7 @@ class ConversationAdapterV2( conversationBanner.hideSubtitle() } } else if (isSelf) { - conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_person_light_24) + conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_note_light_24) } else { val subtitle: String? = recipient.takeIf { it.shouldShowE164() }?.e164?.map { e164: String? -> PhoneNumberFormatter.prettyPrint(e164!!) }?.orElse(null) if (subtitle == null || subtitle == title) { @@ -588,13 +593,25 @@ class ConversationAdapterV2( } } - if (sharedGroups.isEmpty() || isSelf) { + conversationBanner.hideButton() + + if (messageRequestState?.isAccepted == false && sharedGroups.isEmpty() && !isSelf && !recipient.isGroup) { + conversationBanner.setDescription(context.getString(R.string.ConversationUpdateItem_no_groups_in_common_review_requests_carefully), R.drawable.symbol_error_circle_24) + conversationBanner.setButton(context.getString(R.string.ConversationFragment_safety_tips)) { + clickListener.onShowSafetyTips(false) + } + } else if (messageRequestState?.isAccepted == false && recipient.isGroup && !groupInfo.hasExistingContacts) { + conversationBanner.setDescription(context.getString(R.string.ConversationUpdateItem_no_contacts_in_this_group_review_requests_carefully), R.drawable.symbol_error_circle_24) + conversationBanner.setButton(context.getString(R.string.ConversationFragment_safety_tips)) { + clickListener.onShowSafetyTips(true) + } + } else if (sharedGroups.isEmpty() || isSelf) { if (TextUtils.isEmpty(groupInfo.description)) { conversationBanner.setLinkifyDescription(false) conversationBanner.hideDescription() } else { conversationBanner.setLinkifyDescription(true) - val linkifyWebLinks = messageRequestState == MessageRequestState.NONE + val linkifyWebLinks = messageRequestState?.isAccepted == true conversationBanner.showDescription() GroupDescriptionUtil.setText( diff --git a/app/src/main/java/org/tm/archive/conversation/v2/ConversationBannerView.kt b/app/src/main/java/org/tm/archive/conversation/v2/ConversationBannerView.kt index 15a42c60..a2154025 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/ConversationBannerView.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/ConversationBannerView.kt @@ -6,7 +6,6 @@ package org.tm.archive.conversation.v2 import android.content.Context -import android.text.SpannableStringBuilder import android.transition.ChangeBounds import android.transition.Slide import android.transition.TransitionManager @@ -15,8 +14,6 @@ import android.util.AttributeSet import android.view.Gravity import android.view.View import androidx.appcompat.widget.LinearLayoutCompat -import androidx.core.content.ContextCompat -import androidx.core.graphics.drawable.DrawableCompat import androidx.core.transition.addListener import org.tm.archive.R import org.tm.archive.components.identity.UnverifiedBannerView @@ -28,9 +25,7 @@ import org.tm.archive.database.model.IdentityRecord import org.tm.archive.groups.GroupId import org.tm.archive.profiles.spoofing.ReviewBannerView import org.tm.archive.recipients.RecipientId -import org.tm.archive.util.ContextUtil import org.tm.archive.util.IdentityUtil -import org.tm.archive.util.SpanUtil import org.tm.archive.util.ViewUtil import org.tm.archive.util.views.Stub import org.tm.archive.util.visible @@ -114,20 +109,12 @@ class ConversationBannerView @JvmOverloads constructor( stub = reviewBannerStub ) { if (requestReviewState.individualReviewState != null) { - val message: CharSequence = SpannableStringBuilder() - .append(SpanUtil.bold(context.getString(R.string.ConversationFragment__review_requests_carefully))) - .append(" ") - .append(context.getString(R.string.ConversationFragment__signal_found_another_contact_with_the_same_name)) - - setBannerMessage(message) - - val drawable = ContextUtil.requireDrawable(context, R.drawable.symbol_info_24).mutate() - DrawableCompat.setTint(drawable, ContextCompat.getColor(context, R.color.signal_icon_tint_primary)) - setBannerIcon(drawable) - setOnClickListener { listener?.onRequestReviewIndividual(requestReviewState.individualReviewState.recipient.id) } + setBannerMessage(context.getString(R.string.ConversationFragment__review_banner_body)) + setBannerRecipients(requestReviewState.individualReviewState.target, requestReviewState.individualReviewState.firstDuplicate) + setOnClickListener { listener?.onRequestReviewIndividual(requestReviewState.individualReviewState.target.id) } } else if (requestReviewState.groupReviewState != null) { setBannerMessage(context.getString(R.string.ConversationFragment__d_group_members_have_the_same_name, requestReviewState.groupReviewState.count)) - setBannerRecipient(requestReviewState.groupReviewState.recipient) + setBannerRecipients(requestReviewState.groupReviewState.target, requestReviewState.groupReviewState.firstDuplicate) setOnClickListener { listener?.onReviewGroupMembers(requestReviewState.groupReviewState.groupId) } } diff --git a/app/src/main/java/org/tm/archive/conversation/v2/ConversationDialogs.kt b/app/src/main/java/org/tm/archive/conversation/v2/ConversationDialogs.kt index 3ea1fb09..d9e3bc6b 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/ConversationDialogs.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/ConversationDialogs.kt @@ -10,12 +10,10 @@ import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.concurrent.SimpleTask import org.tm.archive.R import org.tm.archive.components.settings.app.AppSettingsActivity -import org.tm.archive.database.model.InMemoryMessageRecord.NoGroupsInCommon import org.tm.archive.database.model.MessageRecord import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.recipients.Recipient import org.tm.archive.sms.MessageSender -import org.tm.archive.util.CommunicationActions import org.tm.archive.verify.VerifyIdentityActivity /** @@ -30,7 +28,7 @@ object ConversationDialogs { fun displayCannotStartGroupCallDueToPermissionsDialog(context: Context) { MaterialAlertDialogBuilder(context).setTitle(R.string.ConversationActivity_cant_start_group_call) .setMessage(R.string.ConversationActivity_only_admins_of_this_group_can_start_a_call) - .setPositiveButton(R.string.ok) { d: DialogInterface, w: Int -> d.dismiss() } + .setPositiveButton(android.R.string.ok) { d: DialogInterface, w: Int -> d.dismiss() } .show() } @@ -82,24 +80,7 @@ object ConversationDialogs { dialog.show() } - fun displayInMemoryMessageDialog(context: Context, messageRecord: MessageRecord) { - if (messageRecord is NoGroupsInCommon) { - val isGroup = messageRecord.isGroup - MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Signal_MaterialAlertDialog) - .setMessage( - if (isGroup) { - R.string.GroupsInCommonMessageRequest__none_of_your_contacts_or_people_you_chat_with_are_in_this_group - } else { - R.string.GroupsInCommonMessageRequest__you_have_no_groups_in_common_with_this_person - } - ) - .setNeutralButton(R.string.GroupsInCommonMessageRequest__about_message_requests) { _, _ -> - CommunicationActions.openBrowserLink(context, context.getString(R.string.GroupsInCommonMessageRequest__support_article)) - } - .setPositiveButton(R.string.GroupsInCommonMessageRequest__okay, null) - .show() - } - } + fun displayInMemoryMessageDialog(context: Context, messageRecord: MessageRecord) = Unit fun displayMessageCouldNotBeSentDialog(context: Context, messageRecord: MessageRecord) { MaterialAlertDialogBuilder(context) diff --git a/app/src/main/java/org/tm/archive/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/tm/archive/conversation/v2/ConversationFragment.kt index 29775257..3009b216 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/ConversationFragment.kt @@ -66,6 +66,7 @@ import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.ConversationLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.BaseTransientBottomBar.Duration import com.google.android.material.snackbar.Snackbar @@ -83,6 +84,7 @@ import org.signal.core.util.PendingIntentFlags import org.signal.core.util.Result import org.signal.core.util.ThreadUtil import org.signal.core.util.concurrent.LifecycleDisposable +import org.signal.core.util.concurrent.ListenableFuture import org.signal.core.util.concurrent.addTo import org.signal.core.util.dp import org.signal.core.util.logging.Log @@ -242,11 +244,9 @@ import org.tm.archive.mediasend.Media import org.tm.archive.mediasend.MediaSendActivityResult import org.tm.archive.messagedetails.MessageDetailsFragment import org.tm.archive.messagerequests.MessageRequestRepository -import org.tm.archive.messagerequests.MessageRequestState import org.tm.archive.mms.AttachmentManager import org.tm.archive.mms.AudioSlide import org.tm.archive.mms.GifSlide -import org.tm.archive.mms.GlideApp import org.tm.archive.mms.ImageSlide import org.tm.archive.mms.MediaConstraints import org.tm.archive.mms.QuoteModel @@ -291,6 +291,7 @@ import org.tm.archive.util.Debouncer import org.tm.archive.util.DeleteDialog import org.tm.archive.util.Dialogs import org.tm.archive.util.DrawableUtil +import org.tm.archive.util.FeatureFlags import org.tm.archive.util.FullscreenHelper import org.tm.archive.util.MediaUtil import org.tm.archive.util.MessageConstraintsUtil @@ -303,7 +304,6 @@ import org.tm.archive.util.StorageUtil import org.tm.archive.util.TextSecurePreferences import org.tm.archive.util.ViewUtil import org.tm.archive.util.WindowUtil -import org.tm.archive.util.concurrent.ListenableFuture import org.tm.archive.util.createActivityViewModel import org.tm.archive.util.doAfterNextLayout import org.tm.archive.util.fragments.requireListener @@ -400,7 +400,8 @@ class ConversationFragment : repository = ConversationRepository(localContext = requireContext(), isInBubble = args.conversationScreenType == ConversationScreenType.BUBBLE), recipientRepository = conversationRecipientRepository, messageRequestRepository = messageRequestRepository, - scheduledMessagesRepository = ScheduledMessagesRepository() + scheduledMessagesRepository = ScheduledMessagesRepository(), + initialChatColors = args.chatColors ) } @@ -590,7 +591,11 @@ class ConversationFragment : inputPanel.setMediaListener(InputPanelMediaListener()) - ChatColorsDrawable.attach(binding.conversationItemRecycler) + binding.conversationItemRecycler.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> + viewModel.onChatBoundsChanged(Rect(left, top, right, bottom)) + } + + binding.conversationItemRecycler.addItemDecoration(ChatColorsDrawable.ChatColorsItemDecoration) } override fun onViewStateRestored(savedInstanceState: Bundle?) { @@ -1135,12 +1140,12 @@ class ConversationFragment : var inputDisabled = true when { inputReadyState.isClientExpired || inputReadyState.isUnauthorized -> disabledInputView.showAsExpiredOrUnauthorized(inputReadyState.isClientExpired, inputReadyState.isUnauthorized) - inputReadyState.messageRequestState != MessageRequestState.NONE && inputReadyState.messageRequestState != MessageRequestState.NONE_HIDDEN -> disabledInputView.showAsMessageRequest(inputReadyState.conversationRecipient, inputReadyState.messageRequestState) + !inputReadyState.messageRequestState.isAccepted -> disabledInputView.showAsMessageRequest(inputReadyState.conversationRecipient, inputReadyState.messageRequestState) inputReadyState.isActiveGroup == false -> disabledInputView.showAsNoLongerAMember() inputReadyState.isRequestingMember == true -> disabledInputView.showAsRequestingMember() inputReadyState.isAnnouncementGroup == true && inputReadyState.isAdmin == false -> disabledInputView.showAsAnnouncementGroupAdminsOnly() inputReadyState.conversationRecipient.isReleaseNotes -> disabledInputView.showAsReleaseNotesChannel(inputReadyState.conversationRecipient) - inputReadyState.shouldShowInviteToSignal() -> disabledInputView.showAsInviteToSignal(requireContext(), inputReadyState.conversationRecipient) + inputReadyState.shouldShowInviteToSignal() -> disabledInputView.showAsInviteToSignal(requireContext(), inputReadyState.conversationRecipient, inputReadyState.threadContainsSms) else -> inputDisabled = false } @@ -1198,7 +1203,7 @@ class ConversationFragment : ) conversationActivityResultContracts.launchMediaEditor(listOf(media), recipientId, composeText.textTrimmed) } else { - attachmentManager.setMedia(GlideApp.with(this), uri, mediaType, MediaConstraints.getPushMediaConstraints(), width, height) + attachmentManager.setMedia(Glide.with(this), uri, mediaType, MediaConstraints.getPushMediaConstraints(), width, height) } } @@ -1294,7 +1299,7 @@ class ConversationFragment : val titleView = binding.conversationTitleView.root - titleView.setTitle(GlideApp.with(this), recipient) + titleView.setTitle(Glide.with(this), recipient) if (recipient.expiresInSeconds > 0) { titleView.showExpiring(recipient) } else { @@ -1369,7 +1374,6 @@ class ConversationFragment : colorFilter = PorterDuffColorFilter(chatColors.asSingleColor(), PorterDuff.Mode.MULTIPLY) invalidateSelf() } - ChatColorsDrawable.setGlobalChatColors(binding.conversationItemRecycler, chatColors) } private fun presentScrollButtons(scrollButtonState: ConversationScrollButtonState) { @@ -1439,7 +1443,7 @@ class ConversationFragment : is ShareOrDraftData.SetLocation -> attachmentManager.setLocation(data.location, MediaConstraints.getPushMediaConstraints()) is ShareOrDraftData.SetEditMessage -> { composeText.setDraftText(data.draftText) - inputPanel.enterEditMessageMode(GlideApp.with(this), data.messageEdit, true) + inputPanel.enterEditMessageMode(Glide.with(this), data.messageEdit, true) } is ShareOrDraftData.SetMedia -> { @@ -1527,14 +1531,15 @@ class ConversationFragment : adapter = ConversationAdapterV2( lifecycleOwner = viewLifecycleOwner, - glideRequests = GlideApp.with(this), + requestManager = Glide.with(this), clickListener = ConversationItemClickListener(), hasWallpaper = args.wallpaper != null, colorizer = colorizer, - startExpirationTimeout = viewModel::startExpirationTimeout + startExpirationTimeout = viewModel::startExpirationTimeout, + chatColorsDataProvider = viewModel::chatColorsSnapshot ) - typingIndicatorAdapter = ConversationTypingIndicatorAdapter(GlideApp.with(this)) + typingIndicatorAdapter = ConversationTypingIndicatorAdapter(Glide.with(this)) scrollToPositionDelegate = ScrollToPositionDelegate( recyclerView = binding.conversationItemRecycler, @@ -1635,7 +1640,7 @@ class ConversationFragment : } else if (state.hasLinks() && !state.linkPreview.isPresent) { inputPanel.setLinkPreviewNoPreview(state.error) } else { - inputPanel.setLinkPreview(GlideApp.with(this), state.linkPreview) + inputPanel.setLinkPreview(Glide.with(this), state.linkPreview) } updateToggleButtonState() @@ -1653,7 +1658,7 @@ class ConversationFragment : val keyboardPage = when (keyboardMode) { TextSecurePreferences.MediaKeyboardMode.EMOJI -> if (isSystemEmojiPreferred) KeyboardPage.STICKER else KeyboardPage.EMOJI TextSecurePreferences.MediaKeyboardMode.STICKER -> KeyboardPage.STICKER - TextSecurePreferences.MediaKeyboardMode.GIF -> KeyboardPage.GIF + TextSecurePreferences.MediaKeyboardMode.GIF -> if (FeatureFlags.gifSearchAvailable()) KeyboardPage.GIF else KeyboardPage.STICKER } inputPanel.setMediaKeyboardToggleMode(keyboardPage) @@ -1848,7 +1853,7 @@ class ConversationFragment : composeTextEventsListener?.typingStatusEnabled = false composeText.setText("") composeTextEventsListener?.typingStatusEnabled = true - attachmentManager.clear(GlideApp.with(this@ConversationFragment), false) + attachmentManager.clear(Glide.with(this@ConversationFragment), false) inputPanel.clearQuote() } scrollToPositionDelegate.markListCommittedVersion() @@ -2093,6 +2098,128 @@ class ConversationFragment : composeText.clearFocus() } + //region Message Request Helpers + + @SuppressLint("CheckResult") + private fun onReportSpam() { + val recipient = viewModel.recipientSnapshot + if (recipient == null) { + Log.w(TAG, "[onBlockClicked] No recipient!") + return + } + + BlockUnblockDialog.showReportSpamFor( + requireContext(), + lifecycle, + recipient, + { + messageRequestViewModel + .onReportSpam() + .doOnSubscribe { binding.conversationDisabledInput.showBusy() } + .doOnTerminate { binding.conversationDisabledInput.hideBusy() } + .subscribeBy { + Log.d(TAG, "report spam complete") + toast(R.string.ConversationFragment_reported_as_spam) + } + }, + if (recipient.isBlocked) { + null + } else { + Runnable { + messageRequestViewModel + .onBlockAndReportSpam() + .doOnSubscribe { binding.conversationDisabledInput.showBusy() } + .doOnTerminate { binding.conversationDisabledInput.hideBusy() } + .subscribeBy { result -> + when (result) { + is Result.Success -> { + Log.d(TAG, "report spam complete") + toast(R.string.ConversationFragment_reported_as_spam_and_blocked) + } + is Result.Failure -> { + Log.d(TAG, "report spam failed ${result.failure}") + toast(GroupErrors.getUserDisplayMessage(result.failure)) + } + } + } + } + } + ) + } + + @SuppressLint("CheckResult") + private fun onBlock() { + val recipient = viewModel.recipientSnapshot + if (recipient == null) { + Log.w(TAG, "[onBlockClicked] No recipient!") + return + } + + BlockUnblockDialog.showBlockFor( + requireContext(), + lifecycle, + recipient + ) { + messageRequestViewModel + .onBlock() + .subscribeWithShowProgress("block") + } + } + + @SuppressLint("CheckResult") + private fun onUnblock() { + val recipient = viewModel.recipientSnapshot + if (recipient == null) { + Log.w(TAG, "[onUnblockClicked] No recipient!") + return + } + + BlockUnblockDialog.showUnblockFor( + requireContext(), + lifecycle, + recipient + ) { + messageRequestViewModel + .onUnblock() + .subscribeWithShowProgress("unblock") + } + } + + private fun onMessageRequestAccept() { + messageRequestViewModel + .onAccept() + .subscribeWithShowProgress("accept message request") + .addTo(disposables) + } + + private fun onDeleteConversation() { + val recipient = viewModel.recipientSnapshot + if (recipient == null) { + Log.w(TAG, "[onDeleteConversation] No recipient!") + return + } + + ConversationDialogs.displayDeleteDialog(requireContext(), recipient) { + messageRequestViewModel + .onDelete() + .subscribeWithShowProgress("delete message request") + } + } + + private fun Single>.subscribeWithShowProgress(logMessage: String): Disposable { + return doOnSubscribe { binding.conversationDisabledInput.showBusy() } + .doOnTerminate { binding.conversationDisabledInput.hideBusy() } + .subscribeBy { result -> + when (result) { + is Result.Success -> Log.d(TAG, "$logMessage complete") + is Result.Failure -> { + Log.d(TAG, "$logMessage failed ${result.failure}") + toast(GroupErrors.getUserDisplayMessage(result.failure)) + } + } + } + } + private inner class BackPressedDelegate : OnBackPressedCallback(true) { override fun handleOnBackPressed() { Log.d(TAG, "onBackPressed()") @@ -2109,6 +2236,8 @@ class ConversationFragment : } } + // endregion + //region Message action handling private fun handleReplyToMessage(conversationMessage: ConversationMessage) { @@ -2124,7 +2253,7 @@ class ConversationFragment : val author = conversationMessage.messageRecord.fromRecipient inputPanel.setQuote( - GlideApp.with(this), + Glide.with(this), conversationMessage.messageRecord.dateSent, author, body, @@ -2142,7 +2271,7 @@ class ConversationFragment : viewModel.resolveMessageToEdit(conversationMessage) .subscribeBy { updatedMessage -> - inputPanel.enterEditMessageMode(GlideApp.with(this), updatedMessage, false) + inputPanel.enterEditMessageMode(Glide.with(this), updatedMessage, false) } .addTo(disposables) } @@ -2596,7 +2725,7 @@ class ConversationFragment : override fun onGroupMemberClicked(recipientId: RecipientId, groupId: GroupId) { context ?: return - RecipientBottomSheetDialogFragment.create(recipientId, groupId).show(childFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) + RecipientBottomSheetDialogFragment.show(childFragmentManager, recipientId, groupId) } override fun onMessageWithErrorClicked(messageRecord: MessageRecord) { @@ -2729,19 +2858,17 @@ class ConversationFragment : override fun onRecipientNameClicked(target: RecipientId) { context ?: return disposables += viewModel.recipient.firstOrError().observeOn(AndroidSchedulers.mainThread()).subscribeBy { - RecipientBottomSheetDialogFragment.create( + RecipientBottomSheetDialogFragment.show( + parentFragmentManager, target, it.groupId.orElse(null) - ).show(parentFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) + ) } } override fun onInviteToSignalClicked() { - val recipient = viewModel.recipientSnapshot ?: return InviteActions.inviteUserToSignal( requireContext(), - recipient, - binding.conversationInputPanel.embeddedTextEditor::appendInvite, this@ConversationFragment::startActivity ) } @@ -2977,6 +3104,31 @@ class ConversationFragment : CommunicationActions.startVideoCall(this@ConversationFragment, callLinkRootKey) } + override fun onShowSafetyTips(forGroup: Boolean) { + SafetyTipsBottomSheetDialog.show(childFragmentManager, forGroup) + } + + override fun onReportSpamLearnMoreClicked() { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.ConversationFragment_reported_spam) + .setMessage(R.string.ConversationFragment_reported_spam_message) + .setPositiveButton(android.R.string.ok, null) + .show() + } + + override fun onMessageRequestAcceptOptionsClicked() { + val recipient: Recipient? = viewModel.recipientSnapshot + + if (recipient != null) { + MaterialAlertDialogBuilder(requireContext()) + .setMessage(getString(R.string.ConversationFragment_you_accepted_a_message_request_from_s, recipient.getDisplayName(requireContext()))) + .setPositiveButton(R.string.ConversationFragment_block) { _, _ -> onBlock() } + .setNegativeButton(R.string.ConversationFragment_report_spam) { _, _ -> onReportSpam() } + .setNeutralButton(R.string.ConversationFragment__cancel, null) + .show() + } + } + private fun MessageRecord.getAudioUriForLongClick(): Uri? { val playbackState = getVoiceNoteMediaController().voiceNotePlaybackState.value if (playbackState == null || !playbackState.isPlaying) { @@ -3006,7 +3158,7 @@ class ConversationFragment : hasActiveGroupCall = groupCallViewModel.hasOngoingGroupCallSnapshot, distributionType = args.distributionType, threadId = args.threadId, - isInMessageRequest = viewModel.hasMessageRequestState, + messageRequestState = viewModel.messageRequestState, isInBubble = args.conversationScreenType.isInBubble ) } @@ -3043,6 +3195,7 @@ class ConversationFragment : searchNav.visible = true searchNav.setData(0, 0) inputPanel.setHideForSearch(true) + binding.conversationDisabledInput.visible = false (0 until menu.size()).forEach { if (menu.getItem(it) != searchMenuItem) { @@ -3059,6 +3212,7 @@ class ConversationFragment : searchViewModel.onSearchClosed() searchNav.visible = false inputPanel.setHideForSearch(false) + binding.conversationDisabledInput.visible = true viewModel.setSearchQuery(null) invalidateOptionsMenu() return true @@ -3089,14 +3243,9 @@ class ConversationFragment : this@ConversationFragment.handleVideoCall() } - override fun handleDial(isSecure: Boolean) { + override fun handleDial() { val recipient: Recipient = viewModel.recipientSnapshot ?: return - - if (isSecure) { - CommunicationActions.startVoiceCall(this@ConversationFragment, recipient) - } else { - CommunicationActions.startInsecureCall(this@ConversationFragment, recipient) - } + CommunicationActions.startVoiceCall(this@ConversationFragment, recipient) } override fun handleViewMedia() { @@ -3120,7 +3269,7 @@ class ConversationFragment : requireActivity().registerReceiver(pinnedShortcutReceiver, IntentFilter(ACTION_PINNED_SHORTCUT)) } - viewModel.getContactPhotoIcon(requireContext(), GlideApp.with(this@ConversationFragment)) + viewModel.getContactPhotoIcon(requireContext(), Glide.with(this@ConversationFragment)) .subscribe { infoCompat -> val intent = Intent(ACTION_PINNED_SHORTCUT) val callback = PendingIntent.getBroadcast(requireContext(), 902, intent, PendingIntentFlags.mutable()) @@ -3178,8 +3327,6 @@ class ConversationFragment : InviteActions.inviteUserToSignal( context = requireContext(), - recipient = recipient, - appendInviteToComposer = composeText::appendInvite, launchIntent = this@ConversationFragment::startActivity ) } @@ -3239,6 +3386,26 @@ class ConversationFragment : override fun handleFormatText(id: Int) { composeText.handleFormatText(id) } + + override fun handleBlock() { + onBlock() + } + + override fun handleUnblock() { + onUnblock() + } + + override fun handleReportSpam() { + onReportSpam() + } + + override fun handleMessageRequestAccept() { + onMessageRequestAccept() + } + + override fun handleDeleteConversation() { + onDeleteConversation() + } } private inner class OnReactionsSelectedListener : ConversationReactionOverlay.OnReactionSelectedListener { @@ -3495,7 +3662,7 @@ class ConversationFragment : .toTypedArray() MaterialAlertDialogBuilder(requireContext()) - .setIcon(R.drawable.ic_warning) + .setIcon(R.drawable.symbol_error_triangle_fill_24) .setTitle(R.string.ConversationFragment__no_longer_verified) .setItems(unverifiedNames) { _, which: Int -> VerifyIdentityActivity.startOrShowExchangeMessagesDialog(requireContext(), unverifiedIdentities[which], false) } .show() @@ -3550,73 +3717,28 @@ class ConversationFragment : } override fun onAcceptMessageRequestClicked() { - messageRequestViewModel - .onAccept() - .subscribeWithShowProgress("accept message request") - .addTo(disposables) + onMessageRequestAccept() } - override fun onDeleteGroupClicked() { - val recipient = viewModel.recipientSnapshot - if (recipient == null) { - Log.w(TAG, "[onDeleteGroupClicked] No recipient!") - return - } - - ConversationDialogs.displayDeleteDialog(requireContext(), recipient) { - messageRequestViewModel - .onDelete() - .subscribeWithShowProgress("delete message request") - } + override fun onDeleteClicked() { + onDeleteConversation() } override fun onBlockClicked() { - val recipient = viewModel.recipientSnapshot - if (recipient == null) { - Log.w(TAG, "[onBlockClicked] No recipient!") - return - } - - BlockUnblockDialog.showBlockAndReportSpamFor( - requireContext(), - lifecycle, - recipient, - { - messageRequestViewModel - .onBlock() - .subscribeWithShowProgress("block") - }, - { - messageRequestViewModel - .onBlockAndReportSpam() - .subscribeWithShowProgress("block") - } - ) + onBlock() } override fun onUnblockClicked() { - val recipient = viewModel.recipientSnapshot - if (recipient == null) { - Log.w(TAG, "[onUnblockClicked] No recipient!") - return - } + onUnblock() + } - BlockUnblockDialog.showUnblockFor( - requireContext(), - lifecycle, - recipient - ) { - messageRequestViewModel - .onUnblock() - .subscribeWithShowProgress("unblock") - } + override fun onReportSpamClicked() { + onReportSpam() } override fun onInviteToSignal(recipient: Recipient) { InviteActions.inviteUserToSignal( context = requireContext(), - recipient = recipient, - appendInviteToComposer = null, launchIntent = this@ConversationFragment::startActivity ) } @@ -3624,20 +3746,6 @@ class ConversationFragment : override fun onUnmuteReleaseNotesChannel() { viewModel.muteConversation(0L) } - - private fun Single>.subscribeWithShowProgress(logMessage: String): Disposable { - return doOnSubscribe { binding.conversationDisabledInput.showBusy() } - .doOnTerminate { binding.conversationDisabledInput.hideBusy() } - .subscribeBy { result -> - when (result) { - is Result.Success -> Log.d(TAG, "$logMessage complete") - is Result.Failure -> { - Log.d(TAG, "$logMessage failed ${result.failure}") - toast(GroupErrors.getUserDisplayMessage(result.failure)) - } - } - } - } } //endregion diff --git a/app/src/main/java/org/tm/archive/conversation/v2/ConversationRepository.kt b/app/src/main/java/org/tm/archive/conversation/v2/ConversationRepository.kt index 0b197316..03b2fd5f 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/ConversationRepository.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/ConversationRepository.kt @@ -13,6 +13,8 @@ import android.os.Build import android.text.SpannableStringBuilder import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.graphics.drawable.IconCompat +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers @@ -75,8 +77,6 @@ import org.tm.archive.keyboard.KeyboardUtil import org.tm.archive.keyvalue.SignalStore import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.messagerequests.MessageRequestState -import org.tm.archive.mms.GlideApp -import org.tm.archive.mms.GlideRequests import org.tm.archive.mms.OutgoingMessage import org.tm.archive.mms.PartAuthority import org.tm.archive.mms.QuoteModel @@ -123,7 +123,7 @@ class ConversationRepository( */ fun getKeyboardImageDetails(uri: Uri): Maybe { return MaybeCompat.fromCallable { - KeyboardUtil.getImageDetails(GlideApp.with(applicationContext), uri) + KeyboardUtil.getImageDetails(Glide.with(applicationContext), uri) }.subscribeOn(Schedulers.io()) } @@ -366,12 +366,20 @@ class ConversationRepository( fun getRequestReviewState(recipient: Recipient, group: GroupRecord?, messageRequest: MessageRequestState): Single { return Single.fromCallable { - if (group == null && messageRequest != MessageRequestState.INDIVIDUAL) { + if (group == null && messageRequest.state != MessageRequestState.State.INDIVIDUAL) { return@fromCallable RequestReviewState() } - if (group == null && ReviewUtil.isRecipientReviewSuggested(recipient.id)) { - return@fromCallable RequestReviewState(individualReviewState = IndividualReviewState(recipient)) + if (group == null) { + val recipientsToReview = ReviewUtil.getRecipientsToPromptForReview(recipient.id) + if (recipientsToReview.size > 0) { + return@fromCallable RequestReviewState( + individualReviewState = IndividualReviewState( + target = recipient, + firstDuplicate = Recipient.resolvedList(recipientsToReview)[0] + ) + ) + } } if (group != null && group.isV2Group) { @@ -383,6 +391,7 @@ class ConversationRepository( groupReviewState = GroupReviewState( groupId, duplicateRecipients[0], + duplicateRecipients[1], duplicateRecipients.size ) ) @@ -474,12 +483,12 @@ class ConversationRepository( .joinTo(buffer = SpannableStringBuilder(), separator = "\n") } - fun getRecipientContactPhotoBitmap(context: Context, glideRequests: GlideRequests, recipient: Recipient): Single { + fun getRecipientContactPhotoBitmap(context: Context, requestManager: RequestManager, recipient: Recipient): Single { val fallback = recipient.fallbackContactPhoto.asDrawable(context, recipient.avatarColor, false) return Single .create { emitter -> - glideRequests + requestManager .asBitmap() .load(recipient.contactPhoto) .error(fallback) diff --git a/app/src/main/java/org/tm/archive/conversation/v2/ConversationTypingIndicatorAdapter.kt b/app/src/main/java/org/tm/archive/conversation/v2/ConversationTypingIndicatorAdapter.kt index d9ad9e13..e1c35d6b 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/ConversationTypingIndicatorAdapter.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/ConversationTypingIndicatorAdapter.kt @@ -8,14 +8,14 @@ package org.tm.archive.conversation.v2 import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.RequestManager import org.signal.core.util.toInt import org.tm.archive.R import org.tm.archive.components.ConversationTypingView -import org.tm.archive.mms.GlideRequests import org.tm.archive.recipients.Recipient class ConversationTypingIndicatorAdapter( - private val glideRequests: GlideRequests + private val requestManager: RequestManager ) : RecyclerView.Adapter() { private var state: State = State() @@ -42,16 +42,16 @@ class ConversationTypingIndicatorAdapter( override fun getItemCount(): Int = state.typists.isNotEmpty().toInt() override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(glideRequests, state) + holder.bind(requestManager, state) } class ViewHolder(private val conversationTypingView: ConversationTypingView) : RecyclerView.ViewHolder(conversationTypingView) { fun bind( - glideRequests: GlideRequests, + requestManager: RequestManager, state: State ) { conversationTypingView.setTypists( - glideRequests, + requestManager, state.typists, state.isGroupThread, state.hasWallpaper diff --git a/app/src/main/java/org/tm/archive/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/tm/archive/conversation/v2/ConversationViewModel.kt index b282871c..e115778c 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/ConversationViewModel.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/ConversationViewModel.kt @@ -6,11 +6,14 @@ package org.tm.archive.conversation.v2 import android.content.Context +import android.graphics.Rect import android.net.Uri import android.os.Build import androidx.core.content.pm.ShortcutInfoCompat import androidx.lifecycle.ViewModel +import com.bumptech.glide.RequestManager import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.BackpressureStrategy import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Maybe @@ -33,8 +36,10 @@ import org.tm.archive.components.reminder.Reminder import org.tm.archive.contactshare.Contact import org.tm.archive.conversation.ConversationMessage import org.tm.archive.conversation.ScheduledMessagesRepository +import org.tm.archive.conversation.colors.ChatColors import org.tm.archive.conversation.mutiselect.MultiselectPart import org.tm.archive.conversation.v2.data.ConversationElementKey +import org.tm.archive.conversation.v2.items.ChatColorsDrawable import org.tm.archive.database.DatabaseObserver import org.tm.archive.database.MessageTable import org.tm.archive.database.model.IdentityRecord @@ -54,7 +59,6 @@ import org.tm.archive.keyvalue.SignalStore import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.messagerequests.MessageRequestRepository import org.tm.archive.messagerequests.MessageRequestState -import org.tm.archive.mms.GlideRequests import org.tm.archive.mms.QuoteModel import org.tm.archive.mms.Slide import org.tm.archive.mms.SlideDeck @@ -79,6 +83,7 @@ import kotlin.time.Duration class ConversationViewModel( val threadId: Long, private val requestedStartingPosition: Int, + initialChatColors: ChatColors, private val repository: ConversationRepository, recipientRepository: ConversationRecipientRepository, messageRequestRepository: MessageRequestRepository, @@ -110,6 +115,10 @@ class ConversationViewModel( .distinctUntilChanged() .observeOn(AndroidSchedulers.mainThread()) + private val chatBounds: BehaviorSubject = BehaviorSubject.create() + private val chatColors: RxStore = RxStore(ChatColorsDrawable.ChatColorsData(initialChatColors, null)) + val chatColorsSnapshot: ChatColorsDrawable.ChatColorsData get() = chatColors.state + @Volatile var recipientSnapshot: Recipient? = null private set @@ -123,9 +132,11 @@ class ConversationViewModel( private val _inputReadyState: Observable val inputReadyState: Observable - private val hasMessageRequestStateSubject: BehaviorSubject = BehaviorSubject.createDefault(false) + private val hasMessageRequestStateSubject: BehaviorSubject = BehaviorSubject.createDefault(MessageRequestState()) val hasMessageRequestState: Boolean - get() = hasMessageRequestStateSubject.value ?: false + get() = hasMessageRequestStateSubject.value?.state != MessageRequestState.State.NONE + val messageRequestState: MessageRequestState + get() = hasMessageRequestStateSubject.value ?: MessageRequestState() private val refreshReminder: Subject = PublishSubject.create() val reminder: Observable> @@ -153,6 +164,19 @@ class ConversationViewModel( recipientSnapshot = it } + val chatColorsDataObservable: Observable = Observable.combineLatest( + recipient.map { it.chatColors }.distinctUntilChanged(), + chatBounds.distinctUntilChanged() + ) { chatColors, bounds -> + val chatMask = chatColors.chatBubbleMask + + chatMask.bounds = bounds + + ChatColorsDrawable.ChatColorsData(chatColors, chatMask) + } + + disposables += chatColors.update(chatColorsDataObservable.toFlowable(BackpressureStrategy.LATEST)) { c, _ -> c } + disposables += repository.getConversationThreadState(threadId, requestedStartingPosition) .subscribeBy(onSuccess = { pagingController.set(it.items.controller) @@ -214,10 +238,11 @@ class ConversationViewModel( messageRequestState = messageRequestRepository.getMessageRequestState(recipient, threadId), groupRecord = groupRecord.orNull(), isClientExpired = SignalStore.misc().isClientDeprecated, - isUnauthorized = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()) + isUnauthorized = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()), + threadContainsSms = !recipient.isRegistered && !recipient.isPushGroup && !recipient.isSelf && messageRequestRepository.threadContainsSms(threadId) ) }.doOnNext { - hasMessageRequestStateSubject.onNext(it.messageRequestState != MessageRequestState.NONE) + hasMessageRequestStateSubject.onNext(it.messageRequestState) } inputReadyState = _inputReadyState.observeOn(AndroidSchedulers.mainThread()) @@ -251,6 +276,10 @@ class ConversationViewModel( }) } + fun onChatBoundsChanged(bounds: Rect) { + chatBounds.onNext(bounds) + } + fun setSearchQuery(query: String?) { _searchQuery.onNext(query ?: "") } @@ -322,9 +351,9 @@ class ConversationViewModel( .addTo(disposables) } - fun getContactPhotoIcon(context: Context, glideRequests: GlideRequests): Single { + fun getContactPhotoIcon(context: Context, requestManager: RequestManager): Single { return recipient.firstOrError().flatMap { - repository.getRecipientContactPhotoBitmap(context, glideRequests, it) + repository.getRecipientContactPhotoBitmap(context, requestManager, it) } } diff --git a/app/src/main/java/org/tm/archive/conversation/v2/DisabledInputView.kt b/app/src/main/java/org/tm/archive/conversation/v2/DisabledInputView.kt index 1cb72a97..8c49a4b8 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/DisabledInputView.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/DisabledInputView.kt @@ -17,7 +17,6 @@ import androidx.core.content.ContextCompat import com.google.android.material.button.MaterialButton import org.tm.archive.R import org.tm.archive.messagerequests.MessageRequestState -import org.tm.archive.messagerequests.MessageRequestViewModel import org.tm.archive.messagerequests.MessageRequestsBottomView import org.tm.archive.recipients.Recipient import org.tm.archive.util.SpanUtil @@ -80,13 +79,14 @@ class DisabledInputView @JvmOverloads constructor( existingView = messageRequestView, create = { MessageRequestsBottomView(context) }, bind = { - setMessageData(MessageRequestViewModel.MessageData(recipient, messageRequestState)) + setMessageRequestData(recipient, messageRequestState) setWallpaperEnabled(recipient.hasWallpaper()) setAcceptOnClickListener { listener?.onAcceptMessageRequestClicked() } - setDeleteOnClickListener { listener?.onDeleteGroupClicked() } + setDeleteOnClickListener { listener?.onDeleteClicked() } setBlockOnClickListener { listener?.onBlockClicked() } setUnblockOnClickListener { listener?.onUnblockClicked() } + setReportOnClickListener { listener?.onReportSpamClicked() } } ) } @@ -127,15 +127,17 @@ class DisabledInputView @JvmOverloads constructor( ) } - fun showAsInviteToSignal(context: Context, recipient: Recipient) { + fun showAsInviteToSignal(context: Context, recipient: Recipient, threadContainsSms: Boolean) { inviteToSignal = show( existingView = inviteToSignal, create = { inflater.inflate(R.layout.conversation_activity_sms_export_stub, this, false) }, bind = { findViewById(R.id.export_sms_message).text = if (recipient.isMmsGroup) { context.getString(R.string.ConversationActivity__sms_messaging_is_no_longer_supported) - } else { + } else if (threadContainsSms) { context.getString(R.string.ConversationActivity__sms_messaging_is_no_longer_supported_in_signal_invite_s_to_to_signal_to_keep_the_conversation_here, recipient.getDisplayName(context)) + } else { + context.getString(R.string.ConversationActivity__this_person_is_no_longer_using_signal) } findViewById(R.id.export_sms_button).apply { @@ -226,10 +228,11 @@ class DisabledInputView @JvmOverloads constructor( fun onCancelGroupRequestClicked() fun onShowAdminsBottomSheetDialog() fun onAcceptMessageRequestClicked() - fun onDeleteGroupClicked() + fun onDeleteClicked() fun onBlockClicked() fun onUnblockClicked() fun onInviteToSignal(recipient: Recipient) fun onUnmuteReleaseNotesChannel() + fun onReportSpamClicked() } } diff --git a/app/src/main/java/org/tm/archive/conversation/v2/InputReadyState.kt b/app/src/main/java/org/tm/archive/conversation/v2/InputReadyState.kt index 2acdf036..6b2abe89 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/InputReadyState.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/InputReadyState.kt @@ -18,7 +18,8 @@ class InputReadyState( val messageRequestState: MessageRequestState, val groupRecord: GroupRecord?, val isClientExpired: Boolean, - val isUnauthorized: Boolean + val isUnauthorized: Boolean, + val threadContainsSms: Boolean ) { private val selfMemberLevel: GroupTable.MemberLevel? = groupRecord?.memberLevel(Recipient.self()) diff --git a/app/src/main/java/org/tm/archive/conversation/v2/MessageRequestViewModel.kt b/app/src/main/java/org/tm/archive/conversation/v2/MessageRequestViewModel.kt index 1ddda5c1..41f8a12b 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/MessageRequestViewModel.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/MessageRequestViewModel.kt @@ -2,6 +2,7 @@ package org.tm.archive.conversation.v2 import androidx.lifecycle.ViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Single import org.signal.core.util.Result import org.tm.archive.groups.ui.GroupChangeFailureReason @@ -57,6 +58,14 @@ class MessageRequestViewModel( .observeOn(AndroidSchedulers.mainThread()) } + fun onReportSpam(): Completable { + return recipientId + .flatMapCompletable { recipientId -> + messageRequestRepository.reportSpamMessageRequest(recipientId, threadId) + } + .observeOn(AndroidSchedulers.mainThread()) + } + fun onBlockAndReportSpam(): Single> { return recipientId .flatMap { recipientId -> diff --git a/app/src/main/java/org/tm/archive/conversation/v2/RequestReviewState.kt b/app/src/main/java/org/tm/archive/conversation/v2/RequestReviewState.kt index a700b78a..b4d063fa 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/RequestReviewState.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/RequestReviewState.kt @@ -22,8 +22,8 @@ data class RequestReviewState( } /** Recipient is in message request state and has similar name as someone else */ - data class IndividualReviewState(val recipient: Recipient) + data class IndividualReviewState(val target: Recipient, val firstDuplicate: Recipient) /** Group has multiple members with similar names */ - data class GroupReviewState(val groupId: GroupId.V2, val recipient: Recipient, val count: Int) + data class GroupReviewState(val groupId: GroupId.V2, val target: Recipient, val firstDuplicate: Recipient, val count: Int) } diff --git a/app/src/main/java/org/tm/archive/conversation/v2/SafetyTipsBottomSheetDialog.kt b/app/src/main/java/org/tm/archive/conversation/v2/SafetyTipsBottomSheetDialog.kt new file mode 100644 index 00000000..790a9e22 --- /dev/null +++ b/app/src/main/java/org/tm/archive/conversation/v2/SafetyTipsBottomSheetDialog.kt @@ -0,0 +1,277 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.conversation.v2 + +import android.content.res.Configuration +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.rememberNestedScrollInteropConnection +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.os.bundleOf +import androidx.fragment.app.FragmentManager +import kotlinx.coroutines.launch +import org.signal.core.ui.BottomSheets +import org.signal.core.ui.Buttons +import org.signal.core.ui.theme.SignalTheme +import org.tm.archive.R +import org.tm.archive.compose.ComposeBottomSheetDialogFragment + +/** + * Shows tips about typical spam and fraud messages. + */ +class SafetyTipsBottomSheetDialog : ComposeBottomSheetDialogFragment() { + companion object { + private const val FOR_GROUP_ARG = "for_group" + + fun show(fragmentManager: FragmentManager, forGroup: Boolean) { + SafetyTipsBottomSheetDialog() + .apply { + arguments = bundleOf( + FOR_GROUP_ARG to forGroup + ) + } + .show(fragmentManager, "SAFETY_TIPS") + } + } + + override val peekHeightPercentage: Float = 1f + + @Composable + override fun SheetContent() { + val nestedScrollInterop = rememberNestedScrollInteropConnection() + SafetyTipsContent( + forGroup = requireArguments().getBoolean(FOR_GROUP_ARG, false), + modifier = Modifier.nestedScroll(nestedScrollInterop) + ) + } +} + +data class SafetyTipData( + @DrawableRes val heroImage: Int, + @StringRes val titleText: Int, + @StringRes val messageText: Int +) + +private val tips = listOf( + SafetyTipData(heroImage = R.drawable.safety_tip1, titleText = R.string.SafetyTips_tip1_title, messageText = R.string.SafetyTips_tip1_message), + SafetyTipData(heroImage = R.drawable.safety_tip2, titleText = R.string.SafetyTips_tip2_title, messageText = R.string.SafetyTips_tip2_message), + SafetyTipData(heroImage = R.drawable.safety_tip3, titleText = R.string.SafetyTips_tip3_title, messageText = R.string.SafetyTips_tip3_message), + SafetyTipData(heroImage = R.drawable.safety_tip4, titleText = R.string.SafetyTips_tip4_title, messageText = R.string.SafetyTips_tip4_message) +) + +@Preview +@Composable +private fun SafetyTipsContentPreview() { + SignalTheme { + Surface { + SafetyTipsContent() + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun SafetyTipsContent(forGroup: Boolean = false, modifier: Modifier = Modifier) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxWidth() + ) { + BottomSheets.Handle() + } + + val size = remember { tips.size } + val pagerState = rememberPagerState( + pageCount = { size } + ) + val scrollState = rememberScrollState() + + Column( + modifier = Modifier.fillMaxWidth() + ) { + Column( + modifier = modifier + .fillMaxWidth() + .weight(weight = 1f, fill = false) + .padding(top = 22.dp) + .verticalScroll(state = scrollState) + ) { + Text( + text = stringResource(id = R.string.SafetyTips_title), + style = MaterialTheme.typography.headlineMedium.copy(textAlign = TextAlign.Center), + modifier = Modifier + .padding(start = 24.dp, end = 24.dp, bottom = 4.dp, top = 26.dp) + .fillMaxWidth() + ) + + Text( + text = if (forGroup) stringResource(id = R.string.SafetyTips_subtitle_group) else stringResource(id = R.string.SafetyTips_subtitle_individual), + style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onSurfaceVariant), + modifier = Modifier + .padding(start = 36.dp, end = 36.dp) + .fillMaxWidth() + ) + + HorizontalPager( + state = pagerState, + beyondBoundsPageCount = size, + modifier = Modifier.padding(top = 24.dp) + ) { + SafetyTip(tips[it]) + } + + Row( + Modifier + .fillMaxWidth() + .padding(top = 20.dp), + horizontalArrangement = Arrangement.Center + ) { + repeat(pagerState.pageCount) { iteration -> + val color = if (pagerState.currentPage == iteration) { + MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = 0.8f) + } else { + MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = 0.3f) + } + Box( + modifier = Modifier + .padding(3.dp) + .clip(CircleShape) + .background(color) + .size(8.dp) + ) + } + } + } + + Surface( + shadowElevation = if (scrollState.canScrollForward) 8.dp else 0.dp, + modifier = Modifier.fillMaxWidth(), + color = SignalTheme.colors.colorSurface1, + contentColor = MaterialTheme.colorScheme.onSurface + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier + .padding(start = 24.dp, end = 24.dp, bottom = 36.dp, top = 24.dp) + .fillMaxWidth() + ) { + val coroutineScope = rememberCoroutineScope() + + TextButton( + onClick = { + coroutineScope.launch { + pagerState.animateScrollToPage(pagerState.currentPage - 1) + } + }, + enabled = pagerState.currentPage > 0, + modifier = Modifier + ) { + Text(text = stringResource(id = R.string.SafetyTips_previous_tip)) + } + + Buttons.LargeTonal( + onClick = { + coroutineScope.launch { + pagerState.animateScrollToPage(pagerState.currentPage + 1) + } + }, + enabled = pagerState.currentPage + 1 < pagerState.pageCount + ) { + Text(text = stringResource(id = R.string.SafetyTips_next_tip)) + } + } + } + } +} + +@Preview(name = "Light Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "screen", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun SafetyTipPreview() { + SignalTheme { + Surface { + SafetyTip(tips[0]) + } + } +} + +@Composable +private fun SafetyTip(safetyTip: SafetyTipData) { + Surface( + shape = RoundedCornerShape(18.dp), + color = colorResource(id = R.color.safety_tip_background), + contentColor = MaterialTheme.colorScheme.onSurface, + modifier = Modifier + .fillMaxWidth() + .padding(start = 24.dp, end = 24.dp) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + ) { + Surface( + shape = RoundedCornerShape(12.dp), + color = colorResource(id = R.color.safety_tip_image_background), + modifier = Modifier + .padding(12.dp) + .fillMaxWidth() + ) { + Image( + painter = painterResource(id = safetyTip.heroImage), + contentDescription = null, + modifier = Modifier + .padding(16.dp) + ) + } + + Text( + text = stringResource(id = safetyTip.titleText), + style = MaterialTheme.typography.titleMedium, + modifier = Modifier + .padding(start = 24.dp, end = 24.dp, top = 8.dp, bottom = 4.dp) + ) + + Text( + text = stringResource(id = safetyTip.messageText), + style = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurfaceVariant, textAlign = TextAlign.Center), + modifier = Modifier + .padding(start = 24.dp, end = 24.dp, bottom = 24.dp) + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/conversation/v2/data/ConversationDataSource.kt b/app/src/main/java/org/tm/archive/conversation/v2/data/ConversationDataSource.kt index 5881154f..62032f2e 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/data/ConversationDataSource.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/data/ConversationDataSource.kt @@ -15,7 +15,6 @@ import org.tm.archive.conversation.ConversationMessage import org.tm.archive.conversation.ConversationMessage.ConversationMessageFactory import org.tm.archive.database.MessageTable import org.tm.archive.database.SignalDatabase -import org.tm.archive.database.model.InMemoryMessageRecord.NoGroupsInCommon import org.tm.archive.database.model.InMemoryMessageRecord.RemovedContactHidden import org.tm.archive.database.model.InMemoryMessageRecord.UniversalExpireTimerUpdate import org.tm.archive.database.model.MessageRecord @@ -72,7 +71,6 @@ class ConversationDataSource( val startTime = System.currentTimeMillis() val size: Int = getSizeInternal() + THREAD_HEADER_COUNT + - messageRequestData.includeWarningUpdateMessage().toInt() + messageRequestData.isHidden.toInt() + showUniversalExpireTimerUpdate.toInt() @@ -108,10 +106,6 @@ class ConversationDataSource( } } - if (messageRequestData.includeWarningUpdateMessage() && (start + length >= totalSize)) { - records.add(NoGroupsInCommon(threadId, messageRequestData.isGroup)) - } - if (messageRequestData.isHidden && (start + length >= totalSize)) { records.add(RemovedContactHidden(threadId)) } diff --git a/app/src/main/java/org/tm/archive/conversation/v2/items/ChatColorsDrawable.kt b/app/src/main/java/org/tm/archive/conversation/v2/items/ChatColorsDrawable.kt index 1c6f1630..234d248b 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/items/ChatColorsDrawable.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/items/ChatColorsDrawable.kt @@ -11,7 +11,6 @@ import android.graphics.Outline import android.graphics.Path import android.graphics.PixelFormat import android.graphics.PointF -import android.graphics.Rect import android.graphics.RectF import android.graphics.drawable.Drawable import android.view.ViewGroup @@ -29,52 +28,17 @@ import org.tm.archive.util.Projection.Corners * Drawable that renders the given chat colors at a specified coordinate offset. * This is meant to be used in conjunction with [ChatColorsItemDecoration] */ -class ChatColorsDrawable : Drawable() { +class ChatColorsDrawable( + private val dataProvider: () -> ChatColorsData +) : Drawable() { - companion object { - private var globalChatColors: ChatColors? = null - private var globalMask: Drawable? = null - private var latestBounds: Rect? = null - - /** - * Binds the ChatColorsDrawable static cache to the lifecycle of the given recycler-view - */ - fun attach(recyclerView: RecyclerView) { - recyclerView.addOnLayoutChangeListener { _, left, top, right, bottom, _, _, _, _ -> - applyBounds(Rect(left, top, right, bottom)) - } - - recyclerView.addItemDecoration(ChatColorsItemDecoration) - } - - fun setGlobalChatColors(recyclerView: RecyclerView, chatColors: ChatColors) { - if (globalChatColors == chatColors) { - return - } - - globalChatColors = chatColors - - globalMask = if (chatColors.isGradient()) { - chatColors.chatBubbleMask - } else { - null - } - - recyclerView.invalidateItemDecorations() - } - - fun clearGlobalChatColors(recyclerView: RecyclerView) { - globalChatColors = null - globalMask = null - - recyclerView.invalidateItemDecorations() - } - - private fun applyBounds(bounds: Rect) { - latestBounds = bounds - globalMask?.bounds = bounds - } - } + /** + * Object allowing you to inject global color / masking. + */ + data class ChatColorsData( + var chatColors: ChatColors?, + var mask: Drawable? + ) /** * Translation coordinates so that the mask is drawn at the right location @@ -200,11 +164,11 @@ class ChatColorsDrawable : Drawable() { invalidateSelf() } - private fun getChatColors(): ChatColors? = localChatColors ?: globalChatColors + private fun getChatColors(): ChatColors? = localChatColors ?: dataProvider().chatColors - private fun getMask(): Drawable? = localMask ?: globalMask + private fun getMask(): Drawable? = localMask ?: dataProvider().mask - private object ChatColorsItemDecoration : RecyclerView.ItemDecoration() { + object ChatColorsItemDecoration : RecyclerView.ItemDecoration() { override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { parent.children.map { parent.getChildViewHolder(it) }.filterIsInstance().forEach { element -> element.invalidateChatColorsDrawable(parent) diff --git a/app/src/main/java/org/tm/archive/conversation/v2/items/ShrinkWrapLinearLayout.kt b/app/src/main/java/org/tm/archive/conversation/v2/items/ShrinkWrapLinearLayout.kt new file mode 100644 index 00000000..f9a108d8 --- /dev/null +++ b/app/src/main/java/org/tm/archive/conversation/v2/items/ShrinkWrapLinearLayout.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.conversation.v2.items + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.LinearLayoutCompat + +/** + * Custom LinearLayoutCompat that will intercept EXACTLY measure-specs and + * overwrite them with AT_MOST. This guarantees that wrap_content is respected + * when the Layout is within a constraintlayout. + */ +class ShrinkWrapLinearLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : LinearLayoutCompat(context, attrs) { + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val shrinkWrapWidthSpec = shrinkWrapWidthMeasureSpec(widthMeasureSpec) + super.onMeasure(shrinkWrapWidthSpec, heightMeasureSpec) + } + + private fun shrinkWrapWidthMeasureSpec(widthMeasureSpec: Int): Int { + val mode = MeasureSpec.getMode(widthMeasureSpec) + val size = MeasureSpec.getSize(widthMeasureSpec) + + return if (mode == MeasureSpec.EXACTLY) { + MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST) + } else { + widthMeasureSpec + } + } +} diff --git a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationContext.kt b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationContext.kt index beb3c0c8..caa43a12 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationContext.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationContext.kt @@ -5,19 +5,19 @@ package org.tm.archive.conversation.v2.items +import com.bumptech.glide.RequestManager import org.tm.archive.conversation.ConversationAdapter import org.tm.archive.conversation.ConversationItemDisplayMode import org.tm.archive.conversation.colors.Colorizer import org.tm.archive.conversation.mutiselect.MultiselectPart import org.tm.archive.database.model.MessageRecord -import org.tm.archive.mms.GlideRequests /** * Describes the Adapter "context" that would normally have been * visible to an inner class. */ interface V2ConversationContext { - val glideRequests: GlideRequests + val requestManager: RequestManager val displayMode: ConversationItemDisplayMode val clickListener: ConversationAdapter.ItemClickListener val selectedItems: Set @@ -25,6 +25,8 @@ interface V2ConversationContext { val searchQuery: String? val isParentInScroll: Boolean + fun getChatColorsData(): ChatColorsDrawable.ChatColorsData + fun onStartExpirationTimeout(messageRecord: MessageRecord) fun hasWallpaper(): Boolean diff --git a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemMediaViewHolder.kt b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemMediaViewHolder.kt index bc8a1ec0..709993ac 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemMediaViewHolder.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemMediaViewHolder.kt @@ -77,7 +77,7 @@ class V2ConversationItemMediaViewHolder>( binding.quoteStub.visibility = View.VISIBLE quoteView.setQuote( - conversationContext.glideRequests, + conversationContext.requestManager, quote.id, Recipient.live(quote.author).get(), quote.displayText, diff --git a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt index 21b38a1d..52afd026 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt @@ -41,6 +41,8 @@ import org.tm.archive.database.model.MessageRecord import org.tm.archive.database.model.MmsMessageRecord import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.recipients.Recipient +import org.tm.archive.recipients.RecipientForeverObserver import org.tm.archive.recipients.RecipientId import org.tm.archive.util.InterceptableLongClickCopyLinkSpan import org.tm.archive.util.LongClickMovementMethod @@ -66,7 +68,7 @@ open class V2ConversationItemTextOnlyViewHolder>( private val binding: V2ConversationItemTextOnlyBindingBridge, private val conversationContext: V2ConversationContext, footerDelegate: V2FooterPositionDelegate = V2FooterPositionDelegate(binding) -) : V2ConversationItemViewHolder(binding.root, conversationContext), Multiselectable, InteractiveConversationElement { +) : V2ConversationItemViewHolder(binding.root, conversationContext), Multiselectable, InteractiveConversationElement, RecipientForeverObserver { companion object { private val STYLE_FACTORY = SearchUtil.StyleFactory { arrayOf(BackgroundColorSpan(Color.YELLOW), ForegroundColorSpan(Color.BLACK)) } @@ -103,9 +105,9 @@ open class V2ConversationItemTextOnlyViewHolder>( private var reactionMeasureListener: ReactionMeasureListener = ReactionMeasureListener() private var formattedDate: FormattedDate? = null - private val bodyBubbleDrawable = ChatColorsDrawable() - private val footerDrawable = ChatColorsDrawable() - private val senderDrawable = ChatColorsDrawable() + private val bodyBubbleDrawable = ChatColorsDrawable(conversationContext::getChatColorsData) + private val footerDrawable = ChatColorsDrawable(conversationContext::getChatColorsData) + private val senderDrawable = ChatColorsDrawable(conversationContext::getChatColorsData) private val bodyBubbleLayoutTransition = BodyBubbleLayoutTransition() protected lateinit var shape: V2ConversationItemShape.MessageShape @@ -189,7 +191,15 @@ open class V2ConversationItemTextOnlyViewHolder>( } check(model is ConversationMessageElement) + + if (this::conversationMessage.isInitialized) { + conversationMessage.messageRecord.fromRecipient.live().removeForeverObserver(this) + } + conversationMessage = model.conversationMessage + if (conversationMessage.threadRecipient.isGroup) { + conversationMessage.messageRecord.fromRecipient.live().observeForever(this) + } shape = shapeDelegate.setMessageShape( currentMessage = conversationMessage.messageRecord, @@ -531,8 +541,8 @@ open class V2ConversationItemTextOnlyViewHolder>( binding.senderBadge.visible = shape.isEndingShape binding.senderName.text = sender.getDisplayName(context) - binding.senderPhoto.setAvatar(conversationContext.glideRequests, sender, false) - binding.senderBadge.setBadgeFromRecipient(sender, conversationContext.glideRequests) + binding.senderPhoto.setAvatar(conversationContext.requestManager, sender, false) + binding.senderBadge.setBadgeFromRecipient(sender, conversationContext.requestManager) binding.senderPhoto.setOnClickListener { conversationContext.clickListener.onGroupMemberClicked( conversationMessage.messageRecord.fromRecipient.id, @@ -560,7 +570,7 @@ open class V2ConversationItemTextOnlyViewHolder>( binding.body.setCompoundDrawablesWithIntrinsicBounds( 0, 0, - if (record.isKeyExchange) R.drawable.ic_menu_login else 0, + if (record.isKeyExchange) R.drawable.symbol_key_24 else 0, 0 ) @@ -632,6 +642,9 @@ open class V2ConversationItemTextOnlyViewHolder>( } binding.footerDate.setText(errorMessage) + binding.footerDate.setOnClickListener { + conversationContext.clickListener.onMessageWithErrorClicked(record) + } } else if (record.isPendingInsecureSmsFallback) { binding.footerDate.setText(R.string.ConversationItem_click_to_approve_unencrypted) } else if (record.isRateLimited) { @@ -762,4 +775,8 @@ open class V2ConversationItemTextOnlyViewHolder>( return true } } + + override fun onRecipientChanged(recipient: Recipient) { + presentSender() + } } diff --git a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemThumbnail.kt b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemThumbnail.kt index be695d7a..f8709c76 100644 --- a/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemThumbnail.kt +++ b/app/src/main/java/org/tm/archive/conversation/v2/items/V2ConversationItemThumbnail.kt @@ -115,10 +115,10 @@ class V2ConversationItemThumbnail @JvmOverloads constructor( thumbnailSlide = thumbnail this.fastPreflightId = fastPreflightId - conversationContext.glideRequests.clear(this) + conversationContext.requestManager.clear(this) if (placeholderTarget != null) { - conversationContext.glideRequests.clear(placeholderTarget) + conversationContext.requestManager.clear(placeholderTarget) } val thumbnailUri = thumbnail.uri @@ -147,7 +147,7 @@ class V2ConversationItemThumbnail @JvmOverloads constructor( if (thumbnailBlur != null) { val placeholderTarget = PlaceholderTarget(this) conversationContext - .glideRequests + .requestManager .load(thumbnailBlur) .centerInside() .dontAnimate() @@ -159,7 +159,7 @@ class V2ConversationItemThumbnail @JvmOverloads constructor( if (thumbnailUri != null) { conversationContext - .glideRequests + .requestManager .load(DecryptableStreamUriLoader.DecryptableUri(thumbnailUri)) .centerInside() .dontAnimate() diff --git a/app/src/main/java/org/tm/archive/conversationlist/ConversationListAdapter.java b/app/src/main/java/org/tm/archive/conversationlist/ConversationListAdapter.java index 73e56bd1..9717d7d3 100644 --- a/app/src/main/java/org/tm/archive/conversationlist/ConversationListAdapter.java +++ b/app/src/main/java/org/tm/archive/conversationlist/ConversationListAdapter.java @@ -13,13 +13,13 @@ import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.ListAdapter; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; + import org.signal.paging.PagingController; import org.tm.archive.BindableConversationListItem; import org.tm.archive.R; import org.tm.archive.conversationlist.model.Conversation; -import org.tm.archive.conversationlist.model.ConversationReader; import org.tm.archive.conversationlist.model.ConversationSet; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.util.CachedInflater; import org.tm.archive.util.ViewUtil; @@ -46,8 +46,8 @@ class ConversationListAdapter extends ListAdapter typingSet = new HashSet<>(); @@ -55,14 +55,14 @@ class ConversationListAdapter extends ListAdapter typingThreads; private LiveRecipient recipient; private long threadId; - private GlideRequests glideRequests; + private RequestManager requestManager; private EmojiTextView subjectView; private TypingIndicatorView typingView; private FromTextView fromView; @@ -206,24 +208,25 @@ public final class ConversationListItem extends ConstraintLayout implements Bind @Override public void bind(@NonNull LifecycleOwner lifecycleOwner, @NonNull ThreadRecord thread, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager glideRequests, @NonNull Locale locale, @NonNull Set typingThreads, @NonNull ConversationSet selectedConversations) { - bindThread(lifecycleOwner, thread, glideRequests, locale, typingThreads, selectedConversations, null); + bindThread(lifecycleOwner, thread, glideRequests, locale, typingThreads, selectedConversations, null, false); } public void bindThread(@NonNull LifecycleOwner lifecycleOwner, @NonNull ThreadRecord thread, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull Set typingThreads, @NonNull ConversationSet selectedConversations, - @Nullable String highlightSubstring) + @Nullable String highlightSubstring, + boolean appendSystemContactIcon) { this.threadId = thread.getThreadId(); - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.unreadCount = thread.getUnreadCount(); this.lastSeen = thread.getLastSeen(); this.thread = thread; @@ -234,18 +237,26 @@ public final class ConversationListItem extends ConstraintLayout implements Bind observeDisplayBody(null, null); joinMembersDisposable.dispose(); + SpannableStringBuilder suffix = null; + if (appendSystemContactIcon && recipient.get().isSystemContact() && !recipient.get().showVerified()) { + suffix = new SpannableStringBuilder(); + Drawable drawable = ContextUtil.requireDrawable(getContext(), R.drawable.symbol_person_circle_24); + drawable.setTint(ContextCompat.getColor(getContext(), R.color.signal_colorOnSurface)); + SpanUtil.appendCenteredImageSpan(suffix, drawable, 16, 16); + } + if (highlightSubstring != null) { String name = recipient.get().isSelf() ? getContext().getString(R.string.note_to_self) : recipient.get().getDisplayName(getContext()); - this.fromView.setText(recipient.get(), SearchUtil.getHighlightedSpan(locale, searchStyleFactory, name, highlightSubstring, SearchUtil.MATCH_ALL), true, null); + this.fromView.setText(recipient.get(), SearchUtil.getHighlightedSpan(locale, searchStyleFactory, name, highlightSubstring, SearchUtil.MATCH_ALL), suffix); } else { - this.fromView.setText(recipient.get(), false); + this.fromView.setText(recipient.get(), suffix); } this.typingThreads = typingThreads; updateTypingIndicator(typingThreads); - LiveData displayBody = getThreadDisplayBody(getContext(), thread, glideRequests, thumbSize, thumbTarget); + LiveData displayBody = getThreadDisplayBody(getContext(), thread, requestManager, thumbSize, thumbTarget); setSubjectViewText(displayBody.getValue()); observeDisplayBody(lifecycleOwner, displayBody); @@ -272,7 +283,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind setSelectedConversations(selectedConversations); setBadgeFromRecipient(recipient.get()); setUnreadIndicator(thread); - this.contactPhotoImage.setAvatar(glideRequests, recipient.get(), !batchMode); + this.contactPhotoImage.setAvatar(requestManager, recipient.get(), !batchMode); } private void setBadgeFromRecipient(Recipient recipient) { @@ -286,11 +297,11 @@ public final class ConversationListItem extends ConstraintLayout implements Bind public void bindMessage(@NonNull LifecycleOwner lifecycleOwner, @NonNull MessageResult messageResult, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @Nullable String highlightSubstring) { - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.locale = locale; this.highlightSubstring = highlightSubstring; @@ -299,7 +310,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind joinMembersDisposable.dispose(); setSubjectViewText(null); - fromView.setText(recipient.get(), recipient.get().getDisplayNameOrUsername(getContext()), false, null, false); + fromView.setText(recipient.get(), recipient.get().getDisplayName(getContext()), null, false); setSubjectViewText(SearchUtil.getHighlightedSpan(locale, searchStyleFactory, messageResult.getBodySnippet(), highlightSubstring, SearchUtil.MATCH_ALL)); updateDateView = () -> dateView.setText(DateUtils.getBriefRelativeTimeSpanString(getContext(), locale, messageResult.getReceivedTimestampMs())); @@ -313,15 +324,15 @@ public final class ConversationListItem extends ConstraintLayout implements Bind setSelectedConversations(new ConversationSet()); setBadgeFromRecipient(recipient.get()); - contactPhotoImage.setAvatar(glideRequests, recipient.get(), !batchMode, false); + contactPhotoImage.setAvatar(requestManager, recipient.get(), !batchMode, false); } public void bindGroupWithMembers(@NonNull LifecycleOwner lifecycleOwner, @NonNull ContactSearchData.GroupWithMembers groupWithMembers, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale) { - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.locale = locale; this.highlightSubstring = groupWithMembers.getQuery(); @@ -332,9 +343,15 @@ public final class ConversationListItem extends ConstraintLayout implements Bind setSubjectViewText(SearchUtil.getHighlightedSpan(locale, searchStyleFactory, joined, highlightSubstring, SearchUtil.MATCH_ALL)); }); - fromView.setText(recipient.get(), false); + fromView.setText(recipient.get()); - updateDateView = () -> dateView.setText(DateUtils.getBriefRelativeTimeSpanString(getContext(), locale, groupWithMembers.getDate())); + updateDateView = () -> { + if (groupWithMembers.getDate() > 0) { + dateView.setText(DateUtils.getBriefRelativeTimeSpanString(getContext(), locale, groupWithMembers.getDate())); + } else { + dateView.setText(""); + } + }; updateDateView.run(); archivedView.setVisibility(GONE); unreadIndicator.setVisibility(GONE); @@ -344,7 +361,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind setSelectedConversations(new ConversationSet()); setBadgeFromRecipient(recipient.get()); - contactPhotoImage.setAvatar(glideRequests, recipient.get(), !batchMode); + contactPhotoImage.setAvatar(requestManager, recipient.get(), !batchMode); } private @NonNull Single joinMembersToDisplayBody(@NonNull List members, @NonNull String highlightSubstring) { @@ -363,7 +380,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind if (this.recipient != null) { observeRecipient(null, null); setSelectedConversations(new ConversationSet()); - contactPhotoImage.setAvatar(glideRequests, null, !batchMode); + contactPhotoImage.setAvatar(requestManager, null, !batchMode); } observeDisplayBody(null, null); @@ -379,7 +396,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind setSelected(selected); if (recipient != null) { - contactPhotoImage.setAvatar(glideRequests, recipient.get(), !batchMode); + contactPhotoImage.setAvatar(requestManager, recipient.get(), !batchMode); } if (batchMode && selected) { @@ -452,8 +469,8 @@ public final class ConversationListItem extends ConstraintLayout implements Bind } private void observeDisplayBody(@Nullable LifecycleOwner lifecycleOwner, @Nullable LiveData displayBody) { - if (displayBody == null && glideRequests != null) { - glideRequests.clear(thumbTarget); + if (displayBody == null && requestManager != null) { + requestManager.clear(thumbTarget); } if (this.displayBody != null) { @@ -548,17 +565,17 @@ public final class ConversationListItem extends ConstraintLayout implements Bind } else { name = recipient.getDisplayName(getContext()); } - fromView.setText(recipient, SearchUtil.getHighlightedSpan(locale, searchStyleFactory, new SpannableString(name), highlightSubstring, SearchUtil.MATCH_ALL), true, null, thread != null); + fromView.setText(recipient, SearchUtil.getHighlightedSpan(locale, searchStyleFactory, new SpannableString(name), highlightSubstring, SearchUtil.MATCH_ALL), null, thread != null); } else { - fromView.setText(recipient, false); + fromView.setText(recipient); } - contactPhotoImage.setAvatar(glideRequests, recipient, !batchMode, false); + contactPhotoImage.setAvatar(requestManager, recipient, !batchMode, false); setBadgeFromRecipient(recipient); } private static @NonNull LiveData getThreadDisplayBody(@NonNull Context context, @NonNull ThreadRecord thread, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @Px int thumbSize, @NonNull GlideLiveDataTarget thumbTarget) { @@ -572,7 +589,11 @@ public final class ConversationListItem extends ConstraintLayout implements Bind } } else if (MessageTypes.isGroupUpdate(thread.getType())) { if (thread.getRecipient().isPushV2Group()) { - return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getBody(), null), defaultTint); + if (thread.getMessageExtras() != null) { + return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getMessageExtras(), null), defaultTint); + } else { + return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getBody(), null), defaultTint); + } } else { return emphasisAdded(context, context.getString(R.string.ThreadRecord_group_updated), R.drawable.ic_update_group_16, defaultTint); } @@ -655,7 +676,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind MessageStyler.style(thread.getDate(), thread.getBodyRanges(), sourceBody); CharSequence body = StringUtil.replace(sourceBody, '\n', " "); - LiveData finalBody = Transformations.map(createFinalBodyWithMediaIcon(context, body, thread, glideRequests, thumbSize, thumbTarget), updatedBody -> { + LiveData finalBody = Transformations.map(createFinalBodyWithMediaIcon(context, body, thread, requestManager, thumbSize, thumbTarget), updatedBody -> { if (thread.getRecipient().isGroup()) { RecipientId groupMessageSender = thread.getGroupMessageSender(); if (!groupMessageSender.isUnknown()) { @@ -674,7 +695,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind private static LiveData createFinalBodyWithMediaIcon(@NonNull Context context, @NonNull CharSequence body, @NonNull ThreadRecord thread, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @Px int thumbSize, @NonNull GlideLiveDataTarget thumbTarget) { @@ -696,7 +717,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind return LiveDataUtil.just(body); } - glideRequests.asBitmap() + requestManager.asBitmap() .load(new DecryptableStreamUriLoader.DecryptableUri(thread.getSnippetUri())) .override(thumbSize, thumbSize) .transform( diff --git a/app/src/main/java/org/tm/archive/conversationlist/ConversationListItemAction.java b/app/src/main/java/org/tm/archive/conversationlist/ConversationListItemAction.java index 57abb81c..2807dcba 100644 --- a/app/src/main/java/org/tm/archive/conversationlist/ConversationListItemAction.java +++ b/app/src/main/java/org/tm/archive/conversationlist/ConversationListItemAction.java @@ -8,11 +8,12 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.lifecycle.LifecycleOwner; +import com.bumptech.glide.RequestManager; + import org.tm.archive.BindableConversationListItem; import org.tm.archive.R; import org.tm.archive.conversationlist.model.ConversationSet; import org.tm.archive.database.model.ThreadRecord; -import org.tm.archive.mms.GlideRequests; import java.util.Locale; import java.util.Set; @@ -42,7 +43,7 @@ public class ConversationListItemAction extends FrameLayout implements BindableC @Override public void bind(@NonNull LifecycleOwner lifecycleOwner, @NonNull ThreadRecord thread, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull Locale locale, @NonNull Set typingThreads, @NonNull ConversationSet selectedConversations) diff --git a/app/src/main/java/org/tm/archive/conversationlist/ConversationListSearchAdapter.kt b/app/src/main/java/org/tm/archive/conversationlist/ConversationListSearchAdapter.kt index 55563909..a0b4b8f0 100644 --- a/app/src/main/java/org/tm/archive/conversationlist/ConversationListSearchAdapter.kt +++ b/app/src/main/java/org/tm/archive/conversationlist/ConversationListSearchAdapter.kt @@ -5,6 +5,7 @@ import android.view.View import android.widget.TextView import androidx.core.os.bundleOf import androidx.lifecycle.LifecycleOwner +import com.bumptech.glide.RequestManager import org.tm.archive.R import org.tm.archive.contacts.paged.ArbitraryRepository import org.tm.archive.contacts.paged.ContactSearchAdapter @@ -12,7 +13,6 @@ import org.tm.archive.contacts.paged.ContactSearchConfiguration import org.tm.archive.contacts.paged.ContactSearchData import org.tm.archive.contacts.paged.ContactSearchKey import org.tm.archive.conversationlist.model.ConversationSet -import org.tm.archive.mms.GlideRequests import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingModel import org.tm.archive.util.adapter.mapping.MappingViewHolder @@ -32,7 +32,7 @@ class ConversationListSearchAdapter( storyContextMenuCallbacks: StoryContextMenuCallbacks, callButtonClickCallbacks: CallButtonClickCallbacks, lifecycleOwner: LifecycleOwner, - glideRequests: GlideRequests + requestManager: RequestManager ) : ContactSearchAdapter(context, fixedContacts, displayOptions, onClickedCallbacks, longClickCallbacks, storyContextMenuCallbacks, callButtonClickCallbacks), TimestampPayloadSupport { companion object { @@ -42,11 +42,11 @@ class ConversationListSearchAdapter( init { registerFactory( ThreadModel::class.java, - LayoutFactory({ ThreadViewHolder(onClickedCallbacks::onThreadClicked, lifecycleOwner, glideRequests, it) }, R.layout.conversation_list_item_view) + LayoutFactory({ ThreadViewHolder(onClickedCallbacks::onThreadClicked, lifecycleOwner, requestManager, it) }, R.layout.conversation_list_item_view) ) registerFactory( MessageModel::class.java, - LayoutFactory({ MessageViewHolder(onClickedCallbacks::onMessageClicked, lifecycleOwner, glideRequests, it) }, R.layout.conversation_list_item_view) + LayoutFactory({ MessageViewHolder(onClickedCallbacks::onMessageClicked, lifecycleOwner, requestManager, it) }, R.layout.conversation_list_item_view) ) registerFactory( ChatFilterMappingModel::class.java, @@ -62,7 +62,7 @@ class ConversationListSearchAdapter( ) registerFactory( GroupWithMembersModel::class.java, - LayoutFactory({ GroupWithMembersViewHolder(onClickedCallbacks::onGroupWithMembersClicked, lifecycleOwner, glideRequests, it) }, R.layout.conversation_list_item_view) + LayoutFactory({ GroupWithMembersViewHolder(onClickedCallbacks::onGroupWithMembersClicked, lifecycleOwner, requestManager, it) }, R.layout.conversation_list_item_view) ) } @@ -105,7 +105,7 @@ class ConversationListSearchAdapter( private class ThreadViewHolder( private val threadListener: OnClickedCallback, private val lifecycleOwner: LifecycleOwner, - private val glideRequests: GlideRequests, + private val requestManager: RequestManager, itemView: View ) : ConversationListItemViewHolder(itemView) { override fun fullBind(model: ThreadModel) { @@ -116,11 +116,12 @@ class ConversationListSearchAdapter( (itemView as ConversationListItem).bindThread( lifecycleOwner, model.thread.threadRecord, - glideRequests, + requestManager, Locale.getDefault(), emptySet(), ConversationSet(), - model.thread.query + model.thread.query, + true ) } } @@ -128,7 +129,7 @@ class ConversationListSearchAdapter( private class MessageViewHolder( private val messageListener: OnClickedCallback, private val lifecycleOwner: LifecycleOwner, - private val glideRequests: GlideRequests, + private val requestManager: RequestManager, itemView: View ) : ConversationListItemViewHolder(itemView) { override fun fullBind(model: MessageModel) { @@ -139,7 +140,7 @@ class ConversationListSearchAdapter( (itemView as ConversationListItem).bindMessage( lifecycleOwner, model.message.messageResult, - glideRequests, + requestManager, Locale.getDefault(), model.message.query ) @@ -149,7 +150,7 @@ class ConversationListSearchAdapter( private class GroupWithMembersViewHolder( private val groupWithMembersListener: OnClickedCallback, private val lifecycleOwner: LifecycleOwner, - private val glideRequests: GlideRequests, + private val requestManager: RequestManager, itemView: View ) : ConversationListItemViewHolder(itemView) { override fun fullBind(model: GroupWithMembersModel) { @@ -160,7 +161,7 @@ class ConversationListSearchAdapter( (itemView as ConversationListItem).bindGroupWithMembers( lifecycleOwner, model.groupWithMembers, - glideRequests, + requestManager, Locale.getDefault() ) } diff --git a/app/src/main/java/org/tm/archive/conversationlist/ConversationListViewModel.kt b/app/src/main/java/org/tm/archive/conversationlist/ConversationListViewModel.kt index 40040d75..c60b0977 100644 --- a/app/src/main/java/org/tm/archive/conversationlist/ConversationListViewModel.kt +++ b/app/src/main/java/org/tm/archive/conversationlist/ConversationListViewModel.kt @@ -110,6 +110,7 @@ class ConversationListViewModel( hasNoConversations = store .stateFlowable + .subscribeOn(Schedulers.io()) .map { it.filterRequest to it.conversations } .distinctUntilChanged() .map { (filterRequest, conversations) -> diff --git a/app/src/main/java/org/tm/archive/conversationlist/SignalConversationListFragment.java b/app/src/main/java/org/tm/archive/conversationlist/SignalConversationListFragment.java index ad53b2a1..aeb3b98e 100644 --- a/app/src/main/java/org/tm/archive/conversationlist/SignalConversationListFragment.java +++ b/app/src/main/java/org/tm/archive/conversationlist/SignalConversationListFragment.java @@ -68,35 +68,22 @@ import androidx.recyclerview.widget.RecyclerView; import com.airbnb.lottie.SimpleColorFilter; import com.annimon.stream.Stream; +import com.bumptech.glide.Glide; import com.google.android.material.animation.ArgbEvaluatorCompat; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; -import com.tm.androidcopysdk.CommonUtils; -import com.tm.androidcopysdk.network.appSettings.UpdateEvent; -import com.tm.androidcopysdk.network.appSettings.WorkerIntentService; -import com.tm.androidcopysdk.utils.PrefManager; -import com.tm.authenticatorsdk.mamsdk.IMDMAuthenticator; -import com.tm.authenticatorsdk.mamsdk.MDMAuthenticator; -import com.tm.authenticatorsdk.selfAuthenticator.IAuthenticationStatus; -import org.archiver.ArchivePreferenceConstants; -import org.archiver.ArchiveUtil; -import org.archiver.FCMConnector; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import org.intune.IntuneAuthManager; -import org.jetbrains.annotations.NotNull; -import org.selfAuthentication.SelfAuthenticatorManager; import org.signal.core.util.DimensionUnit; import org.signal.core.util.Stopwatch; import org.signal.core.util.concurrent.LifecycleDisposable; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.concurrent.SimpleTask; import org.signal.core.util.logging.Log; -import org.tm.archive.BuildConfig; import org.tm.archive.MainActivity; import org.tm.archive.MainFragment; import org.tm.archive.MainNavigator; @@ -118,7 +105,6 @@ import org.tm.archive.components.reminder.CdsTemporaryErrorReminder; import org.tm.archive.components.reminder.DozeReminder; import org.tm.archive.components.reminder.ExpiredBuildReminder; import org.tm.archive.components.reminder.OutdatedBuildReminder; -import org.tm.archive.components.reminder.PushRegistrationReminder; import org.tm.archive.components.reminder.Reminder; import org.tm.archive.components.reminder.ReminderView; import org.tm.archive.components.reminder.ServiceOutageReminder; @@ -151,8 +137,8 @@ import org.tm.archive.database.ThreadTable; import org.tm.archive.database.model.ThreadRecord; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.events.ReminderUpdateEvent; -import org.tm.archive.exporter.flow.SmsExportDialogs; import org.tm.archive.groups.SelectionLimits; +import org.tm.archive.jobs.RefreshOwnProfileJob; import org.tm.archive.jobs.ServiceOutageDetectionJob; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.lock.v2.CreateSvrPinActivity; @@ -163,12 +149,10 @@ import org.tm.archive.megaphone.Megaphone; import org.tm.archive.megaphone.MegaphoneActionController; import org.tm.archive.megaphone.MegaphoneViewBuilder; import org.tm.archive.megaphone.Megaphones; -import org.tm.archive.megaphone.SmsExportMegaphoneActivity; -import org.tm.archive.mms.GlideApp; import org.tm.archive.notifications.MarkReadReceiver; import org.tm.archive.notifications.profiles.NotificationProfile; import org.tm.archive.permissions.Permissions; -import org.tm.archive.profiles.manage.EditProfileActivity; +import org.tm.archive.profiles.manage.UsernameEditFragment; import org.tm.archive.ratelimit.RecaptchaProofBottomSheetFragment; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; @@ -212,21 +196,19 @@ import java.util.stream.Collectors; import kotlin.Unit; -import static android.app.Activity.RESULT_CANCELED; import static android.app.Activity.RESULT_OK; public class SignalConversationListFragment extends MainFragment implements ActionMode.Callback,//*TM_SA*/change ConversationListFragment to SignalConversationListFragment ConversationListAdapter.OnConversationClickListener, MegaphoneActionController, ClearFilterViewHolder.OnClearFilterClickListener - { public static final short MESSAGE_REQUESTS_REQUEST_CODE_CREATE_NAME = 32562; public static final short SMS_ROLE_REQUEST_CODE = 32563; private static final int LIST_SMOOTH_SCROLL_TO_TOP_THRESHOLD = 25; - private static final String TAG = Log.tag(SignalConversationListFragment.class); + private static final String TAG = Log.tag(ConversationListFragment.class); private static final int MAXIMUM_PINNED_CONVERSATIONS = 4; private static final int MAX_CHATS_ABOVE_FOLD = 7; @@ -261,6 +243,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti private Stopwatch startupStopwatch; private ConversationListTabsViewModel conversationListTabsViewModel; private ContactSearchMediator contactSearchMediator; + public static ConversationListFragment newInstance() { return new ConversationListFragment(); } @@ -279,7 +262,6 @@ public class SignalConversationListFragment extends MainFragment implements Acti @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - Log.d("ConversationListFragment", "onCreate"); setHasOptionsMenu(true); startupStopwatch = new Stopwatch("startup"); } @@ -341,7 +323,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti storyContextMenuCallbacks, callButtonClickCallbacks, getViewLifecycleOwner(), - GlideApp.with(this) + Glide.with(this) ); }, new ConversationListSearchAdapter.ChatFilterRepository() @@ -433,7 +415,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti @Override public void handleOnBackPressed() { if (!closeSearchIfOpen()) { - if (!NavHostFragment.findNavController(SignalConversationListFragment.this).popBackStack()) { + if (!NavHostFragment.findNavController(SignalConversationListFragment.this).popBackStack()) {//*TM_SA*/change to SignalConversationListFragment requireActivity().finish(); } } @@ -480,10 +462,10 @@ public class SignalConversationListFragment extends MainFragment implements Acti @Override public void onResume() { super.onResume(); - Log.d("ConversationListFragment", "onResume"); + initializeSearchListener(); updateReminders(); - + EventBus.getDefault().register(this); itemAnimator.disable(); SpoilerAnnotation.resetRevealedSpoilers(); @@ -552,6 +534,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti requireCallback().getSearchAction().setOnClickListener(null); fab.stopPulse(); cameraFab.stopPulse(); + EventBus.getDefault().unregister(this); } @Override @@ -560,8 +543,6 @@ public class SignalConversationListFragment extends MainFragment implements Acti ApplicationDependencies.getAppForegroundObserver().removeListener(appForegroundObserver); } - - @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { menu.clear(); @@ -703,19 +684,15 @@ public class SignalConversationListFragment extends MainFragment implements Acti @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if (requestCode == SmsExportMegaphoneActivity.REQUEST_CODE) { - ApplicationDependencies.getMegaphoneRepository().markSeen(Megaphones.Event.SMS_EXPORT); - if (resultCode == RESULT_CANCELED) { - Snackbar.make(fab, R.string.ConversationActivity__you_will_be_reminded_again_soon, Snackbar.LENGTH_LONG).show(); - } else { - SmsExportDialogs.showSmsRemovalDialog(requireContext(), fab); - } - } - if (resultCode == RESULT_OK && requestCode == CreateSvrPinActivity.REQUEST_NEW_PIN) { Snackbar.make(fab, R.string.ConfirmKbsPinFragment__pin_created, Snackbar.LENGTH_LONG).show(); viewModel.onMegaphoneCompleted(Megaphones.Event.PINS_FOR_ALL); } + + if (resultCode == RESULT_OK && requestCode == UsernameEditFragment.REQUEST_CODE) { + String snackbarString = getString(R.string.ConversationListFragment_username_recovered_toast, SignalStore.account().getUsername()); + Snackbar.make(fab, snackbarString, Snackbar.LENGTH_LONG).show(); + } } private void onConversationClicked(@NonNull ThreadRecord threadRecord) { @@ -807,7 +784,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti } else if (reminderActionId == R.id.reminder_action_cds_permanent_error_learn_more) { CdsPermanentErrorBottomSheet.show(getChildFragmentManager()); } else if (reminderActionId == R.id.reminder_action_fix_username_and_link) { - startActivity(EditProfileActivity.getIntent(requireContext())); + startActivityForResult(AppSettingsActivity.usernameRecovery(requireContext()), UsernameEditFragment.REQUEST_CODE); } else if (reminderActionId == R.id.reminder_action_fix_username_link) { startActivity(AppSettingsActivity.usernameLinkSettings(requireContext())); } else if (reminderActionId == R.id.reminder_action_re_register) { @@ -897,7 +874,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti private void initializeListAdapters() { - defaultAdapter = new ConversationListAdapter(getViewLifecycleOwner(), GlideApp.with(this), this, this); + defaultAdapter = new ConversationListAdapter(getViewLifecycleOwner(), Glide.with(this), this, this); setAdapter(defaultAdapter); @@ -914,7 +891,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { list.removeOnLayoutChangeListener(this); - list.post(SignalConversationListFragment.this::onFirstRender); + list.post(SignalConversationListFragment.this::onFirstRender);//*TM_SA*/change to SignalConversationListFragment } }); } @@ -1069,8 +1046,6 @@ public class SignalConversationListFragment extends MainFragment implements Acti return Optional.of(new ServiceOutageReminder()); } else if (OutdatedBuildReminder.isEligible()) { return Optional.of(new OutdatedBuildReminder(context)); - } else if (PushRegistrationReminder.isEligible()) { - return Optional.of((new PushRegistrationReminder(context))); } else if (DozeReminder.isEligible(context)) { return Optional.of(new DozeReminder(context)); } else if (CdsTemporaryErrorReminder.isEligible()) { @@ -1078,6 +1053,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti } else if (CdsPermanentErrorReminder.isEligible()) { return Optional.of(new CdsPermanentErrorReminder()); } else if (UsernameOutOfSyncReminder.isEligible()) { + ApplicationDependencies.getJobManager().add(new RefreshOwnProfileJob()); return Optional.of(new UsernameOutOfSyncReminder()); } else { return Optional.empty(); @@ -1224,7 +1200,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti protected void onPreExecute() { dialog = SignalProgressDialog.show(requireActivity(), context.getString(R.string.ConversationListFragment_deleting), - context.getString(R.string.ConversationListFragment_deleting_selected_conversations), + context.getResources().getQuantityString(R.plurals.ConversationListFragment_deleting_selected_conversations, conversationsCount), true, false); } @@ -1353,7 +1329,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti } private void startActionMode() { - actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(SignalConversationListFragment.this); + actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(SignalConversationListFragment.this);//*TM_SA*/change to SignalConversationListFragment ViewUtil.animateIn(bottomActionBar, bottomActionBar.getEnterAnimation()); ViewUtil.fadeOut(fab, 250); ViewUtil.fadeOut(cameraFab, 250); @@ -1861,8 +1837,6 @@ public class SignalConversationListFragment extends MainFragment implements Acti } } - - public class ContactSearchClickCallbacks implements ConversationListSearchAdapter.ConversationListSearchClickCallbacks {//**TM_SA**//public private final ContactSearchAdapter.ClickCallbacks delegate; @@ -1879,7 +1853,7 @@ public class SignalConversationListFragment extends MainFragment implements Acti @Override public void onMessageClicked(@NonNull View view, @NonNull ContactSearchData.Message thread, boolean isSelected) { SignalConversationListFragment.this.onMessageClicked(thread.getMessageResult()); - } + }//*TM_SA*/change to SignalConversationListFragment @Override public void onGroupWithMembersClicked(@NonNull View view, @NonNull ContactSearchData.GroupWithMembers groupWithMembers, boolean isSelected) { @@ -1912,8 +1886,6 @@ public class SignalConversationListFragment extends MainFragment implements Acti } } - - public interface Callback extends Material3OnScrollHelperBinder, SearchBinder { @NonNull Toolbar getToolbar(); diff --git a/app/src/main/java/org/tm/archive/crypto/PreKeyUtil.java b/app/src/main/java/org/tm/archive/crypto/PreKeyUtil.java index 36822d8f..694f7787 100644 --- a/app/src/main/java/org/tm/archive/crypto/PreKeyUtil.java +++ b/app/src/main/java/org/tm/archive/crypto/PreKeyUtil.java @@ -188,7 +188,7 @@ public class PreKeyUtil { return record; } - public synchronized static @NonNull KyberPreKeyRecord generateLastRestortKyberPreKey(int id, @NonNull ECPrivateKey privateKey) { + public synchronized static @NonNull KyberPreKeyRecord generateLastResortKyberPreKey(int id, @NonNull ECPrivateKey privateKey) { Log.i(TAG, "Generating last resort kyber prekey..."); return generateKyberPreKey(id, privateKey); } @@ -201,8 +201,8 @@ public class PreKeyUtil { } public synchronized static void storeLastResortKyberPreKey(@NonNull SignalServiceAccountDataStore protocolStore, @NonNull PreKeyMetadataStore metadataStore, KyberPreKeyRecord record) { - Log.i(TAG, "Storing kyber prekeys..."); - protocolStore.storeKyberPreKey(record.getId(), record); + Log.i(TAG, "Storing last resort kyber prekeys..."); + protocolStore.storeLastResortKyberPreKey(record.getId(), record); metadataStore.setNextKyberPreKeyId((record.getId() + 1) % Medium.MAX_VALUE); } diff --git a/app/src/main/java/org/tm/archive/crypto/PublicKey.java b/app/src/main/java/org/tm/archive/crypto/PublicKey.java index 24759810..4358f761 100644 --- a/app/src/main/java/org/tm/archive/crypto/PublicKey.java +++ b/app/src/main/java/org/tm/archive/crypto/PublicKey.java @@ -37,13 +37,6 @@ public class PublicKey { private final ECPublicKey publicKey; private int id; - public PublicKey(PublicKey publicKey) { - this.id = publicKey.id; - - // FIXME :: This not strictly an accurate copy constructor. - this.publicKey = publicKey.publicKey; - } - public PublicKey(int id, ECPublicKey publicKey) { this.publicKey = publicKey; this.id = id; @@ -59,10 +52,6 @@ public class PublicKey { this.publicKey = Curve.decodePoint(bytes, offset + 3); } - public PublicKey(byte[] bytes) throws InvalidKeyException { - this(bytes, 0); - } - public int getType() { return publicKey.getType(); } @@ -79,20 +68,6 @@ public class PublicKey { return publicKey; } - public String getFingerprint() { - return Hex.toString(getFingerprintBytes()); - } - - public byte[] getFingerprintBytes() { - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - return md.digest(serialize()); - } catch (NoSuchAlgorithmException nsae) { - Log.w(TAG, "LocalKeyPair", nsae); - throw new IllegalArgumentException("SHA-1 isn't supported!"); - } - } - public byte[] serialize() { byte[] keyIdBytes = Conversions.mediumToByteArray(id); byte[] serializedPoint = publicKey.serialize(); diff --git a/app/src/main/java/org/tm/archive/crypto/storage/SignalServiceAccountDataStoreImpl.java b/app/src/main/java/org/tm/archive/crypto/storage/SignalServiceAccountDataStoreImpl.java index d5c5d89d..f7308716 100644 --- a/app/src/main/java/org/tm/archive/crypto/storage/SignalServiceAccountDataStoreImpl.java +++ b/app/src/main/java/org/tm/archive/crypto/storage/SignalServiceAccountDataStoreImpl.java @@ -204,7 +204,7 @@ public class SignalServiceAccountDataStoreImpl implements SignalServiceAccountDa @Override public void storeLastResortKyberPreKey(int kyberPreKeyId, @NonNull KyberPreKeyRecord kyberPreKeyRecord) { - kyberPreKeyStore.storeKyberPreKey(kyberPreKeyId, kyberPreKeyRecord); + kyberPreKeyStore.storeLastResortKyberPreKey(kyberPreKeyId, kyberPreKeyRecord); } @Override diff --git a/app/src/main/java/org/tm/archive/database/ApnDatabase.java b/app/src/main/java/org/tm/archive/database/ApnDatabase.java deleted file mode 100644 index b9324b54..00000000 --- a/app/src/main/java/org/tm/archive/database/ApnDatabase.java +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.database; - -import android.content.Context; -import android.content.res.AssetManager; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.text.TextUtils; - -import org.signal.core.util.StreamUtil; -import org.signal.core.util.logging.Log; -import org.tm.archive.mms.LegacyMmsConnection.Apn; -import org.tm.archive.util.TextSecurePreferences; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Optional; - -/** - * Database to query APN and MMSC information - */ -public class ApnDatabase { - private static final String TAG = Log.tag(ApnDatabase.class); - - private final SQLiteDatabase db; - private final Context context; - - private static final String DATABASE_NAME = "apns.db"; - private static final String ASSET_PATH = "databases" + File.separator + DATABASE_NAME; - - private static final String TABLE_NAME = "apns"; - private static final String ID_COLUMN = "_id"; - private static final String MCC_MNC_COLUMN = "mccmnc"; - private static final String MCC_COLUMN = "mcc"; - private static final String MNC_COLUMN = "mnc"; - private static final String CARRIER_COLUMN = "carrier"; - private static final String APN_COLUMN = "apn"; - private static final String MMSC_COLUMN = "mmsc"; - private static final String PORT_COLUMN = "port"; - private static final String TYPE_COLUMN = "type"; - private static final String PROTOCOL_COLUMN = "protocol"; - private static final String BEARER_COLUMN = "bearer"; - private static final String ROAMING_PROTOCOL_COLUMN = "roaming_protocol"; - private static final String CARRIER_ENABLED_COLUMN = "carrier_enabled"; - private static final String MMS_PROXY_COLUMN = "mmsproxy"; - private static final String MMS_PORT_COLUMN = "mmsport"; - private static final String PROXY_COLUMN = "proxy"; - private static final String MVNO_MATCH_DATA_COLUMN = "mvno_match_data"; - private static final String MVNO_TYPE_COLUMN = "mvno"; - private static final String AUTH_TYPE_COLUMN = "authtype"; - private static final String USER_COLUMN = "user"; - private static final String PASSWORD_COLUMN = "password"; - private static final String SERVER_COLUMN = "server"; - - private static final String BASE_SELECTION = MCC_MNC_COLUMN + " = ?"; - - private static ApnDatabase instance = null; - - public synchronized static ApnDatabase getInstance(Context context) throws IOException { - if (instance == null) instance = new ApnDatabase(context.getApplicationContext()); - return instance; - } - - private ApnDatabase(final Context context) throws IOException { - this.context = context; - - File dbFile = context.getDatabasePath(DATABASE_NAME); - - if (!dbFile.getParentFile().exists() && !dbFile.getParentFile().mkdir()) { - throw new IOException("couldn't make databases directory"); - } - - StreamUtil.copy(context.getAssets().open(ASSET_PATH, AssetManager.ACCESS_STREAMING), - new FileOutputStream(dbFile)); - - try { - this.db = SQLiteDatabase.openDatabase(context.getDatabasePath(DATABASE_NAME).getPath(), - null, - SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS); - } catch (SQLiteException e) { - throw new IOException(e); - } - } - - private Apn getCustomApnParameters() { - String mmsc = TextSecurePreferences.getMmscUrl(context).trim(); - - if (!TextUtils.isEmpty(mmsc) && !mmsc.startsWith("http")) - mmsc = "http://" + mmsc; - - String proxy = TextSecurePreferences.getMmscProxy(context); - String port = TextSecurePreferences.getMmscProxyPort(context); - String user = TextSecurePreferences.getMmscUsername(context); - String pass = TextSecurePreferences.getMmscPassword(context); - - return new Apn(mmsc, proxy, port, user, pass); - } - - public Apn getDefaultApnParameters(String mccmnc, String apn) { - if (mccmnc == null) { - Log.w(TAG, "mccmnc was null, returning null"); - return Apn.EMPTY; - } - - Cursor cursor = null; - - try { - if (apn != null) { - Log.d(TAG, "Querying table for MCC+MNC " + mccmnc + " and APN name " + apn); - cursor = db.query(TABLE_NAME, null, - BASE_SELECTION + " AND " + APN_COLUMN + " = ?", - new String[] {mccmnc, apn}, - null, null, null); - } - - if (cursor == null || !cursor.moveToFirst()) { - if (cursor != null) cursor.close(); - Log.d(TAG, "Querying table for MCC+MNC " + mccmnc + " without APN name"); - cursor = db.query(TABLE_NAME, null, - BASE_SELECTION, - new String[] {mccmnc}, - null, null, null); - } - - if (cursor != null && cursor.moveToFirst()) { - Apn params = new Apn(cursor.getString(cursor.getColumnIndexOrThrow(MMSC_COLUMN)), - cursor.getString(cursor.getColumnIndexOrThrow(MMS_PROXY_COLUMN)), - cursor.getString(cursor.getColumnIndexOrThrow(MMS_PORT_COLUMN)), - cursor.getString(cursor.getColumnIndexOrThrow(USER_COLUMN)), - cursor.getString(cursor.getColumnIndexOrThrow(PASSWORD_COLUMN))); - Log.d(TAG, "Returning preferred APN " + params); - return params; - } - - Log.w(TAG, "No matching APNs found, returning null"); - - return Apn.EMPTY; - } finally { - if (cursor != null) cursor.close(); - } - - } - - public Optional getMmsConnectionParameters(String mccmnc, String apn) { - Apn customApn = getCustomApnParameters(); - Apn defaultApn = getDefaultApnParameters(mccmnc, apn); - Apn result = new Apn(customApn, defaultApn, - TextSecurePreferences.getUseCustomMmsc(context), - TextSecurePreferences.getUseCustomMmscProxy(context), - TextSecurePreferences.getUseCustomMmscProxyPort(context), - TextSecurePreferences.getUseCustomMmscUsername(context), - TextSecurePreferences.getUseCustomMmscPassword(context)); - - if (TextUtils.isEmpty(result.getMmsc())) return Optional.empty(); - else return Optional.of(result); - } -} diff --git a/app/src/main/java/org/tm/archive/database/AttachmentTable.kt b/app/src/main/java/org/tm/archive/database/AttachmentTable.kt index 948a45b5..1f89ec8e 100644 --- a/app/src/main/java/org/tm/archive/database/AttachmentTable.kt +++ b/app/src/main/java/org/tm/archive/database/AttachmentTable.kt @@ -30,16 +30,15 @@ import com.bumptech.glide.Glide import com.fasterxml.jackson.annotation.JsonProperty import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize -import org.archiver.annotation.TeleMessageUnfinalize import org.json.JSONArray import org.json.JSONException -import org.signal.core.util.Base64.encodeWithPadding -import org.signal.core.util.SqlUtil.buildArgs -import org.signal.core.util.SqlUtil.buildCollectionQuery -import org.signal.core.util.SqlUtil.buildSingleCollectionQuery +import org.signal.core.util.Base64 +import org.signal.core.util.SqlUtil import org.signal.core.util.StreamUtil import org.signal.core.util.ThreadUtil import org.signal.core.util.delete +import org.signal.core.util.deleteAll +import org.signal.core.util.drain import org.signal.core.util.exists import org.signal.core.util.forEach import org.signal.core.util.groupBy @@ -55,6 +54,7 @@ import org.signal.core.util.requireNonNullBlob import org.signal.core.util.requireNonNullString import org.signal.core.util.requireString import org.signal.core.util.select +import org.signal.core.util.toInt import org.signal.core.util.update import org.signal.core.util.withinTransaction import org.tm.archive.attachments.Attachment @@ -72,6 +72,7 @@ import org.tm.archive.database.SignalDatabase.Companion.threads import org.tm.archive.database.model.databaseprotos.AudioWaveFormData import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.jobs.AttachmentDownloadJob +import org.tm.archive.jobs.AttachmentUploadJob import org.tm.archive.jobs.GenerateAudioWaveFormJob import org.tm.archive.mms.MediaStream import org.tm.archive.mms.MmsException @@ -93,9 +94,10 @@ import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.util.LinkedList import java.util.Optional +import java.util.UUID +import kotlin.time.Duration.Companion.days -@TeleMessageUnfinalize -open class AttachmentTable( +open class AttachmentTable( //TM_SA make class open context: Context, databaseHelper: SignalDatabase, private val attachmentSecret: AttachmentSecret @@ -119,7 +121,8 @@ open class AttachmentTable( const val DATA_FILE = "data_file" const val DATA_SIZE = "data_size" const val DATA_RANDOM = "data_random" - const val DATA_HASH = "data_hash" + const val DATA_HASH_START = "data_hash_start" + const val DATA_HASH_END = "data_hash_end" const val FILE_NAME = "file_name" const val FAST_PREFLIGHT_ID = "fast_preflight_id" const val VOICE_NOTE = "voice_note" @@ -164,7 +167,6 @@ open class AttachmentTable( DATA_FILE, DATA_SIZE, DATA_RANDOM, - DATA_HASH, FILE_NAME, FAST_PREFLIGHT_ID, VOICE_NOTE, @@ -181,7 +183,9 @@ open class AttachmentTable( BLUR_HASH, TRANSFORM_PROPERTIES, DISPLAY_ORDER, - UPLOAD_TIMESTAMP + UPLOAD_TIMESTAMP, + DATA_HASH_START, + DATA_HASH_END ) const val CREATE_TABLE = """ @@ -200,7 +204,6 @@ open class AttachmentTable( $DATA_FILE TEXT, $DATA_SIZE INTEGER, $DATA_RANDOM BLOB, - $DATA_HASH TEXT DEFAULT NULL, $FILE_NAME TEXT, $FAST_PREFLIGHT_ID TEXT, $VOICE_NOTE INTEGER DEFAULT 0, @@ -217,7 +220,9 @@ open class AttachmentTable( $BLUR_HASH TEXT DEFAULT NULL, $TRANSFORM_PROPERTIES TEXT DEFAULT NULL, $DISPLAY_ORDER INTEGER DEFAULT 0, - $UPLOAD_TIMESTAMP INTEGER DEFAULT 0 + $UPLOAD_TIMESTAMP INTEGER DEFAULT 0, + $DATA_HASH_START TEXT DEFAULT NULL, + $DATA_HASH_END TEXT DEFAULT NULL ) """ @@ -226,14 +231,17 @@ open class AttachmentTable( "CREATE INDEX IF NOT EXISTS attachment_message_id_index ON $TABLE_NAME ($MESSAGE_ID);", "CREATE INDEX IF NOT EXISTS attachment_transfer_state_index ON $TABLE_NAME ($TRANSFER_STATE);", "CREATE INDEX IF NOT EXISTS attachment_sticker_pack_id_index ON $TABLE_NAME ($STICKER_PACK_ID);", - "CREATE INDEX IF NOT EXISTS attachment_data_hash_index ON $TABLE_NAME ($DATA_HASH);", + "CREATE INDEX IF NOT EXISTS attachment_data_hash_start_index ON $TABLE_NAME ($DATA_HASH_START);", + "CREATE INDEX IF NOT EXISTS attachment_data_hash_end_index ON $TABLE_NAME ($DATA_HASH_END);", "CREATE INDEX IF NOT EXISTS attachment_data_index ON $TABLE_NAME ($DATA_FILE);" ) + val ATTACHMENT_POINTER_REUSE_THRESHOLD = 7.days.inWholeMilliseconds + @JvmStatic @JvmOverloads @Throws(IOException::class) - fun newFile(context: Context): File { + fun newDataFile(context: Context): File { val partsDirectory = context.getDir(DIRECTORY, Context.MODE_PRIVATE) return PartFileProtector.protect { File.createTempFile("part", ".mms", partsDirectory) } } @@ -242,12 +250,86 @@ open class AttachmentTable( @Throws(IOException::class) fun getAttachmentStream(attachmentId: AttachmentId, offset: Long): InputStream { return try { - getDataStream(attachmentId, DATA_FILE, offset) + getDataStream(attachmentId, offset) } catch (e: FileNotFoundException) { throw IOException("No stream for: $attachmentId", e) } ?: throw IOException("No stream for: $attachmentId") } + /** + * Returns a [File] for an attachment that has no [DATA_HASH_END] and is in the [TRANSFER_PROGRESS_DONE] state, if present. + */ + fun getUnhashedDataFile(): Pair? { + return readableDatabase + .select(ID, DATA_FILE) + .from(TABLE_NAME) + .where("$DATA_FILE NOT NULL AND $DATA_HASH_END IS NULL AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE") + .orderBy("$ID DESC") + .limit(1) + .run() + .readToSingleObject { + File(it.requireNonNullString(DATA_FILE)) to AttachmentId(it.requireLong(ID)) + } + } + + /** + * Sets the [DATA_HASH_END] for a given file. This is used to backfill the hash for attachments that were created before we started hashing them. + * As a result, this will _not_ update the hashes on files that are not fully uploaded. + */ + fun setHashForDataFile(file: File, hash: ByteArray) { + writableDatabase.withinTransaction { db -> + val hashEnd = Base64.encodeWithPadding(hash) + + val (existingFile: String?, existingSize: Long?, existingRandom: ByteArray?) = db.select(DATA_FILE, DATA_SIZE, DATA_RANDOM) + .from(TABLE_NAME) + .where("$DATA_HASH_END = ? AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND $DATA_FILE NOT NULL AND $DATA_FILE != ?", hashEnd, file.absolutePath) + .limit(1) + .run() + .readToSingleObject { + Triple( + it.requireString(DATA_FILE), + it.requireLong(DATA_SIZE), + it.requireBlob(DATA_RANDOM) + ) + } ?: Triple(null, null, null) + + if (existingFile != null) { + Log.i(TAG, "[setHashForDataFile] Found that a different file has the same HASH_END. Using that one instead. Pre-existing file: $existingFile", true) + + val updateCount = writableDatabase + .update(TABLE_NAME) + .values( + DATA_FILE to existingFile, + DATA_HASH_END to hashEnd, + DATA_SIZE to existingSize, + DATA_RANDOM to existingRandom + ) + .where("$DATA_FILE = ? AND $DATA_HASH_END IS NULL AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE", file.absolutePath) + .run() + + Log.i(TAG, "[setHashForDataFile] Deduped $updateCount attachments.", true) + + val oldFileInUse = db.exists(TABLE_NAME).where("$DATA_FILE = ?", file.absolutePath).run() + if (oldFileInUse) { + Log.i(TAG, "[setHashForDataFile] Old file is still in use by some in-progress attachment.", true) + } else { + Log.i(TAG, "[setHashForDataFile] Deleting unused file: $file") + if (!file.delete()) { + Log.w(TAG, "Failed to delete duped file!") + } + } + } else { + val updateCount = writableDatabase + .update(TABLE_NAME) + .values(DATA_HASH_END to Base64.encodeWithPadding(hash)) + .where("$DATA_FILE = ? AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE", file.absolutePath) + .run() + + Log.i(TAG, "[setHashForDataFile] Updated the HASH_END for $updateCount rows using file ${file.absolutePath}") + } + } + } + fun getAttachment(attachmentId: AttachmentId): DatabaseAttachment? { return readableDatabase .select(*PROJECTION) @@ -275,7 +357,7 @@ open class AttachmentTable( return emptyMap() } - val query = buildSingleCollectionQuery(MESSAGE_ID, mmsIds) + val query = SqlUtil.buildSingleCollectionQuery(MESSAGE_ID, mmsIds) return readableDatabase .select(*PROJECTION) @@ -319,8 +401,8 @@ open class AttachmentTable( ApplicationDependencies.getJobManager().cancelAllInQueue(AttachmentDownloadJob.constructQueueString(attachmentId)) - deleteAttachmentOnDisk( - data = cursor.requireString(DATA_FILE), + deleteDataFileIfPossible( + filePath = cursor.requireString(DATA_FILE), contentType = cursor.requireString(CONTENT_TYPE), attachmentId = attachmentId ) @@ -369,8 +451,8 @@ open class AttachmentTable( .where("$MESSAGE_ID = ?", messageId) .run() .forEach { cursor -> - deleteAttachmentOnDisk( - data = cursor.requireString(DATA_FILE), + deleteDataFileIfPossible( + filePath = cursor.requireString(DATA_FILE), contentType = cursor.requireString(CONTENT_TYPE), attachmentId = AttachmentId(cursor.requireLong(ID)) ) @@ -380,7 +462,8 @@ open class AttachmentTable( .values( DATA_FILE to null, DATA_RANDOM to null, - DATA_HASH to null, + DATA_HASH_START to null, + DATA_HASH_END to null, FILE_NAME to null, CAPTION to null, DATA_SIZE to 0, @@ -419,8 +502,8 @@ open class AttachmentTable( val data = cursor.requireString(DATA_FILE) val contentType = cursor.requireString(CONTENT_TYPE) - deleteAttachmentOnDisk( - data = data, + deleteDataFileIfPossible( + filePath = data, contentType = contentType, attachmentId = id ) @@ -429,7 +512,7 @@ open class AttachmentTable( .where("$ID = ?", id.id) .run() - deleteAttachmentOnDisk(data, contentType, id) + deleteDataFileIfPossible(data, contentType, id) notifyAttachmentListeners() } } @@ -474,12 +557,38 @@ open class AttachmentTable( return onDiskButNotInDatabase.size } + /** + * Removes all references to the provided [DATA_FILE] from all attachments. + * Only do this if the file is known to not exist or has some other critical problem! + */ + fun clearUsagesOfDataFile(file: File) { + val updateCount = writableDatabase + .update(TABLE_NAME) + .values(DATA_FILE to null) + .where("$DATA_FILE = ?", file.absolutePath) + .run() + + Log.i(TAG, "[clearUsagesOfFile] Cleared $updateCount usages of $file", true) + } + + /** + * Indicates that, for whatever reason, a hash could not be calculated for the file in question. + * We put in a "bad hash" that will never match anything else so that we don't attempt to backfill it in the future. + */ + fun markDataFileAsUnhashable(file: File) { + val updateCount = writableDatabase + .update(TABLE_NAME) + .values(DATA_HASH_END to "UNHASHABLE-${UUID.randomUUID()}") + .where("$DATA_FILE = ? AND $DATA_HASH_END IS NULL AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE", file.absolutePath) + .run() + + Log.i(TAG, "[markDataFileAsUnhashable] Marked $updateCount attachments as unhashable with file: ${file.absolutePath}", true) + } + fun deleteAllAttachments() { Log.d(TAG, "[deleteAllAttachments]") - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) FileUtils.deleteDirectoryContents(context.getDir(DIRECTORY, Context.MODE_PRIVATE)) @@ -519,28 +628,50 @@ open class AttachmentTable( notifyConversationListeners(messages.getThreadIdForMessage(mmsId)) } + /** + * When we find out about a new inbound attachment pointer, we insert a row for it that contains all the info we need to download it via [insertAttachmentWithData]. + * Later, we download the data for that pointer. Call this method once you have the data to associate it with the attachment. At this point, it is assumed + * that the content of the attachment will never change. + */ @Throws(MmsException::class) - @TeleMessageUnfinalize - open fun insertAttachmentsForPlaceholder(mmsId: Long, attachmentId: AttachmentId, inputStream: InputStream) { - val placeholder = getAttachment(attachmentId) - val oldInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE) - var dataInfo = storeAttachmentStream(inputStream) - val transferFile = getTransferFile(databaseHelper.signalReadableDatabase, attachmentId) + open fun finalizeAttachmentAfterDownload(mmsId: Long, attachmentId: AttachmentId, inputStream: InputStream) { //TM_SA make fun open + Log.i(TAG, "[finalizeAttachmentAfterDownload] Finalizing downloaded data for $attachmentId. (MessageId: $mmsId, $attachmentId)") - val updated = writableDatabase.withinTransaction { db -> - dataInfo = deduplicateAttachment(dataInfo, attachmentId, placeholder?.transformProperties ?: TransformProperties.empty()) + val existingPlaceholder: DatabaseAttachment = getAttachment(attachmentId) ?: throw MmsException("No attachment found for id: $attachmentId") - if (oldInfo != null) { - updateAttachmentDataHash(db, oldInfo.hash, dataInfo) - } + val fileWriteResult: DataFileWriteResult = writeToDataFile(newDataFile(context), inputStream, TransformProperties.empty()) + val transferFile: File? = getTransferFile(databaseHelper.signalReadableDatabase, attachmentId) + + val foundDuplicate = writableDatabase.withinTransaction { db -> + // We can look and see if we have any exact matches on hash_ends and dedupe the file if we see one. + // We don't look at hash_start here because that could result in us matching on a file that got compressed down to something smaller, effectively lowering + // the quality of the attachment we received. + val hashMatch: DataFileInfo? = readableDatabase + .select(ID, DATA_FILE, DATA_SIZE, DATA_RANDOM, DATA_HASH_START, DATA_HASH_END, TRANSFORM_PROPERTIES, UPLOAD_TIMESTAMP) + .from(TABLE_NAME) + .where("$DATA_HASH_END = ? AND $DATA_HASH_END NOT NULL AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND $DATA_FILE NOT NULL", fileWriteResult.hash) + .run() + .readToList { it.readDataFileInfo() } + .firstOrNull() val values = ContentValues() - values.put(DATA_FILE, dataInfo.file.absolutePath) - values.put(DATA_SIZE, dataInfo.length) - values.put(DATA_RANDOM, dataInfo.random) - values.put(DATA_HASH, dataInfo.hash) - val visualHashString = placeholder.getVisualHashStringOrNull() + if (hashMatch != null) { + Log.i(TAG, "[finalizeAttachmentAfterDownload] Found that ${hashMatch.id} has the same DATA_HASH_END. Deduping. (MessageId: $mmsId, $attachmentId)") + values.put(DATA_FILE, hashMatch.file.absolutePath) + values.put(DATA_SIZE, hashMatch.length) + values.put(DATA_RANDOM, hashMatch.random) + values.put(DATA_HASH_START, hashMatch.hashEnd) + values.put(DATA_HASH_END, hashMatch.hashEnd) + } else { + values.put(DATA_FILE, fileWriteResult.file.absolutePath) + values.put(DATA_SIZE, fileWriteResult.length) + values.put(DATA_RANDOM, fileWriteResult.random) + values.put(DATA_HASH_START, fileWriteResult.hash) + values.put(DATA_HASH_END, fileWriteResult.hash) + } + + val visualHashString = existingPlaceholder.getVisualHashStringOrNull() if (visualHashString != null) { values.put(BLUR_HASH, visualHashString) } @@ -549,26 +680,26 @@ open class AttachmentTable( values.put(TRANSFER_FILE, null as String?) values.put(TRANSFORM_PROPERTIES, TransformProperties.forSkipTransform().serialize()) - val updateCount = db.update(TABLE_NAME) + db.update(TABLE_NAME) .values(values) .where("$ID = ?", attachmentId.id) .run() - updateCount > 0 + hashMatch != null } - if (updated) { - val threadId = messages.getThreadIdForMessage(mmsId) + val threadId = messages.getThreadIdForMessage(mmsId) - if (!messages.isStory(mmsId)) { - threads.updateSnippetUriSilently(threadId, PartAuthority.getAttachmentDataUri(attachmentId)) - } + if (!messages.isStory(mmsId)) { + threads.updateSnippetUriSilently(threadId, PartAuthority.getAttachmentDataUri(attachmentId)) + } - notifyConversationListeners(threadId) - notifyConversationListListeners() - notifyAttachmentListeners() - } else { - if (!dataInfo.file.delete()) { + notifyConversationListeners(threadId) + notifyConversationListListeners() + notifyAttachmentListeners() + + if (foundDuplicate) { + if (!fileWriteResult.file.delete()) { Log.w(TAG, "Failed to delete unused attachment") } } @@ -579,21 +710,67 @@ open class AttachmentTable( } } - if (placeholder != null && MediaUtil.isAudio(placeholder)) { - GenerateAudioWaveFormJob.enqueue(placeholder.attachmentId) + if (MediaUtil.isAudio(existingPlaceholder)) { + GenerateAudioWaveFormJob.enqueue(existingPlaceholder.attachmentId) + } + } + + /** + * Needs to be called after an attachment is successfully uploaded. Writes metadata around it's final remote location, as well as calculates + * it's ending hash, which is critical for backups. + */ + @Throws(IOException::class) + fun finalizeAttachmentAfterUpload(id: AttachmentId, attachment: Attachment, uploadTimestamp: Long) { + Log.i(TAG, "[finalizeAttachmentAfterUpload] Finalizing upload for $id.") + + val dataStream = getAttachmentStream(id, 0) + val messageDigest = MessageDigest.getInstance("SHA-256") + + DigestInputStream(dataStream, messageDigest).use { + it.drain() + } + + val dataHashEnd = Base64.encodeWithPadding(messageDigest.digest()) + + val values = contentValuesOf( + TRANSFER_STATE to TRANSFER_PROGRESS_DONE, + CDN_NUMBER to attachment.cdnNumber, + REMOTE_LOCATION to attachment.remoteLocation, + REMOTE_DIGEST to attachment.remoteDigest, + REMOTE_INCREMENTAL_DIGEST to attachment.incrementalDigest, + REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE to attachment.incrementalMacChunkSize, + REMOTE_KEY to attachment.remoteKey, + DATA_SIZE to attachment.size, + DATA_HASH_END to dataHashEnd, + FAST_PREFLIGHT_ID to attachment.fastPreflightId, + BLUR_HASH to attachment.getVisualHashStringOrNull(), + UPLOAD_TIMESTAMP to uploadTimestamp + ) + + val dataFilePath = getDataFilePath(id) ?: throw IOException("No data file found for attachment!") + + val updateCount = writableDatabase + .update(TABLE_NAME) + .values(values) + .where("$ID = ? OR $DATA_FILE = ?", id.id, dataFilePath) + .run() + + if (updateCount <= 0) { + Log.w(TAG, "[finalizeAttachmentAfterUpload] Failed to update attachment after upload! $id") } } @Throws(MmsException::class) fun copyAttachmentData(sourceId: AttachmentId, destinationId: AttachmentId) { val sourceAttachment = getAttachment(sourceId) ?: throw MmsException("Cannot find attachment for source!") - val sourceDataInfo = getAttachmentDataFileInfo(sourceId, DATA_FILE) ?: throw MmsException("No attachment data found for source!") + val sourceDataInfo = getDataFileInfo(sourceId) ?: throw MmsException("No attachment data found for source!") writableDatabase .update(TABLE_NAME) .values( DATA_FILE to sourceDataInfo.file.absolutePath, - DATA_HASH to sourceDataInfo.hash, + DATA_HASH_START to sourceDataInfo.hashStart, + DATA_HASH_END to sourceDataInfo.hashEnd, DATA_SIZE to sourceDataInfo.length, DATA_RANDOM to sourceDataInfo.random, TRANSFER_STATE to sourceAttachment.transferState, @@ -634,36 +811,8 @@ open class AttachmentTable( } } - fun updateAttachmentAfterUpload(id: AttachmentId, attachment: Attachment, uploadTimestamp: Long) { - val dataInfo = getAttachmentDataFileInfo(id, DATA_FILE) - val values = contentValuesOf( - TRANSFER_STATE to TRANSFER_PROGRESS_DONE, - CDN_NUMBER to attachment.cdnNumber, - REMOTE_LOCATION to attachment.remoteLocation, - REMOTE_DIGEST to attachment.remoteDigest, - REMOTE_INCREMENTAL_DIGEST to attachment.incrementalDigest, - REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE to attachment.incrementalMacChunkSize, - REMOTE_KEY to attachment.remoteKey, - DATA_SIZE to attachment.size, - FAST_PREFLIGHT_ID to attachment.fastPreflightId, - BLUR_HASH to attachment.getVisualHashStringOrNull(), - UPLOAD_TIMESTAMP to uploadTimestamp - ) - - if (dataInfo?.hash != null) { - updateAttachmentAndMatchingHashes(writableDatabase, id, dataInfo.hash, values) - } else { - writableDatabase - .update(TABLE_NAME) - .values(values) - .where("$ID = ?", id.id) - .run() - } - } - @Throws(MmsException::class) - @TeleMessageUnfinalize - open fun insertAttachmentForPreUpload(attachment: Attachment): DatabaseAttachment { + open fun insertAttachmentForPreUpload(attachment: Attachment): DatabaseAttachment { //TM_SA make fun open val result = insertAttachmentsForMessage(PREUPLOAD_MESSAGE_ID, listOf(attachment), emptyList()) if (result.values.isEmpty()) { @@ -697,27 +846,42 @@ open class AttachmentTable( } } + /** + * Inserts new attachments in the table. The [Attachment]s may or may not have data, depending on whether it's an attachment we created locally or some + * inbound attachment that we haven't fetched yet. + * + * If the attachment has no data, it is assumed that you will later call [finalizeAttachmentAfterDownload]. + */ @Throws(MmsException::class) - @TeleMessageUnfinalize - open fun insertAttachmentsForMessage(mmsId: Long, attachments: List, quoteAttachment: List): Map { + open fun insertAttachmentsForMessage(mmsId: Long, attachments: List, quoteAttachment: List): Map { //TM_SA make fun open if (attachments.isEmpty() && quoteAttachment.isEmpty()) { return emptyMap() } - Log.d(TAG, "insertParts(${attachments.size})") + Log.d(TAG, "[insertAttachmentsForMessage] insertParts(${attachments.size})") val insertedAttachments: MutableMap = mutableMapOf() for (attachment in attachments) { - val attachmentId = insertAttachment(mmsId, attachment, attachment.quote) + val attachmentId = if (attachment.uri != null) { + insertAttachmentWithData(mmsId, attachment, attachment.quote) + } else { + insertUndownloadedAttachment(mmsId, attachment, attachment.quote) + } + insertedAttachments[attachment] = attachmentId - Log.i(TAG, "Inserted attachment at ID: $attachmentId") + Log.i(TAG, "[insertAttachmentsForMessage] Inserted attachment at $attachmentId") } try { for (attachment in quoteAttachment) { - val attachmentId = insertAttachment(mmsId, attachment, true) + val attachmentId = if (attachment.uri != null) { + insertAttachmentWithData(mmsId, attachment, true) + } else { + insertUndownloadedAttachment(mmsId, attachment, true) + } + insertedAttachments[attachment] = attachmentId - Log.i(TAG, "Inserted quoted attachment at ID: $attachmentId") + Log.i(TAG, "[insertAttachmentsForMessage] Inserted quoted attachment at $attachmentId") } } catch (e: MmsException) { Log.w(TAG, "Failed to insert quote attachment! messageId: $mmsId") @@ -727,46 +891,33 @@ open class AttachmentTable( } /** - * @param onlyModifyThisAttachment If false and more than one attachment shares this file and quality, they will all - * be updated. If true, then guarantees not to affect other attachments. + * Updates the data stored for an existing attachment. This happens after transformations, like transcoding. */ @Throws(MmsException::class, IOException::class) fun updateAttachmentData( databaseAttachment: DatabaseAttachment, - mediaStream: MediaStream, - onlyModifyThisAttachment: Boolean + mediaStream: MediaStream ) { val attachmentId = databaseAttachment.attachmentId - val oldDataInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE) ?: throw MmsException("No attachment data found!") - var destination = oldDataInfo.file - val isSingleUseOfData = onlyModifyThisAttachment || oldDataInfo.hash == null + val existingDataFileInfo: DataFileInfo = getDataFileInfo(attachmentId) ?: throw MmsException("No attachment data found!") + val newDataFileInfo: DataFileWriteResult = writeToDataFile(existingDataFileInfo.file, mediaStream.stream, databaseAttachment.transformProperties ?: TransformProperties.empty()) - if (isSingleUseOfData && fileReferencedByMoreThanOneAttachment(destination)) { - Log.i(TAG, "Creating a new file as this one is used by more than one attachment") - destination = newFile(context) - } - - var dataInfo: DataInfo = storeAttachmentStream(destination, mediaStream.stream) + // TODO We don't dedupe here because we're assuming that we should have caught any dupe scenarios on first insert. We could consider doing dupe checks here though. writableDatabase.withinTransaction { db -> - dataInfo = deduplicateAttachment(dataInfo, attachmentId, databaseAttachment.transformProperties) - val contentValues = contentValuesOf( - DATA_SIZE to dataInfo.length, + DATA_SIZE to newDataFileInfo.length, CONTENT_TYPE to mediaStream.mimeType, WIDTH to mediaStream.width, HEIGHT to mediaStream.height, - DATA_FILE to dataInfo.file.absolutePath, - DATA_RANDOM to dataInfo.random, - DATA_HASH to dataInfo.hash + DATA_FILE to newDataFileInfo.file.absolutePath, + DATA_RANDOM to newDataFileInfo.random ) - val updateCount = updateAttachmentAndMatchingHashes( - db = db, - attachmentId = attachmentId, - dataHash = if (isSingleUseOfData) dataInfo.hash else oldDataInfo.hash, - contentValues = contentValues - ) + val updateCount = db.update(TABLE_NAME) + .values(contentValues) + .where("$ID = ? OR $DATA_FILE = ?", attachmentId.id, existingDataFileInfo.file.absolutePath) + .run() Log.i(TAG, "[updateAttachmentData] Updated $updateCount rows.") } @@ -774,14 +925,14 @@ open class AttachmentTable( fun duplicateAttachmentsForMessage(destinationMessageId: Long, sourceMessageId: Long, excludedIds: Collection) { writableDatabase.withinTransaction { db -> - db.execSQL("CREATE TEMPORARY TABLE tmp_part AS SELECT * FROM $TABLE_NAME WHERE $MESSAGE_ID = ?", buildArgs(sourceMessageId)) + db.execSQL("CREATE TEMPORARY TABLE tmp_part AS SELECT * FROM $TABLE_NAME WHERE $MESSAGE_ID = ?", SqlUtil.buildArgs(sourceMessageId)) - val queries = buildCollectionQuery(ID, excludedIds) + val queries = SqlUtil.buildCollectionQuery(ID, excludedIds) for (query in queries) { db.delete("tmp_part", query.where, query.whereArgs) } - db.execSQL("UPDATE tmp_part SET $ID = NULL, $MESSAGE_ID = ?", buildArgs(destinationMessageId)) + db.execSQL("UPDATE tmp_part SET $ID = NULL, $MESSAGE_ID = ?", SqlUtil.buildArgs(destinationMessageId)) db.execSQL("INSERT INTO $TABLE_NAME SELECT * FROM tmp_part") db.execSQL("DROP TABLE tmp_part") } @@ -805,46 +956,54 @@ open class AttachmentTable( return transferFile } - @VisibleForTesting - fun getAttachmentDataFileInfo(attachmentId: AttachmentId, dataType: String): DataInfo? { + fun getDataFileInfo(attachmentId: AttachmentId): DataFileInfo? { return readableDatabase - .select(dataType, DATA_SIZE, DATA_RANDOM, DATA_HASH, TRANSFORM_PROPERTIES) + .select(ID, DATA_FILE, DATA_SIZE, DATA_RANDOM, DATA_HASH_START, DATA_HASH_END, TRANSFORM_PROPERTIES, UPLOAD_TIMESTAMP) .from(TABLE_NAME) .where("$ID = ?", attachmentId.id) .run() .readToSingleObject { cursor -> - if (cursor.isNull(dataType)) { + if (cursor.isNull(DATA_FILE)) { null } else { - DataInfo( - file = File(cursor.getString(cursor.getColumnIndexOrThrow(dataType))), - length = cursor.requireLong(DATA_SIZE), - random = cursor.requireNonNullBlob(DATA_RANDOM), - hash = cursor.requireString(DATA_HASH), - transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES)) - ) + cursor.readDataFileInfo() } } } - @TeleMessageUnfinalize - open fun markAttachmentAsTransformed(attachmentId: AttachmentId, withFastStart: Boolean) { + fun getDataFilePath(attachmentId: AttachmentId): String? { + return readableDatabase + .select(DATA_FILE) + .from(TABLE_NAME) + .where("$ID = ?", attachmentId.id) + .run() + .readToSingleObject { it.requireString(DATA_FILE) } + } + + fun markAttachmentAsTransformed(attachmentId: AttachmentId, withFastStart: Boolean) { + Log.i(TAG, "[markAttachmentAsTransformed] Marking $attachmentId as transformed. withFastStart: $withFastStart") writableDatabase.withinTransaction { db -> try { - var transformProperties = getTransformProperties(attachmentId) - if (transformProperties == null) { - Log.w(TAG, "Failed to get transformation properties, attachment no longer exists.") + val dataInfo = getDataFileInfo(attachmentId) + if (dataInfo == null) { + Log.w(TAG, "[markAttachmentAsTransformed] Failed to get transformation properties, attachment no longer exists.") return@withinTransaction } - transformProperties = transformProperties.withSkipTransform() + var transformProperties = dataInfo.transformProperties.withSkipTransform() if (withFastStart) { transformProperties = transformProperties.withMp4FastStart() } - updateAttachmentTransformProperties(attachmentId, transformProperties) + val count = writableDatabase + .update(TABLE_NAME) + .values(TRANSFORM_PROPERTIES to transformProperties.serialize()) + .where("$ID = ? OR $DATA_FILE = ?", attachmentId.id, dataInfo.file.absolutePath) + .run() + + Log.i(TAG, "[markAttachmentAsTransformed] Updated $count rows.") } catch (e: Exception) { - Log.w(TAG, "Could not mark attachment as transformed.", e) + Log.w(TAG, "[markAttachmentAsTransformed] Could not mark attachment as transformed.", e) } } } @@ -861,7 +1020,7 @@ open class AttachmentTable( @RequiresApi(23) fun mediaDataSourceFor(attachmentId: AttachmentId, allowReadingFromTempFile: Boolean): MediaDataSource? { - val dataInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE) + val dataInfo = getDataFileInfo(attachmentId) if (dataInfo != null) { return EncryptedMediaDataSource.createFor(attachmentSecret, dataInfo.file, dataInfo.random, dataInfo.length) } @@ -892,8 +1051,7 @@ open class AttachmentTable( } } - @TeleMessageUnfinalize - open fun markAttachmentUploaded(messageId: Long, attachment: Attachment) { + open fun markAttachmentUploaded(messageId: Long, attachment: Attachment) { //TM_SA make fun open writableDatabase .update(TABLE_NAME) .values(TRANSFER_STATE to TRANSFER_PROGRESS_DONE) @@ -957,7 +1115,8 @@ open class AttachmentTable( audioHash = if (MediaUtil.isAudioType(contentType)) AudioHash.parseOrNull(jsonObject.getString(BLUR_HASH)) else null, transformProperties = TransformProperties.parse(jsonObject.getString(TRANSFORM_PROPERTIES)), displayOrder = jsonObject.getInt(DISPLAY_ORDER), - uploadTimestamp = jsonObject.getLong(UPLOAD_TIMESTAMP) + uploadTimestamp = jsonObject.getLong(UPLOAD_TIMESTAMP), + dataHash = jsonObject.getString(DATA_HASH_END) ) } } @@ -997,52 +1156,47 @@ open class AttachmentTable( return readableDatabase.rawQuery(query, null) } - private fun deleteAttachmentOnDisk( - data: String?, + /** + * Deletes the data file if there's no strong references to other attachments. + * If deleted, it will also clear all weak references (i.e. quotes) of the attachment. + */ + private fun deleteDataFileIfPossible( + filePath: String?, contentType: String?, attachmentId: AttachmentId ) { check(writableDatabase.inTransaction()) { "Must be in a transaction!" } - val dataUsage = getAttachmentFileUsages(data, attachmentId) - if (dataUsage.hasStrongReference) { - Log.i(TAG, "[deleteAttachmentOnDisk] Attachment in use. Skipping deletion. $data $attachmentId") + if (filePath == null) { + Log.w(TAG, "[deleteDataFileIfPossible] Null data file path for $attachmentId! Can't delete anything.") return } - Log.i(TAG, "[deleteAttachmentOnDisk] No other strong uses of this attachment. Safe to delete. $data $attachmentId") - if (!data.isNullOrBlank()) { - if (File(data).delete()) { - Log.i(TAG, "[deleteAttachmentOnDisk] Deleted attachment file. $data $attachmentId") + val strongReferenceExists = readableDatabase + .exists(TABLE_NAME) + .where("$DATA_FILE = ? AND QUOTE = 0 AND $ID != ${attachmentId.id}", filePath) + .run() - if (dataUsage.removableWeakReferences.isNotEmpty()) { - Log.i(TAG, "[deleteAttachmentOnDisk] Deleting ${dataUsage.removableWeakReferences.size} weak references for $data") + if (strongReferenceExists) { + Log.i(TAG, "[deleteDataFileIfPossible] Attachment in use. Skipping deletion of $attachmentId. Path: $filePath") + return + } - var deletedCount = 0 - for (weakReference in dataUsage.removableWeakReferences) { - Log.i(TAG, "[deleteAttachmentOnDisk] Clearing weak reference for $data $weakReference") + val weakReferenceCount = writableDatabase + .update(TABLE_NAME) + .values( + DATA_FILE to null, + DATA_RANDOM to null, + DATA_HASH_START to null, + DATA_HASH_END to null + ) + .where("$DATA_FILE = ?", filePath) + .run() - deletedCount += writableDatabase - .update(TABLE_NAME) - .values( - DATA_FILE to null, - DATA_RANDOM to null, - DATA_HASH to null - ) - .where("$ID = ?", weakReference.id) - .run() - } + Log.i(TAG, "[deleteDataFileIfPossible] Cleared $weakReferenceCount weak references for $attachmentId. Path: $filePath") - val logMessage = "[deleteAttachmentOnDisk] Cleared $deletedCount/${dataUsage.removableWeakReferences.size} weak references for $data" - if (deletedCount != dataUsage.removableWeakReferences.size) { - Log.w(TAG, logMessage) - } else { - Log.i(TAG, logMessage) - } - } - } else { - Log.w(TAG, "[deleteAttachmentOnDisk] Failed to delete attachment. $data $attachmentId") - } + if (!File(filePath).delete()) { + Log.w(TAG, "[deleteDataFileIfPossible] Failed to delete $attachmentId. Path: $filePath") } if (MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType)) { @@ -1051,109 +1205,9 @@ open class AttachmentTable( } } - private fun getAttachmentFileUsages(data: String?, attachmentId: AttachmentId): DataUsageResult { - check(writableDatabase.inTransaction()) { "Must be in a transaction!" } - - if (data == null) { - return DataUsageResult.NOT_IN_USE - } - - val quoteRows: MutableList = mutableListOf() - - readableDatabase - .select(ID, QUOTE) - .from(TABLE_NAME) - .where("$DATA_FILE = ? AND $ID != ?", data, attachmentId.id) - .run() - .forEach { cursor -> - if (cursor.requireBoolean(QUOTE)) { - quoteRows += AttachmentId(cursor.requireLong(ID)) - } else { - return DataUsageResult.IN_USE - } - } - - return DataUsageResult(quoteRows) - } - - /** - * Check if data file is in use by another attachment row with a different hash. Rows with the same data and hash - * will be fixed in a later call to [updateAttachmentAndMatchingHashes]. - */ - private fun isAttachmentFileUsedByOtherAttachments(attachmentId: AttachmentId?, dataInfo: DataInfo): Boolean { - return if (attachmentId == null || dataInfo.hash == null) { - false - } else { - readableDatabase - .exists(TABLE_NAME) - .where("$DATA_FILE = ? AND $DATA_HASH != ?", dataInfo.file.absolutePath, dataInfo.hash) - .run() - } - } - - private fun updateAttachmentDataHash( - db: SQLiteDatabase, - oldHash: String?, - newData: DataInfo - ) { - if (oldHash == null) { - return - } - - db.update(TABLE_NAME) - .values( - DATA_FILE to newData.file.absolutePath, - DATA_RANDOM to newData.random, - DATA_HASH to newData.hash - ) - .where("$DATA_HASH = ?", oldHash) - .run() - } - - private fun updateAttachmentTransformProperties(attachmentId: AttachmentId, transformProperties: TransformProperties) { - val dataInfo = getAttachmentDataFileInfo(attachmentId, DATA_FILE) - if (dataInfo == null) { - Log.w(TAG, "[updateAttachmentTransformProperties] No data info found!") - return - } - - val contentValues = contentValuesOf(TRANSFORM_PROPERTIES to transformProperties.serialize()) - val updateCount = updateAttachmentAndMatchingHashes(databaseHelper.signalWritableDatabase, attachmentId, dataInfo.hash, contentValues) - Log.i(TAG, "[updateAttachmentTransformProperties] Updated $updateCount rows.") - } - - private fun updateAttachmentAndMatchingHashes( - db: SQLiteDatabase, - attachmentId: AttachmentId, - dataHash: String?, - contentValues: ContentValues - ): Int { - return db - .update(TABLE_NAME) - .values(contentValues) - .where("$ID = ? OR ($DATA_HASH NOT NULL AND $DATA_HASH = ?)", attachmentId.id, dataHash.toString()) - .run() - } - - /** - * Returns true if the file referenced by two or more attachments. - * Returns false if the file is referenced by zero or one attachments. - */ - private fun fileReferencedByMoreThanOneAttachment(file: File): Boolean { - return readableDatabase - .select("1") - .from(TABLE_NAME) - .where("$DATA_FILE = ?", file.absolutePath) - .limit(2) - .run() - .use { cursor -> - cursor.moveToNext() && cursor.moveToNext() - } - } - @Throws(FileNotFoundException::class) - private fun getDataStream(attachmentId: AttachmentId, dataType: String, offset: Long): InputStream? { - val dataInfo = getAttachmentDataFileInfo(attachmentId, dataType) ?: return null + private fun getDataStream(attachmentId: AttachmentId, offset: Long): InputStream? { + val dataInfo = getDataFileInfo(attachmentId) ?: return null return try { if (dataInfo.random != null && dataInfo.random.size == 32) { @@ -1176,15 +1230,6 @@ open class AttachmentTable( } } - @Throws(MmsException::class) - private fun storeAttachmentStream(inputStream: InputStream): DataInfo { - return try { - storeAttachmentStream(newFile(context), inputStream) - } catch (e: IOException) { - throw MmsException(e) - } - } - @Throws(IOException::class) private fun newTransferFile(): File { val partsDirectory = context.getDir(DIRECTORY, Context.MODE_PRIVATE) @@ -1194,31 +1239,36 @@ open class AttachmentTable( } /** - * Reads the entire stream and saves to disk. If you need to deduplicate attachments, call [deduplicateAttachment] - * afterwards and use the [DataInfo] returned by it instead. + * Reads the entire stream and saves to disk and returns a bunch of metadat about the write. */ @Throws(MmsException::class, IllegalStateException::class) - private fun storeAttachmentStream(destination: File, inputStream: InputStream): DataInfo { + private fun writeToDataFile(destination: File, inputStream: InputStream, transformProperties: TransformProperties): DataFileWriteResult { return try { - val tempFile = newFile(context) + // Sometimes the destination is a file that's already in use, sometimes it's not. + // To avoid writing to a file while it's in-use, we write to a temp file and then rename it to the destination file at the end. + val tempFile = newDataFile(context) val messageDigest = MessageDigest.getInstance("SHA-256") val digestInputStream = DigestInputStream(inputStream, messageDigest) - val out = ModernEncryptingPartOutputStream.createFor(attachmentSecret, tempFile, false) - val length = StreamUtil.copy(digestInputStream, out.second) - val hash = encodeWithPadding(digestInputStream.messageDigest.digest()) + + val encryptingStreamData = ModernEncryptingPartOutputStream.createFor(attachmentSecret, tempFile, false) + val random = encryptingStreamData.first + val encryptingOutputStream = encryptingStreamData.second + + val length = StreamUtil.copy(digestInputStream, encryptingOutputStream) + val hash = Base64.encodeWithPadding(digestInputStream.messageDigest.digest()) if (!tempFile.renameTo(destination)) { - Log.w(TAG, "Couldn't rename ${tempFile.path} to ${destination.path}") + Log.w(TAG, "[writeToDataFile] Couldn't rename ${tempFile.path} to ${destination.path}") tempFile.delete() throw IllegalStateException("Couldn't rename ${tempFile.path} to ${destination.path}") } - DataInfo( + DataFileWriteResult( file = destination, length = length, - random = out.first, + random = random, hash = hash, - transformProperties = null + transformProperties = transformProperties ) } catch (e: IOException) { throw MmsException(e) @@ -1227,198 +1277,235 @@ open class AttachmentTable( } } - private fun deduplicateAttachment( - dataInfo: DataInfo, - attachmentId: AttachmentId?, - transformProperties: TransformProperties? - ): DataInfo { - check(writableDatabase.inTransaction()) { "Must be in a transaction!" } - - val sharedDataInfos = findDuplicateDataFileInfos(writableDatabase, dataInfo.hash, attachmentId) - - for (sharedDataInfo in sharedDataInfos) { - if (dataInfo.file == sharedDataInfo.file) { - continue + private fun areTransformationsCompatible( + newProperties: TransformProperties, + potentialMatchProperties: TransformProperties, + newHashStart: String, + potentialMatchHashEnd: String?, + newIsQuote: Boolean + ): Boolean { + // If we're starting now where another attachment finished, then it means we're forwarding an attachment. + if (newHashStart == potentialMatchHashEnd) { + // Quotes don't get transcoded or anything and are just a reference to the original attachment, so as long as the hashes match we're fine + if (newIsQuote) { + return true } - val isUsedElsewhere = isAttachmentFileUsedByOtherAttachments(attachmentId, dataInfo) - val isSameQuality = transformProperties?.sentMediaQuality == sharedDataInfo.transformProperties?.sentMediaQuality - - Log.i(TAG, "[deduplicateAttachment] Potential duplicate data file found. usedElsewhere: " + isUsedElsewhere + " sameQuality: " + isSameQuality + " otherFile: " + sharedDataInfo.file.absolutePath) - - if (!isSameQuality) { - continue + // If the new attachment is an edited video, we can't re-use the file + if (newProperties.videoEdited) { + return false } - if (!isUsedElsewhere) { - if (dataInfo.file.delete()) { - Log.i(TAG, "[deduplicateAttachment] Deleted original file. ${dataInfo.file}") - } else { - Log.w(TAG, "[deduplicateAttachment] Original file could not be deleted.") - } - } - - return sharedDataInfo + return true } - Log.i(TAG, "[deduplicateAttachment] No acceptable matching attachment data found. ${dataInfo.file.absolutePath}") - return dataInfo - } - - private fun findDuplicateDataFileInfos( - database: SQLiteDatabase, - hash: String?, - excludedAttachmentId: AttachmentId? - ): List { - check(database.inTransaction()) { "Must be in a transaction!" } - - if (hash == null) { - return emptyList() + if (newProperties.sentMediaQuality != potentialMatchProperties.sentMediaQuality) { + return false } - val selectorArgs: Pair> = buildSharedFileSelectorArgs(hash, excludedAttachmentId) - - return database - .select(DATA_FILE, DATA_RANDOM, DATA_SIZE, TRANSFORM_PROPERTIES) - .from(TABLE_NAME) - .where(selectorArgs.first, selectorArgs.second) - .run() - .readToList { cursor -> - DataInfo( - file = File(cursor.requireNonNullString(DATA_FILE)), - length = cursor.requireLong(DATA_SIZE), - random = cursor.requireNonNullBlob(DATA_RANDOM), - hash = hash, - transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES)) - ) - } - } - - private fun buildSharedFileSelectorArgs(newHash: String, attachmentId: AttachmentId?): Pair> { - return if (attachmentId == null) { - "$DATA_HASH = ?" to arrayOf(newHash) - } else { - "$ID != ? AND $DATA_HASH = ?" to arrayOf( - attachmentId.id.toString(), - newHash - ) + if (newProperties.videoEdited != potentialMatchProperties.videoEdited) { + return false } + + if (newProperties.videoTrimStartTimeUs != potentialMatchProperties.videoTrimStartTimeUs) { + return false + } + + if (newProperties.videoTrimEndTimeUs != potentialMatchProperties.videoTrimEndTimeUs) { + return false + } + + if (newProperties.mp4FastStart != potentialMatchProperties.mp4FastStart) { + return false + } + + return true } + /** + * Attachments need records in the database even if they haven't been downloaded yet. That allows us to store the info we need to download it, what message + * it's associated with, etc. We treat this case separately from attachments with data (see [insertAttachmentWithData]) because it's much simpler, + * and splitting the two use cases makes the code easier to understand. + * + * Callers are expected to later call [finalizeAttachmentAfterDownload] once they have downloaded the data for this attachment. + */ @Throws(MmsException::class) - private fun insertAttachment(mmsId: Long, attachment: Attachment, quote: Boolean): AttachmentId { - Log.d(TAG, "Inserting attachment for mms id: $mmsId") - - var notifyPacks = false + private fun insertUndownloadedAttachment(messageId: Long, attachment: Attachment, quote: Boolean): AttachmentId { + Log.d(TAG, "[insertAttachment] Inserting attachment for messageId $messageId.") val attachmentId: AttachmentId = writableDatabase.withinTransaction { db -> - try { - var dataInfo: DataInfo? = null - - if (attachment.uri != null) { - val storeDataInfo = storeAttachmentStream(PartAuthority.getAttachmentStream(context, attachment.uri!!)) - Log.d(TAG, "Wrote part to file: ${storeDataInfo.file.absolutePath}") - - dataInfo = deduplicateAttachment(storeDataInfo, null, attachment.transformProperties) - } - - var template = attachment - var useTemplateUpload = false - - if (dataInfo != null) { - val possibleTemplates = findTemplateAttachments(dataInfo.hash) - - for (possibleTemplate in possibleTemplates) { - useTemplateUpload = possibleTemplate.uploadTimestamp > attachment.uploadTimestamp && - possibleTemplate.transferState == TRANSFER_PROGRESS_DONE && - possibleTemplate.transformProperties?.shouldSkipTransform() == true && possibleTemplate.remoteDigest != null && - attachment.transformProperties?.videoEdited == false && possibleTemplate.transformProperties?.sentMediaQuality == attachment.transformProperties?.sentMediaQuality - - if (useTemplateUpload) { - Log.i(TAG, "Found a duplicate attachment upon insertion. Using it as a template.") - template = possibleTemplate - break - } - } - } - - val contentValues = ContentValues() - contentValues.put(MESSAGE_ID, mmsId) - contentValues.put(CONTENT_TYPE, template.contentType) - contentValues.put(TRANSFER_STATE, attachment.transferState) - contentValues.put(CDN_NUMBER, if (useTemplateUpload) template.cdnNumber else attachment.cdnNumber) - contentValues.put(REMOTE_LOCATION, if (useTemplateUpload) template.remoteLocation else attachment.remoteLocation) - contentValues.put(REMOTE_DIGEST, if (useTemplateUpload) template.remoteDigest else attachment.remoteDigest) - contentValues.put(REMOTE_INCREMENTAL_DIGEST, if (useTemplateUpload) template.incrementalDigest else attachment.incrementalDigest) - contentValues.put(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE, if (useTemplateUpload) template.incrementalMacChunkSize else attachment.incrementalMacChunkSize) - contentValues.put(REMOTE_KEY, if (useTemplateUpload) template.remoteKey else attachment.remoteKey) - contentValues.put(FILE_NAME, StorageUtil.getCleanFileName(attachment.fileName)) - contentValues.put(DATA_SIZE, template.size) - contentValues.put(FAST_PREFLIGHT_ID, attachment.fastPreflightId) - contentValues.put(VOICE_NOTE, if (attachment.voiceNote) 1 else 0) - contentValues.put(BORDERLESS, if (attachment.borderless) 1 else 0) - contentValues.put(VIDEO_GIF, if (attachment.videoGif) 1 else 0) - contentValues.put(WIDTH, template.width) - contentValues.put(HEIGHT, template.height) - contentValues.put(QUOTE, quote) - contentValues.put(CAPTION, attachment.caption) - contentValues.put(UPLOAD_TIMESTAMP, if (useTemplateUpload) template.uploadTimestamp else attachment.uploadTimestamp) - - if (attachment.transformProperties?.videoEdited == true) { - contentValues.putNull(BLUR_HASH) - contentValues.put(TRANSFORM_PROPERTIES, attachment.transformProperties?.serialize()) - } else { - contentValues.put(BLUR_HASH, template.getVisualHashStringOrNull()) - contentValues.put(TRANSFORM_PROPERTIES, (if (useTemplateUpload) template else attachment).transformProperties?.serialize()) - } + val contentValues = ContentValues().apply { + put(MESSAGE_ID, messageId) + put(CONTENT_TYPE, attachment.contentType) + put(TRANSFER_STATE, attachment.transferState) + put(CDN_NUMBER, attachment.cdnNumber) + put(REMOTE_LOCATION, attachment.remoteLocation) + put(REMOTE_DIGEST, attachment.remoteDigest) + put(REMOTE_INCREMENTAL_DIGEST, attachment.incrementalDigest) + put(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE, attachment.incrementalMacChunkSize) + put(REMOTE_KEY, attachment.remoteKey) + put(FILE_NAME, StorageUtil.getCleanFileName(attachment.fileName)) + put(DATA_SIZE, attachment.size) + put(FAST_PREFLIGHT_ID, attachment.fastPreflightId) + put(VOICE_NOTE, attachment.voiceNote.toInt()) + put(BORDERLESS, attachment.borderless.toInt()) + put(VIDEO_GIF, attachment.videoGif.toInt()) + put(WIDTH, attachment.width) + put(HEIGHT, attachment.height) + put(QUOTE, quote) + put(CAPTION, attachment.caption) + put(UPLOAD_TIMESTAMP, attachment.uploadTimestamp) + put(BLUR_HASH, attachment.blurHash?.hash) attachment.stickerLocator?.let { sticker -> - contentValues.put(STICKER_PACK_ID, sticker.packId) - contentValues.put(STICKER_PACK_KEY, sticker.packKey) - contentValues.put(STICKER_ID, sticker.stickerId) - contentValues.put(STICKER_EMOJI, sticker.emoji) + put(STICKER_PACK_ID, sticker.packId) + put(STICKER_PACK_KEY, sticker.packKey) + put(STICKER_ID, sticker.stickerId) + put(STICKER_EMOJI, sticker.emoji) } - - if (dataInfo != null) { - contentValues.put(DATA_FILE, dataInfo.file.absolutePath) - contentValues.put(DATA_SIZE, dataInfo.length) - contentValues.put(DATA_RANDOM, dataInfo.random) - - if (attachment.transformProperties?.videoEdited == true) { - contentValues.putNull(DATA_HASH) - } else { - contentValues.put(DATA_HASH, dataInfo.hash) - } - } - - notifyPacks = attachment.isSticker && !hasStickerAttachments() - - val rowId = db.insert(TABLE_NAME, null, contentValues) - AttachmentId(rowId) - } catch (e: IOException) { - throw MmsException(e) } - } - if (notifyPacks) { - notifyStickerPackListeners() + val rowId = db.insert(TABLE_NAME, null, contentValues) + AttachmentId(rowId) } notifyAttachmentListeners() return attachmentId } - private fun findTemplateAttachments(dataHash: String?): List { - if (dataHash == null) { - return emptyList() + /** + * Inserts an attachment with existing data. This is likely an outgoing attachment that we're in the process of sending. + */ + @Throws(MmsException::class) + private fun insertAttachmentWithData(messageId: Long, attachment: Attachment, quote: Boolean): AttachmentId { + requireNotNull(attachment.uri) { "Attachment must have a uri!" } + + Log.d(TAG, "[insertAttachmentWithData] Inserting attachment for messageId $messageId. (MessageId: $messageId, ${attachment.uri})") + + val dataStream = try { + PartAuthority.getAttachmentStream(context, attachment.uri!!) + } catch (e: IOException) { + throw MmsException(e) } - return readableDatabase - .select(*PROJECTION) - .from(TABLE_NAME) - .where("$DATA_HASH = ?", dataHash) - .run() - .readToList { it.readAttachment() } + // To avoid performing long-running operations in a transaction, we write the data to an independent file first in a way that doesn't rely on db state. + val fileWriteResult: DataFileWriteResult = writeToDataFile(newDataFile(context), dataStream, attachment.transformProperties ?: TransformProperties.empty()) + Log.d(TAG, "[insertAttachmentWithData] Wrote data to file: ${fileWriteResult.file.absolutePath} (MessageId: $messageId, ${attachment.uri})") + + val (attachmentId: AttachmentId, foundDuplicate: Boolean) = writableDatabase.withinTransaction { db -> + val contentValues = ContentValues() + var transformProperties = attachment.transformProperties ?: TransformProperties.empty() + + // First we'll check if our file hash matches the starting or ending hash of any other attachments and has compatible transform properties. + // We'll prefer the match with the most recent upload timestamp. + val hashMatch: DataFileInfo? = readableDatabase + .select(ID, DATA_FILE, DATA_SIZE, DATA_RANDOM, DATA_HASH_START, DATA_HASH_END, TRANSFORM_PROPERTIES, UPLOAD_TIMESTAMP) + .from(TABLE_NAME) + .where("$DATA_FILE NOT NULL AND ($DATA_HASH_START = ? OR $DATA_HASH_END = ?)", fileWriteResult.hash, fileWriteResult.hash) + .run() + .readToList { it.readDataFileInfo() } + .sortedByDescending { it.uploadTimestamp } + .firstOrNull { existingMatch -> + areTransformationsCompatible( + newProperties = transformProperties, + potentialMatchProperties = existingMatch.transformProperties, + newHashStart = fileWriteResult.hash, + potentialMatchHashEnd = existingMatch.hashEnd, + newIsQuote = quote + ) + } + + if (hashMatch != null) { + if (fileWriteResult.hash == hashMatch.hashStart) { + Log.i(TAG, "[insertAttachmentWithData] Found that the new attachment hash matches the DATA_HASH_START of ${hashMatch.id}. Using all of it's fields. (MessageId: $messageId, ${attachment.uri})") + } else if (fileWriteResult.hash == hashMatch.hashEnd) { + Log.i(TAG, "[insertAttachmentWithData] Found that the new attachment hash matches the DATA_HASH_END of ${hashMatch.id}. Using all of it's fields. (MessageId: $messageId, ${attachment.uri})") + } else { + throw IllegalStateException("Should not be possible based on query.") + } + + contentValues.put(DATA_FILE, hashMatch.file.absolutePath) + contentValues.put(DATA_SIZE, hashMatch.length) + contentValues.put(DATA_RANDOM, hashMatch.random) + contentValues.put(DATA_HASH_START, fileWriteResult.hash) + contentValues.put(DATA_HASH_END, hashMatch.hashEnd) + + if (hashMatch.transformProperties.skipTransform) { + Log.i(TAG, "[insertAttachmentWithData] The hash match has a DATA_HASH_END and skipTransform=true, so skipping transform of the new file as well. (MessageId: $messageId, ${attachment.uri})") + transformProperties = transformProperties.copy(skipTransform = true) + } + } else { + Log.i(TAG, "[insertAttachmentWithData] No matching hash found. (MessageId: $messageId, ${attachment.uri})") + contentValues.put(DATA_FILE, fileWriteResult.file.absolutePath) + contentValues.put(DATA_SIZE, fileWriteResult.length) + contentValues.put(DATA_RANDOM, fileWriteResult.random) + contentValues.put(DATA_HASH_START, fileWriteResult.hash) + } + + // Our hashMatch already represents a transform-compatible attachment with the most recent upload timestamp. We just need to make sure it has all of the + // other necessary fields, and if so, we can use that to skip the upload. + var uploadTemplate: Attachment? = null + if (hashMatch?.hashEnd != null && System.currentTimeMillis() - hashMatch.uploadTimestamp < AttachmentUploadJob.UPLOAD_REUSE_THRESHOLD) { + uploadTemplate = readableDatabase + .select(*PROJECTION) + .from(TABLE_NAME) + .where("$ID = ${hashMatch.id.id} AND $REMOTE_DIGEST NOT NULL AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND $DATA_HASH_END NOT NULL") + .run() + .readToSingleObject { it.readAttachment() } + } + + if (uploadTemplate != null) { + Log.i(TAG, "[insertAttachmentWithData] Found a valid template we could use to skip upload. (MessageId: $messageId, ${attachment.uri})") + transformProperties = (uploadTemplate.transformProperties ?: transformProperties).copy(skipTransform = true) + } + + contentValues.put(MESSAGE_ID, messageId) + contentValues.put(CONTENT_TYPE, uploadTemplate?.contentType ?: attachment.contentType) + contentValues.put(TRANSFER_STATE, attachment.transferState) // Even if we have a template, we let AttachmentUploadJob have the final say so it can re-check and make sure the template is still valid + contentValues.put(CDN_NUMBER, uploadTemplate?.cdnNumber ?: 0) + contentValues.put(REMOTE_LOCATION, uploadTemplate?.remoteLocation) + contentValues.put(REMOTE_DIGEST, uploadTemplate?.remoteDigest) + contentValues.put(REMOTE_INCREMENTAL_DIGEST, uploadTemplate?.incrementalDigest) + contentValues.put(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE, uploadTemplate?.incrementalMacChunkSize ?: 0) + contentValues.put(REMOTE_KEY, uploadTemplate?.remoteKey) + contentValues.put(FILE_NAME, StorageUtil.getCleanFileName(attachment.fileName)) + contentValues.put(FAST_PREFLIGHT_ID, attachment.fastPreflightId) + contentValues.put(VOICE_NOTE, if (attachment.voiceNote) 1 else 0) + contentValues.put(BORDERLESS, if (attachment.borderless) 1 else 0) + contentValues.put(VIDEO_GIF, if (attachment.videoGif) 1 else 0) + contentValues.put(WIDTH, uploadTemplate?.width ?: attachment.width) + contentValues.put(HEIGHT, uploadTemplate?.height ?: attachment.height) + contentValues.put(QUOTE, quote) + contentValues.put(CAPTION, attachment.caption) + contentValues.put(UPLOAD_TIMESTAMP, uploadTemplate?.uploadTimestamp ?: 0) + contentValues.put(TRANSFORM_PROPERTIES, transformProperties.serialize()) + + if (attachment.transformProperties?.videoEdited == true) { + contentValues.putNull(BLUR_HASH) + } else { + contentValues.put(BLUR_HASH, uploadTemplate.getVisualHashStringOrNull()) + } + + attachment.stickerLocator?.let { sticker -> + contentValues.put(STICKER_PACK_ID, sticker.packId) + contentValues.put(STICKER_PACK_KEY, sticker.packKey) + contentValues.put(STICKER_ID, sticker.stickerId) + contentValues.put(STICKER_EMOJI, sticker.emoji) + } + + val rowId = db.insert(TABLE_NAME, null, contentValues) + + AttachmentId(rowId) to (hashMatch != null) + } + + if (foundDuplicate) { + if (!fileWriteResult.file.delete()) { + Log.w(TAG, "[insertAttachmentWithData] Failed to delete duplicate file: ${fileWriteResult.file.absolutePath}") + } + } + + notifyAttachmentListeners() + return attachmentId } private fun getTransferFile(db: SQLiteDatabase, attachmentId: AttachmentId): File? { @@ -1464,7 +1551,8 @@ open class AttachmentTable( audioHash = if (MediaUtil.isAudioType(contentType)) AudioHash.parseOrNull(cursor.requireString(BLUR_HASH)) else null, transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES)), displayOrder = cursor.requireInt(DISPLAY_ORDER), - uploadTimestamp = cursor.requireLong(UPLOAD_TIMESTAMP) + uploadTimestamp = cursor.requireLong(UPLOAD_TIMESTAMP), + dataHash = cursor.requireString(DATA_HASH_END) ) } @@ -1476,6 +1564,19 @@ open class AttachmentTable( return getAttachment(this) } + private fun Cursor.readDataFileInfo(): DataFileInfo { + return DataFileInfo( + id = AttachmentId(this.requireLong(ID)), + file = File(this.requireNonNullString(DATA_FILE)), + length = this.requireLong(DATA_SIZE), + random = this.requireNonNullBlob(DATA_RANDOM), + hashStart = this.requireString(DATA_HASH_START), + hashEnd = this.requireString(DATA_HASH_END), + transformProperties = TransformProperties.parse(this.requireString(TRANSFORM_PROPERTIES)), + uploadTimestamp = this.requireLong(UPLOAD_TIMESTAMP) + ) + } + private fun Cursor.readStickerLocator(): StickerLocator? { return if (this.requireInt(STICKER_ID) >= 0) { StickerLocator( @@ -1492,86 +1593,69 @@ open class AttachmentTable( private fun Attachment?.getVisualHashStringOrNull(): String? { return when { this == null -> null - this.blurHash != null -> this.blurHash!!.hash - this.audioHash != null -> this.audioHash!!.hash + this.blurHash != null -> this.blurHash.hash + this.audioHash != null -> this.audioHash.hash else -> null } } - @VisibleForTesting - class DataInfo( + fun debugGetLatestAttachments(): List { + return readableDatabase + .select(*PROJECTION) + .from(TABLE_NAME) + .where("$TRANSFER_STATE == $TRANSFER_PROGRESS_DONE AND $REMOTE_LOCATION IS NOT NULL AND $DATA_HASH_END IS NOT NULL") + .orderBy("$ID DESC") + .limit(30) + .run() + .readToList { it.readAttachments() } + .flatten() + } + + class DataFileWriteResult( val file: File, val length: Long, val random: ByteArray, - val hash: String?, - val transformProperties: TransformProperties? - ) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false + val hash: String, + val transformProperties: TransformProperties + ) - other as DataInfo - - if (file != other.file) return false - if (length != other.length) return false - if (!random.contentEquals(other.random)) return false - if (hash != other.hash) return false - return transformProperties == other.transformProperties - } - - override fun hashCode(): Int { - var result = file.hashCode() - result = 31 * result + length.hashCode() - result = 31 * result + random.contentHashCode() - result = 31 * result + (hash?.hashCode() ?: 0) - result = 31 * result + (transformProperties?.hashCode() ?: 0) - return result - } - } - - /** - * @param removableWeakReferences Entries in here can be removed from the database. Only possible to be non-empty when [hasStrongReference] is false. - */ - private class DataUsageResult private constructor(val hasStrongReference: Boolean, val removableWeakReferences: List) { - constructor(removableWeakReferences: List) : this(false, removableWeakReferences) - - init { - if (hasStrongReference && removableWeakReferences.isNotEmpty()) { - throw IllegalStateException("There's a strong reference and removable weak references!") - } - } - - companion object { - val IN_USE = DataUsageResult(true, emptyList()) - val NOT_IN_USE = DataUsageResult(false, emptyList()) - } - } + @VisibleForTesting + class DataFileInfo( + val id: AttachmentId, + val file: File, + val length: Long, + val random: ByteArray, + val hashStart: String?, + val hashEnd: String?, + val transformProperties: TransformProperties, + val uploadTimestamp: Long + ) @Parcelize data class TransformProperties( @JsonProperty("skipTransform") @JvmField - val skipTransform: Boolean, + val skipTransform: Boolean = false, @JsonProperty("videoTrim") @JvmField - val videoTrim: Boolean, + val videoTrim: Boolean = false, @JsonProperty("videoTrimStartTimeUs") @JvmField - val videoTrimStartTimeUs: Long, + val videoTrimStartTimeUs: Long = 0, @JsonProperty("videoTrimEndTimeUs") @JvmField - val videoTrimEndTimeUs: Long, + val videoTrimEndTimeUs: Long = 0, @JsonProperty("sentMediaQuality") @JvmField - val sentMediaQuality: Int, + val sentMediaQuality: Int = SentMediaQuality.STANDARD.code, @JsonProperty("mp4Faststart") @JvmField - val mp4FastStart: Boolean + val mp4FastStart: Boolean = false ) : Parcelable { fun shouldSkipTransform(): Boolean { return skipTransform @@ -1583,11 +1667,7 @@ open class AttachmentTable( fun withSkipTransform(): TransformProperties { return this.copy( - skipTransform = true, - videoTrim = false, - videoTrimStartTimeUs = 0, - videoTrimEndTimeUs = 0, - mp4FastStart = false + skipTransform = true ) } @@ -1642,6 +1722,11 @@ open class AttachmentTable( return existing.copy(sentMediaQuality = sentMediaQuality.code) } + @JvmStatic + fun forSentMediaQuality(sentMediaQuality: Int): TransformProperties { + return TransformProperties(sentMediaQuality = sentMediaQuality) + } + @JvmStatic fun parse(serialized: String?): TransformProperties { return if (serialized == null) { diff --git a/app/src/main/java/org/tm/archive/database/CallLinkTable.kt b/app/src/main/java/org/tm/archive/database/CallLinkTable.kt index 2745921c..fdfff94b 100644 --- a/app/src/main/java/org/tm/archive/database/CallLinkTable.kt +++ b/app/src/main/java/org/tm/archive/database/CallLinkTable.kt @@ -142,6 +142,10 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database .readToSingleLong() .let { RecipientId.from(it) } + if (state.revoked) { + SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps() + } + Recipient.live(recipientId).refresh() ApplicationDependencies.getDatabaseObserver().notifyCallLinkObservers(roomId) ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers() @@ -227,6 +231,37 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database } } + /** + * Puts the call link into the "revoked" state which will hide it from the UI and + * delete it after a few days. + */ + fun markRevoked( + roomId: CallLinkRoomId + ) { + writableDatabase.withinTransaction { db -> + db.update(TABLE_NAME) + .values("$REVOKED" to true) + .where("$ROOM_ID", roomId) + .run() + + SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps() + } + } + + /** + * Deletes the call link. This should only happen *after* we send out a sync message + * or receive a sync message which deletes the corresponding link. + */ + fun deleteCallLink( + roomId: CallLinkRoomId + ) { + writableDatabase.withinTransaction { db -> + db.delete(TABLE_NAME) + .where("$ROOM_ID", roomId) + .run() + } + } + fun deleteNonAdminCallLinks(roomIds: Set) { val queries = SqlUtil.buildCollectionQuery(ROOM_ID, roomIds) diff --git a/app/src/main/java/org/tm/archive/database/CallTable.kt b/app/src/main/java/org/tm/archive/database/CallTable.kt index 35964da7..62a7c06c 100644 --- a/app/src/main/java/org/tm/archive/database/CallTable.kt +++ b/app/src/main/java/org/tm/archive/database/CallTable.kt @@ -7,9 +7,12 @@ import androidx.core.content.contentValuesOf import org.signal.core.util.IntSerializer import org.signal.core.util.Serializer import org.signal.core.util.SqlUtil +import org.signal.core.util.count import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.flatten import org.signal.core.util.insertInto +import org.signal.core.util.isAbsent import org.signal.core.util.logging.Log import org.signal.core.util.readToList import org.signal.core.util.readToMap @@ -59,9 +62,10 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl const val TIMESTAMP = "timestamp" const val RINGER = "ringer" const val DELETION_TIMESTAMP = "deletion_timestamp" + const val READ = "read" //language=sql - val CREATE_TABLE = """ + const val CREATE_TABLE = """ CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $CALL_ID INTEGER NOT NULL, @@ -73,6 +77,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl $TIMESTAMP INTEGER NOT NULL, $RINGER INTEGER DEFAULT NULL, $DELETION_TIMESTAMP INTEGER DEFAULT 0, + $READ INTEGER DEFAULT 1, UNIQUE ($CALL_ID, $PEER) ON CONFLICT FAIL ) """ @@ -84,12 +89,29 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl ) } + fun markAllCallEventsRead(timestamp: Long = Long.MAX_VALUE) { + writableDatabase.update(TABLE_NAME) + .values(READ to ReadState.serialize(ReadState.READ)) + .where("$TIMESTAMP <= ?", timestamp) + .run() + + notifyConversationListListeners() + } + + fun getUnreadMissedCallCount(): Long { + return readableDatabase + .count() + .from(TABLE_NAME) + .where("$EVENT = ? AND $READ = ?", Event.serialize(Event.MISSED), ReadState.serialize(ReadState.UNREAD)) + .run() + .readToSingleLong() + } + fun insertOneToOneCall(callId: Long, timestamp: Long, peer: RecipientId, type: Type, direction: Direction, event: Event) { val messageType: Long = Call.getMessageType(type, direction, event) writableDatabase.withinTransaction { val result = SignalDatabase.messages.insertCallLog(peer, messageType, timestamp, direction == Direction.OUTGOING) - val values = contentValuesOf( CALL_ID to callId, MESSAGE_ID to result.messageId, @@ -97,7 +119,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl TYPE to Type.serialize(type), DIRECTION to Direction.serialize(direction), EVENT to Event.serialize(event), - TIMESTAMP to timestamp + TIMESTAMP to timestamp, + READ to ReadState.serialize(ReadState.UNREAD) ) writableDatabase.insert(TABLE_NAME, null, values) @@ -113,7 +136,10 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl return writableDatabase.withinTransaction { writableDatabase .update(TABLE_NAME) - .values(EVENT to Event.serialize(event)) + .values( + EVENT to Event.serialize(event), + READ to ReadState.serialize(ReadState.UNREAD) + ) .where("$CALL_ID = ?", callId) .run() @@ -127,7 +153,12 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl if (call != null) { Log.i(TAG, "Updated call: $callId event: $event") - SignalDatabase.messages.updateCallLog(call.messageId!!, call.messageType) + if (call.messageId == null) { + Log.w(TAG, "Call does not have an associated message id! No message to update.") + } else { + SignalDatabase.messages.updateCallLog(call.messageId, call.messageType) + } + ApplicationDependencies.getMessageNotifier().updateNotification(context) ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers() } @@ -376,6 +407,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl Log.w(TAG, "[acceptOutgoingGroupCall] This shouldn't have been an outgoing ring because the call already existed!") Event.ACCEPTED } + else -> { Log.d(TAG, "[acceptOutgoingGroupCall] Call in state ${call.event} cannot be transitioned by ACCEPTED") return @@ -915,12 +947,12 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl /** * Gets the most recent timestamp from the [TIMESTAMP] column */ - fun getLatestTimestamp(): Long { + fun getLatestCall(): Call? { val statement = """ - SELECT $TIMESTAMP FROM $TABLE_NAME ORDER BY $TIMESTAMP DESC LIMIT 1 + SELECT * FROM $TABLE_NAME ORDER BY $TIMESTAMP DESC LIMIT 1 """.trimIndent() - return readableDatabase.query(statement).readToSingleLong(-1) + return readableDatabase.query(statement).readToSingleObject { Call.deserialize(it) } } fun deleteNonAdHocCallEventsOnOrBefore(timestamp: Long) { @@ -1014,9 +1046,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl @Discouraged("Using this method is generally considered an error. Utilize other deletion methods instead of this.") fun deleteAllCalls() { Log.w(TAG, "Deleting all calls from the local database.") - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } private fun getCallSelectionQuery(callId: Long, recipientId: RecipientId): SqlUtil.Query { @@ -1227,6 +1257,16 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl val actualChildren = inPeriod.takeWhile { children.contains(it) } val peer = Recipient.resolved(call.peer) + val canUserBeginCall = if (peer.isGroup) { + val record = SignalDatabase.groups.getGroup(peer.id) + + !record.isAbsent() && + record.get().isActive && + (!record.get().isAnnouncementGroup || record.get().memberLevel(Recipient.self()) == GroupTable.MemberLevel.ADMINISTRATOR) + } else { + true + } + CallLogRow.Call( record = call, date = call.timestamp, @@ -1234,7 +1274,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl groupCallState = CallLogRow.GroupCallState.fromDetails(groupCallDetails), children = actualChildren.toSet(), searchQuery = searchTerm, - callLinkPeekInfo = ApplicationDependencies.getSignalCallManager().peekInfoSnapshot[peer.id] + callLinkPeekInfo = ApplicationDependencies.getSignalCallManager().peekInfoSnapshot[peer.id], + canUserBeginCall = canUserBeginCall ) } } @@ -1357,6 +1398,21 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl } } + enum class ReadState(private val code: Int) { + UNREAD(0), + READ(1); + + companion object Serializer : IntSerializer { + override fun serialize(data: ReadState): Int { + return data.code + } + + override fun deserialize(data: Int): ReadState { + return ReadState.values().first { it.code == data } + } + } + } + enum class Event(private val code: Int) { /** * 1:1 Calls only. diff --git a/app/src/main/java/org/tm/archive/database/CdsTable.kt b/app/src/main/java/org/tm/archive/database/CdsTable.kt index 34d5c79a..3602d8c4 100644 --- a/app/src/main/java/org/tm/archive/database/CdsTable.kt +++ b/app/src/main/java/org/tm/archive/database/CdsTable.kt @@ -5,6 +5,7 @@ import android.content.Context import androidx.core.content.contentValuesOf import org.signal.core.util.SqlUtil import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.requireNonNullString import org.signal.core.util.select @@ -106,8 +107,6 @@ class CdsTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable * Wipes the entire table. */ fun clearAll() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } } diff --git a/app/src/main/java/org/tm/archive/database/ContentValuesBuilder.java b/app/src/main/java/org/tm/archive/database/ContentValuesBuilder.java deleted file mode 100644 index 31a6df76..00000000 --- a/app/src/main/java/org/tm/archive/database/ContentValuesBuilder.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.database; - -import android.content.ContentValues; - -import com.google.android.mms.pdu_alt.EncodedStringValue; - -import org.tm.archive.util.Util; - -public class ContentValuesBuilder { - - private final ContentValues contentValues; - - public ContentValuesBuilder(ContentValues contentValues) { - this.contentValues = contentValues; - } - - public void add(String key, String charsetKey, EncodedStringValue value) { - if (value != null) { - contentValues.put(key, Util.toIsoString(value.getTextString())); - contentValues.put(charsetKey, value.getCharacterSet()); - } - } - - public void add(String contentKey, byte[] value) { - if (value != null) { - contentValues.put(contentKey, Util.toIsoString(value)); - } - } - - public void add(String contentKey, int b) { - if (b != 0) - contentValues.put(contentKey, b); - } - - public void add(String contentKey, long value) { - if (value != -1L) - contentValues.put(contentKey, value); - } - - public ContentValues getContentValues() { - return contentValues; - } -} diff --git a/app/src/main/java/org/tm/archive/database/DraftTable.kt b/app/src/main/java/org/tm/archive/database/DraftTable.kt index c89b42c4..d7001173 100644 --- a/app/src/main/java/org/tm/archive/database/DraftTable.kt +++ b/app/src/main/java/org/tm/archive/database/DraftTable.kt @@ -5,6 +5,7 @@ import android.net.Uri import androidx.core.content.contentValuesOf import org.signal.core.util.SqlUtil import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.readToList import org.signal.core.util.requireNonNullString @@ -71,9 +72,7 @@ class DraftTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT } fun clearAllDrafts() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } fun getDrafts(threadId: Long): Drafts { diff --git a/app/src/main/java/org/tm/archive/database/GroupReceiptTable.kt b/app/src/main/java/org/tm/archive/database/GroupReceiptTable.kt index bcacad3b..8b421131 100644 --- a/app/src/main/java/org/tm/archive/database/GroupReceiptTable.kt +++ b/app/src/main/java/org/tm/archive/database/GroupReceiptTable.kt @@ -6,6 +6,7 @@ import android.database.Cursor import androidx.core.content.contentValuesOf import org.signal.core.util.SqlUtil import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.forEach import org.signal.core.util.readToList import org.signal.core.util.requireBoolean @@ -172,7 +173,7 @@ class GroupReceiptTable(context: Context?, databaseHelper: SignalDatabase?) : Da } fun deleteAllRows() { - writableDatabase.delete(TABLE_NAME).run() + writableDatabase.deleteAll(TABLE_NAME) } override fun remapRecipient(fromId: RecipientId, toId: RecipientId) { diff --git a/app/src/main/java/org/tm/archive/database/GroupTable.kt b/app/src/main/java/org/tm/archive/database/GroupTable.kt index 75f921e0..1cc15182 100644 --- a/app/src/main/java/org/tm/archive/database/GroupTable.kt +++ b/app/src/main/java/org/tm/archive/database/GroupTable.kt @@ -6,6 +6,7 @@ import android.database.Cursor import android.text.TextUtils import androidx.annotation.WorkerThread import androidx.core.content.contentValuesOf +import okio.ByteString import org.intellij.lang.annotations.Language import org.signal.core.util.SqlUtil import org.signal.core.util.SqlUtil.appendArg @@ -32,6 +33,7 @@ import org.signal.core.util.withinTransaction import org.signal.libsignal.zkgroup.groups.GroupMasterKey import org.signal.storageservice.protos.groups.Member import org.signal.storageservice.protos.groups.local.DecryptedGroup +import org.signal.storageservice.protos.groups.local.DecryptedPendingMember import org.tm.archive.contacts.paged.ContactSearchSortOrder import org.tm.archive.contacts.paged.collections.ContactSearchIterator import org.tm.archive.crypto.SenderKeyUtil @@ -57,6 +59,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI.Companion.parseOrNull import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.io.Closeable import java.security.SecureRandom @@ -639,6 +642,27 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT } } + fun getGroupInviter(groupId: GroupId): Recipient? { + val groupRecord: Optional = getGroup(groupId) + + if (groupRecord.isPresent && groupRecord.get().isV2Group) { + val pendingMembers: List = groupRecord.get().requireV2GroupProperties().decryptedGroup.pendingMembers + val invitedByAci: ByteString? = DecryptedGroupUtil.findPendingByServiceId(pendingMembers, Recipient.self().requireAci()) + .or { DecryptedGroupUtil.findPendingByServiceId(pendingMembers, Recipient.self().requirePni()) } + .map { it.addedByAci } + .orElse(null) + + if (invitedByAci != null) { + val serviceId: ServiceId? = parseOrNull(invitedByAci) + if (serviceId != null) { + return Recipient.externalPush(serviceId) + } + } + } + + return null + } + @CheckReturnValue fun create(groupId: GroupId.V1, title: String?, members: Collection, avatar: SignalServiceAttachmentPointer?): Boolean { if (groupExists(groupId.deriveV2MigrationGroupId())) { diff --git a/app/src/main/java/org/tm/archive/database/JobDatabase.kt b/app/src/main/java/org/tm/archive/database/JobDatabase.kt index 2242f674..fade354d 100644 --- a/app/src/main/java/org/tm/archive/database/JobDatabase.kt +++ b/app/src/main/java/org/tm/archive/database/JobDatabase.kt @@ -21,6 +21,7 @@ import org.signal.core.util.requireNonNullString import org.signal.core.util.requireString import org.signal.core.util.select import org.signal.core.util.update +import org.signal.core.util.updateAll import org.signal.core.util.withinTransaction import org.tm.archive.crypto.DatabaseSecret import org.tm.archive.crypto.DatabaseSecretProvider @@ -235,7 +236,7 @@ class JobDatabase( @Synchronized fun updateAllJobsToBePending() { writableDatabase - .update(Jobs.TABLE_NAME) + .updateAll(Jobs.TABLE_NAME) .values(Jobs.IS_RUNNING to 0) .run() } diff --git a/app/src/main/java/org/tm/archive/database/KyberPreKeyTable.kt b/app/src/main/java/org/tm/archive/database/KyberPreKeyTable.kt index 7ade940b..f9a361e6 100644 --- a/app/src/main/java/org/tm/archive/database/KyberPreKeyTable.kt +++ b/app/src/main/java/org/tm/archive/database/KyberPreKeyTable.kt @@ -2,6 +2,7 @@ package org.tm.archive.database import android.content.Context import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.exists import org.signal.core.util.insertInto import org.signal.core.util.logging.Log @@ -35,7 +36,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $ACCOUNT_ID TEXT NOT NULL, - $KEY_ID INTEGER UNIQUE NOT NULL, + $KEY_ID INTEGER NOT NULL, $TIMESTAMP INTEGER NOT NULL, $LAST_RESORT INTEGER NOT NULL, $SERIALIZED BLOB NOT NULL, @@ -49,13 +50,15 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab val CREATE_INDEXES = arrayOf( "CREATE INDEX IF NOT EXISTS $INDEX_ACCOUNT_KEY ON $TABLE_NAME ($ACCOUNT_ID, $KEY_ID, $LAST_RESORT, $SERIALIZED)" ) + + const val PNI_ACCOUNT_ID = "PNI" } fun get(serviceId: ServiceId, keyId: Int): KyberPreKey? { return readableDatabase .select(LAST_RESORT, SERIALIZED) .from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY") - .where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId) + .where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId.toAccountId(), keyId) .run() .readToSingleObject { cursor -> KyberPreKey( @@ -69,7 +72,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab return readableDatabase .select(LAST_RESORT, SERIALIZED) .from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY") - .where("$ACCOUNT_ID = ?", serviceId) + .where("$ACCOUNT_ID = ?", serviceId.toAccountId()) .run() .readToList { cursor -> KyberPreKey( @@ -83,7 +86,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab return readableDatabase .select(LAST_RESORT, SERIALIZED) .from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY") - .where("$ACCOUNT_ID = ? AND $LAST_RESORT = ?", serviceId, 1) + .where("$ACCOUNT_ID = ? AND $LAST_RESORT = ?", serviceId.toAccountId(), 1) .run() .readToList { cursor -> KyberPreKey( @@ -96,7 +99,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab fun contains(serviceId: ServiceId, keyId: Int): Boolean { return readableDatabase .exists("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY") - .where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId) + .where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId.toAccountId(), keyId) .run() } @@ -104,7 +107,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab writableDatabase .insertInto(TABLE_NAME) .values( - ACCOUNT_ID to serviceId.toString(), + ACCOUNT_ID to serviceId.toAccountId(), KEY_ID to keyId, TIMESTAMP to record.timestamp, SERIALIZED to record.serialize(), @@ -116,14 +119,14 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab fun deleteIfNotLastResort(serviceId: ServiceId, keyId: Int) { writableDatabase .delete("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY") - .where("$ACCOUNT_ID = ? AND $KEY_ID = ? AND $LAST_RESORT = ?", serviceId, keyId, 0) + .where("$ACCOUNT_ID = ? AND $KEY_ID = ? AND $LAST_RESORT = ?", serviceId.toAccountId(), keyId, 0) .run() } fun delete(serviceId: ServiceId, keyId: Int) { writableDatabase .delete("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY") - .where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId) + .where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId.toAccountId(), keyId) .run() } @@ -131,7 +134,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab writableDatabase .update(TABLE_NAME) .values(STALE_TIMESTAMP to staleTime) - .where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0 AND $LAST_RESORT = 0", serviceId) + .where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0 AND $LAST_RESORT = 0", serviceId.toAccountId()) .run() } @@ -161,16 +164,27 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab LIMIT $minCount ) """, - serviceId, - serviceId + serviceId.toAccountId(), + serviceId.toAccountId() ) .run() Log.i(TAG, "Deleted $count stale one-time EC prekeys.") } + fun debugDeleteAll() { + writableDatabase.deleteAll(OneTimePreKeyTable.TABLE_NAME) + } + data class KyberPreKey( val record: KyberPreKeyRecord, val lastResort: Boolean ) + + private fun ServiceId.toAccountId(): String { + return when (this) { + is ServiceId.ACI -> this.toString() + is ServiceId.PNI -> PNI_ACCOUNT_ID + } + } } diff --git a/app/src/main/java/org/tm/archive/database/LogDatabase.kt b/app/src/main/java/org/tm/archive/database/LogDatabase.kt index 66f6354c..f0b28700 100644 --- a/app/src/main/java/org/tm/archive/database/LogDatabase.kt +++ b/app/src/main/java/org/tm/archive/database/LogDatabase.kt @@ -9,6 +9,7 @@ import org.signal.core.util.CursorUtil import org.signal.core.util.SqlUtil import org.signal.core.util.Stopwatch import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.exists import org.signal.core.util.getTableRowCount import org.signal.core.util.insertInto @@ -268,9 +269,7 @@ class LogDatabase private constructor( } fun clearAll() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } private fun getSize(query: String?, args: Array?): Long { @@ -403,9 +402,7 @@ class LogDatabase private constructor( } fun clear() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } private fun CrashConfig.CrashPattern.asLikeQuery(): Pair> { @@ -494,9 +491,7 @@ class LogDatabase private constructor( } fun clear() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } data class AnrRecord( diff --git a/app/src/main/java/org/tm/archive/database/MediaTable.kt b/app/src/main/java/org/tm/archive/database/MediaTable.kt index bb921994..ba05e891 100644 --- a/app/src/main/java/org/tm/archive/database/MediaTable.kt +++ b/app/src/main/java/org/tm/archive/database/MediaTable.kt @@ -48,7 +48,8 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CAPTION}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.UPLOAD_TIMESTAMP}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST}, - ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE}, + ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE}, + ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_HASH_END}, ${MessageTable.TABLE_NAME}.${MessageTable.TYPE}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, @@ -70,13 +71,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD ${MessageTable.VIEW_ONCE} = 0 AND ${MessageTable.STORY_TYPE} = 0 AND ${MessageTable.LATEST_REVISION_ID} IS NULL AND - ( - ${AttachmentTable.QUOTE} = 0 OR - ( - ${AttachmentTable.QUOTE} = 1 AND - ${AttachmentTable.DATA_HASH} IS NULL - ) - ) AND + ${AttachmentTable.QUOTE} = 0 AND ${AttachmentTable.STICKER_PACK_ID} IS NULL AND ${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} > 0 AND $THREAD_RECIPIENT_ID > 0 diff --git a/app/src/main/java/org/tm/archive/database/MessageSendLogTables.kt b/app/src/main/java/org/tm/archive/database/MessageSendLogTables.kt index 268772ff..f4df0d0c 100644 --- a/app/src/main/java/org/tm/archive/database/MessageSendLogTables.kt +++ b/app/src/main/java/org/tm/archive/database/MessageSendLogTables.kt @@ -5,6 +5,7 @@ import android.content.Context import android.database.sqlite.SQLiteConstraintException import org.signal.core.util.CursorUtil import org.signal.core.util.SqlUtil +import org.signal.core.util.delete import org.signal.core.util.logging.Log import org.signal.core.util.readToList import org.signal.core.util.requireBoolean @@ -313,8 +314,6 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal } fun deleteAllRelatedToMessage(messageId: Long) { - if (!FeatureFlags.retryReceipts()) return - val db = databaseHelper.signalWritableDatabase val query = "${MslPayloadTable.ID} IN (SELECT ${MslMessageTable.PAYLOAD_ID} FROM ${MslMessageTable.TABLE_NAME} WHERE ${MslMessageTable.MESSAGE_ID} = ?)" val args = SqlUtil.buildArgs(messageId) @@ -323,14 +322,10 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal } fun deleteEntryForRecipient(dateSent: Long, recipientId: RecipientId, device: Int) { - if (!FeatureFlags.retryReceipts()) return - deleteEntriesForRecipient(listOf(dateSent), recipientId, device) } fun deleteEntriesForRecipient(dateSent: List, recipientId: RecipientId, device: Int) { - if (!FeatureFlags.retryReceipts()) return - val db = databaseHelper.signalWritableDatabase db.beginTransaction() try { @@ -360,15 +355,25 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal } } - fun deleteAll() { + fun deleteAllForRecipient(recipientId: RecipientId) { if (!FeatureFlags.retryReceipts()) return + writableDatabase + .delete(MslRecipientTable.TABLE_NAME) + .where("${MslRecipientTable.RECIPIENT_ID} = ?", recipientId) + .run() + + writableDatabase + .delete(MslPayloadTable.TABLE_NAME) + .where("${MslPayloadTable.ID} NOT IN (SELECT ${MslRecipientTable.PAYLOAD_ID} FROM ${MslRecipientTable.TABLE_NAME})") + .run() + } + + fun deleteAll() { databaseHelper.signalWritableDatabase.delete(MslPayloadTable.TABLE_NAME, null, null) } fun trimOldMessages(currentTime: Long, maxAge: Long) { - if (!FeatureFlags.retryReceipts()) return - val db = databaseHelper.signalWritableDatabase val query = "${MslPayloadTable.DATE_SENT} < ?" val args = SqlUtil.buildArgs(currentTime - maxAge) diff --git a/app/src/main/java/org/tm/archive/database/MessageTable.kt b/app/src/main/java/org/tm/archive/database/MessageTable.kt index 7c73eed2..cccf51a8 100644 --- a/app/src/main/java/org/tm/archive/database/MessageTable.kt +++ b/app/src/main/java/org/tm/archive/database/MessageTable.kt @@ -23,9 +23,6 @@ import android.text.SpannableString import android.text.TextUtils import androidx.annotation.VisibleForTesting import androidx.core.content.contentValuesOf -import com.google.android.mms.pdu_alt.NotificationInd -import com.google.android.mms.pdu_alt.PduHeaders -import org.archiver.annotation.TeleMessageUnfinalize import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -41,6 +38,7 @@ import org.signal.core.util.SqlUtil.getNextAutoIncrementId import org.signal.core.util.Stopwatch import org.signal.core.util.count import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.exists import org.signal.core.util.forEach import org.signal.core.util.insertInto @@ -108,6 +106,7 @@ import org.tm.archive.database.model.databaseprotos.BodyRangeList import org.tm.archive.database.model.databaseprotos.GiftBadge import org.tm.archive.database.model.databaseprotos.GroupCallUpdateDetails import org.tm.archive.database.model.databaseprotos.MessageExportState +import org.tm.archive.database.model.databaseprotos.MessageExtras import org.tm.archive.database.model.databaseprotos.ProfileChangeDetails import org.tm.archive.database.model.databaseprotos.SessionSwitchoverEvent import org.tm.archive.database.model.databaseprotos.ThreadMergeEvent @@ -130,16 +129,13 @@ import org.tm.archive.recipients.RecipientId import org.tm.archive.revealable.ViewOnceExpirationInfo import org.tm.archive.revealable.ViewOnceUtil import org.tm.archive.sms.GroupV2UpdateMessageUtil -import org.tm.archive.sms.MessageSender import org.tm.archive.stories.Stories.isFeatureEnabled -import org.tm.archive.util.FeatureFlags import org.tm.archive.util.JsonUtils import org.tm.archive.util.MediaUtil import org.tm.archive.util.MessageConstraintsUtil import org.tm.archive.util.TextSecurePreferences import org.tm.archive.util.Util import org.tm.archive.util.isStory -import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.internal.push.SyncMessage import java.io.Closeable @@ -208,6 +204,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat const val LATEST_REVISION_ID = "latest_revision_id" const val ORIGINAL_MESSAGE_ID = "original_message_id" const val REVISION_NUMBER = "revision_number" + const val MESSAGE_EXTRAS = "message_extras" const val QUOTE_NOT_PRESENT_ID = 0L const val QUOTE_TARGET_MISSING_ID = -1L @@ -265,7 +262,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat $SCHEDULED_DATE INTEGER DEFAULT -1, $LATEST_REVISION_ID INTEGER DEFAULT NULL REFERENCES $TABLE_NAME ($ID) ON DELETE CASCADE, $ORIGINAL_MESSAGE_ID INTEGER DEFAULT NULL REFERENCES $TABLE_NAME ($ID) ON DELETE CASCADE, - $REVISION_NUMBER INTEGER DEFAULT 0 + $REVISION_NUMBER INTEGER DEFAULT 0, + $MESSAGE_EXTRAS BLOB DEFAULT NULL ) """ @@ -305,7 +303,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat READ, MMS_CONTENT_LOCATION, MMS_EXPIRY, - MMS_MESSAGE_TYPE, MMS_MESSAGE_SIZE, MMS_STATUS, MMS_TRANSACTION_ID, @@ -344,7 +341,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat SCHEDULED_DATE, LATEST_REVISION_ID, ORIGINAL_MESSAGE_ID, - REVISION_NUMBER + REVISION_NUMBER, + MESSAGE_EXTRAS ) private val MMS_PROJECTION: Array = MMS_PROJECTION_BASE + "NULL AS ${AttachmentTable.ATTACHMENT_JSON_ALIAS}" @@ -403,6 +401,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat $LATEST_REVISION_ID IS NULL AND $TYPE & ${MessageTypes.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT} = 0 AND $TYPE & ${MessageTypes.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT} = 0 AND + $TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} != ${MessageTypes.SPECIAL_TYPE_REPORTED_SPAM} AND + $TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} != ${MessageTypes.SPECIAL_TYPE_MESSAGE_REQUEST_ACCEPTED} AND $TYPE NOT IN ( ${MessageTypes.PROFILE_CHANGE_TYPE}, ${MessageTypes.GV1_MIGRATION_TYPE}, @@ -610,8 +610,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat updateTypeBitmask(id, MessageTypes.ENCRYPTION_MASK, MessageTypes.ENCRYPTION_REMOTE_LEGACY_BIT) } - @TeleMessageUnfinalize - open fun markSmsStatus(id: Long, status: Int) { + open fun markSmsStatus(id: Long, status: Int) {//*TM_SA*/ make fun open Log.i(TAG, "Updating ID: $id to status: $status") writableDatabase @@ -625,8 +624,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat notifyConversationListeners(threadId) } - @TeleMessageUnfinalize - protected open fun updateTypeBitmask(id: Long, maskOff: Long, maskOn: Long) { + protected open fun updateTypeBitmask(id: Long, maskOff: Long, maskOn: Long) {//*TM_SA*/ make fun protected open writableDatabase.withinTransaction { db -> db.execSQL( """ @@ -661,7 +659,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat threads.update(threadId, true) notifyConversationListeners(threadId) - return InsertResult(messageId, threadId) + return InsertResult( + messageId = messageId, + threadId = threadId, + threadWasNewlyCreated = false + ) } fun updateBundleMessageBody(messageId: Long, body: String): InsertResult { @@ -687,8 +689,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - @TeleMessageUnfinalize - open fun setIncomingMessagesViewed(messageIds: List): List { + open fun setIncomingMessagesViewed(messageIds: List): List {//*TM_SA*/ make fun open if (messageIds.isEmpty()) { return emptyList() } @@ -769,11 +770,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return results } - @TeleMessageUnfinalize - open fun insertCallLog(recipientId: RecipientId, type: Long, timestamp: Long, outgoing: Boolean): InsertResult { - val unread = MessageTypes.isMissedAudioCall(type) || MessageTypes.isMissedVideoCall(type) + open fun insertCallLog(recipientId: RecipientId, type: Long, timestamp: Long, outgoing: Boolean): InsertResult {//*TM_SA*/ make fun open val recipient = Recipient.resolved(recipientId) - val threadId = threads.getOrCreateThreadIdFor(recipient) + val threadIdResult = threads.getOrCreateThreadIdResultFor(recipient.id, recipient.isGroup) + val threadId = threadIdResult.threadId val values = contentValuesOf( FROM_RECIPIENT_ID to if (outgoing) Recipient.self().id.serialize() else recipientId.serialize(), @@ -781,51 +781,43 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat TO_RECIPIENT_ID to if (outgoing) recipientId.serialize() else Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to timestamp, - READ to if (unread) 0 else 1, + READ to 1, TYPE to type, THREAD_ID to threadId ) val messageId = writableDatabase.insert(TABLE_NAME, null, values) - if (unread) { - threads.incrementUnread(threadId, 1, 0) - } - threads.update(threadId, true) notifyConversationListeners(threadId) TrimThreadJob.enqueueAsync(threadId) - return InsertResult(messageId, threadId) + return InsertResult( + messageId = messageId, + threadId = threadId, + threadWasNewlyCreated = threadIdResult.newlyCreated + ) } - @TeleMessageUnfinalize - open fun updateCallLog(messageId: Long, type: Long) { - val unread = MessageTypes.isMissedAudioCall(type) || MessageTypes.isMissedVideoCall(type) - + open fun updateCallLog(messageId: Long, type: Long) {//*TM_SA*/ make fun open writableDatabase .update(TABLE_NAME) .values( TYPE to type, - READ to if (unread) 0 else 1 + READ to 1 ) .where("$ID = ?", messageId) .run() val threadId = getThreadIdForMessage(messageId) - if (unread) { - threads.incrementUnread(threadId, 1, 0) - } - threads.update(threadId, true) notifyConversationListeners(threadId) ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(MessageId(messageId)) } - @TeleMessageUnfinalize open fun insertGroupCall( groupRecipientId: RecipientId, sender: RecipientId, @@ -833,7 +825,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat eraId: String, joinedUuids: Collection, isCallFull: Boolean - ): MessageId { + ): MessageId {//*TM_SA*/ make fun open val recipient = Recipient.resolved(groupRecipientId) val threadId = threads.getOrCreateThreadIdFor(recipient) val messageId: MessageId = writableDatabase.withinTransaction { db -> @@ -897,8 +889,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - @TeleMessageUnfinalize - open fun updateGroupCall( + open fun updateGroupCall(//*TM_SA*/ make fun open messageId: Long, eraId: String, joinedUuids: Collection, @@ -976,8 +967,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - @TeleMessageUnfinalize - open fun insertEditMessageInbox(mediaMessage: IncomingMessage, targetMessage: MmsMessageRecord): Optional { + open fun insertEditMessageInbox(mediaMessage: IncomingMessage, targetMessage: MmsMessageRecord): Optional {//*TM_SA*/ make fun open val insertResult = insertMessageInbox(retrieved = mediaMessage, editedMessage = targetMessage, notifyObservers = false) if (insertResult.isPresent) { @@ -1003,8 +993,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun insertProfileNameChangeMessages(recipient: Recipient, newProfileName: String, previousProfileName: String) { writableDatabase.withinTransaction { db -> val groupRecords = groups.getGroupsContainingMember(recipient.id, false) - val profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = previousProfileName, newValue = newProfileName)) - .encode() + + val extras = MessageExtras( + profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = previousProfileName, newValue = newProfileName)) + ) val threadIdsToUpdate = mutableListOf().apply { add(threads.getThreadIdFor(recipient.id)) @@ -1027,7 +1019,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat READ to 1, TYPE to MessageTypes.PROFILE_CHANGE_TYPE, THREAD_ID to threadId, - BODY to Base64.encodeWithPadding(profileChangeDetails) + MESSAGE_EXTRAS to extras.encode() ) db.insert(TABLE_NAME, null, values) notifyConversationListeners(threadId) @@ -1036,6 +1028,33 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } + fun insertLearnedProfileNameChangeMessage(recipient: Recipient, previousDisplayName: String) { + val threadId: Long? = SignalDatabase.threads.getThreadIdFor(recipient.id) + + if (threadId != null) { + val extras = MessageExtras( + profileChangeDetails = ProfileChangeDetails(learnedProfileName = ProfileChangeDetails.StringChange(previous = previousDisplayName)) + ) + + writableDatabase + .insertInto(TABLE_NAME) + .values( + FROM_RECIPIENT_ID to recipient.id.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), + DATE_RECEIVED to System.currentTimeMillis(), + DATE_SENT to System.currentTimeMillis(), + READ to 1, + TYPE to MessageTypes.PROFILE_CHANGE_TYPE, + THREAD_ID to threadId, + MESSAGE_EXTRAS to extras.encode() + ) + .run() + + notifyConversationListeners(threadId) + } + } + fun insertGroupV1MigrationEvents(recipientId: RecipientId, threadId: Long, membershipChange: GroupMigrationMembershipChange) { insertGroupV1MigrationNotification(recipientId, threadId) if (!membershipChange.isEmpty) { @@ -1141,7 +1160,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } fun insertSessionSwitchoverEvent(recipientId: RecipientId, threadId: Long, event: SessionSwitchoverEvent) { - check(!FeatureFlags.blockSessionSwitchoverEvents()) { "Should not occur in a non-PNP world!" } writableDatabase .insertInto(TABLE_NAME) .values( @@ -1278,7 +1296,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return MmsReader(rawQueryWithAttachments(query, args, false, limit.toLong())) } - fun getUnreadMisedCallCount(): Long { + fun getUnreadMissedCallCount(): Long { return readableDatabase .select("COUNT(*)") .from(TABLE_NAME) @@ -1670,7 +1688,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val query = meaningfulQuery and isNotJoinedType val hasMeaningfulMessages = readableDatabase - .exists(TABLE_NAME) + .exists("$TABLE_NAME INDEXED BY $INDEX_THREAD_STORY_SCHEDULED_DATE_LATEST_REVISION_ID") .where(query.where, query.whereArgs) .run() @@ -1684,7 +1702,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val query = buildMeaningfulMessagesQuery(threadId) return readableDatabase - .exists(TABLE_NAME) + .exists("$TABLE_NAME INDEXED BY $INDEX_THREAD_STORY_SCHEDULED_DATE_LATEST_REVISION_ID") .where(query.where, query.whereArgs) .run() } @@ -1701,7 +1719,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return readableDatabase .select(ID, HAS_DELIVERY_RECEIPT, HAS_READ_RECEIPT, TYPE) - .from(TABLE_NAME) + .from("$TABLE_NAME INDEXED BY $INDEX_THREAD_STORY_SCHEDULED_DATE_LATEST_REVISION_ID") .where(query.where, query.whereArgs) .orderBy("$DATE_RECEIVED DESC") .limit(1) @@ -1725,7 +1743,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat private fun buildMeaningfulMessagesQuery(threadId: Long): SqlUtil.Query { val query = """ - $THREAD_ID = ? AND + $THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $LATEST_REVISION_ID IS NULL AND $PARENT_STORY_ID <= 0 AND @@ -1735,11 +1753,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat $TYPE != ${MessageTypes.CHANGE_NUMBER_TYPE} AND $TYPE != ${MessageTypes.SMS_EXPORT_TYPE} AND $TYPE != ${MessageTypes.BOOST_REQUEST_TYPE} AND - $TYPE & ${MessageTypes.GROUP_V2_LEAVE_BITS} != ${MessageTypes.GROUP_V2_LEAVE_BITS} + $TYPE & ${MessageTypes.GROUP_V2_LEAVE_BITS} != ${MessageTypes.GROUP_V2_LEAVE_BITS} AND + $TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} != ${MessageTypes.SPECIAL_TYPE_REPORTED_SPAM} AND + $TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} != ${MessageTypes.SPECIAL_TYPE_MESSAGE_REQUEST_ACCEPTED} ) """ - return SqlUtil.buildQuery(query, threadId) + return SqlUtil.buildQuery(query) } fun setNetworkFailures(messageId: Long, failures: Set?) { @@ -1759,29 +1779,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .readToSingleLong(-1) } - private fun getThreadIdFor(retrieved: IncomingMessage): Long { + private fun getThreadIdFor(retrieved: IncomingMessage): ThreadTable.ThreadIdResult { return if (retrieved.groupId != null) { val groupRecipientId = recipients.getOrInsertFromPossiblyMigratedGroupId(retrieved.groupId) val groupRecipients = Recipient.resolved(groupRecipientId) - threads.getOrCreateThreadIdFor(groupRecipients) + threads.getOrCreateThreadIdResultFor(groupRecipients.id, isGroup = true) } else { val sender = Recipient.resolved(retrieved.from) - threads.getOrCreateThreadIdFor(sender) + threads.getOrCreateThreadIdResultFor(sender.id, isGroup = false) } } - private fun getThreadIdFor(notification: NotificationInd): Long { - val fromString = if (notification.from != null && notification.from.textString != null) { - Util.toIsoString(notification.from.textString) - } else { - "" - } - - val recipient = Recipient.external(context, fromString) - return threads.getOrCreateThreadIdFor(recipient) - } - - fun rawQueryWithAttachments(where: String, arguments: Array?, reverse: Boolean = false, limit: Long = 0): Cursor { + private fun rawQueryWithAttachments(where: String, arguments: Array?, reverse: Boolean = false, limit: Long = 0): Cursor { return rawQueryWithAttachments(MMS_PROJECTION_WITH_ATTACHMENTS, where, arguments, reverse, limit) } @@ -1880,8 +1889,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - @TeleMessageUnfinalize - open fun markAsOutbox(messageId: Long) { + open fun markAsOutbox(messageId: Long) {//*TM_SA*/ make fun open val threadId = getThreadIdForMessage(messageId) updateMailboxBitmask(messageId, MessageTypes.BASE_TYPE_MASK, MessageTypes.BASE_OUTBOX_TYPE, Optional.of(threadId)) } @@ -1913,24 +1921,21 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(MessageId(messageId)) } - @TeleMessageUnfinalize - open fun markAsSending(messageId: Long) { + open fun markAsSending(messageId: Long) {//*TM_SA*/ make fun open val threadId = getThreadIdForMessage(messageId) updateMailboxBitmask(messageId, MessageTypes.BASE_TYPE_MASK, MessageTypes.BASE_SENDING_TYPE, Optional.of(threadId)) ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(MessageId(messageId)) ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners() } - @TeleMessageUnfinalize - open fun markAsSentFailed(messageId: Long) { + open fun markAsSentFailed(messageId: Long) {//*TM_SA*/ make fun open val threadId = getThreadIdForMessage(messageId) updateMailboxBitmask(messageId, MessageTypes.BASE_TYPE_MASK, MessageTypes.BASE_SENT_FAILED_TYPE, Optional.of(threadId)) ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(MessageId(messageId)) ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners() } - @TeleMessageUnfinalize - open fun markAsSent(messageId: Long, secure: Boolean) { + open fun markAsSent(messageId: Long, secure: Boolean) {//*TM_SA*/ make fun open val threadId = getThreadIdForMessage(messageId) updateMailboxBitmask(messageId, MessageTypes.BASE_TYPE_MASK, MessageTypes.BASE_SENT_TYPE or if (secure) MessageTypes.PUSH_MESSAGE_BIT or MessageTypes.SECURE_MESSAGE_BIT else 0, Optional.of(threadId)) ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(MessageId(messageId)) @@ -1963,8 +1968,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat markAsRemoteDelete(targetMessage) } - @TeleMessageUnfinalize - protected open fun markAsRemoteDeleteInternal(messageId: Long) { + protected open fun markAsRemoteDeleteInternal(messageId: Long) {//*TM_SA*/ make fun protected open var deletedAttachments = false writableDatabase.withinTransaction { db -> db.update(TABLE_NAME) @@ -2003,8 +2007,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - @TeleMessageUnfinalize - open fun markDownloadState(messageId: Long, state: Long) { + open fun markDownloadState(messageId: Long, state: Long) {//*TM_SA*/ make fun open writableDatabase .update(TABLE_NAME) .values(MMS_STATUS to state) @@ -2202,8 +2205,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return setMessagesRead("$STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND ($READ = 0 OR ($REACTIONS_UNREAD = 1 AND ($outgoingTypeClause)))", null) } - @TeleMessageUnfinalize - protected open fun setMessagesRead(where: String, arguments: Array?): List { + protected open fun setMessagesRead(where: String, arguments: Array?): List {//*TM_SA*/ make fun protected open val releaseChannelId = SignalStore.releaseChannelValues().releaseChannelRecipientId return writableDatabase.rawQuery( """ @@ -2315,6 +2317,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val parentStoryId = ParentStoryId.deserialize(cursor.requireLong(PARENT_STORY_ID)) val messageRangesData = cursor.requireBlob(MESSAGE_RANGES) val scheduledDate = cursor.requireLong(SCHEDULED_DATE) + val messageExtrasBytes = cursor.requireBlob(MESSAGE_EXTRAS) + val messageExtras = if (messageExtrasBytes != null) MessageExtras.ADAPTER.decode(messageExtrasBytes) else null val quoteId = cursor.requireLong(QUOTE_ID) val quoteAuthor = cursor.requireLong(QUOTE_AUTHOR) @@ -2367,7 +2371,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat if (body != null && (MessageTypes.isGroupQuit(outboxType) || MessageTypes.isGroupUpdate(outboxType))) { OutgoingMessage.groupUpdateMessage( threadRecipient = threadRecipient, - groupContext = MessageGroupContext(body, MessageTypes.isGroupV2(outboxType)), + groupContext = if (messageExtras != null) MessageGroupContext(messageExtras, MessageTypes.isGroupV2(outboxType)) else MessageGroupContext(body, MessageTypes.isGroupV2(outboxType)), avatar = attachments, sentTimeMillis = timestamp, expiresIn = 0, @@ -2402,6 +2406,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat sentTimeMillis = timestamp, expiresIn = expiresIn ) + } else if (MessageTypes.isReportedSpam(outboxType)) { + OutgoingMessage.reportSpamMessage( + threadRecipient = threadRecipient, + sentTimeMillis = timestamp, + expiresIn = expiresIn + ) + } else if (MessageTypes.isMessageRequestAccepted(outboxType)) { + OutgoingMessage.messageRequestAcceptMessage( + threadRecipient = threadRecipient, + sentTimeMillis = timestamp, + expiresIn = expiresIn + ) } else { val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(outboxType)) { GiftBadge.ADAPTER.decode(Base64.decode(body)) @@ -2451,8 +2467,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat @JvmOverloads @Throws(MmsException::class) - @TeleMessageUnfinalize - open fun insertMessageInbox( + open fun insertMessageInbox(//*TM_SA*/ make fun open retrieved: IncomingMessage, candidateThreadId: Long = -1, editedMessage: MmsMessageRecord? = null, @@ -2460,11 +2475,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ): Optional { val type = retrieved.toMessageType() - val threadId = if (candidateThreadId == -1L || retrieved.isGroupMessage) { + val threadIdResult = if (candidateThreadId == -1L || retrieved.isGroupMessage) { getThreadIdFor(retrieved) } else { - candidateThreadId + ThreadTable.ThreadIdResult(threadId = candidateThreadId, newlyCreated = false) } + val threadId = threadIdResult.threadId if (retrieved.type == MessageType.GROUP_UPDATE && retrieved.groupContext?.let { GroupV2UpdateMessageUtil.isJoinRequestCancel(it) } == true) { val result = collapseJoinRequestEventsIfPossible(threadId, retrieved) @@ -2487,7 +2503,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat FROM_RECIPIENT_ID to retrieved.from.serialize(), TO_RECIPIENT_ID to Recipient.self().id.serialize(), TYPE to type, - MMS_MESSAGE_TYPE to PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF, THREAD_ID to threadId, MMS_STATUS to MmsStatus.DOWNLOAD_INITIALIZED, DATE_RECEIVED to retrieved.receivedTimeMillis, @@ -2501,7 +2516,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat SERVER_GUID to retrieved.serverGuid, LATEST_REVISION_ID to null, ORIGINAL_MESSAGE_ID to editedMessage?.getOriginalOrOwnMessageId()?.id, - REVISION_NUMBER to (editedMessage?.revisionNumber?.inc() ?: 0) + REVISION_NUMBER to (editedMessage?.revisionNumber?.inc() ?: 0), + MESSAGE_EXTRAS to (retrieved.messageExtras?.encode()) ) val quoteAttachments: MutableList = mutableListOf() @@ -2567,7 +2583,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val isNotStoryGroupReply = retrieved.parentStoryId == null || !retrieved.parentStoryId.isGroupReply() - if (!MessageTypes.isPaymentsActivated(type) && !MessageTypes.isPaymentsRequestToActivate(type) && !MessageTypes.isExpirationTimerUpdate(type) && !retrieved.storyType.isStory && isNotStoryGroupReply && !silent) { + if (!MessageTypes.isPaymentsActivated(type) && + !MessageTypes.isPaymentsRequestToActivate(type) && + !MessageTypes.isReportedSpam(type) && + !MessageTypes.isMessageRequestAccepted(type) && + !MessageTypes.isExpirationTimerUpdate(type) && + !retrieved.storyType.isStory && + isNotStoryGroupReply && + !silent + ) { val incrementUnreadMentions = retrieved.mentions.isNotEmpty() && retrieved.mentions.any { it.recipientId == Recipient.self().id } threads.incrementUnread(threadId, 1, if (incrementUnreadMentions) 1 else 0) ThreadUpdateJob.enqueue(threadId) @@ -2581,11 +2605,20 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ApplicationDependencies.getDatabaseObserver().notifyStoryObservers(threads.getRecipientIdForThreadId(threadId)!!) } - return Optional.of(InsertResult(messageId, threadId, insertedAttachments = insertedAttachments)) + return Optional.of( + InsertResult( + messageId = messageId, + threadId = threadId, + threadWasNewlyCreated = threadIdResult.newlyCreated, + insertedAttachments = insertedAttachments + ) + ) } fun insertChatSessionRefreshedMessage(recipientId: RecipientId, senderDeviceId: Long, sentTimestamp: Long): InsertResult { - val threadId = threads.getOrCreateThreadIdFor(Recipient.resolved(recipientId)) + val recipient = Recipient.resolved(recipientId) + val threadIdResult = threads.getOrCreateThreadIdResultFor(recipient.id, recipient.isGroup) + val threadId = threadIdResult.threadId var type = MessageTypes.SECURE_MESSAGE_BIT or MessageTypes.PUSH_MESSAGE_BIT type = type and MessageTypes.TOTAL_MASK - MessageTypes.ENCRYPTION_MASK or MessageTypes.ENCRYPTION_REMOTE_FAILED_BIT @@ -2611,7 +2644,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat notifyConversationListeners(threadId) TrimThreadJob.enqueueAsync(threadId) - return InsertResult(messageId, threadId) + return InsertResult( + messageId = messageId, + threadId = threadId, + threadWasNewlyCreated = threadIdResult.newlyCreated + ) } fun insertBadDecryptMessage(recipientId: RecipientId, senderDevice: Int, sentTimestamp: Long, receivedTimestamp: Long, threadId: Long) { @@ -2637,17 +2674,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat TrimThreadJob.enqueueAsync(threadId) } - fun markIncomingNotificationReceived(threadId: Long) { - notifyConversationListeners(threadId) - - if (Util.isDefaultSmsProvider(context)) { - threads.incrementUnread(threadId, 1, 0) - } - - threads.update(threadId, true) - TrimThreadJob.enqueueAsync(threadId) - } - fun markGiftRedemptionCompleted(messageId: Long) { markGiftRedemptionState(messageId, GiftBadge.RedemptionState.REDEEMED) } @@ -2696,25 +2722,24 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat message: OutgoingMessage, threadId: Long, forceSms: Boolean, - insertListener: InsertListener?, + insertListener: InsertListener? ): Long { return insertMessageOutbox( message = message, threadId = threadId, forceSms = forceSms, defaultReceiptStatus = GroupReceiptTable.STATUS_UNDELIVERED, - insertListener = insertListener, + insertListener = insertListener ) } @Throws(MmsException::class) - @TeleMessageUnfinalize - open fun insertMessageOutbox( + open fun insertMessageOutbox(//*TM_SA*/ make fun open message: OutgoingMessage, threadId: Long, forceSms: Boolean, defaultReceiptStatus: Int, - insertListener: InsertListener?, + insertListener: InsertListener? ): Long { var type = MessageTypes.BASE_SENDING_TYPE var hasSpecialType = false @@ -2798,6 +2823,22 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat hasSpecialType = true } + if (message.isReportSpam) { + if (hasSpecialType) { + throw MmsException("Cannot insert message with multiple special types.") + } + type = type or MessageTypes.SPECIAL_TYPE_REPORTED_SPAM + hasSpecialType = true + } + + if (message.isMessageRequestAccept) { + if (hasSpecialType) { + throw MmsException("Cannot insert message with multiple special types.") + } + type = type or MessageTypes.SPECIAL_TYPE_MESSAGE_REQUEST_ACCEPTED + hasSpecialType = true + } + val earlyDeliveryReceipts: Map = earlyDeliveryReceiptCache.remove(message.sentTimeMillis) if (earlyDeliveryReceipts.isNotEmpty()) { @@ -2818,7 +2859,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val contentValues = ContentValues() contentValues.put(DATE_SENT, message.sentTimeMillis) - contentValues.put(MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ) contentValues.put(TYPE, type) contentValues.put(THREAD_ID, threadId) contentValues.put(READ, 1) @@ -2835,6 +2875,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat contentValues.put(PARENT_STORY_ID, if (message.parentStoryId != null) message.parentStoryId.serialize() else 0) contentValues.put(SCHEDULED_DATE, message.scheduledDate) contentValues.putNull(LATEST_REVISION_ID) + contentValues.put(MESSAGE_EXTRAS, message.messageExtras?.encode()) if (editedMessage != null) { contentValues.put(ORIGINAL_MESSAGE_ID, editedMessage.getOriginalOrOwnMessageId().id) @@ -2961,11 +3002,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ApplicationDependencies.getDatabaseObserver().notifyStoryObservers(message.threadRecipient.id) } - notifyConversationListListeners() - if (!message.isIdentityVerified && !message.isIdentityDefault) { - TrimThreadJob.enqueueAsync(threadId) + ThreadUpdateJob.enqueue(threadId) } + + TrimThreadJob.enqueueAsync(threadId) + return messageId } @@ -3117,8 +3159,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return deleteMessage(messageId, threadId) } - @TeleMessageUnfinalize - protected open fun deleteMessage(messageId: Long, threadId: Long = getThreadIdForMessage(messageId), notify: Boolean = true, updateThread: Boolean = true): Boolean { + protected open fun deleteMessage(messageId: Long, threadId: Long = getThreadIdForMessage(messageId), notify: Boolean = true, updateThread: Boolean = true): Boolean {//*TM_SA*/ make fun protected open Log.d(TAG, "deleteMessage($messageId)") attachments.deleteAttachmentsForMessage(messageId) @@ -3409,7 +3450,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat attachments.deleteAllAttachments() groupReceipts.deleteAllRows() mentions.deleteAllMentions() - writableDatabase.delete(TABLE_NAME).run() + writableDatabase.deleteAll(TABLE_NAME) calls.updateCallEventDeletionTimestamps() OptimizeMessageSearchIndexJob.enqueue() @@ -3506,7 +3547,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .where("$ID = ?", id) .run() - result = InsertResult(id, threadId) + result = InsertResult( + messageId = id, + threadId = threadId, + threadWasNewlyCreated = false + ) } } } @@ -3549,6 +3594,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .run() } + fun hasReportSpamMessage(threadId: Long): Boolean { + return readableDatabase + .exists(TABLE_NAME) + .where("$THREAD_ID = $threadId AND ($TYPE & ${MessageTypes.SPECIAL_TYPES_MASK}) = ${MessageTypes.SPECIAL_TYPE_REPORTED_SPAM}") + .run() + } + private val outgoingInsecureMessageClause = "($TYPE & ${MessageTypes.BASE_TYPE_MASK}) = ${MessageTypes.BASE_SENT_TYPE} AND NOT ($TYPE & ${MessageTypes.SECURE_MESSAGE_BIT})" private val outgoingSecureMessageClause = "($TYPE & ${MessageTypes.BASE_TYPE_MASK}) = ${MessageTypes.BASE_SENT_TYPE} AND ($TYPE & ${MessageTypes.SECURE_MESSAGE_BIT or MessageTypes.PUSH_MESSAGE_BIT})" @@ -4027,6 +4079,33 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .take(limit) } + fun getGroupReportSpamMessageServerData(threadId: Long, inviter: RecipientId, timestamp: Long, limit: Int): List { + val data: MutableList = ArrayList() + + val incomingGroupUpdateClause = "($TYPE & ${MessageTypes.BASE_TYPE_MASK}) = ${MessageTypes.BASE_INBOX_TYPE} AND ($TYPE & ${MessageTypes.GROUP_UPDATE_BIT}) != 0" + + readableDatabase + .select(FROM_RECIPIENT_ID, SERVER_GUID, DATE_RECEIVED) + .from(TABLE_NAME) + .where("$FROM_RECIPIENT_ID = ? AND $THREAD_ID = ? AND $DATE_RECEIVED <= ? AND $incomingGroupUpdateClause", inviter, threadId, timestamp) + .orderBy("$DATE_RECEIVED DESC") + .limit(limit) + .run() + .forEach { cursor -> + val serverGuid: String? = cursor.requireString(SERVER_GUID) + + if (serverGuid != null && serverGuid.isNotEmpty()) { + data += ReportSpamData( + recipientId = RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)), + serverGuid = serverGuid, + dateReceived = cursor.requireLong(DATE_RECEIVED) + ) + } + } + + return data + } + @Throws(NoSuchMessageException::class) private fun getMessageExportState(messageId: MessageId): MessageExportState { return readableDatabase @@ -4211,8 +4290,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return missingTargetTimestamps } - @TeleMessageUnfinalize - protected open fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier, stopwatch: Stopwatch? = null): Set { + protected open fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier, stopwatch: Stopwatch? = null): Set {//*TM_SA*/ make fun protected open val qualifierWhere: String = when (messageQualifier) { MessageQualifier.NORMAL -> " AND NOT ($IS_STORY_CLAUSE)" MessageQualifier.STORY -> " AND $IS_STORY_CLAUSE" @@ -4300,17 +4378,17 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat /** * @return Unhandled ids */ - fun setTimestampReadFromSyncMessage(readMessages: List, proposedExpireStarted: Long, threadToLatestRead: MutableMap): Collection { + fun setTimestampReadFromSyncMessage(readMessages: List, proposedExpireStarted: Long, threadToLatestRead: MutableMap): Collection { val expiringMessages: MutableList> = mutableListOf() val updatedThreads: MutableSet = mutableSetOf() val unhandled: MutableCollection = mutableListOf() writableDatabase.withinTransaction { for (readMessage in readMessages) { - val authorId: RecipientId = recipients.getOrInsertFromServiceId(readMessage.sender) + val authorId: RecipientId = recipients.getOrInsertFromServiceId(ServiceId.parseOrThrow(readMessage.senderAci!!)) val result: TimestampReadResult = setTimestampReadFromSyncMessageInternal( - messageId = SyncMessageId(authorId, readMessage.timestamp), + messageId = SyncMessageId(authorId, readMessage.timestamp!!), proposedExpireStarted = proposedExpireStarted, threadToLatestRead = threadToLatestRead ) @@ -4319,7 +4397,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat updatedThreads += result.threads if (result.threads.isEmpty()) { - unhandled += SyncMessageId(authorId, readMessage.timestamp) + unhandled += SyncMessageId(authorId, readMessage.timestamp!!) } } @@ -4340,12 +4418,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return unhandled } - fun setTimestampReadFromSyncMessageProto(readMessages: List, proposedExpireStarted: Long, threadToLatestRead: MutableMap): Collection { - val reads: List = readMessages.map { r -> ReadMessage(ServiceId.parseOrThrow(r.senderAci!!), r.timestamp!!) } - - return setTimestampReadFromSyncMessage(reads, proposedExpireStarted, threadToLatestRead) - } - /** * Handles a synchronized read message. * @param messageId An id representing the author-timestamp pair of the message that was read on a linked device. Note that the author could be self when @@ -4767,6 +4839,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return type } + fun threadContainsSms(threadId: Long): Boolean { + return readableDatabase + .exists(TABLE_NAME) + .where(getInsecureMessageClause(threadId)) + .run() + } + protected enum class ReceiptType(val columnName: String, val groupStatus: Int) { READ(HAS_READ_RECEIPT, GroupReceiptTable.STATUS_READ), DELIVERY(HAS_DELIVERY_RECEIPT, GroupReceiptTable.STATUS_DELIVERED), @@ -4814,16 +4893,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat data class InsertResult( val messageId: Long, val threadId: Long, + val threadWasNewlyCreated: Boolean, val insertedAttachments: Map? = null ) - data class MmsNotificationInfo( - val from: RecipientId, - val contentLocation: String, - val transactionId: String, - val subscriptionId: Int - ) - data class MessageReceiptUpdate( val threadId: Long, val messageId: MessageId, @@ -4941,8 +5014,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } override fun getCurrent(): MessageRecord { - val mmsType = cursor.requireLong(MMS_MESSAGE_TYPE) - return getMediaMmsMessageRecord(cursor) } @@ -5004,6 +5075,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val originalMessageId: MessageId? = cursor.requireLong(ORIGINAL_MESSAGE_ID).let { if (it == 0L) null else MessageId(it) } val editCount = cursor.requireInt(REVISION_NUMBER) val isRead = cursor.requireBoolean(READ) + val messageExtraBytes = cursor.requireBlob(MESSAGE_EXTRAS) + val messageExtras = messageExtraBytes?.let { MessageExtras.ADAPTER.decode(it) } if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { hasReadReceipt = false @@ -5091,7 +5164,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat latestRevisionId, originalMessageId, editCount, - isRead + isRead, + messageExtras ) } diff --git a/app/src/main/java/org/tm/archive/database/MessageTypes.java b/app/src/main/java/org/tm/archive/database/MessageTypes.java index 959e19bd..b4b06f98 100644 --- a/app/src/main/java/org/tm/archive/database/MessageTypes.java +++ b/app/src/main/java/org/tm/archive/database/MessageTypes.java @@ -113,6 +113,8 @@ public interface MessageTypes { long SPECIAL_TYPE_GIFT_BADGE = 0x200000000L; long SPECIAL_TYPE_PAYMENTS_NOTIFICATION = 0x300000000L; long SPECIAL_TYPE_PAYMENTS_ACTIVATE_REQUEST = 0x400000000L; + long SPECIAL_TYPE_REPORTED_SPAM = 0x500000000L; + long SPECIAL_TYPE_MESSAGE_REQUEST_ACCEPTED = 0x600000000L; long SPECIAL_TYPE_PAYMENTS_ACTIVATED = 0x800000000L; long IGNORABLE_TYPESMASK_WHEN_COUNTING = END_SESSION_BIT | KEY_EXCHANGE_IDENTITY_UPDATE_BIT | KEY_EXCHANGE_IDENTITY_VERIFIED_BIT; @@ -137,6 +139,14 @@ public interface MessageTypes { return (type & SPECIAL_TYPES_MASK) == SPECIAL_TYPE_PAYMENTS_ACTIVATED; } + static boolean isReportedSpam(long type) { + return (type & SPECIAL_TYPES_MASK) == SPECIAL_TYPE_REPORTED_SPAM; + } + + static boolean isMessageRequestAccepted(long type) { + return (type & SPECIAL_TYPES_MASK) == SPECIAL_TYPE_MESSAGE_REQUEST_ACCEPTED; + } + static boolean isDraftMessageType(long type) { return (type & BASE_TYPE_MASK) == BASE_DRAFT_TYPE; } diff --git a/app/src/main/java/org/tm/archive/database/OneTimePreKeyTable.kt b/app/src/main/java/org/tm/archive/database/OneTimePreKeyTable.kt index 56c87131..a9c0f91a 100644 --- a/app/src/main/java/org/tm/archive/database/OneTimePreKeyTable.kt +++ b/app/src/main/java/org/tm/archive/database/OneTimePreKeyTable.kt @@ -5,6 +5,7 @@ import androidx.core.content.contentValuesOf import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.requireNonNullString import org.signal.core.util.update @@ -31,17 +32,19 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $ACCOUNT_ID TEXT NOT NULL, - $KEY_ID INTEGER UNIQUE, + $KEY_ID INTEGER NOT NULL, $PUBLIC_KEY TEXT NOT NULL, $PRIVATE_KEY TEXT NOT NULL, $STALE_TIMESTAMP INTEGER NOT NULL DEFAULT 0, UNIQUE($ACCOUNT_ID, $KEY_ID) ) """ + + const val PNI_ACCOUNT_ID = "PNI" } fun get(serviceId: ServiceId, keyId: Int): PreKeyRecord? { - readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId), null, null, null).use { cursor -> + readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId), null, null, null).use { cursor -> if (cursor.moveToFirst()) { try { val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0) @@ -60,7 +63,7 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat fun insert(serviceId: ServiceId, keyId: Int, record: PreKeyRecord) { val contentValues = contentValuesOf( - ACCOUNT_ID to serviceId.toString(), + ACCOUNT_ID to serviceId.toAccountId(), KEY_ID to keyId, PUBLIC_KEY to Base64.encodeWithPadding(record.keyPair.publicKey.serialize()), PRIVATE_KEY to Base64.encodeWithPadding(record.keyPair.privateKey.serialize()) @@ -71,14 +74,14 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat fun delete(serviceId: ServiceId, keyId: Int) { val database = databaseHelper.signalWritableDatabase - database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId)) + database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId)) } fun markAllStaleIfNecessary(serviceId: ServiceId, staleTime: Long) { writableDatabase .update(TABLE_NAME) .values(STALE_TIMESTAMP to staleTime) - .where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0", serviceId) + .where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0", serviceId.toAccountId()) .run() } @@ -105,11 +108,22 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat LIMIT $minCount ) """, - serviceId, - serviceId + serviceId.toAccountId(), + serviceId.toAccountId() ) .run() Log.i(TAG, "Deleted $count stale one-time EC prekeys.") } + + fun debugDeleteAll() { + writableDatabase.deleteAll(TABLE_NAME) + } + + private fun ServiceId.toAccountId(): String { + return when (this) { + is ServiceId.ACI -> this.toString() + is ServiceId.PNI -> PNI_ACCOUNT_ID + } + } } diff --git a/app/src/main/java/org/tm/archive/database/PendingPniSignatureMessageTable.kt b/app/src/main/java/org/tm/archive/database/PendingPniSignatureMessageTable.kt index 6f692e7a..56430325 100644 --- a/app/src/main/java/org/tm/archive/database/PendingPniSignatureMessageTable.kt +++ b/app/src/main/java/org/tm/archive/database/PendingPniSignatureMessageTable.kt @@ -3,6 +3,7 @@ package org.tm.archive.database import android.content.Context import androidx.core.content.contentValuesOf import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.exists import org.signal.core.util.logging.Log import org.signal.core.util.update @@ -117,7 +118,7 @@ class PendingPniSignatureMessageTable(context: Context, databaseHelper: SignalDa * Deletes all record of pending PNI verification messages. Should only be called after the user changes their number. */ fun deleteAll() { - writableDatabase.delete(TABLE_NAME).run() + writableDatabase.deleteAll(TABLE_NAME) } override fun remapRecipient(oldId: RecipientId, newId: RecipientId) { diff --git a/app/src/main/java/org/tm/archive/database/RecipientTable.kt b/app/src/main/java/org/tm/archive/database/RecipientTable.kt index 4e2a3aa6..4acb0642 100644 --- a/app/src/main/java/org/tm/archive/database/RecipientTable.kt +++ b/app/src/main/java/org/tm/archive/database/RecipientTable.kt @@ -16,6 +16,7 @@ import org.signal.core.util.CursorUtil import org.signal.core.util.SqlUtil import org.signal.core.util.delete import org.signal.core.util.exists +import org.signal.core.util.forEach import org.signal.core.util.logging.Log import org.signal.core.util.nullIfBlank import org.signal.core.util.optionalString @@ -25,13 +26,16 @@ import org.signal.core.util.readToList import org.signal.core.util.readToSet import org.signal.core.util.readToSingleBoolean import org.signal.core.util.readToSingleLong +import org.signal.core.util.readToSingleObject import org.signal.core.util.requireBlob import org.signal.core.util.requireInt import org.signal.core.util.requireLong import org.signal.core.util.requireNonNullString import org.signal.core.util.requireString import org.signal.core.util.select +import org.signal.core.util.toInt import org.signal.core.util.update +import org.signal.core.util.updateAll import org.signal.core.util.withinTransaction import org.signal.libsignal.protocol.IdentityKey import org.signal.libsignal.protocol.InvalidKeyException @@ -42,6 +46,7 @@ import org.tm.archive.badges.Badges.toDatabaseBadge import org.tm.archive.badges.models.Badge import org.tm.archive.color.MaterialColor import org.tm.archive.color.MaterialColor.UnknownColorException +import org.tm.archive.contacts.paged.ContactSearchSortOrder import org.tm.archive.conversation.colors.AvatarColor import org.tm.archive.conversation.colors.AvatarColorHash import org.tm.archive.conversation.colors.ChatColors @@ -110,6 +115,7 @@ import java.util.LinkedList import java.util.Objects import java.util.Optional import java.util.concurrent.TimeUnit +import kotlin.jvm.optionals.getOrNull import kotlin.math.max open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable(context, databaseHelper) { @@ -178,6 +184,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da const val NEEDS_PNI_SIGNATURE = "needs_pni_signature" const val REPORTING_TOKEN = "reporting_token" const val PHONE_NUMBER_SHARING = "phone_number_sharing" + const val PHONE_NUMBER_DISCOVERABLE = "phone_number_discoverable" + const val PNI_SIGNATURE_VERIFIED = "pni_signature_verified" + const val NICKNAME_GIVEN_NAME = "nickname_given_name" + const val NICKNAME_FAMILY_NAME = "nickname_family_name" + const val NICKNAME_JOINED_NAME = "nickname_joined_name" + const val NOTE = "note" const val SEARCH_PROFILE_NAME = "search_signal_profile" const val SORT_NAME = "sort_name" @@ -244,7 +256,13 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da $BADGES BLOB DEFAULT NULL, $NEEDS_PNI_SIGNATURE INTEGER DEFAULT 0, $REPORTING_TOKEN BLOB DEFAULT NULL, - $PHONE_NUMBER_SHARING INTEGER DEFAULT ${PhoneNumberSharingState.UNKNOWN.id} + $PHONE_NUMBER_SHARING INTEGER DEFAULT ${PhoneNumberSharingState.UNKNOWN.id}, + $PHONE_NUMBER_DISCOVERABLE INTEGER DEFAULT ${PhoneNumberDiscoverableState.UNKNOWN.id}, + $PNI_SIGNATURE_VERIFIED INTEGER DEFAULT 0, + $NICKNAME_GIVEN_NAME TEXT DEFAULT NULL, + $NICKNAME_FAMILY_NAME TEXT DEFAULT NULL, + $NICKNAME_JOINED_NAME TEXT DEFAULT NULL, + $NOTE TEXT DEFAULT NULL ) """ @@ -304,7 +322,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da BADGES, NEEDS_PNI_SIGNATURE, REPORTING_TOKEN, - PHONE_NUMBER_SHARING + PHONE_NUMBER_SHARING, + NICKNAME_GIVEN_NAME, + NICKNAME_FAMILY_NAME, + NOTE ) private val ID_PROJECTION = arrayOf(ID) @@ -325,6 +346,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da """ LOWER( COALESCE( + NULLIF($NICKNAME_JOINED_NAME, ''), + NULLIF($NICKNAME_GIVEN_NAME, ''), NULLIF($SYSTEM_JOINED_NAME, ''), NULLIF($SYSTEM_GIVEN_NAME, ''), NULLIF($PROFILE_JOINED_NAME, ''), @@ -364,6 +387,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da """ REPLACE( COALESCE( + NULLIF($NICKNAME_JOINED_NAME, ''), + NULLIF($NICKNAME_GIVEN_NAME, ''), NULLIF($SYSTEM_JOINED_NAME, ''), NULLIF($SYSTEM_GIVEN_NAME, ''), NULLIF($PROFILE_JOINED_NAME, ''), @@ -383,12 +408,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da @JvmStatic fun maskCapabilitiesToLong(capabilities: SignalServiceProfile.Capabilities): Long { var value: Long = 0 - value = Bitmask.update(value, Capabilities.GROUPS_V1_MIGRATION, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isGv1Migration).serialize().toLong()) - value = Bitmask.update(value, Capabilities.SENDER_KEY, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isSenderKey).serialize().toLong()) - value = Bitmask.update(value, Capabilities.ANNOUNCEMENT_GROUPS, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isAnnouncementGroup).serialize().toLong()) - value = Bitmask.update(value, Capabilities.CHANGE_NUMBER, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isChangeNumber).serialize().toLong()) - value = Bitmask.update(value, Capabilities.STORIES, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isStories).serialize().toLong()) - value = Bitmask.update(value, Capabilities.GIFT_BADGES, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isGiftBadges).serialize().toLong()) value = Bitmask.update(value, Capabilities.PNP, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isPnp).serialize().toLong()) value = Bitmask.update(value, Capabilities.PAYMENT_ACTIVATION, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isPaymentActivation).serialize().toLong()) return value @@ -430,6 +449,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return readableDatabase.exists(TABLE_NAME).where("$ACI_COLUMN = ? AND $PNI_COLUMN = ?", serviceId.toString(), pni.toString()).run() } + fun getByE164IfRegisteredAndDiscoverable(e164: String): RecipientId? { + return readableDatabase + .select(ID) + .from(TABLE_NAME) + .where("$E164 = ? AND $REGISTERED = ${RegisteredState.REGISTERED.id} AND $PHONE_NUMBER_DISCOVERABLE = ${PhoneNumberDiscoverableState.DISCOVERABLE.id} AND ($PNI_COLUMN NOT NULL OR $ACI_COLUMN NOT NULL)", e164) + .run() + .readToSingleObject { RecipientId.from(it.requireLong(ID)) } + } + @JvmOverloads fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId { require(serviceId != null || e164 != null) { "Must provide an ACI or E164!" } @@ -823,7 +851,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val recipientId: RecipientId if (id < 0) { Log.w(TAG, "[applyStorageSyncContactInsert] Failed to insert. Possibly merging.") - recipientId = getAndPossiblyMergePnpVerified(insert.aci.orNull(), insert.pni.orNull(), insert.number.orNull()) + recipientId = getAndPossiblyMerge(aci = insert.aci.orNull(), pni = insert.pni.orNull(), e164 = insert.number.orNull(), pniVerified = insert.isPniSignatureVerified) db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId)) } else { recipientId = RecipientId.from(id) @@ -861,7 +889,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da var recipientId = getByColumn(STORAGE_SERVICE_ID, Base64.encodeWithPadding(update.old.id.raw)).get() Log.w(TAG, "[applyStorageSyncContactUpdate] Found user $recipientId. Possibly merging.") - recipientId = getAndPossiblyMergePnpVerified(update.new.aci.orElse(null), update.new.pni.orElse(null), update.new.number.orElse(null)) + recipientId = getAndPossiblyMerge(aci = update.new.aci.orElse(null), pni = update.new.pni.orElse(null), e164 = update.new.number.orElse(null), pniVerified = update.new.isPniSignatureVerified) Log.w(TAG, "[applyStorageSyncContactUpdate] Merged into $recipientId") db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId)) @@ -1107,6 +1135,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da SYSTEM_NICKNAME, "$TABLE_NAME.$STORAGE_SERVICE_PROTO", "$TABLE_NAME.$UNREGISTERED_TIMESTAMP", + "$TABLE_NAME.$PNI_SIGNATURE_VERIFIED", "${GroupTable.TABLE_NAME}.${GroupTable.V2_MASTER_KEY}", "${ThreadTable.TABLE_NAME}.${ThreadTable.ARCHIVED}", "${ThreadTable.TABLE_NAME}.${ThreadTable.READ}", @@ -1710,6 +1739,20 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } + fun setNicknameAndNote(id: RecipientId, nickname: ProfileName, note: String) { + val contentValues = contentValuesOf( + NICKNAME_GIVEN_NAME to nickname.givenName.nullIfBlank(), + NICKNAME_FAMILY_NAME to nickname.familyName.nullIfBlank(), + NICKNAME_JOINED_NAME to nickname.toString().nullIfBlank(), + NOTE to note.nullIfBlank() + ) + if (update(id, contentValues)) { + rotateStorageId(id) + ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id) + StorageSyncHelper.scheduleSyncForDataChange() + } + } + fun setProfileName(id: RecipientId, profileName: ProfileName) { val contentValues = ContentValues(1).apply { put(PROFILE_GIVEN_NAME, profileName.givenName.nullIfBlank()) @@ -1936,6 +1979,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return 0 } + fun getPhoneNumberDiscoverability(id: RecipientId): PhoneNumberDiscoverableState? { + return readableDatabase + .select(PHONE_NUMBER_DISCOVERABLE) + .from(TABLE_NAME) + .where("$ID = ?", id) + .run() + .readToSingleObject { PhoneNumberDiscoverableState.fromId(it.requireInt(PHONE_NUMBER_DISCOVERABLE)) } + } + /** * @return True if setting the phone number resulted in changed recipientId, otherwise false. */ @@ -2008,7 +2060,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da /** * Does *not* handle clearing the recipient cache. It is assumed the caller handles this. */ - fun updateSelfPhone(e164: String, pni: PNI) { + fun updateSelfE164(e164: String, pni: PNI) { val db = writableDatabase db.beginTransaction() @@ -2019,11 +2071,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da if (id == newId) { Log.i(TAG, "[updateSelfPhone] Phone updated for self") } else { - throw AssertionError("[updateSelfPhone] Self recipient id changed when updating phone. old: $id new: $newId") + throw AssertionError("[updateSelfPhone] Self recipient id changed when updating e164. old: $id new: $newId") } - db - .update(TABLE_NAME) + db.updateAll(TABLE_NAME) .values(NEEDS_PNI_SIGNATURE to 0) .run() @@ -2233,9 +2284,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da * Removes the target recipient's E164+PNI, then creates a new recipient with that E164+PNI. * Done so we can match a split contact during storage sync. */ - fun splitForStorageSync(storageId: ByteArray) { - val record = getByStorageId(storageId)!! - check(record.aci != null && record.pni != null) + fun splitForStorageSyncIfNecessary(aci: ACI) { + val recipientId = getByAci(aci).getOrNull() ?: return + val record = getRecord(recipientId) + + if (record.pni == null && record.e164 == null) { + return + } + + Log.i(TAG, "Splitting $recipientId for storage sync", true) writableDatabase .update(TABLE_NAME) @@ -2249,6 +2306,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da getAndPossiblyMerge(null, record.pni, record.e164) } + fun processIndividualCdsLookup(aci: ACI?, pni: PNI, e164: String): RecipientId { + return getAndPossiblyMerge(aci = aci, pni = pni, e164 = e164) + } + /** * Processes CDSv2 results, merging recipients as necessary. Does not mark users as * registered. @@ -2352,7 +2413,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } - val finalId: RecipientId = writePnpChangeSetToDisk(changeSet, pni) + val finalId: RecipientId = writePnpChangeSetToDisk(changeSet, pni, pniVerified) return ProcessPnpTupleResult( finalId = finalId, @@ -2366,7 +2427,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } @VisibleForTesting - fun writePnpChangeSetToDisk(changeSet: PnpChangeSet, inputPni: PNI?): RecipientId { + fun writePnpChangeSetToDisk(changeSet: PnpChangeSet, inputPni: PNI?, pniVerified: Boolean): RecipientId { var hadThreadMerge = false for (operation in changeSet.operations) { @Exhaustive @@ -2382,7 +2443,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da is PnpOperation.RemovePni -> { writableDatabase .update(TABLE_NAME) - .values(PNI_COLUMN to null) + .values( + PNI_COLUMN to null, + PNI_SIGNATURE_VERIFIED to 0 + ) .where("$ID = ?", operation.recipientId) .run() } @@ -2393,7 +2457,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .values( ACI_COLUMN to operation.aci.toString(), REGISTERED to RegisteredState.REGISTERED.id, - UNREGISTERED_TIMESTAMP to 0 + UNREGISTERED_TIMESTAMP to 0, + PNI_SIGNATURE_VERIFIED to pniVerified.toInt() ) .where("$ID = ?", operation.recipientId) .run() @@ -2413,14 +2478,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .values( PNI_COLUMN to operation.pni.toString(), REGISTERED to RegisteredState.REGISTERED.id, - UNREGISTERED_TIMESTAMP to 0 + UNREGISTERED_TIMESTAMP to 0, + PNI_SIGNATURE_VERIFIED to 0 ) .where("$ID = ?", operation.recipientId) .run() } is PnpOperation.Merge -> { - val mergeResult: MergeResult = merge(operation.primaryId, operation.secondaryId, inputPni) + val mergeResult: MergeResult = merge(operation.primaryId, operation.secondaryId, inputPni, pniVerified) hadThreadMerge = hadThreadMerge || mergeResult.neededThreadMerge } @@ -2434,14 +2500,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da try { SignalDatabase.messages.insertSessionSwitchoverEvent(operation.recipientId, threadId, event) } catch (e: Exception) { - Log.e(TAG, "About to crash! Breadcrumbs: ${changeSet.breadCrumbs}, Operations: ${changeSet.operations}, ID: ${changeSet.id}") + Log.e(TAG, "About to crash! Breadcrumbs: ${changeSet.breadCrumbs}, Operations: ${changeSet.operations}, ID: ${changeSet.id}", true) val allPnis: Set = getAllPnis() val pnisWithSessions: Set = sessions.findAllThatHaveAnySession(allPnis) - Log.e(TAG, "We know of ${allPnis.size} PNIs, and there are sessions with ${pnisWithSessions.size} of them.") + Log.e(TAG, "We know of ${allPnis.size} PNIs, and there are sessions with ${pnisWithSessions.size} of them.", true) val record = getRecord(operation.recipientId) - Log.e(TAG, "ID: ${record.id}, E164: ${record.e164}, ACI: ${record.aci}, PNI: ${record.pni}, Registered: ${record.registered}") + Log.e(TAG, "ID: ${record.id}, E164: ${record.e164}, ACI: ${record.aci}, PNI: ${record.pni}, Registered: ${record.registered}", true) if (record.aci != null && record.aci == SignalStore.account().aci) { if (pnisWithSessions.contains(SignalStore.account().pni!!)) { @@ -2499,7 +2565,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } is PnpIdResolver.PnpInsert -> { - val id: Long = writableDatabase.insert(TABLE_NAME, null, buildContentValuesForNewUser(changeSet.id.e164, changeSet.id.pni, changeSet.id.aci)) + val id: Long = writableDatabase.insert(TABLE_NAME, null, buildContentValuesForNewUser(changeSet.id.e164, changeSet.id.pni, changeSet.id.aci, pniVerified)) RecipientId.from(id) } } @@ -2915,16 +2981,18 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da primaryId = data.byAci, secondaryId = data.byPni ) - } else if (data.pniRecord.aci == null && data.pniRecord.e164 == data.e164) { - // The PNI record also has the E164 on it with no ACI. We're going to be stealing all of it's fields, + } else if (data.pniRecord.aci == null && (data.e164 == null || data.pniRecord.e164 == data.e164)) { + // The PNI has no ACI and possibly some e164. We're going to be stealing all of it's fields, // so this is basically a merge with a little bit of extra prep. - breadCrumbs += "PniRecordHasMatchingE164AndNoAci" + breadCrumbs += "PniRecordHasNoAci" if (data.aciRecord.pni != null) { operations += PnpOperation.RemovePni(data.byAci) } - if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164) { + val newE164 = data.pniRecord.e164 ?: data.e164 + + if (data.aciRecord.e164 != null && data.aciRecord.e164 != newE164 && newE164 != null) { operations += PnpOperation.RemoveE164(data.byAci) // This also becomes a change number event @@ -2933,7 +3001,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da operations += PnpOperation.ChangeNumberInsert( recipientId = data.byAci, oldE164 = data.aciRecord.e164, - newE164 = data.e164!! + newE164 = newE164 ) } } @@ -2943,10 +3011,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da secondaryId = data.byPni ) } else { - // The PNI record either has an ACI or a non-matching e164, meaning we need to steal what we need and leave the rest behind + // The PNI record has a different ACI, meaning we need to steal what we need and leave the rest behind breadCrumbs += if (data.pniRecord.aci != null && data.pniRecord.e164 != data.e164) { - "PniRecordHasAciAndNonMatchingE164" + "PniRecordHasAci" } else if (data.pniRecord.aci != null) { "PniRecordHasAci" } else { @@ -3111,11 +3179,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .readToSingleBoolean() } - fun getRegisteredE164s(): Set { + /** All e164's that are eligible for having a signal link added to their system contact entry. */ + fun getE164sForSystemContactLinks(): Set { return readableDatabase .select(E164) .from(TABLE_NAME) - .where("$REGISTERED = ? and $HIDDEN = ? AND $E164 NOT NULL", RegisteredState.REGISTERED.id, Recipient.HiddenState.NOT_HIDDEN.serialize()) + .where("$REGISTERED = ? and $HIDDEN = ? AND $E164 NOT NULL AND $PHONE_NUMBER_DISCOVERABLE != ?", RegisteredState.REGISTERED.id, Recipient.HiddenState.NOT_HIDDEN.serialize(), PhoneNumberDiscoverableState.NOT_DISCOVERABLE) .run() .readToSet { cursor -> cursor.requireNonNullString(E164) @@ -3201,7 +3270,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return getSignalContacts(includeSelf)?.count ?: 0 } - fun getSignalContacts(includeSelf: Boolean, orderBy: String? = null): Cursor? { + private fun getSignalContacts(includeSelf: Boolean, orderBy: String? = null): Cursor? { val searchSelection = ContactSearchSelection.Builder() .withRegistered(true) .withGroups(false) @@ -3212,20 +3281,46 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return readableDatabase.query(TABLE_NAME, SEARCH_PROJECTION, selection, args, null, null, orderBy) } - fun querySignalContacts(inputQuery: String, includeSelf: Boolean): Cursor? { - val query = SqlUtil.buildCaseInsensitiveGlobPattern(inputQuery) + fun querySignalContacts(contactSearchQuery: ContactSearchQuery): Cursor? { + val query = SqlUtil.buildCaseInsensitiveGlobPattern(contactSearchQuery.query) val searchSelection = ContactSearchSelection.Builder() .withRegistered(true) .withGroups(false) - .excludeId(if (includeSelf) null else Recipient.self().id) + .excludeId(if (contactSearchQuery.includeSelf) null else Recipient.self().id) .withSearchQuery(query) .build() val selection = searchSelection.where val args = searchSelection.args - val orderBy = "$SORT_NAME, $SYSTEM_JOINED_NAME, $SEARCH_PROFILE_NAME, $E164" + val orderBy = "${if (contactSearchQuery.contactSearchSortOrder == ContactSearchSortOrder.RECENCY) "${ThreadTable.TABLE_NAME}.${ThreadTable.DATE} DESC, " else ""}$SORT_NAME, $SYSTEM_JOINED_NAME, $SEARCH_PROFILE_NAME, $E164" - return readableDatabase.query(TABLE_NAME, SEARCH_PROJECTION, selection, args, null, null, orderBy) + //language=roomsql + val join = if (contactSearchQuery.contactSearchSortOrder == ContactSearchSortOrder.RECENCY) { + "LEFT OUTER JOIN ${ThreadTable.TABLE_NAME} ON ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} = $TABLE_NAME.$ID" + } else { + "" + } + + return if (contactSearchQuery.contactSearchSortOrder == ContactSearchSortOrder.RECENCY) { + val ambiguous = listOf(ID) + val projection = SEARCH_PROJECTION.map { + if (it in ambiguous) "$TABLE_NAME.$it" else it + } + "${ThreadTable.TABLE_NAME}.${ThreadTable.DATE}" + + //language=roomsql + readableDatabase.query( + """ + SELECT ${projection.joinToString(",")} + FROM $TABLE_NAME + $join + WHERE $selection + ORDER BY $orderBy + """.trimIndent(), + args + ) + } else { + readableDatabase.query(TABLE_NAME, SEARCH_PROJECTION, selection, args, null, null, orderBy) + } } fun querySignalContactLetterHeaders(inputQuery: String, includeSelf: Boolean, includePush: Boolean, includeSms: Boolean): Map { @@ -3428,7 +3523,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da fun getRecipientsForMultiDeviceSync(): List { val subquery = "SELECT ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} FROM ${ThreadTable.TABLE_NAME}" - val selection = "$REGISTERED = ? AND $GROUP_ID IS NULL AND $ID != ? AND ($SYSTEM_CONTACT_URI NOT NULL OR $ID IN ($subquery))" + val selection = "$REGISTERED = ? AND $GROUP_ID IS NULL AND $ID != ? AND ($ACI_COLUMN NOT NULL OR $E164 NOT NULL) AND ($SYSTEM_CONTACT_URI NOT NULL OR $ID IN ($subquery))" val args = arrayOf(RegisteredState.REGISTERED.id.toString(), Recipient.self().id.serialize()) val recipients: MutableList = ArrayList() @@ -3662,6 +3757,24 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } + fun updatePhoneNumberDiscoverability(presentInCds: Set, missingFromCds: Set) { + SqlUtil.buildCollectionQuery(ID, presentInCds).forEach { query -> + writableDatabase + .update(TABLE_NAME) + .values(PHONE_NUMBER_DISCOVERABLE to PhoneNumberDiscoverableState.DISCOVERABLE.id) + .where(query.where, query.whereArgs) + .run() + } + + SqlUtil.buildCollectionQuery(ID, missingFromCds).forEach { query -> + writableDatabase + .update(TABLE_NAME) + .values(PHONE_NUMBER_DISCOVERABLE to PhoneNumberDiscoverableState.NOT_DISCOVERABLE.id) + .where(query.where, query.whereArgs) + .run() + } + } + private fun updateExtras(recipientId: RecipientId, updater: java.util.function.Function) { val db = writableDatabase db.beginTransaction() @@ -3804,7 +3917,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da * Merges one ACI recipient with an E164 recipient. It is assumed that the E164 recipient does * *not* have an ACI. */ - private fun merge(primaryId: RecipientId, secondaryId: RecipientId, newPni: PNI? = null): MergeResult { + private fun merge(primaryId: RecipientId, secondaryId: RecipientId, newPni: PNI? = null, pniVerified: Boolean): MergeResult { ensureInTransaction() val db = writableDatabase val primaryRecord = getRecord(primaryId) @@ -3865,7 +3978,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da SYSTEM_CONTACT_URI to secondaryRecord.systemContactUri, PROFILE_SHARING to (primaryRecord.profileSharing || secondaryRecord.profileSharing), CAPABILITIES to max(primaryRecord.capabilities.rawBits, secondaryRecord.capabilities.rawBits), - MENTION_SETTING to if (primaryRecord.mentionSetting != MentionSetting.ALWAYS_NOTIFY) primaryRecord.mentionSetting.id else secondaryRecord.mentionSetting.id + MENTION_SETTING to if (primaryRecord.mentionSetting != MentionSetting.ALWAYS_NOTIFY) primaryRecord.mentionSetting.id else secondaryRecord.mentionSetting.id, + PNI_SIGNATURE_VERIFIED to pniVerified.toInt() ) if (primaryRecord.profileSharing || secondaryRecord.profileSharing) { @@ -3890,13 +4004,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da check(writableDatabase.inTransaction()) { "Must be in a transaction!" } } - private fun buildContentValuesForNewUser(e164: String?, pni: PNI?, aci: ACI?): ContentValues { + private fun buildContentValuesForNewUser(e164: String?, pni: PNI?, aci: ACI?, pniVerified: Boolean): ContentValues { check(e164 != null || pni != null || aci != null) { "Must provide some sort of identifier!" } val values = contentValuesOf( E164 to e164, ACI_COLUMN to aci?.toString(), PNI_COLUMN to pni?.toString(), + PNI_SIGNATURE_VERIFIED to pniVerified.toInt(), STORAGE_SERVICE_ID to Base64.encodeWithPadding(StorageSyncHelper.generateKey()), AVATAR_COLOR to AvatarColorHash.forAddress((aci ?: pni)?.toString(), e164).serialize() ) @@ -3914,6 +4029,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val profileName = ProfileName.fromParts(contact.profileGivenName.orElse(null), contact.profileFamilyName.orElse(null)) val systemName = ProfileName.fromParts(contact.systemGivenName.orElse(null), contact.systemFamilyName.orElse(null)) val username = contact.username.orElse(null) + val nickname = ProfileName.fromParts(contact.nicknameGivenName.orNull(), contact.nicknameFamilyName.orNull()) put(ACI_COLUMN, contact.aci.orElse(null)?.toString()) put(PNI_COLUMN, contact.pni.orElse(null)?.toString()) @@ -3932,6 +4048,11 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da put(MUTE_UNTIL, contact.muteUntil) put(STORAGE_SERVICE_ID, Base64.encodeWithPadding(contact.id.raw)) put(HIDDEN, contact.isHidden) + put(PNI_SIGNATURE_VERIFIED, contact.isPniSignatureVerified.toInt()) + put(NICKNAME_GIVEN_NAME, nickname.givenName.nullIfBlank()) + put(NICKNAME_FAMILY_NAME, nickname.familyName.nullIfBlank()) + put(NICKNAME_JOINED_NAME, nickname.toString().nullIfBlank()) + put(NOTE, contact.note.orNull().nullIfBlank()) if (contact.hasUnknownFields()) { put(STORAGE_SERVICE_PROTO, Base64.encodeWithPadding(Objects.requireNonNull(contact.serializeUnknownFields()))) @@ -4061,7 +4182,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da PROFILE_FAMILY_NAME to null, PROFILE_JOINED_NAME to null, LAST_PROFILE_FETCH to 0, - PROFILE_AVATAR to null + PROFILE_AVATAR to null, + PROFILE_SHARING to 0 ) .run { if (recipientId == null) { @@ -4168,16 +4290,16 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da put(SYSTEM_CONTACT_URI, systemContactUri) } - val updatedValues = update(id, refreshQualifyingValues) - if (updatedValues) { + val updateQuery = SqlUtil.buildTrueUpdateQuery("$ID = ? AND $PHONE_NUMBER_DISCOVERABLE != ?", SqlUtil.buildArgs(id, PhoneNumberDiscoverableState.NOT_DISCOVERABLE.id), refreshQualifyingValues) + if (update(updateQuery, refreshQualifyingValues)) { pendingRecipients.add(id) } - val otherValues = ContentValues().apply { - put(SYSTEM_INFO_PENDING, 0) - } - - update(id, otherValues) + writableDatabase + .update(TABLE_NAME) + .values(SYSTEM_INFO_PENDING to 0) + .where("$ID = ? AND $PHONE_NUMBER_DISCOVERABLE != ?", id, PhoneNumberDiscoverableState.NOT_DISCOVERABLE.id) + .run() } fun finish() { @@ -4203,18 +4325,25 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } private fun clearSystemDataForPendingInfo() { - database.update(TABLE_NAME) - .values( - SYSTEM_INFO_PENDING to 0, - SYSTEM_GIVEN_NAME to null, - SYSTEM_FAMILY_NAME to null, - SYSTEM_JOINED_NAME to null, - SYSTEM_PHOTO_URI to null, - SYSTEM_PHONE_LABEL to null, - SYSTEM_CONTACT_URI to null - ) - .where("$SYSTEM_INFO_PENDING = ?", 1) - .run() + writableDatabase.rawQuery( + """ + UPDATE $TABLE_NAME + SET + $SYSTEM_INFO_PENDING = 0, + $SYSTEM_GIVEN_NAME = NULL, + $SYSTEM_FAMILY_NAME = NULL, + $SYSTEM_JOINED_NAME = NULL, + $SYSTEM_PHOTO_URI = NULL, + $SYSTEM_PHONE_LABEL = NULL, + $SYSTEM_CONTACT_URI = NULL + WHERE $SYSTEM_INFO_PENDING = 1 + RETURNING $ID + """, + null + ).forEach { cursor -> + val id = RecipientId.from(cursor.requireLong(ID)) + ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id) + } } } @@ -4271,6 +4400,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da private class GetOrInsertResult(val recipientId: RecipientId, val neededInsert: Boolean) + data class ContactSearchQuery( + val query: String, + val includeSelf: Boolean, + val contactSearchSortOrder: ContactSearchSortOrder = ContactSearchSortOrder.NATURAL + ) + @VisibleForTesting internal class ContactSearchSelection private constructor(val where: String, val args: Array) { @@ -4427,13 +4562,13 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da internal object Capabilities { const val BIT_LENGTH = 2 - // const val GROUPS_V2 = 0 - const val GROUPS_V1_MIGRATION = 1 - const val SENDER_KEY = 2 - const val ANNOUNCEMENT_GROUPS = 3 - const val CHANGE_NUMBER = 4 - const val STORIES = 5 - const val GIFT_BADGES = 6 +// const val GROUPS_V2 = 0 +// const val GROUPS_V1_MIGRATION = 1 +// const val SENDER_KEY = 2 +// const val ANNOUNCEMENT_GROUPS = 3 +// const val CHANGE_NUMBER = 4 +// const val STORIES = 5 +// const val GIFT_BADGES = 6 const val PNP = 7 const val PAYMENT_ACTIVATION = 8 } @@ -4519,6 +4654,16 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } + enum class PhoneNumberDiscoverableState(val id: Int) { + UNKNOWN(0), DISCOVERABLE(1), NOT_DISCOVERABLE(2); + + companion object { + fun fromId(id: Int): PhoneNumberDiscoverableState { + return PhoneNumberDiscoverableState.values()[id] + } + } + } + data class CdsV2Result( val pni: PNI, val aci: ACI? diff --git a/app/src/main/java/org/tm/archive/database/RecipientTableCursorUtil.kt b/app/src/main/java/org/tm/archive/database/RecipientTableCursorUtil.kt index 33ee1f1e..05417f32 100644 --- a/app/src/main/java/org/tm/archive/database/RecipientTableCursorUtil.kt +++ b/app/src/main/java/org/tm/archive/database/RecipientTableCursorUtil.kt @@ -165,7 +165,9 @@ object RecipientTableCursorUtil { needsPniSignature = cursor.requireBoolean(RecipientTable.NEEDS_PNI_SIGNATURE), hiddenState = Recipient.HiddenState.deserialize(cursor.requireInt(RecipientTable.HIDDEN)), callLinkRoomId = cursor.requireString(RecipientTable.CALL_LINK_ROOM_ID)?.let { CallLinkRoomId.DatabaseSerializer.deserialize(it) }, - phoneNumberSharing = cursor.requireInt(RecipientTable.PHONE_NUMBER_SHARING).let { RecipientTable.PhoneNumberSharingState.fromId(it) } + phoneNumberSharing = cursor.requireInt(RecipientTable.PHONE_NUMBER_SHARING).let { RecipientTable.PhoneNumberSharingState.fromId(it) }, + nickname = ProfileName.fromParts(cursor.requireString(RecipientTable.NICKNAME_GIVEN_NAME), cursor.requireString(RecipientTable.NICKNAME_FAMILY_NAME)), + note = cursor.requireString(RecipientTable.NOTE) ) } @@ -173,12 +175,6 @@ object RecipientTableCursorUtil { val capabilities = cursor.requireLong(RecipientTable.CAPABILITIES) return RecipientRecord.Capabilities( rawBits = capabilities, - groupsV1MigrationCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.GROUPS_V1_MIGRATION, Capabilities.BIT_LENGTH).toInt()), - senderKeyCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.SENDER_KEY, Capabilities.BIT_LENGTH).toInt()), - announcementGroupCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.ANNOUNCEMENT_GROUPS, Capabilities.BIT_LENGTH).toInt()), - changeNumberCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.CHANGE_NUMBER, Capabilities.BIT_LENGTH).toInt()), - storiesCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.STORIES, Capabilities.BIT_LENGTH).toInt()), - giftBadgesCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.GIFT_BADGES, Capabilities.BIT_LENGTH).toInt()), pnpCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.PNP, Capabilities.BIT_LENGTH).toInt()), paymentActivation = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.PAYMENT_ACTIVATION, Capabilities.BIT_LENGTH).toInt()) ) @@ -209,25 +205,16 @@ object RecipientTableCursorUtil { } fun getSyncExtras(cursor: Cursor): RecipientRecord.SyncExtras { - val storageProtoRaw = cursor.optionalString(RecipientTable.STORAGE_SERVICE_PROTO).orElse(null) - val storageProto = if (storageProtoRaw != null) Base64.decodeOrThrow(storageProtoRaw) else null - val archived = cursor.optionalBoolean(ThreadTable.ARCHIVED).orElse(false) - val forcedUnread = cursor.optionalInt(ThreadTable.READ).map { status: Int -> status == ThreadTable.ReadStatus.FORCED_UNREAD.serialize() }.orElse(false) - val groupMasterKey = cursor.optionalBlob(GroupTable.V2_MASTER_KEY).map { GroupUtil.requireMasterKey(it) }.orElse(null) - val identityKey = cursor.optionalString(RecipientTable.IDENTITY_KEY).map { Base64.decodeOrThrow(it) }.orElse(null) - val identityStatus = cursor.optionalInt(RecipientTable.IDENTITY_STATUS).map { VerifiedStatus.forState(it) }.orElse(VerifiedStatus.DEFAULT) - val unregisteredTimestamp = cursor.optionalLong(RecipientTable.UNREGISTERED_TIMESTAMP).orElse(0) - val systemNickname = cursor.optionalString(RecipientTable.SYSTEM_NICKNAME).orElse(null) - return RecipientRecord.SyncExtras( - storageProto = storageProto, - groupMasterKey = groupMasterKey, - identityKey = identityKey, - identityStatus = identityStatus, - isArchived = archived, - isForcedUnread = forcedUnread, - unregisteredTimestamp = unregisteredTimestamp, - systemNickname = systemNickname + storageProto = cursor.optionalString(RecipientTable.STORAGE_SERVICE_PROTO).orElse(null)?.let { Base64.decodeOrThrow(it) }, + groupMasterKey = cursor.optionalBlob(GroupTable.V2_MASTER_KEY).map { GroupUtil.requireMasterKey(it) }.orElse(null), + identityKey = cursor.optionalString(RecipientTable.IDENTITY_KEY).map { Base64.decodeOrThrow(it) }.orElse(null), + identityStatus = cursor.optionalInt(RecipientTable.IDENTITY_STATUS).map { VerifiedStatus.forState(it) }.orElse(VerifiedStatus.DEFAULT), + isArchived = cursor.optionalBoolean(ThreadTable.ARCHIVED).orElse(false), + isForcedUnread = cursor.optionalInt(ThreadTable.READ).map { status: Int -> status == ThreadTable.ReadStatus.FORCED_UNREAD.serialize() }.orElse(false), + unregisteredTimestamp = cursor.optionalLong(RecipientTable.UNREGISTERED_TIMESTAMP).orElse(0), + systemNickname = cursor.optionalString(RecipientTable.SYSTEM_NICKNAME).orElse(null), + pniSignatureVerified = cursor.optionalBoolean(RecipientTable.PNI_SIGNATURE_VERIFIED).orElse(false) ) } diff --git a/app/src/main/java/org/tm/archive/database/RemoteMegaphoneTable.kt b/app/src/main/java/org/tm/archive/database/RemoteMegaphoneTable.kt index 8b32ea2f..c0c77af7 100644 --- a/app/src/main/java/org/tm/archive/database/RemoteMegaphoneTable.kt +++ b/app/src/main/java/org/tm/archive/database/RemoteMegaphoneTable.kt @@ -8,7 +8,7 @@ import androidx.core.content.contentValuesOf import androidx.core.net.toUri import org.json.JSONException import org.json.JSONObject -import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.readToList import org.signal.core.util.requireInt @@ -194,9 +194,7 @@ class RemoteMegaphoneTable(context: Context, databaseHelper: SignalDatabase) : D /** Only call from internal settings */ fun debugRemoveAll() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } private fun RemoteMegaphoneRecord.toContentValues(): ContentValues { diff --git a/app/src/main/java/org/tm/archive/database/SenderKeySharedTable.kt b/app/src/main/java/org/tm/archive/database/SenderKeySharedTable.kt index 13033ac0..1c9100e9 100644 --- a/app/src/main/java/org/tm/archive/database/SenderKeySharedTable.kt +++ b/app/src/main/java/org/tm/archive/database/SenderKeySharedTable.kt @@ -4,6 +4,7 @@ import android.content.Context import android.database.Cursor import androidx.core.content.contentValuesOf import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.readToSet import org.signal.core.util.requireInt @@ -137,9 +138,7 @@ class SenderKeySharedTable internal constructor(context: Context?, databaseHelpe * Clears all database content. */ fun deleteAll() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } /** diff --git a/app/src/main/java/org/tm/archive/database/SenderKeyTable.kt b/app/src/main/java/org/tm/archive/database/SenderKeyTable.kt index 7108ab2f..87ce5e9e 100644 --- a/app/src/main/java/org/tm/archive/database/SenderKeyTable.kt +++ b/app/src/main/java/org/tm/archive/database/SenderKeyTable.kt @@ -5,6 +5,7 @@ import android.database.Cursor import androidx.core.content.contentValuesOf import org.signal.core.util.CursorUtil import org.signal.core.util.delete +import org.signal.core.util.deleteAll import org.signal.core.util.firstOrNull import org.signal.core.util.logging.Log import org.signal.core.util.requireLong @@ -123,8 +124,6 @@ class SenderKeyTable internal constructor(context: Context?, databaseHelper: Sig * Deletes all database state. */ fun deleteAll() { - writableDatabase - .delete(TABLE_NAME) - .run() + writableDatabase.deleteAll(TABLE_NAME) } } diff --git a/app/src/main/java/org/tm/archive/database/SignalDatabase.kt b/app/src/main/java/org/tm/archive/database/SignalDatabase.kt index 8523e92e..dc2fa0dc 100644 --- a/app/src/main/java/org/tm/archive/database/SignalDatabase.kt +++ b/app/src/main/java/org/tm/archive/database/SignalDatabase.kt @@ -78,17 +78,6 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data val kyberPreKeyTable: KyberPreKeyTable = KyberPreKeyTable(context, this) val callLinkTable: CallLinkTable = CallLinkTable(context, this) - override fun messageDao(): IArchiveMessageDao = messageTable as TeleMessageTable - - override fun beginTransaction() {} - - override fun endTransaction() {} - - override fun setTransactionSuccessful() {} - - override fun isInTransaction() = false - - override fun onOpen(db: net.zetetic.database.sqlcipher.SQLiteDatabase) { db.setForeignKeyConstraintsEnabled(true) } @@ -542,4 +531,15 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data val callLinks: CallLinkTable get() = instance!!.callLinkTable } + // TM_SA implement IDatabase start + override fun beginTransaction() {} + + override fun endTransaction() {} + + override fun isInTransaction(): Boolean = false + + override fun messageDao(): IArchiveMessageDao = messageTable as TeleMessageTable + + override fun setTransactionSuccessful() {} + // TM_SA implement IDatabase end } diff --git a/app/src/main/java/org/tm/archive/database/SignedPreKeyTable.kt b/app/src/main/java/org/tm/archive/database/SignedPreKeyTable.kt index 70af0561..1b01c9ce 100644 --- a/app/src/main/java/org/tm/archive/database/SignedPreKeyTable.kt +++ b/app/src/main/java/org/tm/archive/database/SignedPreKeyTable.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.core.content.contentValuesOf import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil +import org.signal.core.util.deleteAll import org.signal.core.util.logging.Log import org.signal.core.util.requireInt import org.signal.core.util.requireLong @@ -28,11 +29,12 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data const val PRIVATE_KEY = "private_key" const val SIGNATURE = "signature" const val TIMESTAMP = "timestamp" + const val CREATE_TABLE = """ CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $ACCOUNT_ID TEXT NOT NULL, - $KEY_ID INTEGER UNIQUE, + $KEY_ID INTEGER NOT NULL, $PUBLIC_KEY TEXT NOT NULL, $PRIVATE_KEY TEXT NOT NULL, $SIGNATURE TEXT NOT NULL, @@ -40,10 +42,12 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data UNIQUE($ACCOUNT_ID, $KEY_ID) ) """ + + const val PNI_ACCOUNT_ID = "PNI" } fun get(serviceId: ServiceId, keyId: Int): SignedPreKeyRecord? { - readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId), null, null, null).use { cursor -> + readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId), null, null, null).use { cursor -> if (cursor.moveToFirst()) { try { val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0) @@ -64,7 +68,7 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data fun getAll(serviceId: ServiceId): List { val results: MutableList = LinkedList() - readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId), null, null, null).use { cursor -> + readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId()), null, null, null).use { cursor -> while (cursor.moveToNext()) { try { val keyId = cursor.requireInt(KEY_ID) @@ -86,7 +90,7 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data fun insert(serviceId: ServiceId, keyId: Int, record: SignedPreKeyRecord) { val contentValues = contentValuesOf( - ACCOUNT_ID to serviceId.toString(), + ACCOUNT_ID to serviceId.toAccountId(), KEY_ID to keyId, PUBLIC_KEY to Base64.encodeWithPadding(record.keyPair.publicKey.serialize()), PRIVATE_KEY to Base64.encodeWithPadding(record.keyPair.privateKey.serialize()), @@ -97,6 +101,17 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data } fun delete(serviceId: ServiceId, keyId: Int) { - writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId)) + writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId)) + } + + fun debugDeleteAll() { + writableDatabase.deleteAll(OneTimePreKeyTable.TABLE_NAME) + } + + private fun ServiceId.toAccountId(): String { + return when (this) { + is ServiceId.ACI -> this.toString() + is ServiceId.PNI -> PNI_ACCOUNT_ID + } } } diff --git a/app/src/main/java/org/tm/archive/database/ThreadBodyUtil.java b/app/src/main/java/org/tm/archive/database/ThreadBodyUtil.java index 2d3fc19c..ffa3a5b3 100644 --- a/app/src/main/java/org/tm/archive/database/ThreadBodyUtil.java +++ b/app/src/main/java/org/tm/archive/database/ThreadBodyUtil.java @@ -1,9 +1,11 @@ package org.tm.archive.database; import android.content.Context; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import org.signal.core.util.logging.Log; @@ -32,24 +34,28 @@ public final class ThreadBodyUtil { public static @NonNull ThreadBody getFormattedBodyFor(@NonNull Context context, @NonNull MessageRecord record) { if (record.isMms()) { - return getFormattedBodyForMms(context, (MmsMessageRecord) record); + return getFormattedBodyForMms(context, (MmsMessageRecord) record, null); } return new ThreadBody(record.getBody()); } - private static @NonNull ThreadBody getFormattedBodyForMms(@NonNull Context context, @NonNull MmsMessageRecord record) { + public static @NonNull CharSequence getFormattedBodyForNotification(@NonNull Context context, @NonNull MessageRecord record, @Nullable CharSequence bodyOverride) { + return getFormattedBodyForMms(context, (MmsMessageRecord) record, bodyOverride).body; + } + + private static @NonNull ThreadBody getFormattedBodyForMms(@NonNull Context context, @NonNull MmsMessageRecord record, @Nullable CharSequence bodyOverride) { if (record.getSharedContacts().size() > 0) { Contact contact = record.getSharedContacts().get(0); return new ThreadBody(ContactUtil.getStringSummary(context, contact).toString()); } else if (record.getSlideDeck().getDocumentSlide() != null) { - return format(context, record, EmojiStrings.FILE, R.string.ThreadRecord_file); + return format(context, record, EmojiStrings.FILE, R.string.ThreadRecord_file, bodyOverride); } else if (record.getSlideDeck().getAudioSlide() != null) { - return format(context, record, EmojiStrings.AUDIO, R.string.ThreadRecord_voice_message); + return format(context, record, EmojiStrings.AUDIO, R.string.ThreadRecord_voice_message, bodyOverride); } else if (MessageRecordUtil.hasSticker(record)) { String emoji = getStickerEmoji(record); - return format(context, record, emoji, R.string.ThreadRecord_sticker); + return format(context, record, emoji, R.string.ThreadRecord_sticker, bodyOverride); } else if (MessageRecordUtil.hasGiftBadge(record)) { return format(EmojiStrings.GIFT, getGiftSummary(context, record)); } else if (MessageRecordUtil.isStoryReaction(record)) { @@ -77,11 +83,11 @@ public final class ThreadBodyUtil { } if (hasGif) { - return format(context, record, EmojiStrings.GIF, R.string.ThreadRecord_gif); + return format(context, record, EmojiStrings.GIF, R.string.ThreadRecord_gif, bodyOverride); } else if (hasVideo) { - return format(context, record, EmojiStrings.VIDEO, R.string.ThreadRecord_video); + return format(context, record, EmojiStrings.VIDEO, R.string.ThreadRecord_video, bodyOverride); } else if (hasImage) { - return format(context, record, EmojiStrings.PHOTO, R.string.ThreadRecord_photo); + return format(context, record, EmojiStrings.PHOTO, R.string.ThreadRecord_photo, bodyOverride); } else if (TextUtils.isEmpty(record.getBody())) { return new ThreadBody(context.getString(R.string.ThreadRecord_media_message)); } else { @@ -153,18 +159,25 @@ public final class ThreadBodyUtil { return ""; } } - - private static @NonNull ThreadBody format(@NonNull Context context, @NonNull MessageRecord record, @NonNull String emoji, @StringRes int defaultStringRes) { - CharSequence body = getBodyOrDefault(context, record, defaultStringRes).getBody(); + + private static @NonNull ThreadBody format(@NonNull Context context, + @NonNull MessageRecord record, + @NonNull String emoji, + @StringRes int defaultStringRes, + @Nullable CharSequence bodyOverride) + { + CharSequence body = !TextUtils.isEmpty(bodyOverride) ? bodyOverride + : TextUtils.isEmpty(record.getBody()) ? context.getString(defaultStringRes) + : getBody(context, record).getBody(); return format(emoji, body); } private static @NonNull ThreadBody format(@NonNull CharSequence prefix, @NonNull CharSequence body) { - return new ThreadBody(String.format("%s %s", prefix, body), prefix.length() + 1); - } - - private static @NonNull ThreadBody getBodyOrDefault(@NonNull Context context, @NonNull MessageRecord record, @StringRes int defaultStringRes) { - return TextUtils.isEmpty(record.getBody()) ? new ThreadBody(context.getString(defaultStringRes)) : getBody(context, record); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(prefix) + .append(" ") + .append(body); + return new ThreadBody(builder, prefix.length() + 1); } private static @NonNull ThreadBody getBody(@NonNull Context context, @NonNull MessageRecord record) { diff --git a/app/src/main/java/org/tm/archive/database/ThreadTable.kt b/app/src/main/java/org/tm/archive/database/ThreadTable.kt index 1db9d831..e9909d7d 100644 --- a/app/src/main/java/org/tm/archive/database/ThreadTable.kt +++ b/app/src/main/java/org/tm/archive/database/ThreadTable.kt @@ -6,7 +6,6 @@ import android.content.Context import android.database.Cursor import android.database.MergeCursor import android.net.Uri -import androidx.annotation.VisibleForTesting import androidx.core.content.contentValuesOf import com.fasterxml.jackson.annotation.JsonProperty import org.json.JSONObject @@ -19,6 +18,7 @@ import org.signal.core.util.exists import org.signal.core.util.logging.Log import org.signal.core.util.or import org.signal.core.util.readToList +import org.signal.core.util.readToSingleLong import org.signal.core.util.requireBoolean import org.signal.core.util.requireInt import org.signal.core.util.requireLong @@ -26,6 +26,7 @@ import org.signal.core.util.requireString import org.signal.core.util.select import org.signal.core.util.toInt import org.signal.core.util.update +import org.signal.core.util.updateAll import org.signal.core.util.withinTransaction import org.signal.libsignal.zkgroup.InvalidInputException import org.signal.libsignal.zkgroup.groups.GroupMasterKey @@ -44,6 +45,7 @@ import org.tm.archive.database.model.MessageRecord import org.tm.archive.database.model.MmsMessageRecord import org.tm.archive.database.model.ThreadRecord import org.tm.archive.database.model.databaseprotos.BodyRangeList +import org.tm.archive.database.model.databaseprotos.MessageExtras import org.tm.archive.database.model.serialize import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.groups.BadGroupIdException @@ -97,6 +99,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa const val SNIPPET_URI = "snippet_uri" const val SNIPPET_CONTENT_TYPE = "snippet_content_type" const val SNIPPET_EXTRAS = "snippet_extras" + const val SNIPPET_MESSAGE_EXTRAS = "snippet_message_extras" const val ARCHIVED = "archived" const val STATUS = "status" const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt" @@ -137,7 +140,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa $LAST_SCROLLED INTEGER DEFAULT 0, $PINNED INTEGER DEFAULT 0, $UNREAD_SELF_MENTION_COUNT INTEGER DEFAULT 0, - $ACTIVE INTEGER DEFAULT 0 + $ACTIVE INTEGER DEFAULT 0, + $SNIPPET_MESSAGE_EXTRAS BLOB DEFAULT NULL ) """ @@ -164,6 +168,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa SNIPPET_URI, SNIPPET_CONTENT_TYPE, SNIPPET_EXTRAS, + SNIPPET_MESSAGE_EXTRAS, ARCHIVED, STATUS, HAS_DELIVERY_RECEIPT, @@ -223,7 +228,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa expiresIn: Long, readReceiptCount: Int, unreadCount: Int, - unreadMentionCount: Int + unreadMentionCount: Int, + messageExtras: MessageExtras? ) { var extraSerialized: String? = null @@ -249,7 +255,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa EXPIRES_IN to expiresIn, ACTIVE to 1, UNREAD_COUNT to unreadCount, - UNREAD_SELF_MENTION_COUNT to unreadMentionCount + UNREAD_SELF_MENTION_COUNT to unreadMentionCount, + SNIPPET_MESSAGE_EXTRAS to messageExtras?.encode() ) writableDatabase @@ -403,7 +410,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa fun setAllThreadsRead(): List { writableDatabase - .update(TABLE_NAME) + .updateAll(TABLE_NAME) .values( READ to ReadStatus.READ.serialize(), UNREAD_COUNT to 0, @@ -1107,14 +1114,6 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa ConversationUtil.clearShortcuts(context, recipientIds) } - @VisibleForTesting - fun clearForTests() { - writableDatabase.withinTransaction { - deleteAllConversations() - it.delete(TABLE_NAME).run() - } - } - @SuppressLint("DiscouragedApi") fun deleteAllConversations() { writableDatabase.withinTransaction { db -> @@ -1167,9 +1166,23 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } fun getOrCreateThreadIdFor(recipientId: RecipientId, isGroup: Boolean, distributionType: Int = DistributionTypes.DEFAULT): Long { + return getOrCreateThreadIdResultFor(recipientId, isGroup, distributionType).threadId + } + + fun getOrCreateThreadIdResultFor(recipientId: RecipientId, isGroup: Boolean, distributionType: Int = DistributionTypes.DEFAULT): ThreadIdResult { return writableDatabase.withinTransaction { val threadId = getThreadIdFor(recipientId) - threadId ?: createThreadForRecipient(recipientId, isGroup, distributionType) + if (threadId != null) { + ThreadIdResult( + threadId = threadId, + newlyCreated = false + ) + } else { + ThreadIdResult( + threadId = createThreadForRecipient(recipientId, isGroup, distributionType), + newlyCreated = true + ) + } } } @@ -1243,6 +1256,13 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa return getThreadIdIfExistsFor(recipientId) > -1 } + fun hasActiveThread(recipientId: RecipientId): Boolean { + return readableDatabase + .exists(TABLE_NAME) + .where("$RECIPIENT_ID = ? AND $ACTIVE = 1", recipientId) + .run() + } + fun updateLastSeenAndMarkSentAndLastScrolledSilenty(threadId: Long) { writableDatabase .update(TABLE_NAME) @@ -1294,7 +1314,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa writableDatabase.withinTransaction { db -> applyStorageSyncUpdate(recipientId, record.isNoteToSelfArchived, record.isNoteToSelfForcedUnread) - db.update(TABLE_NAME) + db.updateAll(TABLE_NAME) .values(PINNED to 0) .run() @@ -1487,7 +1507,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa expiresIn = 0, readReceiptCount = 0, unreadCount = 0, - unreadMentionCount = 0 + unreadMentionCount = 0, + messageExtras = null ) } return@withinTransaction true @@ -1516,7 +1537,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa expiresIn = record.expiresIn, readReceiptCount = record.hasReadReceipt().toInt(), unreadCount = unreadCount, - unreadMentionCount = unreadMentionCount + unreadMentionCount = unreadMentionCount, + messageExtras = record.messageExtras ) if (notifyListeners) { @@ -1578,64 +1600,69 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa check(databaseHelper.signalWritableDatabase.inTransaction()) { "Must be in a transaction!" } Log.w(TAG, "Merging threads. Primary: $primaryRecipientId, Secondary: $secondaryRecipientId", true) - val primary: ThreadRecord? = getThreadRecord(getThreadIdFor(primaryRecipientId)) - val secondary: ThreadRecord? = getThreadRecord(getThreadIdFor(secondaryRecipientId)) + val primaryThreadId: Long? = getThreadIdFor(primaryRecipientId) + val secondaryThreadId: Long? = getThreadIdFor(secondaryRecipientId) - return if (primary != null && secondary == null) { + return if (primaryThreadId != null && secondaryThreadId == null) { Log.w(TAG, "[merge] Only had a thread for primary. Returning that.", true) - MergeResult(threadId = primary.threadId, previousThreadId = -1, neededMerge = false) - } else if (primary == null && secondary != null) { + MergeResult(threadId = primaryThreadId, previousThreadId = -1, neededMerge = false) + } else if (primaryThreadId == null && secondaryThreadId != null) { Log.w(TAG, "[merge] Only had a thread for secondary. Updating it to have the recipientId of the primary.", true) writableDatabase .update(TABLE_NAME) .values(RECIPIENT_ID to primaryRecipientId.serialize()) - .where("$ID = ?", secondary.threadId) + .where("$ID = ?", secondaryThreadId) .run() synchronized(threadIdCache) { threadIdCache.remove(secondaryRecipientId) } - MergeResult(threadId = secondary.threadId, previousThreadId = -1, neededMerge = false) - } else if (primary == null && secondary == null) { + MergeResult(threadId = secondaryThreadId, previousThreadId = -1, neededMerge = false) + } else if (primaryThreadId == null && secondaryThreadId == null) { Log.w(TAG, "[merge] No thread for either.") MergeResult(threadId = -1, previousThreadId = -1, neededMerge = false) } else { Log.w(TAG, "[merge] Had a thread for both. Deleting the secondary and merging the attributes together.", true) - check(primary != null) - check(secondary != null) + check(primaryThreadId != null) + check(secondaryThreadId != null) for (table in threadIdDatabaseTables) { - table.remapThread(secondary.threadId, primary.threadId) + table.remapThread(secondaryThreadId, primaryThreadId) } writableDatabase .delete(TABLE_NAME) - .where("$ID = ?", secondary.threadId) + .where("$ID = ?", secondaryThreadId) .run() synchronized(threadIdCache) { threadIdCache.remove(secondaryRecipientId) } - if (primary.expiresIn != secondary.expiresIn) { - val values = ContentValues() - if (primary.expiresIn == 0L) { - values.put(EXPIRES_IN, secondary.expiresIn) - } else if (secondary.expiresIn == 0L) { - values.put(EXPIRES_IN, primary.expiresIn) - } else { - values.put(EXPIRES_IN, min(primary.expiresIn, secondary.expiresIn)) - } + val primaryExpiresIn = getExpiresIn(primaryThreadId) + val secondaryExpiresIn = getExpiresIn(secondaryThreadId) - writableDatabase - .update(TABLE_NAME) - .values(values) - .where("$ID = ?", primary.threadId) - .run() + val values = ContentValues() + values.put(ACTIVE, true) + + if (primaryExpiresIn != secondaryExpiresIn) { + if (primaryExpiresIn == 0L) { + values.put(EXPIRES_IN, secondaryExpiresIn) + } else if (secondaryExpiresIn == 0L) { + values.put(EXPIRES_IN, primaryExpiresIn) + } else { + values.put(EXPIRES_IN, min(primaryExpiresIn, secondaryExpiresIn)) + } } - RemappedRecords.getInstance().addThread(secondary.threadId, primary.threadId) + writableDatabase + .update(TABLE_NAME) + .values(values) + .where("$ID = ?", primaryThreadId) + .run() - MergeResult(threadId = primary.threadId, previousThreadId = secondary.threadId, neededMerge = true) + RemappedRecords.getInstance().addThread(secondaryThreadId, primaryThreadId) + + MergeResult(threadId = primaryThreadId, previousThreadId = secondaryThreadId, neededMerge = true) } } @@ -1655,6 +1682,15 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } } + private fun getExpiresIn(threadId: Long): Long { + return readableDatabase + .select(EXPIRES_IN) + .from(TABLE_NAME) + .where("$ID = $threadId") + .run() + .readToSingleLong() + } + private fun SQLiteDatabase.deactivateThreads() { deactivateThread(query = null) } @@ -1664,36 +1700,43 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } private fun SQLiteDatabase.deactivateThread(query: SqlUtil.Query?) { - val update = update(TABLE_NAME) - .values( - DATE to 0, - MEANINGFUL_MESSAGES to 0, - READ to ReadStatus.READ.serialize(), - TYPE to 0, - ERROR to 0, - SNIPPET to null, - SNIPPET_TYPE to 0, - SNIPPET_URI to null, - SNIPPET_CONTENT_TYPE to null, - SNIPPET_EXTRAS to null, - UNREAD_COUNT to 0, - ARCHIVED to 0, - STATUS to 0, - HAS_DELIVERY_RECEIPT to 0, - HAS_READ_RECEIPT to 0, - EXPIRES_IN to 0, - LAST_SEEN to 0, - HAS_SENT to 0, - LAST_SCROLLED to 0, - PINNED to 0, - UNREAD_SELF_MENTION_COUNT to 0, - ACTIVE to 0 - ) + val contentValues = contentValuesOf( + DATE to 0, + MEANINGFUL_MESSAGES to 0, + READ to ReadStatus.READ.serialize(), + TYPE to 0, + ERROR to 0, + SNIPPET to null, + SNIPPET_TYPE to 0, + SNIPPET_URI to null, + SNIPPET_CONTENT_TYPE to null, + SNIPPET_EXTRAS to null, + SNIPPET_MESSAGE_EXTRAS to null, + UNREAD_COUNT to 0, + ARCHIVED to 0, + STATUS to 0, + HAS_DELIVERY_RECEIPT to 0, + HAS_READ_RECEIPT to 0, + EXPIRES_IN to 0, + LAST_SEEN to 0, + HAS_SENT to 0, + LAST_SCROLLED to 0, + PINNED to 0, + UNREAD_SELF_MENTION_COUNT to 0, + ACTIVE to 0 + ) if (query != null) { - update.where(query.where, query.whereArgs).run() + writableDatabase + .update(TABLE_NAME) + .values(contentValues) + .where(query.where, query.whereArgs) + .run() } else { - update.run() + writableDatabase + .updateAll(TABLE_NAME) + .values(contentValues) + .run() } } @@ -1900,6 +1943,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT) val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS)) + val messageExtraBytes = cursor.getBlob(cursor.getColumnIndexOrThrow(SNIPPET_MESSAGE_EXTRAS)) + val messageExtras = if (messageExtraBytes != null) MessageExtras.ADAPTER.decode(messageExtraBytes) else null val extra: Extra? = if (extraString != null) { try { val jsonObject = SaneJSONObject(JSONObject(extraString)) @@ -1944,6 +1989,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa .setPinned(cursor.requireBoolean(PINNED)) .setUnreadSelfMentionsCount(cursor.requireInt(UNREAD_SELF_MENTION_COUNT)) .setExtra(extra) + .setSnippetMessageExtras(messageExtras) .build() } @@ -2079,4 +2125,9 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa ) data class MergeResult(val threadId: Long, val previousThreadId: Long, val neededMerge: Boolean) + + data class ThreadIdResult( + val threadId: Long, + val newlyCreated: Boolean + ) } diff --git a/app/src/main/java/org/tm/archive/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/tm/archive/database/helpers/SignalDatabaseMigrations.kt index d44c39a9..9389b5a5 100644 --- a/app/src/main/java/org/tm/archive/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/tm/archive/database/helpers/SignalDatabaseMigrations.kt @@ -73,6 +73,14 @@ import org.tm.archive.database.helpers.migration.V212_RemoveDistributionListUniq import org.tm.archive.database.helpers.migration.V213_FixUsernameInE164Column import org.tm.archive.database.helpers.migration.V214_PhoneNumberSharingColumn import org.tm.archive.database.helpers.migration.V215_RemoveAttachmentUniqueId +import org.tm.archive.database.helpers.migration.V216_PhoneNumberDiscoverable +import org.tm.archive.database.helpers.migration.V217_MessageTableExtrasColumn +import org.tm.archive.database.helpers.migration.V218_RecipientPniSignatureVerified +import org.tm.archive.database.helpers.migration.V219_PniPreKeyStores +import org.tm.archive.database.helpers.migration.V220_PreKeyConstraints +import org.tm.archive.database.helpers.migration.V221_AddReadColumnToCallEventsTable +import org.tm.archive.database.helpers.migration.V222_DataHashRefactor +import org.tm.archive.database.helpers.migration.V223_AddNicknameAndNoteFieldsToRecipientTable /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -148,10 +156,18 @@ object SignalDatabaseMigrations { 212 to V212_RemoveDistributionListUniqueConstraint, 213 to V213_FixUsernameInE164Column, 214 to V214_PhoneNumberSharingColumn, - 215 to V215_RemoveAttachmentUniqueId + 215 to V215_RemoveAttachmentUniqueId, + 216 to V216_PhoneNumberDiscoverable, + 217 to V217_MessageTableExtrasColumn, + 218 to V218_RecipientPniSignatureVerified, + 219 to V219_PniPreKeyStores, + 220 to V220_PreKeyConstraints, + 221 to V221_AddReadColumnToCallEventsTable, + 222 to V222_DataHashRefactor, + 223 to V223_AddNicknameAndNoteFieldsToRecipientTable ) - const val DATABASE_VERSION = 215 + const val DATABASE_VERSION = 223 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V216_PhoneNumberDiscoverable.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V216_PhoneNumberDiscoverable.kt new file mode 100644 index 00000000..dceabec4 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V216_PhoneNumberDiscoverable.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +object V216_PhoneNumberDiscoverable : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("""ALTER TABLE recipient ADD COLUMN phone_number_discoverable INTEGER DEFAULT 0""") + } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V217_MessageTableExtrasColumn.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V217_MessageTableExtrasColumn.kt new file mode 100644 index 00000000..96c7e350 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V217_MessageTableExtrasColumn.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Adds a message_extras column to the messages table. This allows us to + * store extra data for messages in a more future proof and structured way. + */ +@Suppress("ClassName") +object V217_MessageTableExtrasColumn : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE message ADD COLUMN message_extras BLOB DEFAULT NULL") + db.execSQL("ALTER TABLE thread ADD COLUMN snippet_message_extras BLOB DEFAULT NULL") + } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V218_RecipientPniSignatureVerified.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V218_RecipientPniSignatureVerified.kt new file mode 100644 index 00000000..13e6bd6e --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V218_RecipientPniSignatureVerified.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Adds a pni_signature_verified column to the recipient table, letting us track whether the ACI/PNI association is verified and sync that to storage service. + */ +@Suppress("ClassName") +object V218_RecipientPniSignatureVerified : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE recipient ADD COLUMN pni_signature_verified INTEGER DEFAULT 0") + } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V219_PniPreKeyStores.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V219_PniPreKeyStores.kt new file mode 100644 index 00000000..c7a4f87e --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V219_PniPreKeyStores.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Changes our PNI prekey stores to use a constant indicating it's for a PNI rather than the specific PNI. + */ +@Suppress("ClassName") +object V219_PniPreKeyStores : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL( + """ + UPDATE one_time_prekeys + SET account_id = "PNI" + WHERE account_id LIKE "PNI:%" + """ + ) + + db.execSQL( + """ + UPDATE signed_prekeys + SET account_id = "PNI" + WHERE account_id LIKE "PNI:%" + """ + ) + + db.execSQL( + """ + UPDATE kyber_prekey + SET account_id = "PNI" + WHERE account_id LIKE "PNI:%" + """ + ) + } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V220_PreKeyConstraints.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V220_PreKeyConstraints.kt new file mode 100644 index 00000000..6fa95da4 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V220_PreKeyConstraints.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase +import org.signal.core.util.Stopwatch +import org.signal.core.util.logging.Log + +/** + * A while back we added an accountId to the prekey tables to support a mix of ACI and PNI identities. + * Unfortunately, we didn't remove the unique constraint on the keyId, which isn't correct: the uniqueness + * is now based on the combination of (accountId, keyId). This migration fixes that by removing the unique + * address from the keyId column itself. + */ +object V220_PreKeyConstraints : SignalDatabaseMigration { + + private val TAG = Log.tag(V220_PreKeyConstraints::class.java) + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + val stopwatch = Stopwatch("migration", decimalPlaces = 2) + migrateSignedEcKeyTable(db) + stopwatch.split("signed-ec") + + migrateOneTimeEcPreKeysTable(db) + stopwatch.split("one-time-ec") + + migrateKyberTable(db) + stopwatch.split("kyber") + + stopwatch.stop(TAG) + } + + private fun migrateKyberTable(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE kyber_prekey_temp ( + _id INTEGER PRIMARY KEY, + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + timestamp INTEGER NOT NULL, + last_resort INTEGER NOT NULL, + serialized BLOB NOT NULL, + stale_timestamp INTEGER NOT NULL DEFAULT 0, + UNIQUE(account_id, key_id) + ) + """ + ) + + db.execSQL("INSERT INTO kyber_prekey_temp SELECT * FROM kyber_prekey") + + db.execSQL("DROP TABLE kyber_prekey") + db.execSQL("DROP INDEX IF EXISTS kyber_account_id_key_id") + + db.execSQL("ALTER TABLE kyber_prekey_temp RENAME TO kyber_prekey") + db.execSQL("CREATE INDEX IF NOT EXISTS kyber_account_id_key_id ON kyber_prekey (account_id, key_id, last_resort, serialized)") + } + + private fun migrateSignedEcKeyTable(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE signed_prekeys_temp ( + _id INTEGER PRIMARY KEY, + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + public_key TEXT NOT NULL, + private_key TEXT NOT NULL, + signature TEXT NOT NULL, + timestamp INTEGER DEFAULT 0, + UNIQUE(account_id, key_id) + ) + """ + ) + + db.execSQL("INSERT INTO signed_prekeys_temp SELECT * FROM signed_prekeys") + + db.execSQL("DROP TABLE signed_prekeys") + + db.execSQL("ALTER TABLE signed_prekeys_temp RENAME TO signed_prekeys") + } + + private fun migrateOneTimeEcPreKeysTable(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE one_time_prekeys_temp ( + _id INTEGER PRIMARY KEY, + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + public_key TEXT NOT NULL, + private_key TEXT NOT NULL, + stale_timestamp INTEGER NOT NULL DEFAULT 0, + UNIQUE(account_id, key_id) + ) + """ + ) + + db.execSQL("INSERT INTO one_time_prekeys_temp SELECT * FROM one_time_prekeys") + + db.execSQL("DROP TABLE one_time_prekeys") + + db.execSQL("ALTER TABLE one_time_prekeys_temp RENAME TO one_time_prekeys") } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V221_AddReadColumnToCallEventsTable.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V221_AddReadColumnToCallEventsTable.kt new file mode 100644 index 00000000..7fcf5ea7 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V221_AddReadColumnToCallEventsTable.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Adds read state to call events to separately track from the primary messages table. + * Copies the current read state in from the message database, and then clears the message + * database 'read' flag as well as decrements the unread count in the thread databse. + */ +@Suppress("ClassName") +object V221_AddReadColumnToCallEventsTable : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE call ADD COLUMN read INTEGER DEFAULT 1") + + db.execSQL( + """ + UPDATE call + SET read = (SELECT read FROM message WHERE _id = call.message_id) + WHERE event = 3 AND direction = 0 + """.trimIndent() + ) + + db.execSQL( + """ + UPDATE thread + SET unread_count = thread.unread_count - 1 + WHERE _id IN (SELECT thread_id FROM message WHERE (type = 3 OR type = 8) AND read = 0) AND unread_count > 0 + """.trimIndent() + ) + + db.execSQL( + """ + UPDATE message + SET read = 1 + WHERE (type = 3 OR type = 8) AND read = 0 + """.trimIndent() + ) + } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V222_DataHashRefactor.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V222_DataHashRefactor.kt new file mode 100644 index 00000000..f4007ec4 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V222_DataHashRefactor.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Adds the new data hash columns and indexes. + */ +@Suppress("ClassName") +object V222_DataHashRefactor : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("DROP INDEX attachment_data_hash_index") + db.execSQL("ALTER TABLE attachment DROP COLUMN data_hash") + + db.execSQL("ALTER TABLE attachment ADD COLUMN data_hash_start TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE attachment ADD COLUMN data_hash_end TEXT DEFAULT NULL") + db.execSQL("CREATE INDEX attachment_data_hash_start_index ON attachment (data_hash_start)") + db.execSQL("CREATE INDEX attachment_data_hash_end_index ON attachment (data_hash_end)") + } +} diff --git a/app/src/main/java/org/tm/archive/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt b/app/src/main/java/org/tm/archive/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt new file mode 100644 index 00000000..9359bd03 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Adds necessary fields to the recipeints table for the nickname & notes feature. + */ +@Suppress("ClassName") +object V223_AddNicknameAndNoteFieldsToRecipientTable : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE recipient ADD COLUMN nickname_given_name TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE recipient ADD COLUMN nickname_family_name TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE recipient ADD COLUMN nickname_joined_name TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE recipient ADD COLUMN note TEXT DEFAULT NULL") + } +} diff --git a/app/src/main/java/org/tm/archive/database/loaders/DeviceListLoader.java b/app/src/main/java/org/tm/archive/database/loaders/DeviceListLoader.java index 85ff5818..df8e5aa0 100644 --- a/app/src/main/java/org/tm/archive/database/loaders/DeviceListLoader.java +++ b/app/src/main/java/org/tm/archive/database/loaders/DeviceListLoader.java @@ -17,6 +17,7 @@ import org.signal.libsignal.protocol.ecc.ECPublicKey; import org.signal.libsignal.protocol.util.ByteUtil; import org.tm.archive.devicelist.Device; import org.tm.archive.keyvalue.SignalStore; +import org.tm.archive.registration.secondary.DeviceNameCipher; import org.tm.archive.util.AsyncLoader; import org.signal.core.util.Base64; import org.whispersystems.signalservice.api.SignalServiceAccountManager; @@ -78,50 +79,19 @@ public class DeviceListLoader extends AsyncLoader> { throw new IOException("Got a DeviceName that wasn't properly populated."); } - return new Device(deviceInfo.getId(), new String(decryptName(deviceName, SignalStore.account().getAciIdentityKey())), deviceInfo.getCreated(), deviceInfo.getLastSeen()); + byte[] plaintext = DeviceNameCipher.decryptDeviceName(deviceName, SignalStore.account().getAciIdentityKey()); + if (plaintext == null) { + throw new IOException("Failed to decrypt device name."); + } + return new Device(deviceInfo.getId(), new String(plaintext), deviceInfo.getCreated(), deviceInfo.getLastSeen()); } catch (IOException e) { Log.w(TAG, "Failed while reading the protobuf.", e); - } catch (GeneralSecurityException | InvalidKeyException e) { - Log.w(TAG, "Failed during decryption.", e); } return new Device(deviceInfo.getId(), deviceInfo.getName(), deviceInfo.getCreated(), deviceInfo.getLastSeen()); } - @VisibleForTesting - public static byte[] decryptName(DeviceName deviceName, IdentityKeyPair identityKeyPair) throws InvalidKeyException, GeneralSecurityException { - byte[] syntheticIv = Objects.requireNonNull(deviceName.syntheticIv).toByteArray(); - byte[] cipherText = Objects.requireNonNull(deviceName.ciphertext).toByteArray(); - ECPrivateKey identityKey = identityKeyPair.getPrivateKey(); - ECPublicKey ephemeralPublic = Curve.decodePoint(Objects.requireNonNull(deviceName.ephemeralPublic).toByteArray(), 0); - byte[] masterSecret = Curve.calculateAgreement(ephemeralPublic, identityKey); - - Mac mac = Mac.getInstance("HmacSHA256"); - mac.init(new SecretKeySpec(masterSecret, "HmacSHA256")); - byte[] cipherKeyPart1 = mac.doFinal("cipher".getBytes()); - - mac.init(new SecretKeySpec(cipherKeyPart1, "HmacSHA256")); - byte[] cipherKey = mac.doFinal(syntheticIv); - - Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(new byte[16])); - final byte[] plaintext = cipher.doFinal(cipherText); - - mac.init(new SecretKeySpec(masterSecret, "HmacSHA256")); - byte[] verificationPart1 = mac.doFinal("auth".getBytes()); - - mac.init(new SecretKeySpec(verificationPart1, "HmacSHA256")); - byte[] verificationPart2 = mac.doFinal(plaintext); - byte[] ourSyntheticIv = ByteUtil.trim(verificationPart2, 16); - - if (!MessageDigest.isEqual(ourSyntheticIv, syntheticIv)) { - throw new GeneralSecurityException("The computed syntheticIv didn't match the actual syntheticIv."); - } - - return plaintext; - } - private static class DeviceComparator implements Comparator { @Override diff --git a/app/src/main/java/org/tm/archive/database/model/DisplayRecord.java b/app/src/main/java/org/tm/archive/database/model/DisplayRecord.java index 7e406654..6ff60712 100644 --- a/app/src/main/java/org/tm/archive/database/model/DisplayRecord.java +++ b/app/src/main/java/org/tm/archive/database/model/DisplayRecord.java @@ -239,4 +239,12 @@ public abstract class DisplayRecord { public boolean isPaymentsActivated() { return MessageTypes.isPaymentsActivated(type); } + + public boolean isReportedSpam() { + return MessageTypes.isReportedSpam(type); + } + + public boolean isMessageRequestAccepted() { + return MessageTypes.isMessageRequestAccepted(type); + } } diff --git a/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageConverter.kt b/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageConverter.kt new file mode 100644 index 00000000..c908f935 --- /dev/null +++ b/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageConverter.kt @@ -0,0 +1,681 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.database.model + +import ProtoUtil.isNullOrEmpty +import okio.ByteString +import org.signal.core.util.StringUtil +import org.signal.storageservice.protos.groups.AccessControl +import org.signal.storageservice.protos.groups.AccessControl.AccessRequired +import org.signal.storageservice.protos.groups.Member +import org.signal.storageservice.protos.groups.local.DecryptedGroup +import org.signal.storageservice.protos.groups.local.DecryptedGroupChange +import org.signal.storageservice.protos.groups.local.DecryptedPendingMember +import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember +import org.signal.storageservice.protos.groups.local.EnabledState +import org.tm.archive.backup.v2.proto.GenericGroupUpdate +import org.tm.archive.backup.v2.proto.GroupAdminStatusUpdate +import org.tm.archive.backup.v2.proto.GroupAnnouncementOnlyChangeUpdate +import org.tm.archive.backup.v2.proto.GroupAttributesAccessLevelChangeUpdate +import org.tm.archive.backup.v2.proto.GroupAvatarUpdate +import org.tm.archive.backup.v2.proto.GroupChangeChatUpdate +import org.tm.archive.backup.v2.proto.GroupCreationUpdate +import org.tm.archive.backup.v2.proto.GroupDescriptionUpdate +import org.tm.archive.backup.v2.proto.GroupExpirationTimerUpdate +import org.tm.archive.backup.v2.proto.GroupInvitationAcceptedUpdate +import org.tm.archive.backup.v2.proto.GroupInvitationDeclinedUpdate +import org.tm.archive.backup.v2.proto.GroupInvitationRevokedUpdate +import org.tm.archive.backup.v2.proto.GroupInviteLinkAdminApprovalUpdate +import org.tm.archive.backup.v2.proto.GroupInviteLinkDisabledUpdate +import org.tm.archive.backup.v2.proto.GroupInviteLinkEnabledUpdate +import org.tm.archive.backup.v2.proto.GroupInviteLinkResetUpdate +import org.tm.archive.backup.v2.proto.GroupJoinRequestApprovalUpdate +import org.tm.archive.backup.v2.proto.GroupJoinRequestCanceledUpdate +import org.tm.archive.backup.v2.proto.GroupJoinRequestUpdate +import org.tm.archive.backup.v2.proto.GroupMemberAddedUpdate +import org.tm.archive.backup.v2.proto.GroupMemberJoinedByLinkUpdate +import org.tm.archive.backup.v2.proto.GroupMemberJoinedUpdate +import org.tm.archive.backup.v2.proto.GroupMemberLeftUpdate +import org.tm.archive.backup.v2.proto.GroupMemberRemovedUpdate +import org.tm.archive.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate +import org.tm.archive.backup.v2.proto.GroupNameUpdate +import org.tm.archive.backup.v2.proto.GroupSelfInvitationRevokedUpdate +import org.tm.archive.backup.v2.proto.GroupSequenceOfRequestsAndCancelsUpdate +import org.tm.archive.backup.v2.proto.GroupUnknownInviteeUpdate +import org.tm.archive.backup.v2.proto.GroupV2AccessLevel +import org.tm.archive.backup.v2.proto.SelfInvitedOtherUserToGroupUpdate +import org.tm.archive.backup.v2.proto.SelfInvitedToGroupUpdate +import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context +import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil +import org.whispersystems.signalservice.api.push.ServiceId.Companion.parseOrNull +import org.whispersystems.signalservice.api.push.ServiceIds +import org.whispersystems.signalservice.api.util.UuidUtil +import java.util.LinkedList +import java.util.Optional +import java.util.stream.Collectors + +/** + * Object to help with the translation between DecryptedGroupV2Context group updates + * and GroupChangeChatUpdates, which store the update messages as distinct messages rather + * than diffs of the group state. + */ +object GroupsV2UpdateMessageConverter { + + @JvmStatic + fun translateDecryptedChange(selfIds: ServiceIds, groupContext: DecryptedGroupV2Context): GroupChangeChatUpdate { + if (groupContext.change != null && ((groupContext.groupState != null && groupContext.groupState.revision != 0) || groupContext.previousGroupState != null)) { + return translateDecryptedChangeUpdate(selfIds, groupContext) + } else { + return translateDecryptedChangeNewGroup(selfIds, groupContext) + } + } + + @JvmStatic + fun translateDecryptedChangeNewGroup(selfIds: ServiceIds, groupContext: DecryptedGroupV2Context): GroupChangeChatUpdate { + var selfPending = Optional.empty() + val decryptedGroupChange = groupContext.change + val group = groupContext.groupState + val updates: MutableList = LinkedList() + + if (group != null) { + selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.aci) + if (selfPending.isEmpty() && selfIds.pni != null) { + selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.pni) + } + } + + if (selfPending.isPresent) { + updates.add( + GroupChangeChatUpdate.Update( + selfInvitedToGroupUpdate = SelfInvitedToGroupUpdate(inviterAci = selfPending.get().addedByAci) + ) + ) + return GroupChangeChatUpdate(updates = updates) + } + + if (decryptedGroupChange != null) { + val foundingMemberUuid: ByteString = decryptedGroupChange.editorServiceIdBytes + if (foundingMemberUuid.size > 0) { + if (selfIds.matches(foundingMemberUuid)) { + updates.add( + GroupChangeChatUpdate.Update( + groupCreationUpdate = GroupCreationUpdate(updaterAci = foundingMemberUuid) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberAddedUpdate = GroupMemberAddedUpdate(updaterAci = foundingMemberUuid, newMemberAci = selfIds.aci.toByteString()) + ) + ) + } + return GroupChangeChatUpdate(updates = updates) + } + } + + if (group != null && DecryptedGroupUtil.findMemberByAci(group.members, selfIds.aci).isPresent) { + updates.add(GroupChangeChatUpdate.Update(groupMemberJoinedUpdate = GroupMemberJoinedUpdate(newMemberAci = selfIds.aci.toByteString()))) + } + return GroupChangeChatUpdate(updates = updates) + } + + @JvmStatic + fun translateDecryptedChangeUpdate(selfIds: ServiceIds, groupContext: DecryptedGroupV2Context): GroupChangeChatUpdate { + var previousGroupState = groupContext.previousGroupState + val change = groupContext.change!! + if (DecryptedGroup().equals(previousGroupState)) { + previousGroupState = null + } + val updates: MutableList = LinkedList() + var editorUnknown = change.editorServiceIdBytes.size == 0 + val editorServiceId = if (editorUnknown) null else parseOrNull(change.editorServiceIdBytes) + if (editorServiceId == null || editorServiceId.isUnknown) { + editorUnknown = true + } + translateMemberAdditions(change, editorUnknown, updates) + translateModifyMemberRoles(change, editorUnknown, updates) + translateInvitations(selfIds, change, editorUnknown, updates) + translateRevokedInvitations(selfIds, change, editorUnknown, updates) + translatePromotePending(selfIds, change, editorUnknown, updates) + translateNewTitle(change, editorUnknown, updates) + translateNewDescription(change, editorUnknown, updates) + translateNewAvatar(change, editorUnknown, updates) + translateNewTimer(change, editorUnknown, updates) + translateNewAttributeAccess(change, editorUnknown, updates) + translateNewMembershipAccess(change, editorUnknown, updates) + translateNewGroupInviteLinkAccess(previousGroupState, change, editorUnknown, updates) + translateRequestingMembers(selfIds, change, editorUnknown, updates) + translateRequestingMemberApprovals(selfIds, change, editorUnknown, updates) + translateRequestingMemberDeletes(selfIds, change, editorUnknown, updates) + translateAnnouncementGroupChange(change, editorUnknown, updates) + translatePromotePendingPniAci(selfIds, change, editorUnknown, updates) + translateMemberRemovals(selfIds, change, editorUnknown, updates) + if (updates.isEmpty()) { + translateUnknownChange(change, editorUnknown, updates) + } + return GroupChangeChatUpdate(updates = updates) + } + + @JvmStatic + fun translateMemberAdditions(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + for (member in change.newMembers) { + if (!editorUnknown && member.aciBytes == change.editorServiceIdBytes) { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberJoinedByLinkUpdate = GroupMemberJoinedByLinkUpdate(newMemberAci = member.aciBytes) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberAddedUpdate = GroupMemberAddedUpdate( + updaterAci = if (editorUnknown) null else change.editorServiceIdBytes, + newMemberAci = member.aciBytes, + hadOpenInvitation = false + ) + ) + ) + } + } + } + + @JvmStatic + fun translateModifyMemberRoles(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + for (roleChange in change.modifyMemberRoles) { + updates.add( + GroupChangeChatUpdate.Update( + groupAdminStatusUpdate = GroupAdminStatusUpdate( + updaterAci = if (editorUnknown) null else change.editorServiceIdBytes, + memberAci = roleChange.aciBytes, + wasAdminStatusGranted = roleChange.role == Member.Role.ADMINISTRATOR + ) + ) + ) + } + } + + @JvmStatic + fun translateInvitations(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val editorIsYou = selfIds.matches(change.editorServiceIdBytes) + + var notYouInviteCount = 0 + for (invitee in change.newPendingMembers) { + val newMemberIsYou = selfIds.matches(invitee.serviceIdBytes) + if (newMemberIsYou) { + updates.add( + GroupChangeChatUpdate.Update( + selfInvitedToGroupUpdate = SelfInvitedToGroupUpdate( + inviterAci = if (editorUnknown) convertUnknownUUIDtoNull(invitee.addedByAci) else change.editorServiceIdBytes + ) + ) + ) + } else { + if (editorIsYou) { + updates.add(GroupChangeChatUpdate.Update(selfInvitedOtherUserToGroupUpdate = SelfInvitedOtherUserToGroupUpdate(inviteeServiceId = invitee.serviceIdBytes))) + } else { + notYouInviteCount++ + } + } + } + if (notYouInviteCount > 0) { + updates.add( + GroupChangeChatUpdate.Update( + groupUnknownInviteeUpdate = GroupUnknownInviteeUpdate( + inviterAci = if (editorUnknown) null else change.editorServiceIdBytes, + inviteeCount = notYouInviteCount + ) + ) + ) + } + } + + @JvmStatic + fun translateRevokedInvitations(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + + val revokedInvitees = LinkedList() + + for (invitee in change.deletePendingMembers) { + val decline = invitee.serviceIdBytes == editorAci + if (decline) { + updates.add( + GroupChangeChatUpdate.Update( + groupInvitationDeclinedUpdate = GroupInvitationDeclinedUpdate(inviteeAci = invitee.serviceIdBytes) + ) + ) + } else if (selfIds.matches(invitee.serviceIdBytes)) { + updates.add( + GroupChangeChatUpdate.Update( + groupSelfInvitationRevokedUpdate = GroupSelfInvitationRevokedUpdate(revokerAci = editorAci) + ) + ) + } else { + revokedInvitees.add( + GroupInvitationRevokedUpdate.Invitee( + inviteeAci = invitee.serviceIdBytes + ) + ) + } + } + + if (revokedInvitees.isNotEmpty()) { + updates.add( + GroupChangeChatUpdate.Update( + groupInvitationRevokedUpdate = GroupInvitationRevokedUpdate( + updaterAci = editorAci, + invitees = revokedInvitees + ) + ) + ) + } + } + + @JvmStatic + fun translatePromotePending(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + val editorIsYou = if (editorUnknown) false else selfIds.matches(editorAci) + + for (member in change.promotePendingMembers) { + val newMemberIsYou: Boolean = selfIds.matches(member.aciBytes) + if (editorIsYou) { + if (newMemberIsYou) { + updates.add( + GroupChangeChatUpdate.Update( + groupInvitationAcceptedUpdate = GroupInvitationAcceptedUpdate( + inviterAci = null, + newMemberAci = member.aciBytes + ) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberAddedUpdate = GroupMemberAddedUpdate( + updaterAci = editorAci, + newMemberAci = member.aciBytes, + hadOpenInvitation = true + ) + ) + ) + } + } else if (editorUnknown) { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberJoinedUpdate = GroupMemberJoinedUpdate( + newMemberAci = member.aciBytes + ) + ) + ) + } else if (member.aciBytes == change.editorServiceIdBytes) { + updates.add( + GroupChangeChatUpdate.Update( + groupInvitationAcceptedUpdate = GroupInvitationAcceptedUpdate( + inviterAci = null, + newMemberAci = member.aciBytes + ) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberAddedUpdate = GroupMemberAddedUpdate( + updaterAci = editorAci, + newMemberAci = member.aciBytes, + hadOpenInvitation = true + ) + ) + ) + } + } + } + + @JvmStatic + fun translateNewTitle(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newTitle != null) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + val newTitle = StringUtil.isolateBidi(change.newTitle?.value_) + updates.add( + GroupChangeChatUpdate.Update( + groupNameUpdate = GroupNameUpdate( + updaterAci = editorAci, + newGroupName = newTitle + ) + ) + ) + } + } + + @JvmStatic + fun translateNewDescription(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newDescription != null) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + updates.add( + GroupChangeChatUpdate.Update( + groupDescriptionUpdate = GroupDescriptionUpdate( + updaterAci = editorAci, + newDescription = change.newDescription?.value_ + ) + ) + ) + } + } + + @JvmStatic + fun translateNewAvatar(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newAvatar != null) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + updates.add( + GroupChangeChatUpdate.Update( + groupAvatarUpdate = GroupAvatarUpdate( + updaterAci = editorAci, + wasRemoved = change.newAvatar?.value_.isNullOrEmpty() + ) + ) + ) + } + } + + @JvmStatic + fun translateNewTimer(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newTimer != null) { + updates.add( + GroupChangeChatUpdate.Update( + groupExpirationTimerUpdate = GroupExpirationTimerUpdate( + expiresInMs = change.newTimer!!.duration * 1000, + updaterAci = if (editorUnknown) null else change.editorServiceIdBytes + ) + ) + ) + } + } + + @JvmStatic + fun translateNewAttributeAccess(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + updates.add( + GroupChangeChatUpdate.Update( + groupAttributesAccessLevelChangeUpdate = GroupAttributesAccessLevelChangeUpdate( + updaterAci = editorAci, + accessLevel = translateGv2AccessLevel(change.newAttributeAccess) + ) + ) + ) + } + } + + private fun translateGv2AccessLevel(accessRequired: AccessRequired): GroupV2AccessLevel { + return when (accessRequired) { + AccessRequired.ANY -> GroupV2AccessLevel.ANY + AccessRequired.MEMBER -> GroupV2AccessLevel.MEMBER + AccessRequired.ADMINISTRATOR -> GroupV2AccessLevel.ADMINISTRATOR + AccessRequired.UNSATISFIABLE -> GroupV2AccessLevel.UNSATISFIABLE + AccessRequired.UNKNOWN -> GroupV2AccessLevel.UNKNOWN + else -> GroupV2AccessLevel.UNKNOWN + } + } + + @JvmStatic + fun translateNewMembershipAccess(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newMemberAccess !== AccessRequired.UNKNOWN) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + updates.add( + GroupChangeChatUpdate.Update( + groupMembershipAccessLevelChangeUpdate = GroupMembershipAccessLevelChangeUpdate( + updaterAci = editorAci, + accessLevel = translateGv2AccessLevel(change.newMemberAccess) + ) + ) + ) + } + } + + @JvmStatic + fun translateNewGroupInviteLinkAccess(previousGroupState: DecryptedGroup?, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + var previousAccessControl: AccessRequired? = null + + if (previousGroupState?.accessControl != null) { + previousAccessControl = previousGroupState.accessControl!!.addFromInviteLink + } + + var groupLinkEnabled = false + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + + when (change.newInviteLinkAccess) { + AccessRequired.ANY -> { + groupLinkEnabled = true + updates.add( + if (previousAccessControl == AccessControl.AccessRequired.ADMINISTRATOR) { + GroupChangeChatUpdate.Update( + groupInviteLinkAdminApprovalUpdate = GroupInviteLinkAdminApprovalUpdate( + updaterAci = editorAci, + linkRequiresAdminApproval = false + ) + ) + } else { + GroupChangeChatUpdate.Update( + groupInviteLinkEnabledUpdate = GroupInviteLinkEnabledUpdate( + updaterAci = editorAci, + linkRequiresAdminApproval = false + ) + ) + } + ) + } + AccessRequired.ADMINISTRATOR -> { + groupLinkEnabled = true + updates.add( + if (previousAccessControl == AccessControl.AccessRequired.ANY) { + GroupChangeChatUpdate.Update( + groupInviteLinkAdminApprovalUpdate = GroupInviteLinkAdminApprovalUpdate( + updaterAci = editorAci, + linkRequiresAdminApproval = true + ) + ) + } else { + GroupChangeChatUpdate.Update( + groupInviteLinkEnabledUpdate = GroupInviteLinkEnabledUpdate( + updaterAci = editorAci, + linkRequiresAdminApproval = true + ) + ) + } + ) + } + AccessRequired.UNSATISFIABLE -> { + updates.add( + GroupChangeChatUpdate.Update( + groupInviteLinkDisabledUpdate = GroupInviteLinkDisabledUpdate( + updaterAci = editorAci + ) + ) + ) + } + else -> {} + } + if (!groupLinkEnabled && change.newInviteLinkPassword.size > 0) { + updates.add( + GroupChangeChatUpdate.Update( + groupInviteLinkResetUpdate = GroupInviteLinkResetUpdate( + updaterAci = editorAci + ) + ) + ) + } + } + + @JvmStatic + fun translateRequestingMembers(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val deleteRequestingUuids: Set = HashSet(change.deleteRequestingMembers) + for (member in change.newRequestingMembers) { + val requestingMemberIsYou = selfIds.matches(member.aciBytes) + if (!requestingMemberIsYou && deleteRequestingUuids.contains(member.aciBytes)) { + updates.add( + GroupChangeChatUpdate.Update( + groupSequenceOfRequestsAndCancelsUpdate = GroupSequenceOfRequestsAndCancelsUpdate( + requestorAci = member.aciBytes, + count = change.deleteRequestingMembers.size + ) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupJoinRequestUpdate = GroupJoinRequestUpdate( + requestorAci = member.aciBytes + ) + ) + ) + } + } + } + + @JvmStatic + fun translateRequestingMemberApprovals(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + for (requestingMember in change.promoteRequestingMembers) { + updates.add( + GroupChangeChatUpdate.Update( + groupJoinRequestApprovalUpdate = GroupJoinRequestApprovalUpdate( + updaterAci = editorAci, + requestorAci = requestingMember.aciBytes, + wasApproved = true + ) + ) + ) + } + } + + @JvmStatic + fun translateRequestingMemberDeletes(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val newRequestingUuids = change.newRequestingMembers.stream().map { m: DecryptedRequestingMember -> m.aciBytes }.collect(Collectors.toSet()) + + val editorIsYou = selfIds.matches(change.editorServiceIdBytes) + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + for (requestingMember in change.deleteRequestingMembers) { + if (newRequestingUuids.contains(requestingMember)) { + continue + } + + val requestingMemberIsYou = selfIds.matches(requestingMember) + if ((requestingMemberIsYou && editorIsYou) || (change.editorServiceIdBytes == requestingMember)) { + updates.add( + GroupChangeChatUpdate.Update( + groupJoinRequestCanceledUpdate = GroupJoinRequestCanceledUpdate( + requestorAci = requestingMember + ) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupJoinRequestApprovalUpdate = GroupJoinRequestApprovalUpdate( + requestorAci = requestingMember, + updaterAci = editorAci, + wasApproved = false + ) + ) + ) + } + } + } + + @JvmStatic + fun translateAnnouncementGroupChange(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + if (change.newIsAnnouncementGroup == EnabledState.ENABLED || change.newIsAnnouncementGroup == EnabledState.DISABLED) { + val editorAci = if (editorUnknown) null else change.editorServiceIdBytes + updates.add( + GroupChangeChatUpdate.Update( + groupAnnouncementOnlyChangeUpdate = GroupAnnouncementOnlyChangeUpdate( + updaterAci = editorAci, + isAnnouncementOnly = change.newIsAnnouncementGroup == EnabledState.ENABLED + ) + ) + ) + } + } + + @JvmStatic + fun translatePromotePendingPniAci(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val editorIsYou = selfIds.matches(change.editorServiceIdBytes) + for (newMember in change.promotePendingPniAciMembers) { + if (editorUnknown) { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberJoinedUpdate = GroupMemberJoinedUpdate( + newMemberAci = newMember.aciBytes + ) + ) + ) + } else { + if ((selfIds.matches(newMember.aciBytes) && editorIsYou) || newMember.aciBytes == change.editorServiceIdBytes) { + updates.add( + GroupChangeChatUpdate.Update( + groupInvitationAcceptedUpdate = GroupInvitationAcceptedUpdate( + inviterAci = null, + newMemberAci = newMember.aciBytes + ) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberAddedUpdate = GroupMemberAddedUpdate( + newMemberAci = newMember.aciBytes, + updaterAci = change.editorServiceIdBytes, + hadOpenInvitation = true, + inviterAci = null + ) + ) + ) + } + } + } + } + + @JvmStatic + fun translateMemberRemovals(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + val editorIsYou: Boolean = selfIds.matches(change.editorServiceIdBytes) + for (member in change.deleteMembers) { + val removedMemberIsYou: Boolean = selfIds.matches(member) + if ((editorIsYou && removedMemberIsYou) || member == change.editorServiceIdBytes) { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberLeftUpdate = GroupMemberLeftUpdate(aci = member) + ) + ) + } else { + updates.add( + GroupChangeChatUpdate.Update( + groupMemberRemovedUpdate = GroupMemberRemovedUpdate( + removerAci = if (editorUnknown) null else change.editorServiceIdBytes, + removedAci = member + ) + ) + ) + } + } + } + + @JvmStatic + fun translateUnknownChange(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList) { + updates.add( + GroupChangeChatUpdate.Update( + genericGroupUpdate = GenericGroupUpdate( + updaterAci = if (editorUnknown) null else change.editorServiceIdBytes + ) + ) + ) + } + + private fun convertUnknownUUIDtoNull(id: ByteString?): ByteString? { + if (id.isNullOrEmpty()) return null + val uuid = UuidUtil.fromByteStringOrUnknown(id) + + if (UuidUtil.UNKNOWN_UUID == uuid) return null + return id + } +} diff --git a/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageProducer.java b/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageProducer.java index f4e31d69..62ac7aea 100644 --- a/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageProducer.java +++ b/app/src/main/java/org/tm/archive/database/model/GroupsV2UpdateMessageProducer.java @@ -25,17 +25,57 @@ import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemov import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; import org.signal.storageservice.protos.groups.local.EnabledState; import org.tm.archive.R; +import org.tm.archive.backup.v2.proto.GenericGroupUpdate; +import org.tm.archive.backup.v2.proto.GroupAdminStatusUpdate; +import org.tm.archive.backup.v2.proto.GroupAnnouncementOnlyChangeUpdate; +import org.tm.archive.backup.v2.proto.GroupAttributesAccessLevelChangeUpdate; +import org.tm.archive.backup.v2.proto.GroupAvatarUpdate; +import org.tm.archive.backup.v2.proto.GroupChangeChatUpdate; +import org.tm.archive.backup.v2.proto.GroupCreationUpdate; +import org.tm.archive.backup.v2.proto.GroupDescriptionUpdate; +import org.tm.archive.backup.v2.proto.GroupExpirationTimerUpdate; +import org.tm.archive.backup.v2.proto.GroupInvitationAcceptedUpdate; +import org.tm.archive.backup.v2.proto.GroupInvitationDeclinedUpdate; +import org.tm.archive.backup.v2.proto.GroupInvitationRevokedUpdate; +import org.tm.archive.backup.v2.proto.GroupInviteLinkAdminApprovalUpdate; +import org.tm.archive.backup.v2.proto.GroupInviteLinkDisabledUpdate; +import org.tm.archive.backup.v2.proto.GroupInviteLinkEnabledUpdate; +import org.tm.archive.backup.v2.proto.GroupInviteLinkResetUpdate; +import org.tm.archive.backup.v2.proto.GroupJoinRequestApprovalUpdate; +import org.tm.archive.backup.v2.proto.GroupJoinRequestCanceledUpdate; +import org.tm.archive.backup.v2.proto.GroupJoinRequestUpdate; +import org.tm.archive.backup.v2.proto.GroupMemberAddedUpdate; +import org.tm.archive.backup.v2.proto.GroupMemberJoinedByLinkUpdate; +import org.tm.archive.backup.v2.proto.GroupMemberJoinedUpdate; +import org.tm.archive.backup.v2.proto.GroupMemberLeftUpdate; +import org.tm.archive.backup.v2.proto.GroupMemberRemovedUpdate; +import org.tm.archive.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate; +import org.tm.archive.backup.v2.proto.GroupNameUpdate; +import org.tm.archive.backup.v2.proto.GroupSelfInvitationRevokedUpdate; +import org.tm.archive.backup.v2.proto.GroupUnknownInviteeUpdate; +import org.tm.archive.backup.v2.proto.GroupV2AccessLevel; +import org.tm.archive.backup.v2.proto.GroupV2MigrationDroppedMembersUpdate; +import org.tm.archive.backup.v2.proto.GroupV2MigrationInvitedMembersUpdate; +import org.tm.archive.backup.v2.proto.GroupV2MigrationSelfInvitedUpdate; +import org.tm.archive.backup.v2.proto.GroupV2MigrationUpdate; +import org.tm.archive.backup.v2.proto.SelfInvitedOtherUserToGroupUpdate; +import org.tm.archive.backup.v2.proto.SelfInvitedToGroupUpdate; +import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context; +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription; import org.tm.archive.groups.GV2AccessLevelUtil; +import org.tm.archive.groups.GroupMigrationMembershipChange; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.ExpirationUtil; import org.tm.archive.util.SpanUtil; +import org.tm.archive.util.Util; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceIds; import org.whispersystems.signalservice.api.util.UuidUtil; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -104,6 +144,533 @@ final class GroupsV2UpdateMessageProducer { } } + List describeChanges(@NonNull List groupUpdates) { + List updates = new LinkedList<>(); + for (GroupChangeChatUpdate.Update update : groupUpdates) { + describeUpdate(update, updates); + } + if (updates.isEmpty()) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16)); + } + + return updates; + } + + private void describeUpdate(@NonNull GroupChangeChatUpdate.Update update, @NonNull List updates) { + if (update.genericGroupUpdate != null) { + describeGenericGroupUpdate(update.genericGroupUpdate, updates); + } else if (update.groupCreationUpdate != null) { + describeGroupCreationUpdate(update.groupCreationUpdate, updates); + } else if (update.groupNameUpdate != null) { + describeGroupNameUpdate(update.groupNameUpdate, updates); + } else if (update.groupAvatarUpdate != null) { + describeAvatarChange(update.groupAvatarUpdate, updates); + } else if (update.groupDescriptionUpdate != null) { + describeDescriptionChange(update.groupDescriptionUpdate, updates); + } else if (update.groupMembershipAccessLevelChangeUpdate != null) { + describeGroupMembershipAccessLevelChange(update.groupMembershipAccessLevelChangeUpdate, updates); + } else if (update.groupAttributesAccessLevelChangeUpdate != null) { + describeGroupAttributesAccessLevelChange(update.groupAttributesAccessLevelChangeUpdate, updates); + } else if (update.groupAnnouncementOnlyChangeUpdate != null) { + describeGroupAnnouncementOnlyUpdate(update.groupAnnouncementOnlyChangeUpdate, updates); + } else if (update.groupAdminStatusUpdate != null) { + describeAdminStatusChange(update.groupAdminStatusUpdate, updates); + } else if (update.groupMemberLeftUpdate != null) { + describeGroupMemberLeftChange(update.groupMemberLeftUpdate, updates); + } else if (update.groupMemberRemovedUpdate != null) { + describeGroupMemberRemovedChange(update.groupMemberRemovedUpdate, updates); + } else if (update.selfInvitedToGroupUpdate != null) { + describeSelfInvitedToGroupUpdate(update.selfInvitedToGroupUpdate, updates); + } else if (update.selfInvitedOtherUserToGroupUpdate != null) { + describeSelfInvitedOtherUserToGroupUpdate(update.selfInvitedOtherUserToGroupUpdate, updates); + } else if (update.groupUnknownInviteeUpdate != null) { + describeUnknownUsersInvitedUpdate(update.groupUnknownInviteeUpdate, updates); + } else if (update.groupInvitationAcceptedUpdate != null) { + describeGroupInvitationAcceptedUpdate(update.groupInvitationAcceptedUpdate, updates); + } else if (update.groupMemberJoinedUpdate != null) { + describeGroupMemberJoinedUpdate(update.groupMemberJoinedUpdate, updates); + } else if (update.groupMemberAddedUpdate != null) { + describeGroupMemberAddedUpdate(update.groupMemberAddedUpdate, updates); + } else if (update.groupInvitationDeclinedUpdate != null) { + describeGroupInvitationDeclinedUpdate(update.groupInvitationDeclinedUpdate, updates); + } else if (update.groupInvitationRevokedUpdate != null) { + describeGroupInvitationRevokedUpdate(update.groupInvitationRevokedUpdate, updates); + } else if (update.groupJoinRequestUpdate != null) { + describeGroupJoinRequestUpdate(update.groupJoinRequestUpdate, updates); + } else if (update.groupJoinRequestApprovalUpdate != null) { + describeGroupJoinRequestApprovedUpdate(update.groupJoinRequestApprovalUpdate, updates); + } else if (update.groupJoinRequestCanceledUpdate != null) { + describeGroupJoinRequestCanceledUpdate(update.groupJoinRequestCanceledUpdate, updates); + } else if (update.groupInviteLinkResetUpdate != null) { + describeInviteLinkResetUpdate(update.groupInviteLinkResetUpdate, updates); + } else if (update.groupInviteLinkEnabledUpdate != null) { + describeInviteLinkEnabledUpdate(update.groupInviteLinkEnabledUpdate, updates); + } else if (update.groupInviteLinkDisabledUpdate != null) { + describeInviteLinkDisabledUpdate(update.groupInviteLinkDisabledUpdate, updates); + } else if (update.groupInviteLinkAdminApprovalUpdate != null) { + describeGroupInviteLinkAdminApprovalUpdate(update.groupInviteLinkAdminApprovalUpdate, updates); + } else if (update.groupV2MigrationUpdate != null) { + describeGroupV2MigrationUpdate(update.groupV2MigrationUpdate, updates); + } else if (update.groupV2MigrationDroppedMembersUpdate != null) { + describeGroupV2MigrationDroppedMembersUpdate(update.groupV2MigrationDroppedMembersUpdate, updates); + } else if (update.groupV2MigrationInvitedMembersUpdate != null) { + describeGroupV2MigrationInvitedMembersUpdate(update.groupV2MigrationInvitedMembersUpdate, updates); + } else if (update.groupV2MigrationSelfInvitedUpdate != null) { + describeGroupV2MigrationSelfInvitedUpdate(update.groupV2MigrationSelfInvitedUpdate, updates); + } else if (update.groupMemberJoinedByLinkUpdate != null) { + describeGroupMemberJoinedByLinkUpdate(update.groupMemberJoinedByLinkUpdate, updates); + } else if (update.groupExpirationTimerUpdate != null) { + describeGroupExpirationTimerUpdate(update.groupExpirationTimerUpdate, updates); + } else if (update.groupSelfInvitationRevokedUpdate != null) { + describeGroupSelfInvitationRevokedUpdate(update.groupSelfInvitationRevokedUpdate, updates); + } + } + + private void describeGroupSelfInvitationRevokedUpdate(@NonNull GroupSelfInvitationRevokedUpdate update, @NonNull List updates) { + if (update.revokerAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, update.revokerAci, R.drawable.ic_update_group_decline_16)); + } + } + private void describeGroupExpirationTimerUpdate(@NonNull GroupExpirationTimerUpdate update, @NonNull List updates) { + final int duration = update.expiresInMs / 1000; + String time = ExpirationUtil.getExpirationDisplayValue(context, duration); + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16)); + } else { + boolean editorIsYou = selfIds.matches(update.updaterAci); + if (duration <= 0) { + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages), R.drawable.ic_update_timer_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_disabled_disappearing_messages, update.updaterAci, R.drawable.ic_update_timer_16)); + } + } else { + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, update.updaterAci, time, R.drawable.ic_update_timer_16)); + } + } + } + } + + private void describeGroupMemberJoinedByLinkUpdate(@NonNull GroupMemberJoinedByLinkUpdate update, @NonNull List updates) { + if (selfIds.matches(update.newMemberAci)) { + updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group_via_the_group_link), R.drawable.ic_update_group_accept_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group_via_the_group_link, update.newMemberAci, R.drawable.ic_update_group_accept_16)); + } + } + + private void describeGroupV2MigrationSelfInvitedUpdate(@NonNull GroupV2MigrationSelfInvitedUpdate update, @NonNull List updates) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_couldnt_be_added_to_the_new_group_and_have_been_invited_to_join), R.drawable.ic_update_group_add_16)); + } + + private void describeGroupV2MigrationDroppedMembersUpdate(@NonNull GroupV2MigrationDroppedMembersUpdate update, @NonNull List updates) { + updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, update.droppedMembersCount, update.droppedMembersCount), R.drawable.ic_update_group_remove_16)); + } + + private void describeGroupV2MigrationInvitedMembersUpdate(@NonNull GroupV2MigrationInvitedMembersUpdate update, @NonNull List updates) { + updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, update.invitedMembersCount, update.invitedMembersCount), R.drawable.ic_update_group_remove_16)); + } + + private void describeGroupV2MigrationUpdate(@NonNull GroupV2MigrationUpdate update, @NonNull List updates) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_this_group_was_updated_to_a_new_group), R.drawable.ic_update_group_role_16)); + } + + private void describeGroupInviteLinkAdminApprovalUpdate(@NonNull GroupInviteLinkAdminApprovalUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + if (update.linkRequiresAdminApproval) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_admin_approval_for_the_group_link_has_been_turned_on), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_admin_approval_for_the_group_link_has_been_turned_off), R.drawable.ic_update_group_role_16)); + } + } else { + if (selfIds.matches(update.updaterAci)) { + if (update.linkRequiresAdminApproval) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_on_admin_approval_for_the_group_link), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_off_admin_approval_for_the_group_link), R.drawable.ic_update_group_role_16)); + } + } else { + if (update.linkRequiresAdminApproval) { + updates.add(updateDescription(R.string.MessageRecord_s_turned_on_admin_approval_for_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_turned_off_admin_approval_for_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16)); + } + } + } + } + + private void describeInviteLinkDisabledUpdate(@NonNull GroupInviteLinkDisabledUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_turned_off), R.drawable.ic_update_group_role_16)); + } else { + if (selfIds.matches(update.updaterAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_off_the_group_link), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_turned_off_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16)); + } + } + } + + private void describeInviteLinkEnabledUpdate(@NonNull GroupInviteLinkEnabledUpdate update, @NonNull List updates) { + + if (update.updaterAci == null) { + if (update.linkRequiresAdminApproval) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_turned_on_with_admin_approval_on), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_turned_on_with_admin_approval_off), R.drawable.ic_update_group_role_16)); + } + } else { + if (selfIds.matches(update.updaterAci)) { + if (update.linkRequiresAdminApproval) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_on_the_group_link_with_admin_approval_on), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_on_the_group_link_with_admin_approval_off), R.drawable.ic_update_group_role_16)); + } + } else { + if (update.linkRequiresAdminApproval) { + updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_on, update.updaterAci, R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_off, update.updaterAci, R.drawable.ic_update_group_role_16)); + } + } + } + } + + private void describeInviteLinkResetUpdate(@NonNull GroupInviteLinkResetUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_reset), R.drawable.ic_update_group_role_16)); + } else { + if (selfIds.matches(update.updaterAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_reset_the_group_link), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_reset_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16)); + } + } + } + + private void describeGroupJoinRequestCanceledUpdate(@NonNull GroupJoinRequestCanceledUpdate update, @NonNull List updates) { + boolean requestingMemberIsYou = selfIds.matches(update.requestorAci); + + if (requestingMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_canceled_your_request_to_join_the_group), R.drawable.ic_update_group_decline_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_canceled_their_request_to_join_the_group, update.requestorAci, R.drawable.ic_update_group_decline_16)); + } + } + + private void describeGroupJoinRequestApprovedUpdate(@NonNull GroupJoinRequestApprovalUpdate update, @NonNull List updates) { + boolean requestingMemberIsYou = selfIds.matches(update.requestorAci); + + if (update.wasApproved) { + if (update.updaterAci == null) { + if (requestingMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_approved), R.drawable.ic_update_group_accept_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_approved, update.requestorAci, R.drawable.ic_update_group_accept_16)); + } + } else { + if (requestingMemberIsYou) { + updates.add(updateDescription(R.string.MessageRecord_s_approved_your_request_to_join_the_group, update.updaterAci, R.drawable.ic_update_group_accept_16)); + } else { + boolean editorIsYou = selfIds.matches(update.updaterAci); + + if (editorIsYou) { + updates.add(updateDescription(R.string.MessageRecord_you_approved_a_request_to_join_the_group_from_s, update.requestorAci, R.drawable.ic_update_group_accept_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_approved_a_request_to_join_the_group_from_s, update.updaterAci, update.requestorAci, R.drawable.ic_update_group_accept_16)); + } + } + } + } else { + if (update.updaterAci == null) { + if (requestingMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_denied_by_an_admin), R.drawable.ic_update_group_decline_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_denied, update.requestorAci, R.drawable.ic_update_group_decline_16)); + } + } else { + if (requestingMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_denied_by_an_admin), R.drawable.ic_update_group_decline_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_denied_a_request_to_join_the_group_from_s, update.updaterAci, update.requestorAci, R.drawable.ic_update_group_decline_16)); + } + } + } + } + + private void describeGroupJoinRequestUpdate(@NonNull GroupJoinRequestUpdate update, @NonNull List updates) { + if (selfIds.matches(update.requestorAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_sent_a_request_to_join_the_group), R.drawable.ic_update_group_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_requested_to_join_via_the_group_link, update.requestorAci, R.drawable.ic_update_group_16)); + } + } + + private void describeGroupInvitationRevokedUpdate(@NonNull GroupInvitationRevokedUpdate update, @NonNull List updates) { + int revokedMeCount = 0; + for (GroupInvitationRevokedUpdate.Invitee invitee : update.invitees) { + if ((invitee.inviteeAci != null && selfIds.matches(invitee.inviteeAci)) || (invitee.inviteePni != null && selfIds.matches(invitee.inviteePni))) { + revokedMeCount++; + } + } + + int notMeInvitees = update.invitees.size() - revokedMeCount; + + if (update.updaterAci == null) { + if (revokedMeCount > 0) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); + } + if (notMeInvitees > 0) { + updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_d_invitations_were_revoked, notMeInvitees, notMeInvitees), R.drawable.ic_update_group_decline_16)); + } + } else { + if (revokedMeCount > 0) { + updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, update.updaterAci, R.drawable.ic_update_group_decline_16)); + } + if (selfIds.matches(update.updaterAci)) { + updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_you_revoked_invites, notMeInvitees, notMeInvitees), R.drawable.ic_update_group_decline_16)); + } else { + updates.add(updateDescription(R.plurals.MessageRecord_s_revoked_invites, notMeInvitees, update.updaterAci, notMeInvitees, R.drawable.ic_update_group_decline_16)); + } + } + } + + private void describeGroupInvitationDeclinedUpdate(@NonNull GroupInvitationDeclinedUpdate update, @NonNull List updates) { + if (selfIds.matches(update.inviteeAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_declined_the_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); + } + } + + private void describeGroupMemberAddedUpdate(@NonNull GroupMemberAddedUpdate update, @NonNull List updates) { + boolean newMemberIsYou = selfIds.matches(update.newMemberAci); + + if (update.updaterAci == null) { + if (newMemberIsYou) { + updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, update.newMemberAci, R.drawable.ic_update_group_add_16)); + } + } else { + if (newMemberIsYou) { + updates.add(0, updateDescription(R.string.MessageRecord_s_added_you, update.updaterAci, R.drawable.ic_update_group_add_16)); + } else if (selfIds.matches(update.updaterAci)) { + if (update.hadOpenInvitation) { + updates.add(updateDescription(R.string.MessageRecord_you_added_invited_member_s, update.newMemberAci, R.drawable.ic_update_group_add_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_you_added_s, update.newMemberAci, R.drawable.ic_update_group_add_16)); + } + } else { + if (update.hadOpenInvitation) { + updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, update.updaterAci, update.newMemberAci, R.drawable.ic_update_group_add_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_added_s, update.updaterAci, update.newMemberAci, R.drawable.ic_update_group_add_16)); + } + } + } + } + + private void describeGroupMemberJoinedUpdate(@NonNull GroupMemberJoinedUpdate update, @NonNull List updates) { + boolean newMemberIsYou = selfIds.matches(update.newMemberAci); + + if (newMemberIsYou) { + updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, update.newMemberAci, R.drawable.ic_update_group_add_16)); + } + } + + private void describeGroupInvitationAcceptedUpdate(@NonNull GroupInvitationAcceptedUpdate update, @NonNull List updates) { + if (selfIds.matches(update.newMemberAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_accepted_invite), R.drawable.ic_update_group_accept_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_accepted_invite, update.newMemberAci, R.drawable.ic_update_group_accept_16)); + } + } + + private void describeUnknownUsersInvitedUpdate(@NonNull GroupUnknownInviteeUpdate update, @NonNull List updates) { + if (update.inviterAci == null) { + updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_d_people_were_invited_to_the_group, update.inviteeCount, update.inviteeCount), R.drawable.ic_update_group_add_16)); + } else { + updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, update.inviteeCount, update.inviterAci, update.inviteeCount, R.drawable.ic_update_group_add_16)); + } + } + private void describeSelfInvitedOtherUserToGroupUpdate(@NonNull SelfInvitedOtherUserToGroupUpdate update, @NonNull List updates) { + updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, update.inviteeServiceId, R.drawable.ic_update_group_add_16)); + } + + private void describeSelfInvitedToGroupUpdate(@NonNull SelfInvitedToGroupUpdate update, @NonNull List updates) { + if (update.inviterAci == null) { + updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_were_invited_to_the_group), R.drawable.ic_update_group_add_16)); + } else { + updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, update.inviterAci, R.drawable.ic_update_group_add_16)); + } + } + + private void describeGenericGroupUpdate(@NonNull GenericGroupUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_was_updated), R.drawable.ic_update_group_16)); + } else { + boolean editorIsYou = selfIds.matches(update.updaterAci); + + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_updated_group, update.updaterAci, R.drawable.ic_update_group_16)); + } + } + } + + private void describeGroupCreationUpdate(@NonNull GroupCreationUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16)); + } else { + if (selfIds.matches(update.updaterAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_created_the_group), R.drawable.ic_update_group_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_added_you, update.updaterAci, R.drawable.ic_update_group_add_16)); + } + } + } + + private void describeGroupNameUpdate(@NonNull GroupNameUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(update.newGroupName)), R.drawable.ic_update_group_name_16)); + } else { + String newTitle = StringUtil.isolateBidi(update.newGroupName); + if (selfIds.matches(update.updaterAci)) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_name_to_s, newTitle), R.drawable.ic_update_group_name_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_name_to_s, update.updaterAci, newTitle, R.drawable.ic_update_group_name_16)); + } + } + } + + private void describeGroupMembershipAccessLevelChange(@NonNull GroupMembershipAccessLevelChangeUpdate update, @NonNull List updates) { + if (update.accessLevel == GroupV2AccessLevel.UNKNOWN) { + return; + } + String accessLevel = GV2AccessLevelUtil.toString(context, backupGv2AccessLevelToGroups(update.accessLevel)); + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_membership_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16)); + } else { + boolean editorIsYou = selfIds.matches(update.updaterAci); + + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_membership_to_s, accessLevel), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_membership_to_s, update.updaterAci, accessLevel, R.drawable.ic_update_group_role_16)); + } + } + } + + private void describeGroupAttributesAccessLevelChange(@NonNull GroupAttributesAccessLevelChangeUpdate update, @NonNull List updates) { + if (update.accessLevel == GroupV2AccessLevel.UNKNOWN) { + return; + } + String accessLevel = GV2AccessLevelUtil.toString(context, backupGv2AccessLevelToGroups(update.accessLevel)); + if (update.updaterAci == null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_info_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16)); + } else { + boolean editorIsYou = selfIds.matches(update.updaterAci); + + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_info_to_s, accessLevel), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_info_to_s, update.updaterAci, accessLevel, R.drawable.ic_update_group_role_16)); + } + } + } + + private void describeGroupAnnouncementOnlyUpdate(@NonNull GroupAnnouncementOnlyChangeUpdate update, @NonNull List updates) { + if (update.updaterAci == null) { + if (update.isAnnouncementOnly) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_only_admins_to_send), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_all_members_to_send), R.drawable.ic_update_group_role_16)); + } + } else { + boolean editorIsYou = selfIds.matches(update.updaterAci); + + if (update.isAnnouncementOnly) { + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_only_admins_to_send), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_allow_only_admins_to_send, update.updaterAci, R.drawable.ic_update_group_role_16)); + } + } else { + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_all_members_to_send), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_allow_all_members_to_send, update.updaterAci, R.drawable.ic_update_group_role_16)); + } + } + } + } + + private void describeGroupMemberLeftChange(@NonNull GroupMemberLeftUpdate update, @NonNull List updates) { + if (update.aci == null) { + return; + } + boolean editorIsYou = selfIds.matches(update.aci); + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_left_the_group), R.drawable.ic_update_group_leave_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_left_the_group, update.aci, R.drawable.ic_update_group_leave_16)); + } + } + + private void describeGroupMemberRemovedChange(@NonNull GroupMemberRemovedUpdate update, @NonNull List updates) { + if (update.removerAci == null) { + boolean removedMemberIsYou = selfIds.matches(update.removedAci); + + if (removedMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_no_longer_in_the_group), R.drawable.ic_update_group_leave_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_in_the_group, update.removedAci, R.drawable.ic_update_group_leave_16)); + } + } else { + boolean editorIsYou = selfIds.matches(update.removerAci); + + boolean removedMemberIsYou = selfIds.matches(update.removedAci); + + if (editorIsYou) { + if (removedMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_left_the_group), R.drawable.ic_update_group_leave_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_you_removed_s, update.removedAci, R.drawable.ic_update_group_remove_16)); + } + } else { + if (removedMemberIsYou) { + updates.add(updateDescription(R.string.MessageRecord_s_removed_you_from_the_group, update.removerAci, R.drawable.ic_update_group_remove_16)); + } else { + if (update.removerAci.equals(update.removedAci)) { + updates.add(updateDescription(R.string.MessageRecord_s_left_the_group, update.removedAci, R.drawable.ic_update_group_leave_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_removed_s, update.removerAci, update.removedAci, R.drawable.ic_update_group_remove_16)); + } + } + } + } + } + + private AccessControl.AccessRequired backupGv2AccessLevelToGroups(@NonNull GroupV2AccessLevel accessLevel) { + switch (accessLevel) { + case ANY: return AccessControl.AccessRequired.ANY; + case MEMBER: return AccessControl.AccessRequired.MEMBER; + case ADMINISTRATOR: return AccessControl.AccessRequired.ADMINISTRATOR; + case UNSATISFIABLE: return AccessControl.AccessRequired.UNSATISFIABLE; + default: + case UNKNOWN: return AccessControl.AccessRequired.UNKNOWN; + } + } + List describeChanges(@Nullable DecryptedGroup previousGroupState, @NonNull DecryptedGroupChange change) { if (new DecryptedGroup().equals(previousGroupState)) { previousGroupState = null; @@ -317,6 +884,51 @@ final class GroupsV2UpdateMessageProducer { } } + private void describeAdminStatusChange(@NonNull GroupAdminStatusUpdate groupAdminStatusUpdate, List updates) { + boolean changedMemberIsYou = selfIds.matches(groupAdminStatusUpdate.memberAci); + + if (groupAdminStatusUpdate.updaterAci != null) { + boolean editorIsYou = selfIds.matches(groupAdminStatusUpdate.updaterAci); + + if (groupAdminStatusUpdate.wasAdminStatusGranted) { + if (editorIsYou) { + updates.add(updateDescription(R.string.MessageRecord_you_made_s_an_admin, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16)); + } else { + if (changedMemberIsYou) { + updates.add(updateDescription(R.string.MessageRecord_s_made_you_an_admin, groupAdminStatusUpdate.updaterAci, R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_made_s_an_admin, groupAdminStatusUpdate.updaterAci, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16)); + + } + } + } else { + if (editorIsYou) { + updates.add(updateDescription(R.string.MessageRecord_you_revoked_admin_privileges_from_s, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16)); + } else { + if (changedMemberIsYou) { + updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_admin_privileges, groupAdminStatusUpdate.updaterAci, R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_revoked_admin_privileges_from_s, groupAdminStatusUpdate.updaterAci, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16)); + } + } + } + } else { + if (groupAdminStatusUpdate.wasAdminStatusGranted) { + if (changedMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_now_an_admin), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_is_now_an_admin, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16)); + } + } else { + if (changedMemberIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_no_longer_an_admin), R.drawable.ic_update_group_role_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_an_admin, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16)); + } + } + } + } + private void describeInvitations(@NonNull DecryptedGroupChange change, @NonNull List updates) { boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); int notYouInviteCount = 0; @@ -481,6 +1093,20 @@ final class GroupsV2UpdateMessageProducer { } } + private void describeDescriptionChange(@NonNull GroupDescriptionUpdate groupDescriptionUpdate, @NonNull List updates) { + if (groupDescriptionUpdate.updaterAci != null) { + boolean editorIsYou = selfIds.matches(groupDescriptionUpdate.updaterAci); + + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_description), R.drawable.ic_update_group_name_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_description, groupDescriptionUpdate.updaterAci, R.drawable.ic_update_group_name_16)); + } + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(groupDescriptionUpdate.newDescription)), R.drawable.ic_update_group_name_16)); + } + } + private void describeUnknownEditorNewDescription(@NonNull DecryptedGroupChange change, @NonNull List updates) { if (change.newDescription != null) { updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_description_has_changed), R.drawable.ic_update_group_name_16)); @@ -499,6 +1125,20 @@ final class GroupsV2UpdateMessageProducer { } } + private void describeAvatarChange(@NonNull GroupAvatarUpdate groupAvatarUpdate, @NonNull List updates) { + if (groupAvatarUpdate.updaterAci != null) { + boolean editorIsYou = selfIds.matches(groupAvatarUpdate.updaterAci); + + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_avatar), R.drawable.ic_update_group_avatar_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_avatar, groupAvatarUpdate.updaterAci, R.drawable.ic_update_group_avatar_16)); + } + } else { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16)); + } + } + private void describeUnknownEditorNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List updates) { if (change.newAvatar != null) { updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16)); @@ -509,11 +1149,20 @@ final class GroupsV2UpdateMessageProducer { boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); if (change.newTimer != null) { - String time = ExpirationUtil.getExpirationDisplayValue(context, change.newTimer.duration); - if (editorIsYou) { - updates.add(updateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16)); + final int duration = change.newTimer.duration; + if (duration <= 0) { + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages), R.drawable.ic_update_timer_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_disabled_disappearing_messages, change.editorServiceIdBytes, R.drawable.ic_update_timer_16)); + } } else { - updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, change.editorServiceIdBytes, time, R.drawable.ic_update_timer_16)); + String time = ExpirationUtil.getExpirationDisplayValue(context, duration); + if (editorIsYou) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16)); + } else { + updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, change.editorServiceIdBytes, time, R.drawable.ic_update_timer_16)); + } } } } diff --git a/app/src/main/java/org/tm/archive/database/model/InMemoryMessageRecord.java b/app/src/main/java/org/tm/archive/database/model/InMemoryMessageRecord.java index faca8e8b..2a015ff2 100644 --- a/app/src/main/java/org/tm/archive/database/model/InMemoryMessageRecord.java +++ b/app/src/main/java/org/tm/archive/database/model/InMemoryMessageRecord.java @@ -56,7 +56,8 @@ public class InMemoryMessageRecord extends MessageRecord { false, -1, null, - 0); + 0, + null); } @Override @@ -82,45 +83,6 @@ public class InMemoryMessageRecord extends MessageRecord { return 0; } - /** - * Warning message to show during message request state if you do not have groups in common - * with an individual or do not know anyone in the group. - */ - public static final class NoGroupsInCommon extends InMemoryMessageRecord { - private final boolean isGroup; - - public NoGroupsInCommon(long threadId, boolean isGroup) { - super(NO_GROUPS_IN_COMMON_ID, "", Recipient.UNKNOWN, threadId, 0); - this.isGroup = isGroup; - } - - @Override - public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context, @Nullable Consumer recipientClickHandler) { - return UpdateDescription.staticDescription(context.getString(isGroup ? R.string.ConversationUpdateItem_no_contacts_in_this_group_review_requests_carefully - : R.string.ConversationUpdateItem_no_groups_in_common_review_requests_carefully), - R.drawable.symbol_info_compact_16); - } - - @Override - public boolean isUpdate() { - return true; - } - - @Override - public boolean showActionButton() { - return true; - } - - public boolean isGroup() { - return isGroup; - } - - @Override - public @StringRes int getActionButtonText() { - return R.string.ConversationUpdateItem_learn_more; - } - } - public static final class RemovedContactHidden extends InMemoryMessageRecord { public RemovedContactHidden(long threadId) { diff --git a/app/src/main/java/org/tm/archive/database/model/MessageRecord.java b/app/src/main/java/org/tm/archive/database/model/MessageRecord.java index 07fd9fbc..eea1a45d 100644 --- a/app/src/main/java/org/tm/archive/database/model/MessageRecord.java +++ b/app/src/main/java/org/tm/archive/database/model/MessageRecord.java @@ -45,6 +45,7 @@ import org.tm.archive.database.documents.NetworkFailure; import org.tm.archive.database.model.databaseprotos.BodyRangeList; import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context; import org.tm.archive.database.model.databaseprotos.GroupCallUpdateDetails; +import org.tm.archive.database.model.databaseprotos.MessageExtras; import org.tm.archive.database.model.databaseprotos.ProfileChangeDetails; import org.tm.archive.database.model.databaseprotos.SessionSwitchoverEvent; import org.tm.archive.database.model.databaseprotos.ThreadMergeEvent; @@ -104,6 +105,7 @@ public abstract class MessageRecord extends DisplayRecord { private final long receiptTimestamp; private final MessageId originalMessageId; private final int revisionNumber; + private final MessageExtras messageExtras; protected Boolean isJumboji = null; @@ -123,7 +125,8 @@ public abstract class MessageRecord extends DisplayRecord { boolean viewed, long receiptTimestamp, @Nullable MessageId originalMessageId, - int revisionNumber) + int revisionNumber, + @Nullable MessageExtras messageExtras) { super(body, fromRecipient, toRecipient, dateSent, dateReceived, threadId, deliveryStatus, hasDeliveryReceipt, type, @@ -143,6 +146,7 @@ public abstract class MessageRecord extends DisplayRecord { this.receiptTimestamp = receiptTimestamp; this.originalMessageId = originalMessageId; this.revisionNumber = revisionNumber; + this.messageExtras = messageExtras; } public abstract boolean isMms(); @@ -176,7 +180,11 @@ public abstract class MessageRecord extends DisplayRecord { public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context, @Nullable Consumer recipientClickHandler) { if (isGroupUpdate() && isGroupV2()) { - return getGv2ChangeDescription(context, getBody(), recipientClickHandler); + if (messageExtras != null) { + return getGv2ChangeDescription(context, messageExtras, recipientClickHandler); + } else { + return getGv2ChangeDescription(context, getBody(), recipientClickHandler); + } } else if (isGroupUpdate() && isOutgoing()) { return staticUpdateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16); } else if (isGroupUpdate()) { @@ -219,7 +227,7 @@ public abstract class MessageRecord extends DisplayRecord { if (isOutgoing()) return fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), R.drawable.ic_update_info_16); else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16); } else if (isProfileChange()) { - return staticUpdateDescription(getProfileChangeDescription(context), R.drawable.ic_update_profile_16); + return getProfileChangeDescription(context); } else if (isChangeNumber()) { return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), R.drawable.ic_phone_16); } else if (isBoostRequest()) { @@ -252,14 +260,13 @@ public abstract class MessageRecord extends DisplayRecord { if (event.e164.isEmpty()) { return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16); } else { - return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(r.requireE164()), r.getDisplayName(context)), R.drawable.ic_update_info_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(event.e164), r.getDisplayName(context)), R.drawable.ic_update_info_16); } } catch (IOException e) { throw new AssertionError(e); } } else if (isSmsExportType()) { - int messageResource = SignalStore.misc().getSmsExportPhase().isSmsSupported() ? R.string.MessageRecord__you_will_no_longer_be_able_to_send_sms_messages_from_signal_soon - : R.string.MessageRecord__you_can_no_longer_send_sms_messages_in_signal; + int messageResource = R.string.MessageRecord__you_can_no_longer_send_sms_messages_in_signal; return fromRecipient(getFromRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), R.drawable.ic_update_info_16); } else if (isPaymentsRequestToActivate()) { return isOutgoing() ? fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments) @@ -267,6 +274,10 @@ public abstract class MessageRecord extends DisplayRecord { } else if (isPaymentsActivated()) { return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_activated_payments), R.drawable.ic_card_activate_payments) : fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments); + } else if (isReportedSpam()) { + return staticUpdateDescription(context.getString(R.string.MessageRecord_reported_as_spam), R.drawable.symbol_spam_16); + } else if (isMessageRequestAccepted()) { + return staticUpdateDescription(context.getString(R.string.MessageRecord_you_accepted_the_message_request), R.drawable.symbol_thread_16); } return null; @@ -287,6 +298,10 @@ public abstract class MessageRecord extends DisplayRecord { return selfCreatedGroup(change); } + public @Nullable MessageExtras getMessageExtras() { + return messageExtras; + } + @VisibleForTesting @Nullable DecryptedGroupV2Context getDecryptedGroupV2Context() { if (!isGroupUpdate() || !isGroupV2()) { @@ -315,6 +330,30 @@ public abstract class MessageRecord extends DisplayRecord { try { byte[] decoded = Base64.decode(body); DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded); + return getGv2ChangeDescription(context, decryptedGroupV2Context, recipientClickHandler); + } catch (IOException | IllegalArgumentException | IllegalStateException e) { + Log.w(TAG, "GV2 Message update detail could not be read", e); + return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16); + } + } + + public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull MessageExtras messageExtras, @Nullable Consumer recipientClickHandler) { + if (messageExtras.gv2UpdateDescription != null) { + if (messageExtras.gv2UpdateDescription.groupChangeUpdate != null) { + GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler); + + return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(messageExtras.gv2UpdateDescription.groupChangeUpdate.updates)); + } else if (messageExtras.gv2UpdateDescription.gv2ChangeDescription != null) { + return getGv2ChangeDescription(context, messageExtras.gv2UpdateDescription.gv2ChangeDescription, recipientClickHandler); + } else { + Log.w(TAG, "GV2 Update Description missing group change update!"); + } + } + return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16); + } + + public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull DecryptedGroupV2Context decryptedGroupV2Context, @Nullable Consumer recipientClickHandler) { + try { GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler); if (decryptedGroupV2Context.change != null && ((decryptedGroupV2Context.groupState != null && decryptedGroupV2Context.groupState.revision != 0) || decryptedGroupV2Context.previousGroupState != null)) { @@ -332,7 +371,7 @@ public abstract class MessageRecord extends DisplayRecord { } return UpdateDescription.concatWithNewLines(newGroupDescriptions); } - } catch (IOException | IllegalArgumentException | IllegalStateException e) { + } catch (IllegalArgumentException | IllegalStateException e) { Log.w(TAG, "GV2 Message update detail could not be read", e); return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16); } @@ -392,27 +431,41 @@ public abstract class MessageRecord extends DisplayRecord { return UpdateDescription.staticDescription(string, iconResource, lightTint, darkTint); } - private @NonNull String getProfileChangeDescription(@NonNull Context context) { - try { - byte[] decoded = Base64.decode(getBody()); - ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.ADAPTER.decode(decoded); + private @NonNull UpdateDescription getProfileChangeDescription(@NonNull Context context) { + ProfileChangeDetails profileChangeDetails = null; + MessageExtras extras = getMessageExtras(); + if (extras != null) { + profileChangeDetails = extras.profileChangeDetails; + } else { + try { + byte[] decoded = Base64.decode(getBody()); + profileChangeDetails = ProfileChangeDetails.ADAPTER.decode(decoded); + } catch (IOException e) { + Log.w(TAG, "Profile name change details could not be read", e); + } + } + + if (profileChangeDetails != null) { if (profileChangeDetails.profileNameChange != null) { String displayName = getFromRecipient().getDisplayName(context); String newName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.profileNameChange.newValue).toString()); String previousName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.profileNameChange.previous).toString()); + String updateMessage; if (getFromRecipient().isSystemContact()) { - return context.getString(R.string.MessageRecord_changed_their_profile_name_from_to, displayName, previousName, newName); + updateMessage = context.getString(R.string.MessageRecord_changed_their_profile_name_from_to, displayName, previousName, newName); } else { - return context.getString(R.string.MessageRecord_changed_their_profile_name_to, previousName, newName); + updateMessage = context.getString(R.string.MessageRecord_changed_their_profile_name_to, previousName, newName); } + + return staticUpdateDescription(updateMessage, R.drawable.ic_update_profile_16); + } else if (profileChangeDetails.learnedProfileName != null) { + return staticUpdateDescription(context.getString(R.string.MessageRecord_started_this_chat, profileChangeDetails.learnedProfileName.previous), R.drawable.symbol_thread_16); } - } catch (IOException e) { - Log.w(TAG, "Profile name change details could not be read", e); } - return context.getString(R.string.MessageRecord_changed_their_profile, getFromRecipient().getDisplayName(context)); + return staticUpdateDescription(context.getString(R.string.MessageRecord_changed_their_profile, getFromRecipient().getDisplayName(context)), R.drawable.ic_update_profile_16); } private UpdateDescription getGroupMigrationEventDescription(@NonNull Context context) { @@ -600,7 +653,7 @@ public abstract class MessageRecord extends DisplayRecord { isEndSession() || isIdentityUpdate() || isIdentityVerified() || isIdentityDefault() || isProfileChange() || isGroupV1MigrationEvent() || isChatSessionRefresh() || isBadDecryptType() || isChangeNumber() || isBoostRequest() || isThreadMergeEventType() || isSmsExportType() || isSessionSwitchoverEventType() || - isPaymentsRequestToActivate() || isPaymentsActivated(); + isPaymentsRequestToActivate() || isPaymentsActivated() || isReportedSpam() || isMessageRequestAccepted(); } public boolean isMediaPending() { diff --git a/app/src/main/java/org/tm/archive/database/model/MmsMessageRecord.java b/app/src/main/java/org/tm/archive/database/model/MmsMessageRecord.java index 57469c89..8d8a2cd7 100644 --- a/app/src/main/java/org/tm/archive/database/model/MmsMessageRecord.java +++ b/app/src/main/java/org/tm/archive/database/model/MmsMessageRecord.java @@ -26,6 +26,7 @@ import org.tm.archive.database.documents.IdentityKeyMismatch; import org.tm.archive.database.documents.NetworkFailure; import org.tm.archive.database.model.databaseprotos.BodyRangeList; import org.tm.archive.database.model.databaseprotos.GiftBadge; +import org.tm.archive.database.model.databaseprotos.MessageExtras; import org.tm.archive.linkpreview.LinkPreview; import org.tm.archive.mms.Slide; import org.tm.archive.mms.SlideDeck; @@ -111,12 +112,13 @@ public class MmsMessageRecord extends MessageRecord { @Nullable MessageId latestRevisionId, @Nullable MessageId originalMessageId, int revisionNumber, - boolean isRead) + boolean isRead, + @Nullable MessageExtras messageExtras) { super(id, body, fromRecipient, fromDeviceId, toRecipient, dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, hasDeliveryReceipt, mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, hasReadReceipt, - unidentified, reactions, remoteDelete, notifiedTimestamp, viewed, receiptTimestamp, originalMessageId, revisionNumber); + unidentified, reactions, remoteDelete, notifiedTimestamp, viewed, receiptTimestamp, originalMessageId, revisionNumber, messageExtras); this.slideDeck = slideDeck; this.quote = quote; @@ -299,7 +301,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber(), isRead()); + getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras()); } public @NonNull MmsMessageRecord withoutQuote() { @@ -307,7 +309,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber(), isRead()); + getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras()); } public @NonNull MmsMessageRecord withAttachments(@NonNull List attachments) { @@ -329,7 +331,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber(), isRead()); + getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras()); } public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) { @@ -337,7 +339,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber(), isRead()); + getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras()); } @@ -346,7 +348,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber(), isRead()); + getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras()); } private static @NonNull List updateContacts(@NonNull List contacts, @NonNull Map attachmentIdMap) { diff --git a/app/src/main/java/org/tm/archive/database/model/RecipientRecord.kt b/app/src/main/java/org/tm/archive/database/model/RecipientRecord.kt index 621ce1e9..a0338660 100644 --- a/app/src/main/java/org/tm/archive/database/model/RecipientRecord.kt +++ b/app/src/main/java/org/tm/archive/database/model/RecipientRecord.kt @@ -78,7 +78,9 @@ data class RecipientRecord( val needsPniSignature: Boolean, val hiddenState: Recipient.HiddenState, val callLinkRoomId: CallLinkRoomId?, - val phoneNumberSharing: PhoneNumberSharingState + val phoneNumberSharing: PhoneNumberSharingState, + val nickname: ProfileName, + val note: String? ) { fun e164Only(): Boolean { @@ -111,17 +113,12 @@ data class RecipientRecord( val isArchived: Boolean, val isForcedUnread: Boolean, val unregisteredTimestamp: Long, - val systemNickname: String? + val systemNickname: String?, + val pniSignatureVerified: Boolean ) data class Capabilities( val rawBits: Long, - val groupsV1MigrationCapability: Recipient.Capability, - val senderKeyCapability: Recipient.Capability, - val announcementGroupCapability: Recipient.Capability, - val changeNumberCapability: Recipient.Capability, - val storiesCapability: Recipient.Capability, - val giftBadgesCapability: Recipient.Capability, val pnpCapability: Recipient.Capability, val paymentActivation: Recipient.Capability ) { @@ -130,12 +127,6 @@ data class RecipientRecord( val UNKNOWN = Capabilities( 0, Recipient.Capability.UNKNOWN, - Recipient.Capability.UNKNOWN, - Recipient.Capability.UNKNOWN, - Recipient.Capability.UNKNOWN, - Recipient.Capability.UNKNOWN, - Recipient.Capability.UNKNOWN, - Recipient.Capability.UNKNOWN, Recipient.Capability.UNKNOWN ) } diff --git a/app/src/main/java/org/tm/archive/database/model/ThreadRecord.java b/app/src/main/java/org/tm/archive/database/model/ThreadRecord.java index e0c65ac6..c1188e9f 100644 --- a/app/src/main/java/org/tm/archive/database/model/ThreadRecord.java +++ b/app/src/main/java/org/tm/archive/database/model/ThreadRecord.java @@ -26,6 +26,7 @@ import org.tm.archive.database.MessageTypes; import org.tm.archive.database.ThreadTable; import org.tm.archive.database.ThreadTable.Extra; import org.tm.archive.database.model.databaseprotos.BodyRangeList; +import org.tm.archive.database.model.databaseprotos.MessageExtras; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.whispersystems.signalservice.api.util.Preconditions; @@ -37,26 +38,27 @@ import java.util.Objects; */ public final class ThreadRecord { - private final long threadId; - private final String body; - private final Recipient recipient; - private final long type; - private final long date; - private final long deliveryStatus; - private final boolean hasDeliveryReceipt; - private final boolean hasReadReceipt; - private final Uri snippetUri; - private final String contentType; - private final Extra extra; - private final boolean meaningfulMessages; - private final int unreadCount; - private final boolean forcedUnread; - private final int distributionType; - private final boolean archived; - private final long expiresIn; - private final long lastSeen; - private final boolean isPinned; - private final int unreadSelfMentionsCount; + private final long threadId; + private final String body; + private final Recipient recipient; + private final long type; + private final long date; + private final long deliveryStatus; + private final boolean hasDeliveryReceipt; + private final boolean hasReadReceipt; + private final Uri snippetUri; + private final String contentType; + private final Extra extra; + private final boolean meaningfulMessages; + private final int unreadCount; + private final boolean forcedUnread; + private final int distributionType; + private final boolean archived; + private final long expiresIn; + private final long lastSeen; + private final boolean isPinned; + private final int unreadSelfMentionsCount; + private final MessageExtras messageExtras; private ThreadRecord(@NonNull Builder builder) { this.threadId = builder.threadId; @@ -79,6 +81,7 @@ public final class ThreadRecord { this.lastSeen = builder.lastSeen; this.isPinned = builder.isPinned; this.unreadSelfMentionsCount = builder.unreadSelfMentionsCount; + this.messageExtras = builder.messageExtras; } public long getThreadId() { @@ -189,6 +192,10 @@ public final class ThreadRecord { return extra != null && extra.isScheduled(); } + public @Nullable MessageExtras getMessageExtras() { + return messageExtras; + } + public @Nullable RecipientId getGroupAddedBy() { if (extra != null && extra.getGroupAddedBy() != null) return RecipientId.from(extra.getGroupAddedBy()); else return null; @@ -287,26 +294,27 @@ public final class ThreadRecord { } public static class Builder { - private long threadId; - private String body; - private Recipient recipient = Recipient.UNKNOWN; - private long type; - private long date; - private long deliveryStatus; - private boolean hasDeliveryReceipt; - private boolean hasReadReceipt; - private Uri snippetUri; - private String contentType; - private Extra extra; - private boolean meaningfulMessages; - private int unreadCount; - private boolean forcedUnread; - private int distributionType; - private boolean archived; - private long expiresIn; - private long lastSeen; - private boolean isPinned; - private int unreadSelfMentionsCount; + private long threadId; + private String body; + private Recipient recipient = Recipient.UNKNOWN; + private long type; + private long date; + private long deliveryStatus; + private boolean hasDeliveryReceipt; + private boolean hasReadReceipt; + private Uri snippetUri; + private String contentType; + private Extra extra; + private boolean meaningfulMessages; + private int unreadCount; + private boolean forcedUnread; + private int distributionType; + private boolean archived; + private long expiresIn; + private long lastSeen; + private boolean isPinned; + private int unreadSelfMentionsCount; + private MessageExtras messageExtras; public Builder(long threadId) { this.threadId = threadId; @@ -407,6 +415,11 @@ public final class ThreadRecord { return this; } + public Builder setSnippetMessageExtras(@Nullable MessageExtras messageExtras) { + this.messageExtras = messageExtras; + return this; + } + public Builder setUnreadSelfMentionsCount(int unreadSelfMentionsCount) { this.unreadSelfMentionsCount = unreadSelfMentionsCount; return this; diff --git a/app/src/main/java/org/tm/archive/delete/DeleteAccountFragment.java b/app/src/main/java/org/tm/archive/delete/DeleteAccountFragment.java index b6c4e6fc..4d725d05 100644 --- a/app/src/main/java/org/tm/archive/delete/DeleteAccountFragment.java +++ b/app/src/main/java/org/tm/archive/delete/DeleteAccountFragment.java @@ -85,13 +85,13 @@ public class DeleteAccountFragment extends Fragment { } private @NonNull CharSequence buildBulletsText(@NonNull Optional formattedBalance) { - SpannableStringBuilder builder = new SpannableStringBuilder().append(SpanUtil.bullet(getString(R.string.DeleteAccountFragment__delete_your_account_info_and_profile_photo))) + SpannableStringBuilder builder = new SpannableStringBuilder().append(SpanUtil.bullet(getString(R.string.DeleteAccountFragment__delete_your_account_info_and_profile_photo),8)) .append("\n") - .append(SpanUtil.bullet(getString(R.string.DeleteAccountFragment__delete_all_your_messages))); + .append(SpanUtil.bullet(getString(R.string.DeleteAccountFragment__delete_all_your_messages),8)); if (formattedBalance.isPresent()) { builder.append("\n"); - builder.append(SpanUtil.bullet(getString(R.string.DeleteAccountFragment__delete_s_in_your_payments_account, formattedBalance.get()))); + builder.append(SpanUtil.bullet(getString(R.string.DeleteAccountFragment__delete_s_in_your_payments_account, formattedBalance.get()),8)); } return builder; diff --git a/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencies.java b/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencies.java index 40ea5734..2b6ca1ef 100644 --- a/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencies.java +++ b/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencies.java @@ -589,6 +589,12 @@ public class ApplicationDependencies { return protocolStore; } + public static void resetProtocolStores() { + synchronized (LOCK) { + protocolStore = null; + } + } + public static @NonNull GiphyMp4Cache getGiphyMp4Cache() { if (giphyMp4Cache == null) { synchronized (LOCK) { diff --git a/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencyProvider.java index 0e8d99d5..66b39d95 100644 --- a/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/tm/archive/dependencies/ApplicationDependencyProvider.java @@ -136,7 +136,8 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr provideGroupsV2Operations(signalServiceConfiguration).getProfileOperations(), SignalExecutors.newCachedBoundedExecutor("signal-messages", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 16, 30), ByteUnit.KILOBYTES.toBytes(256), - FeatureFlags.okHttpAutomaticRetry()); + FeatureFlags.okHttpAutomaticRetry(), + FeatureFlags.useRxMessageSending()); } @Override diff --git a/app/src/main/java/org/tm/archive/devicetransfer/DeviceTransferSetupFragment.java b/app/src/main/java/org/tm/archive/devicetransfer/DeviceTransferSetupFragment.java index e297044c..1f8e384d 100644 --- a/app/src/main/java/org/tm/archive/devicetransfer/DeviceTransferSetupFragment.java +++ b/app/src/main/java/org/tm/archive/devicetransfer/DeviceTransferSetupFragment.java @@ -282,7 +282,7 @@ public abstract class DeviceTransferSetupFragment extends LoggingFragment { Permissions.with(this) .request(WifiDirect.requiredPermission()) .ifNecessary() - .withRationaleDialog(getString(getErrorTextForStep(SetupStep.PERMISSIONS_DENIED)), false, R.drawable.ic_location_on_white_24dp) + .withRationaleDialog(getString(getErrorTextForStep(SetupStep.PERMISSIONS_DENIED)), false, R.drawable.symbol_location_white_24) .withPermanentDenialDialog(getString(getErrorTextForStep(SetupStep.PERMISSIONS_DENIED))) .onAllGranted(() -> viewModel.onPermissionsGranted()) .onAnyDenied(() -> viewModel.onLocationPermissionDenied()) diff --git a/app/src/main/java/org/tm/archive/devicetransfer/moreoptions/MoreTransferOrRestoreOptionsMode.kt b/app/src/main/java/org/tm/archive/devicetransfer/moreoptions/MoreTransferOrRestoreOptionsMode.kt new file mode 100644 index 00000000..b0a443d2 --- /dev/null +++ b/app/src/main/java/org/tm/archive/devicetransfer/moreoptions/MoreTransferOrRestoreOptionsMode.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.devicetransfer.moreoptions + +/** + * Allows component opening sheet to specify mode + */ +enum class MoreTransferOrRestoreOptionsMode { + /** + * Only display the option to log in without transferring. Selection + * will be disabled. + */ + SKIP_ONLY, + + /** + * Display transfer/restore local/skip as well as a next and cancel button + */ + SELECTION +} diff --git a/app/src/main/java/org/tm/archive/devicetransfer/moreoptions/MoreTransferOrRestoreOptionsSheet.kt b/app/src/main/java/org/tm/archive/devicetransfer/moreoptions/MoreTransferOrRestoreOptionsSheet.kt new file mode 100644 index 00000000..28d4a32b --- /dev/null +++ b/app/src/main/java/org/tm/archive/devicetransfer/moreoptions/MoreTransferOrRestoreOptionsSheet.kt @@ -0,0 +1,338 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.devicetransfer.moreoptions + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import org.signal.core.ui.BottomSheets +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.tm.archive.R +import org.tm.archive.compose.ComposeBottomSheetDialogFragment +import org.tm.archive.devicetransfer.newdevice.BackupRestorationType + +/** + * Lists a set of options the user can choose from for restoring backup or skipping restoration + */ +class MoreTransferOrRestoreOptionsSheet : ComposeBottomSheetDialogFragment() { + + private val args by navArgs() + + @Composable + override fun SheetContent() { + var selectedOption by remember { + mutableStateOf(null) + } + + MoreOptionsSheetContent( + mode = args.mode, + selectedOption = selectedOption, + onOptionSelected = { selectedOption = it }, + onCancelClick = { findNavController().popBackStack() }, + onNextClick = { + this.onNextClicked(selectedOption ?: BackupRestorationType.NONE) + } + ) + } + + private fun onNextClicked(selectedOption: BackupRestorationType) { + // TODO [message-requests] -- Launch next screen based off user choice + } +} + +@Preview +@Composable +private fun MoreOptionsSheetContentPreview() { + Previews.BottomSheetPreview { + MoreOptionsSheetContent( + mode = MoreTransferOrRestoreOptionsMode.SKIP_ONLY, + selectedOption = null, + onOptionSelected = {}, + onCancelClick = {}, + onNextClick = {} + ) + } +} + +@Preview +@Composable +private fun MoreOptionsSheetSelectableContentPreview() { + Previews.BottomSheetPreview { + MoreOptionsSheetContent( + mode = MoreTransferOrRestoreOptionsMode.SELECTION, + selectedOption = null, + onOptionSelected = {}, + onCancelClick = {}, + onNextClick = {} + ) + } +} + +@Composable +private fun MoreOptionsSheetContent( + mode: MoreTransferOrRestoreOptionsMode, + selectedOption: BackupRestorationType?, + onOptionSelected: (BackupRestorationType) -> Unit, + onCancelClick: () -> Unit, + onNextClick: () -> Unit +) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + BottomSheets.Handle() + + Spacer(modifier = Modifier.size(42.dp)) + + if (mode == MoreTransferOrRestoreOptionsMode.SELECTION) { + TransferFromAndroidDeviceOption( + selectedOption = selectedOption, + onOptionSelected = onOptionSelected + ) + Spacer(modifier = Modifier.size(16.dp)) + RestoreLocalBackupOption( + selectedOption = selectedOption, + onOptionSelected = onOptionSelected + ) + Spacer(modifier = Modifier.size(16.dp)) + } + + LogInWithoutTransferringOption( + selectedOption = selectedOption, + onOptionSelected = when (mode) { + MoreTransferOrRestoreOptionsMode.SKIP_ONLY -> { _ -> onNextClick() } + MoreTransferOrRestoreOptionsMode.SELECTION -> onOptionSelected + } + ) + + if (mode == MoreTransferOrRestoreOptionsMode.SELECTION) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 30.dp, bottom = 24.dp) + ) { + TextButton( + onClick = onCancelClick + ) { + Text(text = stringResource(id = android.R.string.cancel)) + } + + Spacer(modifier = Modifier.weight(1f)) + + Buttons.LargeTonal( + enabled = selectedOption != null, + onClick = onNextClick + ) { + Text(text = stringResource(id = R.string.RegistrationActivity_next)) + } + } + } else { + Spacer(modifier = Modifier.size(45.dp)) + } + } +} + +@Preview +@Composable +private fun LogInWithoutTransferringOptionPreview() { + Previews.BottomSheetPreview { + LogInWithoutTransferringOption( + selectedOption = null, + onOptionSelected = {} + ) + } +} + +@Composable +private fun LogInWithoutTransferringOption( + selectedOption: BackupRestorationType?, + onOptionSelected: (BackupRestorationType) -> Unit +) { + Option( + icon = { + Box( + modifier = Modifier.padding(horizontal = 18.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.symbol_backup_light), // TODO [message-backups] Finalized asset. + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(36.dp) + ) + } + }, + isSelected = selectedOption == BackupRestorationType.NONE, + title = "Log in without transferring", // TODO [message-backups] Finalized copy. + subtitle = "Continue without transferring your messages and media", // TODO [message-backups] Finalized copy. + onClick = { onOptionSelected(BackupRestorationType.NONE) } + ) +} + +@Preview +@Composable +private fun TransferFromAndroidDeviceOptionPreview() { + Previews.BottomSheetPreview { + TransferFromAndroidDeviceOption( + selectedOption = null, + onOptionSelected = {} + ) + } +} + +@Composable +private fun TransferFromAndroidDeviceOption( + selectedOption: BackupRestorationType?, + onOptionSelected: (BackupRestorationType) -> Unit +) { + Option( + icon = { + Box( + modifier = Modifier.padding(horizontal = 18.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.symbol_backup_light), // TODO [message-backups] Finalized asset. + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(36.dp) + ) + } + }, + isSelected = selectedOption == BackupRestorationType.DEVICE_TRANSFER, + title = "Transfer from Android device", // TODO [message-backups] Finalized copy. + subtitle = "Transfer your account and messages from your old device.", // TODO [message-backups] Finalized copy. + onClick = { onOptionSelected(BackupRestorationType.DEVICE_TRANSFER) } + ) +} + +@Preview +@Composable +private fun RestoreLocalBackupOptionPreview() { + Previews.BottomSheetPreview { + RestoreLocalBackupOption( + selectedOption = null, + onOptionSelected = {} + ) + } +} + +@Composable +private fun RestoreLocalBackupOption( + selectedOption: BackupRestorationType?, + onOptionSelected: (BackupRestorationType) -> Unit +) { + Option( + icon = { + Box( + modifier = Modifier.padding(horizontal = 18.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.symbol_backup_light), // TODO [message-backups] Finalized asset. + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(36.dp) + ) + } + }, + isSelected = selectedOption == BackupRestorationType.LOCAL_BACKUP, + title = "Restore local backup", // TODO [message-backups] Finalized copy. + subtitle = "Restore your messages from a backup file you saved on your device.", // TODO [message-backups] Finalized copy. + onClick = { onOptionSelected(BackupRestorationType.LOCAL_BACKUP) } + ) +} + +@Preview +@Composable +private fun OptionPreview() { + Previews.BottomSheetPreview { + Option( + icon = { + Box( + modifier = Modifier.padding(horizontal = 18.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.symbol_backup_light), // TODO [message-backups] Finalized asset. + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(36.dp) + ) + } + }, + isSelected = false, + title = "Log in without transferring", // TODO [message-backups] Finalized copy. + subtitle = "Continue without transferring your messages and media", // TODO [message-backups] Finalized copy. + onClick = {} + ) + } +} + +@Composable +private fun Option( + icon: @Composable () -> Unit, + isSelected: Boolean, + title: String, + subtitle: String, + onClick: () -> Unit +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .background( + color = MaterialTheme.colorScheme.surface, + shape = RoundedCornerShape(12.dp) + ) + .border( + width = if (isSelected) 2.dp else 0.dp, + color = if (isSelected) MaterialTheme.colorScheme.primary else Color.Transparent + ) + .clip(RoundedCornerShape(12.dp)) + .clickable { onClick() } + .padding(vertical = 21.dp) + ) { + icon() + Column { + Text( + text = title, + style = MaterialTheme.typography.bodyLarge + ) + Text( + text = subtitle, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/devicetransfer/newdevice/BackupRestorationType.kt b/app/src/main/java/org/tm/archive/devicetransfer/newdevice/BackupRestorationType.kt new file mode 100644 index 00000000..d3f154c2 --- /dev/null +++ b/app/src/main/java/org/tm/archive/devicetransfer/newdevice/BackupRestorationType.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.devicetransfer.newdevice + +/** + * What kind of backup restore the user wishes to perform. + */ +enum class BackupRestorationType { + DEVICE_TRANSFER, + LOCAL_BACKUP, + REMOTE_BACKUP, + NONE +} diff --git a/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreFragment.java b/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreFragment.java index 9448ab17..0923f0cb 100644 --- a/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreFragment.java +++ b/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreFragment.java @@ -1,16 +1,18 @@ package org.tm.archive.devicetransfer.newdevice; -import android.os.Build; import android.os.Bundle; import android.view.View; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.Navigation; +import org.signal.core.util.concurrent.LifecycleDisposable; import org.tm.archive.LoggingFragment; import org.tm.archive.R; +import org.tm.archive.databinding.FragmentTransferRestoreBinding; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.SpanUtil; import org.tm.archive.util.navigation.SafeNavigation; @@ -19,22 +21,51 @@ import org.tm.archive.util.navigation.SafeNavigation; */ public final class TransferOrRestoreFragment extends LoggingFragment { + private final LifecycleDisposable lifecycleDisposable = new LifecycleDisposable(); + + private FragmentTransferRestoreBinding binding; + public TransferOrRestoreFragment() { super(R.layout.fragment_transfer_restore); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - view.findViewById(R.id.transfer_or_restore_fragment_transfer) - .setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(v), R.id.action_new_device_transfer_instructions)); + binding = FragmentTransferRestoreBinding.bind(view); - View restoreBackup = view.findViewById(R.id.transfer_or_restore_fragment_restore); - restoreBackup.setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(v), R.id.action_choose_backup)); + TransferOrRestoreViewModel viewModel = new ViewModelProvider(this).get(TransferOrRestoreViewModel.class); + + binding.transferOrRestoreFragmentTransfer.setOnClickListener(v -> viewModel.onTransferFromAndroidDeviceSelected()); + binding.transferOrRestoreFragmentRestore.setOnClickListener(v -> viewModel.onRestoreFromLocalBackupSelected()); + binding.transferOrRestoreFragmentRestoreRemote.setOnClickListener(v -> viewModel.onRestoreFromRemoteBackupSelected()); + binding.transferOrRestoreFragmentNext.setOnClickListener(v -> launchSelection(viewModel.getStateSnapshot())); + binding.transferOrRestoreFragmentMoreOptions.setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), R.id.action_transferOrRestore_to_moreOptions)); + + int visibility = FeatureFlags.messageBackups() ? View.VISIBLE : View.GONE; + binding.transferOrRestoreFragmentRestoreRemoteCard.setVisibility(visibility); + binding.transferOrRestoreFragmentMoreOptions.setVisibility(visibility); String description = getString(R.string.TransferOrRestoreFragment__transfer_your_account_and_messages_from_your_old_android_device); String toBold = getString(R.string.TransferOrRestoreFragment__you_need_access_to_your_old_device); - TextView transferDescriptionView = view.findViewById(R.id.transfer_or_restore_fragment_transfer_description); - transferDescriptionView.setText(SpanUtil.boldSubstring(description, toBold)); + binding.transferOrRestoreFragmentTransferDescription.setText(SpanUtil.boldSubstring(description, toBold)); + + lifecycleDisposable.bindTo(getViewLifecycleOwner()); + lifecycleDisposable.add(viewModel.getState().subscribe(this::updateSelection)); + } + + private void updateSelection(BackupRestorationType restorationType) { + binding.transferOrRestoreFragmentTransferCard.setSelected(restorationType == BackupRestorationType.DEVICE_TRANSFER); + binding.transferOrRestoreFragmentRestoreCard.setSelected(restorationType == BackupRestorationType.LOCAL_BACKUP); + binding.transferOrRestoreFragmentRestoreRemoteCard.setSelected(restorationType == BackupRestorationType.REMOTE_BACKUP); + } + + private void launchSelection(BackupRestorationType restorationType) { + switch (restorationType) { + case DEVICE_TRANSFER -> SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), R.id.action_new_device_transfer_instructions); + case LOCAL_BACKUP -> SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), R.id.action_choose_backup); + case REMOTE_BACKUP -> {} + default -> throw new IllegalArgumentException(); + } } } diff --git a/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreViewModel.kt b/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreViewModel.kt new file mode 100644 index 00000000..1fdc8c0d --- /dev/null +++ b/app/src/main/java/org/tm/archive/devicetransfer/newdevice/TransferOrRestoreViewModel.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.devicetransfer.newdevice + +import androidx.lifecycle.ViewModel +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Flowable +import io.reactivex.rxjava3.processors.BehaviorProcessor + +/** + * Maintains state of the TransferOrRestoreFragment + */ +class TransferOrRestoreViewModel : ViewModel() { + + private val internalState = BehaviorProcessor.createDefault(BackupRestorationType.DEVICE_TRANSFER) + + val state: Flowable = internalState.distinctUntilChanged().observeOn(AndroidSchedulers.mainThread()) + val stateSnapshot: BackupRestorationType get() = internalState.value!! + + fun onTransferFromAndroidDeviceSelected() { + internalState.onNext(BackupRestorationType.DEVICE_TRANSFER) + } + + fun onRestoreFromLocalBackupSelected() { + internalState.onNext(BackupRestorationType.LOCAL_BACKUP) + } + + fun onRestoreFromRemoteBackupSelected() { + internalState.onNext(BackupRestorationType.REMOTE_BACKUP) + } +} diff --git a/app/src/main/java/org/tm/archive/devicetransfer/olddevice/OldDeviceClientTask.java b/app/src/main/java/org/tm/archive/devicetransfer/olddevice/OldDeviceClientTask.java index a55d6c1b..7d689a16 100644 --- a/app/src/main/java/org/tm/archive/devicetransfer/olddevice/OldDeviceClientTask.java +++ b/app/src/main/java/org/tm/archive/devicetransfer/olddevice/OldDeviceClientTask.java @@ -67,7 +67,7 @@ final class OldDeviceClientTask implements ClientTask { @Override public void success() { - SignalStore.misc().markOldDeviceTransferLocked(); + SignalStore.misc().setOldDeviceTransferLocked(true); EventBus.getDefault().post(new Status(0, 0, 0,true)); } diff --git a/app/src/main/java/org/tm/archive/events/CallParticipant.kt b/app/src/main/java/org/tm/archive/events/CallParticipant.kt index 802b1117..86ceb061 100644 --- a/app/src/main/java/org/tm/archive/events/CallParticipant.kt +++ b/app/src/main/java/org/tm/archive/events/CallParticipant.kt @@ -7,7 +7,7 @@ import org.tm.archive.components.webrtc.BroadcastVideoSink import org.tm.archive.recipients.Recipient import org.tm.archive.ringrtc.CameraState -data class CallParticipant constructor( +data class CallParticipant( val callParticipantId: CallParticipantId = CallParticipantId(Recipient.UNKNOWN), val recipient: Recipient = Recipient.UNKNOWN, val identityKey: IdentityKey? = null, diff --git a/app/src/main/java/org/tm/archive/events/WebRtcViewModel.kt b/app/src/main/java/org/tm/archive/events/WebRtcViewModel.kt index 6f7d225b..604b9707 100644 --- a/app/src/main/java/org/tm/archive/events/WebRtcViewModel.kt +++ b/app/src/main/java/org/tm/archive/events/WebRtcViewModel.kt @@ -47,7 +47,10 @@ class WebRtcViewModel(state: WebRtcServiceState) { get() = this == CALL_PRE_JOIN || this == NETWORK_FAILURE val isPassedPreJoin: Boolean - get() = ordinal > ordinal + get() = ordinal > CALL_PRE_JOIN.ordinal + + val inOngoingCall: Boolean + get() = this == CALL_INCOMING || this == CALL_OUTGOING || this == CALL_CONNECTED || this == CALL_RINGING || this == CALL_RECONNECTING } enum class GroupCallState { diff --git a/app/src/main/java/org/tm/archive/exporter/SignalSmsExportReader.kt b/app/src/main/java/org/tm/archive/exporter/SignalSmsExportReader.kt deleted file mode 100644 index bae06c20..00000000 --- a/app/src/main/java/org/tm/archive/exporter/SignalSmsExportReader.kt +++ /dev/null @@ -1,177 +0,0 @@ -package org.tm.archive.exporter - -import org.json.JSONException -import org.signal.core.util.logging.Log -import org.signal.smsexporter.ExportableMessage -import org.signal.smsexporter.SmsExportState -import org.tm.archive.attachments.DatabaseAttachment -import org.tm.archive.database.MessageTable -import org.tm.archive.database.SignalDatabase -import org.tm.archive.database.model.MessageId -import org.tm.archive.database.model.MessageRecord -import org.tm.archive.database.model.MmsMessageRecord -import org.tm.archive.database.model.databaseprotos.MessageExportState -import org.tm.archive.dependencies.ApplicationDependencies -import org.tm.archive.recipients.Recipient -import org.tm.archive.util.JsonUtils -import java.io.Closeable -import kotlin.time.Duration.Companion.milliseconds - -/** - * Reads through the SMS and MMS databases for insecure messages that haven't been exported. Due to cursor size limitations - * we "page" through the unexported messages to reduce chances of exceeding that limit. - */ -class SignalSmsExportReader( - private val messageTable: MessageTable = SignalDatabase.messages -) : Iterable, Closeable { - - companion object { - private val TAG = Log.tag(SignalSmsExportReader::class.java) - private const val CURSOR_LIMIT = 1000 - } - - private var messageReader: MessageTable.MmsReader? = null - private var done: Boolean = false - - override fun iterator(): Iterator { - return ExportableMessageIterator() - } - - fun getCount(): Int { - return messageTable.getUnexportedInsecureMessagesCount() - } - - override fun close() { - messageReader?.close() - } - - private fun refreshReaders() { - if (!done) { - messageReader?.close() - messageReader = null - - val refreshedMmsReader = MessageTable.mmsReaderFor(messageTable.getUnexportedInsecureMessages(CURSOR_LIMIT)) - if (refreshedMmsReader.getCount() > 0) { - messageReader = refreshedMmsReader - return - } else { - refreshedMmsReader.close() - done = true - } - } - } - - private inner class ExportableMessageIterator : Iterator { - - private var messageIterator: Iterator? = null - - private fun refreshIterators() { - refreshReaders() - messageIterator = messageReader?.iterator() - } - - override fun hasNext(): Boolean { - if (messageIterator?.hasNext() == true) { - return true - } else if (!done) { - refreshIterators() - if (messageIterator?.hasNext() == true) { - return true - } - } - - return false - } - - override fun next(): ExportableMessage { - var record: MessageRecord? = null - try { - return if (messageIterator?.hasNext() == true) { - record = messageIterator!!.next() - readExportableMmsMessageFromRecord(record, messageReader!!.getMessageExportStateForCurrentRecord()) - } else { - throw NoSuchElementException() - } - } catch (e: Throwable) { - if (e.cause is JSONException) { - Log.w(TAG, "Error processing attachment json, skipping message.", e) - return ExportableMessage.Skip(messageReader!!.getCurrentId()) - } - - Log.w(TAG, "Error processing message: isMms: ${record?.isMms} type: ${record?.type}") - throw e - } - } - - private fun readExportableMmsMessageFromRecord(record: MessageRecord, exportState: MessageExportState): ExportableMessage { - val self = Recipient.self() - val threadRecipient: Recipient? = SignalDatabase.threads.getRecipientForThreadId(record.threadId) - val addresses: Set = if (threadRecipient?.isMmsGroup == true) { - Recipient - .resolvedList(threadRecipient.participantIds) - .filter { it != self } - .map { r -> r.smsExportAddress() } - .toSet() - } else if (threadRecipient != null) { - setOf(threadRecipient.smsExportAddress()) - } else { - setOf(record.toRecipient.smsExportAddress()) - } - - val parts: MutableList = mutableListOf() - if (record.body.isNotBlank()) { - parts.add(ExportableMessage.Mms.Part.Text(record.body)) - } - - if (record is MmsMessageRecord) { - val slideDeck = record.slideDeck - slideDeck - .slides - .filter { it.asAttachment() is DatabaseAttachment } - .forEach { - parts.add( - ExportableMessage.Mms.Part.Stream( - id = JsonUtils.toJson((it.asAttachment() as DatabaseAttachment).attachmentId), - contentType = it.contentType - ) - ) - } - } - - val sender: String = if (record.isOutgoing) Recipient.self().smsExportAddress() else record.fromRecipient.smsExportAddress() - - return ExportableMessage.Mms( - id = MessageId(record.id), - exportState = mapExportState(exportState), - addresses = addresses, - dateReceived = record.dateReceived.milliseconds, - dateSent = record.dateSent.milliseconds, - isRead = true, - isOutgoing = record.isOutgoing, - parts = parts, - sender = sender - ) - } - - private fun mapExportState(messageExportState: MessageExportState): SmsExportState { - return SmsExportState( - messageId = messageExportState.messageId, - startedRecipients = messageExportState.startedRecipients.toSet(), - completedRecipients = messageExportState.completedRecipients.toSet(), - startedAttachments = messageExportState.startedAttachments.toSet(), - completedAttachments = messageExportState.completedAttachments.toSet(), - progress = messageExportState.progress.let { - when (it) { - MessageExportState.Progress.INIT -> SmsExportState.Progress.INIT - MessageExportState.Progress.STARTED -> SmsExportState.Progress.STARTED - MessageExportState.Progress.COMPLETED -> SmsExportState.Progress.COMPLETED - } - } - ) - } - - private fun Recipient.smsExportAddress(): String { - return smsAddress.orElseGet { getDisplayName(ApplicationDependencies.getApplication()) } - } - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/SignalSmsExportService.kt b/app/src/main/java/org/tm/archive/exporter/SignalSmsExportService.kt deleted file mode 100644 index ea395ac9..00000000 --- a/app/src/main/java/org/tm/archive/exporter/SignalSmsExportService.kt +++ /dev/null @@ -1,208 +0,0 @@ -package org.tm.archive.exporter - -import android.content.Context -import android.content.Intent -import androidx.core.app.NotificationCompat -import app.cash.exhaustive.Exhaustive -import org.signal.core.util.PendingIntentFlags -import org.signal.smsexporter.ExportableMessage -import org.signal.smsexporter.SmsExportService -import org.tm.archive.R -import org.tm.archive.attachments.AttachmentId -import org.tm.archive.crypto.ModernDecryptingPartInputStream -import org.tm.archive.database.SignalDatabase -import org.tm.archive.database.model.MessageId -import org.tm.archive.database.model.databaseprotos.MessageExportState -import org.tm.archive.dependencies.ApplicationDependencies -import org.tm.archive.exporter.flow.SmsExportActivity -import org.tm.archive.jobs.ForegroundServiceUtil -import org.tm.archive.notifications.NotificationChannels -import org.tm.archive.notifications.NotificationIds -import org.tm.archive.notifications.v2.NotificationPendingIntentHelper -import org.tm.archive.util.JsonUtils -import java.io.EOFException -import java.io.IOException -import java.io.InputStream - -/** - * Service which integrates the SMS exporter functionality. - */ -class SignalSmsExportService : SmsExportService() { - - companion object { - /** - * Launches the export service and immediately begins exporting messages. - */ - fun start(context: Context, clearPreviousExportState: Boolean) { - val intent = Intent(context, SignalSmsExportService::class.java) - .apply { putExtra(CLEAR_PREVIOUS_EXPORT_STATE_EXTRA, clearPreviousExportState) } - ForegroundServiceUtil.startOrThrow(context, intent) - } - } - - private var reader: SignalSmsExportReader? = null - - override fun getNotification(progress: Int, total: Int): ExportNotification { - val pendingIntent = NotificationPendingIntentHelper.getActivity( - this, - 0, - SmsExportActivity.createIntent(this), - PendingIntentFlags.mutable() - ) - - return ExportNotification( - NotificationIds.SMS_EXPORT_SERVICE, - NotificationCompat.Builder(this, NotificationChannels.getInstance().BACKUPS) - .setSmallIcon(R.drawable.ic_signal_backup) - .setContentTitle(getString(R.string.SignalSmsExportService__exporting_messages)) - .setContentIntent(pendingIntent) - .setProgress(total, progress, false) - .build() - ) - } - - override fun getExportCompleteNotification(): ExportNotification? { - if (ApplicationDependencies.getAppForegroundObserver().isForegrounded) { - return null - } - - val pendingIntent = NotificationPendingIntentHelper.getActivity( - this, - 0, - SmsExportActivity.createIntent(this), - PendingIntentFlags.mutable() - ) - - return ExportNotification( - NotificationIds.SMS_EXPORT_COMPLETE, - NotificationCompat.Builder(this, NotificationChannels.getInstance().APP_ALERTS) - .setSmallIcon(R.drawable.ic_notification) - .setContentTitle(getString(R.string.SignalSmsExportService__signal_sms_export_complete)) - .setContentText(getString(R.string.SignalSmsExportService__tap_to_return_to_signal)) - .setContentIntent(pendingIntent) - .build() - ) - } - - override fun clearPreviousExportState() { - SignalDatabase.messages.clearExportState() - } - - override fun prepareForExport() { - SignalDatabase.messages.clearInsecureMessageExportedErrorStatus() - } - - override fun getUnexportedMessageCount(): Int { - ensureReader() - return reader!!.getCount() - } - - override fun getUnexportedMessages(): Iterable { - ensureReader() - return reader!! - } - - override fun onMessageExportStarted(exportableMessage: ExportableMessage) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().progress(MessageExportState.Progress.STARTED).build() - } - } - - override fun onMessageExportSucceeded(exportableMessage: ExportableMessage) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().progress(MessageExportState.Progress.COMPLETED).build() - } - - SignalDatabase.messages.markMessageExported(exportableMessage.getMessageId()) - } - - override fun onMessageExportFailed(exportableMessage: ExportableMessage) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().progress(MessageExportState.Progress.INIT).build() - } - - SignalDatabase.messages.markMessageExportFailed(exportableMessage.getMessageId()) - } - - override fun onMessageIdCreated(exportableMessage: ExportableMessage, messageId: Long) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().messageId(messageId).build() - } - } - - override fun onAttachmentPartExportStarted(exportableMessage: ExportableMessage, part: ExportableMessage.Mms.Part) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().apply { startedAttachments += part.contentId }.build() - } - } - - override fun onAttachmentPartExportSucceeded(exportableMessage: ExportableMessage, part: ExportableMessage.Mms.Part) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().apply { completedAttachments += part.contentId }.build() - } - } - - override fun onAttachmentPartExportFailed(exportableMessage: ExportableMessage, part: ExportableMessage.Mms.Part) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - val startedAttachments = it.startedAttachments - part.contentId - it.newBuilder().startedAttachments(startedAttachments).build() - } - } - - override fun onRecipientExportStarted(exportableMessage: ExportableMessage, recipient: String) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().apply { startedRecipients += recipient }.build() - } - } - - override fun onRecipientExportSucceeded(exportableMessage: ExportableMessage, recipient: String) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.newBuilder().apply { completedRecipients += recipient }.build() - } - } - - override fun onRecipientExportFailed(exportableMessage: ExportableMessage, recipient: String) { - SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - val startedAttachments = it.startedRecipients - recipient - it.newBuilder().startedRecipients(startedAttachments).build() - } - } - - @Throws(IOException::class) - override fun getInputStream(part: ExportableMessage.Mms.Part): InputStream { - try { - return SignalDatabase.attachments.getAttachmentStream(JsonUtils.fromJson(part.contentId, AttachmentId::class.java), 0) - } catch (e: IOException) { - if (e.message == ModernDecryptingPartInputStream.PREMATURE_END_ERROR_MESSAGE) { - throw EOFException(e.message) - } else { - throw e - } - } - } - - override fun onExportPassCompleted() { - reader?.close() - } - - private fun ExportableMessage.getMessageId(): MessageId { - @Exhaustive - val messageId: Any = when (this) { - is ExportableMessage.Mms<*> -> id - is ExportableMessage.Sms<*> -> id - is ExportableMessage.Skip<*> -> id - } - - if (messageId is MessageId) { - return messageId - } else { - throw AssertionError("Exportable message id must be type MessageId. Type: ${messageId.javaClass}") - } - } - - private fun ensureReader() { - if (reader == null) { - reader = SignalSmsExportReader() - } - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ChooseANewDefaultSmsAppFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/ChooseANewDefaultSmsAppFragment.kt deleted file mode 100644 index f98d8749..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ChooseANewDefaultSmsAppFragment.kt +++ /dev/null @@ -1,59 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.app.Activity -import android.os.Build -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import org.signal.core.util.logging.Log -import org.signal.smsexporter.DefaultSmsHelper -import org.signal.smsexporter.ReleaseSmsAppFailure -import org.tm.archive.R -import org.tm.archive.databinding.ChooseANewDefaultSmsAppFragmentBinding - -/** - * Fragment which can launch the user into picking an alternative - * SMS app, or give them instructions on how to do so manually. - */ -class ChooseANewDefaultSmsAppFragment : Fragment(R.layout.choose_a_new_default_sms_app_fragment) { - - companion object { - private val TAG = Log.tag(ChooseANewDefaultSmsAppFragment::class.java) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = ChooseANewDefaultSmsAppFragmentBinding.bind(view) - - if (Build.VERSION.SDK_INT < 24) { - binding.bullet1Text.setText(R.string.ChooseANewDefaultSmsAppFragment__open_your_phones_settings_app) - binding.bullet2Text.setText(R.string.ChooseANewDefaultSmsAppFragment__navigate_to_apps_default_apps_sms_app) - binding.continueButton.setText(R.string.ChooseANewDefaultSmsAppFragment__done) - } - - DefaultSmsHelper.releaseDefaultSms(requireContext()).either( - onSuccess = { - binding.continueButton.setOnClickListener { _ -> startActivity(it) } - }, - onFailure = { - when (it) { - ReleaseSmsAppFailure.APP_IS_INELIGIBLE_TO_RELEASE_SMS_SELECTION -> { - Log.w(TAG, "App is ineligible to release sms selection") - binding.continueButton.setOnClickListener { requireActivity().finish() } - } - ReleaseSmsAppFailure.NO_METHOD_TO_RELEASE_SMS_AVIALABLE -> { - Log.w(TAG, "We can't navigate the user to a specific spot so we should display instructions instead.") - binding.continueButton.setOnClickListener { requireActivity().finish() } - } - } - } - ) - } - - override fun onResume() { - super.onResume() - if (!DefaultSmsHelper.isDefaultSms(requireContext())) { - requireActivity().setResult(Activity.RESULT_OK) - requireActivity().finish() - } - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsCompleteFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsCompleteFragment.kt deleted file mode 100644 index 35ee73f3..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsCompleteFragment.kt +++ /dev/null @@ -1,27 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import org.tm.archive.R -import org.tm.archive.SmsExportDirections -import org.tm.archive.databinding.ExportSmsCompleteFragmentBinding -import org.tm.archive.util.navigation.safeNavigate - -/** - * Shown when export sms completes. - */ -class ExportSmsCompleteFragment : Fragment(R.layout.export_sms_complete_fragment) { - - private val args: ExportSmsCompleteFragmentArgs by navArgs() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val exportSuccessCount = args.exportMessageCount - args.exportMessageFailureCount - - val binding = ExportSmsCompleteFragmentBinding.bind(view) - binding.exportCompleteNext.setOnClickListener { findNavController().safeNavigate(SmsExportDirections.actionDirectToChooseANewDefaultSmsAppFragment()) } - binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, exportSuccessCount, args.exportMessageCount) - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsFullErrorFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsFullErrorFragment.kt deleted file mode 100644 index 91713db5..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsFullErrorFragment.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.content.Context -import android.os.Bundle -import android.view.ContextThemeWrapper -import android.view.LayoutInflater -import android.view.View -import androidx.core.content.ContextCompat -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import org.tm.archive.LoggingFragment -import org.tm.archive.R -import org.tm.archive.SmsExportDirections -import org.tm.archive.databinding.ExportSmsFullErrorFragmentBinding -import org.tm.archive.util.navigation.safeNavigate - -/** - * Fragment shown when all export messages failed. - */ -class ExportSmsFullErrorFragment : LoggingFragment(R.layout.export_sms_full_error_fragment) { - private val args: ExportSmsFullErrorFragmentArgs by navArgs() - - override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater { - val inflater = super.onGetLayoutInflater(savedInstanceState) - val contextThemeWrapper: Context = ContextThemeWrapper(requireContext(), R.style.Signal_DayNight) - return inflater.cloneInContext(contextThemeWrapper) - } - - @Suppress("UsePropertyAccessSyntax") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = ExportSmsFullErrorFragmentBinding.bind(view) - - val exportSuccessCount = args.exportMessageCount - args.exportMessageFailureCount - binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, exportSuccessCount, args.exportMessageCount) - binding.retryButton.setOnClickListener { findNavController().safeNavigate(SmsExportDirections.actionDirectToExportYourSmsMessagesFragment()) } - binding.pleaseTryAgain.apply { - setLinkColor(ContextCompat.getColor(requireContext(), R.color.signal_colorPrimary)) - setLearnMoreVisible(true, R.string.ExportSmsPartiallyComplete__contact_us) - setOnLinkClickListener { - findNavController().safeNavigate(SmsExportDirections.actionDirectToHelpFragment()) - } - } - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsPartiallyCompleteFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsPartiallyCompleteFragment.kt deleted file mode 100644 index 3b747ac2..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ExportSmsPartiallyCompleteFragment.kt +++ /dev/null @@ -1,57 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.content.Context -import android.os.Bundle -import android.text.format.Formatter -import android.view.ContextThemeWrapper -import android.view.LayoutInflater -import android.view.View -import androidx.core.content.ContextCompat -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import org.signal.core.util.concurrent.SimpleTask -import org.tm.archive.LoggingFragment -import org.tm.archive.R -import org.tm.archive.SmsExportDirections -import org.tm.archive.database.SignalDatabase -import org.tm.archive.databinding.ExportSmsPartiallyCompleteFragmentBinding -import org.tm.archive.util.navigation.safeNavigate - -/** - * Fragment shown when some messages exported and some failed. - */ -class ExportSmsPartiallyCompleteFragment : LoggingFragment(R.layout.export_sms_partially_complete_fragment) { - - private val args: ExportSmsPartiallyCompleteFragmentArgs by navArgs() - - override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater { - val inflater = super.onGetLayoutInflater(savedInstanceState) - val contextThemeWrapper: Context = ContextThemeWrapper(requireContext(), R.style.Signal_DayNight) - return inflater.cloneInContext(contextThemeWrapper) - } - - @Suppress("UsePropertyAccessSyntax") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = ExportSmsPartiallyCompleteFragmentBinding.bind(view) - - val exportSuccessCount = args.exportMessageCount - args.exportMessageFailureCount - binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, exportSuccessCount, args.exportMessageCount) - binding.retryButton.setOnClickListener { findNavController().safeNavigate(SmsExportDirections.actionDirectToExportYourSmsMessagesFragment()) } - binding.continueButton.setOnClickListener { findNavController().safeNavigate(SmsExportDirections.actionDirectToChooseANewDefaultSmsAppFragment()) } - binding.bullet3Text.apply { - setLinkColor(ContextCompat.getColor(requireContext(), R.color.signal_colorPrimary)) - setLearnMoreVisible(true, R.string.ExportSmsPartiallyComplete__contact_us) - setOnLinkClickListener { - findNavController().safeNavigate(SmsExportDirections.actionDirectToHelpFragment()) - } - } - - SimpleTask.runWhenValid( - viewLifecycleOwner.lifecycle, - { SignalDatabase.messages.getUnexportedInsecureMessagesEstimatedSize() + SignalDatabase.messages.getUnexportedInsecureMessagesEstimatedSize() }, - { totalSize -> - binding.bullet1Text.setText(getString(R.string.ExportSmsPartiallyComplete__ensure_you_have_an_additional_s_free_on_your_phone_to_export_your_messages, Formatter.formatFileSize(requireContext(), totalSize))) - } - ) - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ExportYourSmsMessagesFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/ExportYourSmsMessagesFragment.kt deleted file mode 100644 index 015b073f..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ExportYourSmsMessagesFragment.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.disposables.Disposable -import org.signal.smsexporter.DefaultSmsHelper -import org.signal.smsexporter.SmsExportProgress -import org.signal.smsexporter.SmsExportService -import org.tm.archive.R -import org.tm.archive.databinding.ExportYourSmsMessagesFragmentBinding -import org.tm.archive.util.Material3OnScrollHelper -import org.tm.archive.util.navigation.safeNavigate - -/** - * "Welcome" screen for exporting sms - */ -class ExportYourSmsMessagesFragment : Fragment(R.layout.export_your_sms_messages_fragment) { - - private var navigationDisposable = Disposable.disposed() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = ExportYourSmsMessagesFragmentBinding.bind(view) - - binding.toolbar.setOnClickListener { - requireActivity().finish() - } - - binding.continueButton.setOnClickListener { - if (DefaultSmsHelper.isDefaultSms(requireContext())) { - findNavController().safeNavigate(ExportYourSmsMessagesFragmentDirections.actionExportYourSmsMessagesFragmentToExportingSmsMessagesFragment()) - } else { - findNavController().safeNavigate(ExportYourSmsMessagesFragmentDirections.actionExportYourSmsMessagesFragmentToSetSignalAsDefaultSmsAppFragment()) - } - } - - Material3OnScrollHelper(requireActivity(), binding.toolbar, viewLifecycleOwner).attach(binding.scrollView) - } - - override fun onResume() { - super.onResume() - navigationDisposable = SmsExportService - .progressState - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - if (it !is SmsExportProgress.Init) { - findNavController().safeNavigate(ExportYourSmsMessagesFragmentDirections.actionExportYourSmsMessagesFragmentToExportingSmsMessagesFragment()) - } - } - } - - override fun onPause() { - super.onPause() - navigationDisposable.dispose() - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ExportingSmsMessagesFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/ExportingSmsMessagesFragment.kt deleted file mode 100644 index d8f1e1c0..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ExportingSmsMessagesFragment.kt +++ /dev/null @@ -1,120 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.Manifest -import android.content.Context -import android.os.Bundle -import android.text.format.Formatter -import android.view.ContextThemeWrapper -import android.view.LayoutInflater -import android.view.View -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.navigation.fragment.findNavController -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.disposables.Disposable -import org.signal.core.util.concurrent.LifecycleDisposable -import org.signal.smsexporter.SmsExportProgress -import org.signal.smsexporter.SmsExportService -import org.tm.archive.R -import org.tm.archive.databinding.ExportingSmsMessagesFragmentBinding -import org.tm.archive.exporter.SignalSmsExportService -import org.tm.archive.permissions.Permissions -import org.tm.archive.util.mb -import org.tm.archive.util.navigation.safeNavigate - -/** - * "Export in progress" fragment which should be displayed - * when we start exporting messages. - */ -class ExportingSmsMessagesFragment : Fragment(R.layout.exporting_sms_messages_fragment) { - - private val viewModel: SmsExportViewModel by activityViewModels() - - private val lifecycleDisposable = LifecycleDisposable() - private var navigationDisposable = Disposable.disposed() - - override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater { - val inflater = super.onGetLayoutInflater(savedInstanceState) - val contextThemeWrapper: Context = ContextThemeWrapper(requireContext(), R.style.Signal_DayNight) - return inflater.cloneInContext(contextThemeWrapper) - } - - @Suppress("KotlinConstantConditions") - override fun onResume() { - super.onResume() - navigationDisposable = SmsExportService - .progressState - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { smsExportProgress -> - if (smsExportProgress is SmsExportProgress.Done) { - SmsExportService.clearProgressState() - if (smsExportProgress.errorCount == 0) { - findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsCompleteFragment(smsExportProgress.total, smsExportProgress.errorCount)) - } else if (smsExportProgress.errorCount == smsExportProgress.total) { - findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsFullErrorFragment(smsExportProgress.total, smsExportProgress.errorCount)) - } else { - findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsPartiallyCompleteFragment(smsExportProgress.total, smsExportProgress.errorCount)) - } - } - } - } - - override fun onPause() { - super.onPause() - navigationDisposable.dispose() - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = ExportingSmsMessagesFragmentBinding.bind(view) - - lifecycleDisposable.bindTo(viewLifecycleOwner) - lifecycleDisposable += SmsExportService.progressState.observeOn(AndroidSchedulers.mainThread()).subscribe { - when (it) { - SmsExportProgress.Init -> binding.progress.isIndeterminate = true - SmsExportProgress.Starting -> binding.progress.isIndeterminate = true - is SmsExportProgress.InProgress -> { - binding.progress.isIndeterminate = false - binding.progress.max = it.total - binding.progress.progress = it.progress - binding.progressLabel.text = resources.getQuantityString(R.plurals.ExportingSmsMessagesFragment__exporting_d_of_d, it.total, it.progress, it.total) - } - is SmsExportProgress.Done -> Unit - } - } - - lifecycleDisposable += ExportingSmsRepository() - .getSmsExportSizeEstimations() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { (internalFreeSpace, estimatedRequiredSpace) -> - val adjustedFreeSpace = internalFreeSpace - estimatedRequiredSpace - 100.mb - if (estimatedRequiredSpace > adjustedFreeSpace) { - MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.ExportingSmsMessagesFragment__you_may_not_have_enough_disk_space) - .setMessage(getString(R.string.ExportingSmsMessagesFragment__you_need_approximately_s_to_export_your_messages_ensure_you_have_enough_space_before_continuing, Formatter.formatFileSize(requireContext(), estimatedRequiredSpace))) - .setPositiveButton(R.string.ExportingSmsMessagesFragment__continue_anyway) { _, _ -> checkPermissionsAndStartExport() } - .setNegativeButton(android.R.string.cancel) { _, _ -> findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionDirectToExportYourSmsMessagesFragment()) } - .setCancelable(false) - .show() - } else { - checkPermissionsAndStartExport() - } - } - } - - @Suppress("OVERRIDE_DEPRECATION") - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults) - } - - private fun checkPermissionsAndStartExport() { - Permissions.with(this) - .request(Manifest.permission.READ_SMS) - .ifNecessary() - .withRationaleDialog(getString(R.string.ExportingSmsMessagesFragment__signal_needs_the_sms_permission_to_be_able_to_export_your_sms_messages), R.drawable.ic_messages_solid_24) - .onAllGranted { SignalSmsExportService.start(requireContext(), viewModel.isReExport) } - .withPermanentDenialDialog(getString(R.string.ExportingSmsMessagesFragment__signal_needs_the_sms_permission_to_be_able_to_export_your_sms_messages)) { requireActivity().finish() } - .onAnyDenied { checkPermissionsAndStartExport() } - .execute() - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/ExportingSmsRepository.kt b/app/src/main/java/org/tm/archive/exporter/flow/ExportingSmsRepository.kt deleted file mode 100644 index f7c4a271..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/ExportingSmsRepository.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.app.Application -import android.os.Build -import android.os.storage.StorageManager -import androidx.core.content.ContextCompat -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers -import org.tm.archive.database.SignalDatabase -import org.tm.archive.dependencies.ApplicationDependencies -import java.io.File - -class ExportingSmsRepository(private val context: Application = ApplicationDependencies.getApplication()) { - - @Suppress("UsePropertyAccessSyntax") - fun getSmsExportSizeEstimations(): Single { - return Single.fromCallable { - val internalStorageFile = if (Build.VERSION.SDK_INT < 24) { - File(context.applicationInfo.dataDir) - } else { - context.dataDir - } - - val internalFreeSpace: Long = if (Build.VERSION.SDK_INT < 26) { - internalStorageFile.usableSpace - } else { - val storageManagerFreeSpace = ContextCompat.getSystemService(context, StorageManager::class.java)?.let { storageManager -> - storageManager.getAllocatableBytes(storageManager.getUuidForPath(internalStorageFile)) - } - storageManagerFreeSpace ?: internalStorageFile.usableSpace - } - - SmsExportSizeEstimations(internalFreeSpace, SignalDatabase.messages.getUnexportedInsecureMessagesEstimatedSize() + SignalDatabase.messages.getUnexportedInsecureMessagesEstimatedSize()) - }.subscribeOn(Schedulers.io()) - } - - data class SmsExportSizeEstimations(val estimatedInternalFreeSpace: Long, val estimatedRequiredSpace: Long) -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/SetSignalAsDefaultSmsAppFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/SetSignalAsDefaultSmsAppFragment.kt deleted file mode 100644 index f14dd042..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/SetSignalAsDefaultSmsAppFragment.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.os.Bundle -import android.view.View -import androidx.activity.result.contract.ActivityResultContracts -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import org.signal.smsexporter.BecomeSmsAppFailure -import org.signal.smsexporter.DefaultSmsHelper -import org.tm.archive.R -import org.tm.archive.databinding.SetSignalAsDefaultSmsAppFragmentBinding -import org.tm.archive.util.navigation.safeNavigate - -class SetSignalAsDefaultSmsAppFragment : Fragment(R.layout.set_signal_as_default_sms_app_fragment) { - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = SetSignalAsDefaultSmsAppFragmentBinding.bind(view) - - val smsDefaultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (DefaultSmsHelper.isDefaultSms(requireContext())) { - navigateToExporter() - } - } - - binding.continueButton.setOnClickListener { - DefaultSmsHelper.becomeDefaultSms(requireContext()).either( - onSuccess = { - smsDefaultLauncher.launch(it) - }, - onFailure = { - when (it) { - BecomeSmsAppFailure.ALREADY_DEFAULT_SMS -> navigateToExporter() - BecomeSmsAppFailure.ROLE_IS_NOT_AVAILABLE -> error("Should never happen") - } - } - ) - } - } - - private fun navigateToExporter() { - findNavController().safeNavigate(SetSignalAsDefaultSmsAppFragmentDirections.actionSetSignalAsDefaultSmsAppFragmentToExportingSmsMessagesFragment()) - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportActivity.kt b/app/src/main/java/org/tm/archive/exporter/flow/SmsExportActivity.kt deleted file mode 100644 index 373d9b66..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportActivity.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import androidx.activity.OnBackPressedCallback -import androidx.core.app.NotificationManagerCompat -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import androidx.navigation.findNavController -import androidx.navigation.fragment.NavHostFragment -import org.tm.archive.R -import org.tm.archive.components.FragmentWrapperActivity -import org.tm.archive.notifications.NotificationIds -import org.tm.archive.util.WindowUtil - -class SmsExportActivity : FragmentWrapperActivity() { - - private lateinit var viewModel: SmsExportViewModel - - override fun onResume() { - super.onResume() - WindowUtil.setLightStatusBarFromTheme(this) - NotificationManagerCompat.from(this).cancel(NotificationIds.SMS_EXPORT_COMPLETE) - } - - @Suppress("ReplaceGetOrSet") - override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { - super.onCreate(savedInstanceState, ready) - onBackPressedDispatcher.addCallback(this, OnBackPressed()) - - val factory = SmsExportViewModel.Factory(intent.getBooleanExtra(IS_FROM_MEGAPHONE, false), intent.getBooleanExtra(IS_RE_EXPORT, false)) - viewModel = ViewModelProvider(this, factory).get(SmsExportViewModel::class.java) - } - - override fun getFragment(): Fragment { - return NavHostFragment.create(R.navigation.sms_export) - } - - private inner class OnBackPressed : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - if (!findNavController(R.id.fragment_container).popBackStack()) { - finish() - } - } - } - - companion object { - private const val IS_RE_EXPORT = "is_re_export" - private const val IS_FROM_MEGAPHONE = "is_from_megaphone" - - @JvmOverloads - @JvmStatic - fun createIntent(context: Context, isFromMegaphone: Boolean = false, isReExport: Boolean = false): Intent { - return Intent(context, SmsExportActivity::class.java).apply { - putExtra(IS_RE_EXPORT, isReExport) - putExtra(IS_FROM_MEGAPHONE, isFromMegaphone) - } - } - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportDialogs.kt b/app/src/main/java/org/tm/archive/exporter/flow/SmsExportDialogs.kt deleted file mode 100644 index 0bc2760c..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportDialogs.kt +++ /dev/null @@ -1,39 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.content.Context -import android.view.View -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.snackbar.Snackbar -import org.signal.core.util.concurrent.SignalExecutors -import org.tm.archive.R -import org.tm.archive.database.SignalDatabase - -object SmsExportDialogs { - @JvmStatic - fun showSmsRemovalDialog(context: Context, view: View) { - MaterialAlertDialogBuilder(context) - .setTitle(R.string.RemoveSmsMessagesDialogFragment__remove_sms_messages) - .setMessage(R.string.RemoveSmsMessagesDialogFragment__you_can_now_remove_sms_messages_from_signal) - .setPositiveButton(R.string.RemoveSmsMessagesDialogFragment__keep_messages) { _, _ -> - Snackbar.make(view, R.string.SmsSettingsFragment__you_can_remove_sms_messages_from_signal_in_settings, Snackbar.LENGTH_SHORT).show() - } - .setNegativeButton(R.string.RemoveSmsMessagesDialogFragment__remove_messages) { _, _ -> - SignalExecutors.BOUNDED.execute { - SignalDatabase.messages.deleteExportedMessages() - SignalDatabase.messages.deleteExportedMessages() - } - Snackbar.make(view, R.string.SmsSettingsFragment__removing_sms_messages_from_signal, Snackbar.LENGTH_SHORT).show() - } - .show() - } - - @JvmStatic - fun showSmsReExportDialog(context: Context, continueCallback: Runnable) { - MaterialAlertDialogBuilder(context) - .setTitle(R.string.ReExportSmsMessagesDialogFragment__export_sms_again) - .setMessage(R.string.ReExportSmsMessagesDialogFragment__you_already_exported_your_sms_messages) - .setPositiveButton(R.string.ReExportSmsMessagesDialogFragment__continue) { _, _ -> continueCallback.run() } - .setNegativeButton(R.string.ReExportSmsMessagesDialogFragment__cancel, null) - .show() - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportHelpFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/SmsExportHelpFragment.kt deleted file mode 100644 index ed27cfed..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportHelpFragment.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.os.Bundle -import android.view.View -import androidx.core.os.bundleOf -import androidx.navigation.fragment.findNavController -import org.tm.archive.LoggingFragment -import org.tm.archive.R -import org.tm.archive.databinding.SmsExportHelpFragmentBinding -import org.tm.archive.help.HelpFragment - -/** - * Fragment wrapper around the app settings help fragment to provide a toolbar and set default category for sms export. - */ -class SmsExportHelpFragment : LoggingFragment(R.layout.sms_export_help_fragment) { - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val binding = SmsExportHelpFragmentBinding.bind(view) - - binding.toolbar.setOnClickListener { - if (!findNavController().popBackStack()) { - requireActivity().finish() - } - } - - childFragmentManager - .beginTransaction() - .replace(binding.smsExportHelpFragmentFragment.id, HelpFragment().apply { arguments = bundleOf(HelpFragment.START_CATEGORY_INDEX to HelpFragment.SMS_EXPORT_INDEX) }) - .commitNow() - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportViewModel.kt b/app/src/main/java/org/tm/archive/exporter/flow/SmsExportViewModel.kt deleted file mode 100644 index 2d1e6c84..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/SmsExportViewModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.tm.archive.exporter.flow - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider - -/** - * Hold shared state for the SMS export flow. - * - * Note: Will be expanded on eventually to support different behavior when entering via megaphone. - */ -class SmsExportViewModel(val isFromMegaphone: Boolean, val isReExport: Boolean) : ViewModel() { - class Factory(private val isFromMegaphone: Boolean, private val isReExport: Boolean) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - return requireNotNull(modelClass.cast(SmsExportViewModel(isFromMegaphone, isReExport))) - } - } -} diff --git a/app/src/main/java/org/tm/archive/exporter/flow/SmsRemovalInformationFragment.kt b/app/src/main/java/org/tm/archive/exporter/flow/SmsRemovalInformationFragment.kt deleted file mode 100644 index d88f2019..00000000 --- a/app/src/main/java/org/tm/archive/exporter/flow/SmsRemovalInformationFragment.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.tm.archive.exporter.flow - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.activityViewModels -import androidx.navigation.fragment.findNavController -import org.tm.archive.LoggingFragment -import org.tm.archive.R -import org.tm.archive.databinding.SmsRemovalInformationFragmentBinding -import org.tm.archive.util.CommunicationActions -import org.tm.archive.util.navigation.safeNavigate - -/** - * Fragment shown when entering the sms export flow from the basic megaphone. - * - * Layout shared with full screen megaphones for Phase 2/3. - */ -class SmsRemovalInformationFragment : LoggingFragment() { - private val viewModel: SmsExportViewModel by activityViewModels() - - private lateinit var binding: SmsRemovalInformationFragmentBinding - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - binding = SmsRemovalInformationFragmentBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - if (!viewModel.isFromMegaphone) { - findNavController().safeNavigate(SmsRemovalInformationFragmentDirections.actionSmsRemovalInformationFragmentToExportYourSmsMessagesFragment()) - } else { - val goBackClickListener = { _: View -> - if (!findNavController().popBackStack()) { - requireActivity().finish() - } - } - - binding.bullet1Text.text = getString(R.string.SmsRemoval_info_bullet_1) - - binding.toolbar.setNavigationOnClickListener(goBackClickListener) - binding.laterButton.setOnClickListener(goBackClickListener) - - binding.learnMoreButton.setOnClickListener { - CommunicationActions.openBrowserLink(requireContext(), getString(R.string.sms_export_url)) - } - - binding.exportSmsButton.setOnClickListener { - findNavController().safeNavigate(SmsRemovalInformationFragmentDirections.actionSmsRemovalInformationFragmentToExportYourSmsMessagesFragment()) - } - } - } -} diff --git a/app/src/main/java/org/tm/archive/fonts/SignalSymbols.kt b/app/src/main/java/org/tm/archive/fonts/SignalSymbols.kt new file mode 100644 index 00000000..21f26cd3 --- /dev/null +++ b/app/src/main/java/org/tm/archive/fonts/SignalSymbols.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.fonts + +import android.content.Context +import android.graphics.Typeface +import android.text.SpannableStringBuilder +import android.text.TextPaint +import android.text.style.MetricAffectingSpan + +/** + * Helper object for working with the SignalSymbols font + */ +object SignalSymbols { + + enum class Glyph(val unicode: Char) { + CHEVRON_RIGHT('\uE025'), + PERSON_CIRCLE('\uE05E') + } + + enum class Weight { + BOLD + } + + private val cache = mutableMapOf() + + fun getSpannedString( + context: Context, + weight: Weight, + glyph: Glyph + ): CharSequence { + val typeface = getTypeface(context, weight) + val span = CustomTypefaceSpan(typeface) + + val text = SpannableStringBuilder(glyph.unicode.toString()) + text.setSpan(span, 0, text.length, 0) + + return text + } + + private fun getTypeface(context: Context, weight: Weight): Typeface { + return when (weight) { + Weight.BOLD -> getBoldWeightedFont(context) + else -> error("Unsupported weight: $weight") + } + } + + private fun getBoldWeightedFont(context: Context): Typeface { + return cache.getOrPut( + Weight.BOLD + ) { + Typeface.createFromAsset( + context.assets, + "fonts/SignalSymbols-Bold.otf" + ) + } + } + + /** + * Custom TypefaceSpan to support TypefaceSpan in API<28 + * + * Source: https://www.youtube.com/watch?v=x-FcOX6ErdI&t=486s + */ + private class CustomTypefaceSpan(val font: Typeface?) : MetricAffectingSpan() { + override fun updateMeasureState(textPaint: TextPaint) = update(textPaint) + override fun updateDrawState(textPaint: TextPaint?) = update(textPaint) + + private fun update(tp: TextPaint?) { + tp.apply { + val old = this!!.typeface + val oldStyle = old?.style ?: 0 + val font = Typeface.create(font, oldStyle) + typeface = font + } + } + } +} diff --git a/app/src/main/java/org/tm/archive/gcm/FcmReceiveService.java b/app/src/main/java/org/tm/archive/gcm/FcmReceiveService.java index a82d78e8..1e5f89dd 100644 --- a/app/src/main/java/org/tm/archive/gcm/FcmReceiveService.java +++ b/app/src/main/java/org/tm/archive/gcm/FcmReceiveService.java @@ -27,13 +27,13 @@ public class FcmReceiveService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { Log.i(TAG, String.format(Locale.US, - "onMessageReceived() ID: %s, Delay: %d (Server offset: %d), Priority: %d, Original Priority: %d, Network: %s", - remoteMessage.getMessageId(), - (System.currentTimeMillis() - remoteMessage.getSentTime()), - SignalStore.misc().getLastKnownServerTimeOffset(), - remoteMessage.getPriority(), - remoteMessage.getOriginalPriority(), - NetworkUtil.getNetworkStatus(this))); + "onMessageReceived() ID: %s, Delay: %d (Server offset: %d), Priority: %d, Original Priority: %d, Network: %s", + remoteMessage.getMessageId(), + (System.currentTimeMillis() - remoteMessage.getSentTime()), + SignalStore.misc().getLastKnownServerTimeOffset(), + remoteMessage.getPriority(), + remoteMessage.getOriginalPriority(), + NetworkUtil.getNetworkStatus(this))); String registrationChallenge = remoteMessage.getData().get("challenge"); String rateLimitChallenge = remoteMessage.getData().get("rateLimitChallenge"); diff --git a/app/src/main/java/org/tm/archive/giph/mp4/GiphyMp4ViewHolder.java b/app/src/main/java/org/tm/archive/giph/mp4/GiphyMp4ViewHolder.java index 26e20eb1..31c98b3a 100644 --- a/app/src/main/java/org/tm/archive/giph/mp4/GiphyMp4ViewHolder.java +++ b/app/src/main/java/org/tm/archive/giph/mp4/GiphyMp4ViewHolder.java @@ -10,6 +10,7 @@ import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; @@ -22,7 +23,6 @@ import org.tm.archive.R; import org.tm.archive.conversation.colors.ChatColorsPalette; import org.tm.archive.giph.model.ChunkedImageUrl; import org.tm.archive.giph.model.GiphyImage; -import org.tm.archive.mms.GlideApp; import org.tm.archive.util.Projection; import org.tm.archive.util.Util; import org.tm.archive.util.ViewUtil; @@ -99,7 +99,7 @@ final class GiphyMp4ViewHolder extends MappingViewHolder implements } private void loadPlaceholderImage(@NonNull GiphyImage giphyImage) { - GlideApp.with(itemView) + Glide.with(itemView) .load(new ChunkedImageUrl(giphyImage.getStillUrl())) .placeholder(placeholder) .diskCacheStrategy(DiskCacheStrategy.ALL) diff --git a/app/src/main/java/org/tm/archive/giph/ui/GiphyActivity.java b/app/src/main/java/org/tm/archive/giph/ui/GiphyActivity.java index c9ed3d33..880b12a7 100644 --- a/app/src/main/java/org/tm/archive/giph/ui/GiphyActivity.java +++ b/app/src/main/java/org/tm/archive/giph/ui/GiphyActivity.java @@ -26,6 +26,7 @@ import org.tm.archive.providers.BlobProvider; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.DynamicNoActionBarTheme; import org.tm.archive.util.DynamicTheme; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.MediaUtil; import org.tm.archive.util.ViewUtil; import org.tm.archive.util.views.SimpleProgressDialog; @@ -59,6 +60,9 @@ public class GiphyActivity extends PassphraseRequiredActivity implements Keyboar @SuppressLint("MissingInflatedId") @Override public void onCreate(Bundle bundle, boolean ready) { + if (!FeatureFlags.gifSearchAvailable()) { + finish(); + } setContentView(R.layout.giphy_activity); final boolean forMms = getIntent().getBooleanExtra(EXTRA_IS_MMS, false); diff --git a/glide-webp/lib/src/main/java/org/signal/glide/webp/WebpInputStreamResourceDecoder.kt b/app/src/main/java/org/tm/archive/glide/cache/WebpSanDecoder.kt similarity index 59% rename from glide-webp/lib/src/main/java/org/signal/glide/webp/WebpInputStreamResourceDecoder.kt rename to app/src/main/java/org/tm/archive/glide/cache/WebpSanDecoder.kt index ffdb27da..a1a5e9e4 100644 --- a/glide-webp/lib/src/main/java/org/signal/glide/webp/WebpInputStreamResourceDecoder.kt +++ b/app/src/main/java/org/tm/archive/glide/cache/WebpSanDecoder.kt @@ -1,25 +1,27 @@ /* - * Copyright 2023 Signal Messenger, LLC + * Copyright 2024 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ -package org.signal.glide.webp +package org.tm.archive.glide.cache import android.graphics.Bitmap import com.bumptech.glide.load.Options import com.bumptech.glide.load.ResourceDecoder import com.bumptech.glide.load.engine.Resource -import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool -import com.bumptech.glide.load.resource.bitmap.BitmapResource import org.signal.core.util.StreamUtil import org.signal.core.util.logging.Log +import org.signal.libsignal.media.WebpSanitizer import java.io.IOException import java.io.InputStream -class WebpInputStreamResourceDecoder(private val bitmapPool: BitmapPool) : ResourceDecoder { +/** + * Uses WebpSanitizer to check for invalid webp. + */ +class WebpSanDecoder : ResourceDecoder { companion object { - private const val TAG = "WebpResourceDecoder" // Name > 23 characters + private val TAG = Log.tag(WebpSanDecoder::class.java) private val MAGIC_NUMBER_P1 = byteArrayOf(0x52, 0x49, 0x46, 0x46) // "RIFF" private val MAGIC_NUMBER_P2 = byteArrayOf(0x57, 0x45, 0x42, 0x50) // "WEBP" @@ -34,10 +36,12 @@ class WebpInputStreamResourceDecoder(private val bitmapPool: BitmapPool) : Resou * [4-7]: File length * [8-11]: "WEBP" * - * We're not verifying the file length here, so we just need to check the first and last + * We're not verifying the file length here, so we just need to check the first and last. + * + * We then sanitize the webp and block the load if the check fails. */ override fun handles(source: InputStream, options: Options): Boolean { - return try { + try { val magicNumberP1 = ByteArray(4) StreamUtil.readFully(source, magicNumberP1) @@ -47,24 +51,27 @@ class WebpInputStreamResourceDecoder(private val bitmapPool: BitmapPool) : Resou val magicNumberP2 = ByteArray(4) StreamUtil.readFully(source, magicNumberP2) - magicNumberP1.contentEquals(MAGIC_NUMBER_P1) && magicNumberP2.contentEquals(MAGIC_NUMBER_P2) + if (magicNumberP1.contentEquals(MAGIC_NUMBER_P1) && magicNumberP2.contentEquals(MAGIC_NUMBER_P2)) { + try { + source.reset() + source.mark(MAX_WEBP_COMPRESSED_SIZE) + WebpSanitizer.sanitize(source) + source.reset() + } catch (e: Exception) { + Log.w(TAG, "Sanitize check failed or mark position invalidated by reset", e) + return true + } + } } catch (e: IOException) { Log.w(TAG, "Failed to read magic number from stream!", e) - false + return true } + + return false } override fun decode(source: InputStream, width: Int, height: Int, options: Options): Resource? { - Log.d(TAG, "decode()") - - val webp: ByteArray = try { - StreamUtil.readFully(source, MAX_WEBP_COMPRESSED_SIZE) - } catch (e: IOException) { - Log.w(TAG, "Unexpected IOException hit while reading image data", e) - throw e - } - - val bitmap: Bitmap? = WebpDecoder().nativeDecodeBitmapScaled(webp, width, height) - return BitmapResource.obtain(bitmap, bitmapPool) + Log.w(TAG, "Image did not pass sanitizer") + throw IOException("Unable to load image") } } diff --git a/app/src/main/java/org/tm/archive/groups/GroupId.java b/app/src/main/java/org/tm/archive/groups/GroupId.java index c0afd9f1..47e2fb52 100644 --- a/app/src/main/java/org/tm/archive/groups/GroupId.java +++ b/app/src/main/java/org/tm/archive/groups/GroupId.java @@ -118,6 +118,14 @@ public abstract class GroupId implements DatabaseId { } } + public static GroupId.Push pushOrNull(byte[] bytes) { + try { + return GroupId.push(bytes); + } catch (BadGroupIdException e) { + return null; + } + } + public static @NonNull GroupId parseOrThrow(@NonNull String encodedGroupId) { try { return parse(encodedGroupId); diff --git a/app/src/main/java/org/tm/archive/groups/GroupManager.java b/app/src/main/java/org/tm/archive/groups/GroupManager.java index 2d1b843a..7131866e 100644 --- a/app/src/main/java/org/tm/archive/groups/GroupManager.java +++ b/app/src/main/java/org/tm/archive/groups/GroupManager.java @@ -200,11 +200,12 @@ public final class GroupManager { @Nullable GroupSecretParams groupSecretParams, int revision, long timestamp, - @Nullable byte[] signedGroupChange) + @Nullable byte[] signedGroupChange, + @Nullable String serverGuid) throws GroupChangeBusyException, IOException, GroupNotAMemberException { try (GroupManagerV2.GroupUpdater updater = new GroupManagerV2(context).updater(groupMasterKey)) { - return updater.updateLocalToServerRevision(revision, timestamp, groupRecord, groupSecretParams, signedGroupChange); + return updater.updateLocalToServerRevision(revision, timestamp, groupRecord, groupSecretParams, signedGroupChange, serverGuid); } } diff --git a/app/src/main/java/org/tm/archive/groups/GroupManagerV2.java b/app/src/main/java/org/tm/archive/groups/GroupManagerV2.java index 0860cad2..85abd483 100644 --- a/app/src/main/java/org/tm/archive/groups/GroupManagerV2.java +++ b/app/src/main/java/org/tm/archive/groups/GroupManagerV2.java @@ -35,6 +35,7 @@ import org.tm.archive.database.SignalDatabase; import org.tm.archive.database.ThreadTable; import org.tm.archive.database.model.GroupRecord; import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context; +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.groups.v2.GroupCandidateHelper; import org.tm.archive.groups.v2.GroupInviteLinkUrl; @@ -805,11 +806,16 @@ final class GroupManagerV2 { } @WorkerThread - GroupsV2StateProcessor.GroupUpdateResult updateLocalToServerRevision(int revision, long timestamp, @NonNull Optional localRecord, @Nullable GroupSecretParams groupSecretParams, @Nullable byte[] signedGroupChange) + GroupsV2StateProcessor.GroupUpdateResult updateLocalToServerRevision(int revision, + long timestamp, + @NonNull Optional localRecord, + @Nullable GroupSecretParams groupSecretParams, + @Nullable byte[] signedGroupChange, + @Nullable String serverGuid) throws IOException, GroupNotAMemberException { return new GroupsV2StateProcessor(context).forGroup(serviceIds, groupMasterKey, groupSecretParams) - .updateLocalGroupToRevision(revision, timestamp, localRecord, getDecryptedGroupChange(signedGroupChange)); + .updateLocalGroupToRevision(revision, timestamp, localRecord, getDecryptedGroupChange(signedGroupChange), serverGuid); } @WorkerThread @@ -1290,10 +1296,10 @@ final class GroupManagerV2 { @Nullable GroupChange signedGroupChange, boolean sendToMembers) { - GroupId.V2 groupId = GroupId.v2(masterKey); - Recipient groupRecipient = Recipient.externalGroupExact(groupId); - DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, groupMutation, signedGroupChange); - OutgoingMessage outgoingMessage = OutgoingMessage.groupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis()); + GroupId.V2 groupId = GroupId.v2(masterKey); + Recipient groupRecipient = Recipient.externalGroupExact(groupId); + GV2UpdateDescription updateDescription = GroupProtoUtil.createOutgoingGroupV2UpdateDescription(masterKey, groupMutation, signedGroupChange); + OutgoingMessage outgoingMessage = OutgoingMessage.groupUpdateMessage(groupRecipient, updateDescription, System.currentTimeMillis()); DecryptedGroupChange plainGroupChange = groupMutation.getGroupChange(); diff --git a/app/src/main/java/org/tm/archive/groups/GroupProtoUtil.java b/app/src/main/java/org/tm/archive/groups/GroupProtoUtil.java index 9ca9b26d..f088bc50 100644 --- a/app/src/main/java/org/tm/archive/groups/GroupProtoUtil.java +++ b/app/src/main/java/org/tm/archive/groups/GroupProtoUtil.java @@ -10,7 +10,13 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedMember; import org.signal.storageservice.protos.groups.local.DecryptedPendingMember; +import org.tm.archive.backup.v2.proto.GroupChangeChatUpdate; +import org.tm.archive.database.SignalDatabase; +import org.tm.archive.database.model.GroupsV2UpdateMessageConverter; import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context; +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription; +import org.tm.archive.database.model.databaseprotos.MessageExtras; +import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup; @@ -45,6 +51,19 @@ public final class GroupProtoUtil { throw new GroupNotAMemberException(); } + public static GV2UpdateDescription createOutgoingGroupV2UpdateDescription(@NonNull GroupMasterKey masterKey, + @NonNull GroupMutation groupMutation, + @Nullable GroupChange signedServerChange) + { + DecryptedGroupV2Context groupV2Context = createDecryptedGroupV2Context(masterKey, groupMutation, signedServerChange); + GroupChangeChatUpdate update = GroupsV2UpdateMessageConverter.translateDecryptedChange(SignalStore.account().getServiceIds(), groupV2Context); + + return new GV2UpdateDescription.Builder() + .gv2ChangeDescription(groupV2Context) + .groupChangeUpdate(update) + .build(); + } + public static DecryptedGroupV2Context createDecryptedGroupV2Context(@NonNull GroupMasterKey masterKey, @NonNull GroupMutation groupMutation, @Nullable GroupChange signedServerChange) diff --git a/app/src/main/java/org/tm/archive/groups/ui/GroupMemberListAdapter.java b/app/src/main/java/org/tm/archive/groups/ui/GroupMemberListAdapter.java index 89bd294b..1735fee8 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/GroupMemberListAdapter.java +++ b/app/src/main/java/org/tm/archive/groups/ui/GroupMemberListAdapter.java @@ -257,6 +257,7 @@ final class GroupMemberListAdapter extends RecyclerView.Adapter findByActivityLauncher; public static @NonNull Intent createIntent(@NonNull Context context, @NonNull GroupId groupId, @@ -70,6 +79,12 @@ public class AddMembersActivity extends PushContactSelectionActivity { ); disableDone(); + + findByActivityLauncher = registerForActivityResult(new FindByActivity.Contract(), result -> { + if (result != null) { + contactsFragment.addRecipientToSelectionIfAble(result); + } + }); } @Override @@ -93,9 +108,34 @@ public class AddMembersActivity extends PushContactSelectionActivity { getContactFilterView().clear(); } - enableDone(); + if (recipientId.isPresent()) { + callback.accept(true); + enableDone(); + return; + } - callback.accept(true); + AlertDialog progress = SimpleProgressDialog.show(this); + + SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(this, number), result -> { + progress.dismiss(); + + if (result instanceof RecipientRepository.LookupResult.Success) { + enableDone(); + callback.accept(true); + } else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) { + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number)) + .setPositiveButton(android.R.string.ok, null) + .show(); + callback.accept(false); + } else { + new MaterialAlertDialogBuilder(this) + .setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again) + .setPositiveButton(android.R.string.ok, null) + .show(); + callback.accept(false); + } + }); } @Override @@ -119,6 +159,16 @@ public class AddMembersActivity extends PushContactSelectionActivity { } } + @Override + public void onFindByPhoneNumber() { + findByActivityLauncher.launch(FindByMode.PHONE_NUMBER); + } + + @Override + public void onFindByUsername() { + findByActivityLauncher.launch(FindByMode.USERNAME); + } + private void enableDone() { done.setEnabled(true); done.animate().alpha(1f); @@ -141,7 +191,7 @@ public class AddMembersActivity extends PushContactSelectionActivity { Recipient recipient = Util.firstNonNull(state.getRecipient(), Recipient.UNKNOWN); String message = getResources().getQuantityString(R.plurals.AddMembersActivity__add_d_members_to_s, state.getSelectionCount(), - recipient.getDisplayNameOrUsername(this), state.getGroupTitle(), state.getSelectionCount()); + recipient.getDisplayName(this), state.getGroupTitle(), state.getSelectionCount()); new MaterialAlertDialogBuilder(this) .setMessage(message) diff --git a/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupViewModel.java b/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupViewModel.java index 9f053e42..e5252c4b 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupViewModel.java +++ b/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupViewModel.java @@ -47,7 +47,7 @@ public final class AddToGroupViewModel extends ViewModel { SignalExecutors.BOUNDED.execute(() -> { Recipient recipient = Recipient.resolved(recipientId); Recipient groupRecipient = Recipient.resolved(groupRecipientIds.get(0)); - String recipientName = recipient.getDisplayNameOrUsername(context); + String recipientName = recipient.getDisplayName(context); String groupName = groupRecipient.getDisplayName(context); if (groupRecipient.getGroupId().get().isV1() && !recipient.hasE164()) { diff --git a/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupsActivity.java b/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupsActivity.java index 89a82a16..dbc71d6e 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupsActivity.java +++ b/app/src/main/java/org/tm/archive/groups/ui/addtogroup/AddToGroupsActivity.java @@ -8,17 +8,21 @@ import android.view.View; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.ViewModelProvider; import com.annimon.stream.Stream; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import org.signal.core.util.concurrent.SimpleTask; import org.tm.archive.ContactSelectionActivity; import org.tm.archive.ContactSelectionListFragment; import org.tm.archive.R; import org.tm.archive.contacts.ContactSelectionDisplayMode; import org.tm.archive.groups.ui.addtogroup.AddToGroupViewModel.Event; import org.tm.archive.recipients.RecipientId; +import org.tm.archive.recipients.RecipientRepository; +import org.tm.archive.util.views.SimpleProgressDialog; import java.util.ArrayList; import java.util.Collections; @@ -50,7 +54,7 @@ public final class AddToGroupsActivity extends ContactSelectionActivity { intent.putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.add_to_group_activity); intent.putExtra(EXTRA_RECIPIENT_ID, recipientId); - intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, ContactSelectionDisplayMode.FLAG_ACTIVE_GROUPS); + intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, ContactSelectionDisplayMode.FLAG_ACTIVE_GROUPS | ContactSelectionDisplayMode.FLAG_GROUPS_AFTER_CONTACTS); intent.putParcelableArrayListExtra(ContactSelectionListFragment.CURRENT_SELECTION, new ArrayList<>(currentGroupsMemberOf)); diff --git a/app/src/main/java/org/tm/archive/groups/ui/creategroup/CreateGroupActivity.java b/app/src/main/java/org/tm/archive/groups/ui/creategroup/CreateGroupActivity.java index e99bf92c..732271e6 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/creategroup/CreateGroupActivity.java +++ b/app/src/main/java/org/tm/archive/groups/ui/creategroup/CreateGroupActivity.java @@ -6,14 +6,17 @@ import android.os.Bundle; import android.view.MenuItem; import android.view.View; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import com.google.android.material.button.MaterialButton; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import org.signal.core.util.DimensionUnit; +import org.signal.core.util.Stopwatch; import org.signal.core.util.concurrent.SimpleTask; import org.signal.core.util.logging.Log; import org.tm.archive.ContactSelectionActivity; @@ -21,13 +24,14 @@ import org.tm.archive.ContactSelectionListFragment; import org.tm.archive.R; import org.tm.archive.contacts.ContactSelectionDisplayMode; import org.tm.archive.contacts.sync.ContactDiscovery; -import org.tm.archive.database.RecipientTable; import org.tm.archive.groups.ui.creategroup.details.AddGroupDetailsActivity; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; +import org.tm.archive.recipients.RecipientRepository; +import org.tm.archive.recipients.ui.findby.FindByActivity; +import org.tm.archive.recipients.ui.findby.FindByMode; import org.tm.archive.util.FeatureFlags; -import org.signal.core.util.Stopwatch; import org.tm.archive.util.views.SimpleProgressDialog; import java.io.IOException; @@ -38,14 +42,16 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; -public class CreateGroupActivity extends ContactSelectionActivity { +public class CreateGroupActivity extends ContactSelectionActivity implements ContactSelectionListFragment.FindByCallback { private static final String TAG = Log.tag(CreateGroupActivity.class); private static final short REQUEST_CODE_ADD_DETAILS = 17275; - private MaterialButton skip; - private FloatingActionButton next; + private MaterialButton skip; + private FloatingActionButton next; + private ActivityResultLauncher findByActivityLauncher; + public static Intent newIntent(@NonNull Context context) { Intent intent = new Intent(context, CreateGroupActivity.class); @@ -53,9 +59,7 @@ public class CreateGroupActivity extends ContactSelectionActivity { intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false); intent.putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.create_group_activity); - boolean smsEnabled = SignalStore.misc().getSmsExportPhase().allowSmsFeatures(); - int displayMode = smsEnabled ? ContactSelectionDisplayMode.FLAG_SMS | ContactSelectionDisplayMode.FLAG_PUSH - : ContactSelectionDisplayMode.FLAG_PUSH; + int displayMode = ContactSelectionDisplayMode.FLAG_PUSH; intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode); intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, FeatureFlags.groupLimits().excludingSelf()); @@ -77,6 +81,12 @@ public class CreateGroupActivity extends ContactSelectionActivity { skip.setOnClickListener(v -> handleNextPressed()); next.setOnClickListener(v -> handleNextPressed()); + + findByActivityLauncher = registerForActivityResult(new FindByActivity.Contract(), result -> { + if (result != null) { + contactsFragment.addRecipientToSelectionIfAble(result); + } + }); } @Override @@ -92,6 +102,7 @@ public class CreateGroupActivity extends ContactSelectionActivity { @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == REQUEST_CODE_ADD_DETAILS && resultCode == RESULT_OK) { + setResult(RESULT_OK); finish(); } else { super.onActivityResult(requestCode, resultCode, data); @@ -106,7 +117,32 @@ public class CreateGroupActivity extends ContactSelectionActivity { shrinkSkip(); - callback.accept(true); + if (recipientId.isPresent()) { + callback.accept(true); + return; + } + + AlertDialog progress = SimpleProgressDialog.show(this); + + SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(this, number), result -> { + progress.dismiss(); + + if (result instanceof RecipientRepository.LookupResult.Success) { + callback.accept(true); + } else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) { + new MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number)) + .setPositiveButton(android.R.string.ok, null) + .show(); + callback.accept(false); + } else { + new MaterialAlertDialogBuilder(this) + .setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again) + .setPositiveButton(android.R.string.ok, null) + .show(); + callback.accept(false); + } + }); } @Override @@ -131,6 +167,16 @@ public class CreateGroupActivity extends ContactSelectionActivity { } } + @Override + public void onFindByPhoneNumber() { + findByActivityLauncher.launch(FindByMode.PHONE_NUMBER); + } + + @Override + public void onFindByUsername() { + findByActivityLauncher.launch(FindByMode.USERNAME); + } + private void extendSkip() { skip.setVisibility(View.VISIBLE); next.setVisibility(View.GONE); diff --git a/app/src/main/java/org/tm/archive/groups/ui/creategroup/details/AddGroupDetailsFragment.java b/app/src/main/java/org/tm/archive/groups/ui/creategroup/details/AddGroupDetailsFragment.java index 5eb7f24e..08d20dbb 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/creategroup/details/AddGroupDetailsFragment.java +++ b/app/src/main/java/org/tm/archive/groups/ui/creategroup/details/AddGroupDetailsFragment.java @@ -25,6 +25,7 @@ import androidx.navigation.Navigation; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import com.airbnb.lottie.SimpleColorFilter; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; @@ -39,7 +40,6 @@ import org.tm.archive.groups.ui.GroupMemberListView; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.mediasend.Media; import org.tm.archive.mms.DecryptableStreamUriLoader; -import org.tm.archive.mms.GlideApp; import org.tm.archive.profiles.AvatarHelper; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; @@ -136,7 +136,7 @@ public class AddGroupDetailsFragment extends LoggingFragment { if (avatarBytes == null) { avatar.setImageDrawable(new InsetDrawable(avatarPlaceholder, ViewUtil.dpToPx(AVATAR_PLACEHOLDER_INSET_DP))); } else { - GlideApp.with(this) + Glide.with(this) .load(avatarBytes) .circleCrop() .skipMemoryCache(true) @@ -178,7 +178,7 @@ public class AddGroupDetailsFragment extends LoggingFragment { viewModel.setAvatarMedia(result); - GlideApp.with(this) + Glide.with(this) .asBitmap() .load(decryptableUri) .skipMemoryCache(true) diff --git a/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/invited/PendingMemberInvitesFragment.java b/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/invited/PendingMemberInvitesFragment.java index 60a9e6d8..0822e627 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/invited/PendingMemberInvitesFragment.java +++ b/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/invited/PendingMemberInvitesFragment.java @@ -52,9 +52,7 @@ public class PendingMemberInvitesFragment extends Fragment { youInvited.initializeAdapter(getViewLifecycleOwner()); othersInvited.initializeAdapter(getViewLifecycleOwner()); - youInvited.setRecipientClickListener(recipient -> - RecipientBottomSheetDialogFragment.create(recipient.getId(), null) - .show(requireActivity().getSupportFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)); + youInvited.setRecipientClickListener(recipient -> RecipientBottomSheetDialogFragment.show(requireActivity().getSupportFragmentManager(), recipient.getId(), null)); youInvited.setAdminActionsListener(new AdminActionsListener() { diff --git a/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/requesting/RequestingMembersFragment.java b/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/requesting/RequestingMembersFragment.java index 4a510054..a6380cb2 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/requesting/RequestingMembersFragment.java +++ b/app/src/main/java/org/tm/archive/groups/ui/invitesandrequests/requesting/RequestingMembersFragment.java @@ -55,8 +55,7 @@ public class RequestingMembersFragment extends Fragment { requestingMembers.initializeAdapter(getViewLifecycleOwner()); requestingMembers.setRecipientClickListener(recipient -> { - RecipientBottomSheetDialogFragment.create(recipient.getId(), null) - .show(requireActivity().getSupportFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG); + RecipientBottomSheetDialogFragment.show(requireActivity().getSupportFragmentManager(), recipient.getId(), null); }); requestingMembers.setAdminActionsListener(new AdminActionsListener() { diff --git a/app/src/main/java/org/tm/archive/groups/ui/managegroup/dialogs/GroupInviteSentDialog.java b/app/src/main/java/org/tm/archive/groups/ui/managegroup/dialogs/GroupInviteSentDialog.java index 98ef5cb3..525ee8a9 100644 --- a/app/src/main/java/org/tm/archive/groups/ui/managegroup/dialogs/GroupInviteSentDialog.java +++ b/app/src/main/java/org/tm/archive/groups/ui/managegroup/dialogs/GroupInviteSentDialog.java @@ -31,12 +31,9 @@ public final class GroupInviteSentDialog { AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context) .setTitle(context.getResources().getQuantityString(R.plurals.GroupManagement_invitation_sent, size, size)) - // TODO: GV2 Need a URL for learn more - // .setNegativeButton(R.string.GroupManagement_learn_more, (dialog, which) -> { - // }) .setPositiveButton(android.R.string.ok, null); if (size == 1) { - builder.setMessage(context.getString(R.string.GroupManagement_invite_single_user, recipients.get(0).getDisplayNameOrUsername(context))); + builder.setMessage(context.getString(R.string.GroupManagement_invite_single_user, recipients.get(0).getDisplayName(context))); } else { builder.setMessage(R.string.GroupManagement_invite_multiple_users) .setView(R.layout.dialog_multiple_group_invites_sent); diff --git a/app/src/main/java/org/tm/archive/groups/v2/ProfileKeySet.java b/app/src/main/java/org/tm/archive/groups/v2/ProfileKeySet.java index cbec8dd9..ae567265 100644 --- a/app/src/main/java/org/tm/archive/groups/v2/ProfileKeySet.java +++ b/app/src/main/java/org/tm/archive/groups/v2/ProfileKeySet.java @@ -61,10 +61,6 @@ public final class ProfileKeySet { for (DecryptedMember member : change.promotePendingPniAciMembers) { addMemberKey(member, editor); } - - for (DecryptedMember member : change.promotePendingPniAciMembers) { - addMemberKey(member, editor); - } } /** diff --git a/app/src/main/java/org/tm/archive/groups/v2/processing/GroupsV2StateProcessor.java b/app/src/main/java/org/tm/archive/groups/v2/processing/GroupsV2StateProcessor.java index 6618d178..4342169c 100644 --- a/app/src/main/java/org/tm/archive/groups/v2/processing/GroupsV2StateProcessor.java +++ b/app/src/main/java/org/tm/archive/groups/v2/processing/GroupsV2StateProcessor.java @@ -18,13 +18,16 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedMember; import org.signal.storageservice.protos.groups.local.DecryptedPendingMember; +import org.tm.archive.backup.v2.proto.GroupChangeChatUpdate; import org.tm.archive.database.GroupTable; import org.tm.archive.database.MessageTable; import org.tm.archive.database.RecipientTable; import org.tm.archive.database.SignalDatabase; import org.tm.archive.database.ThreadTable; import org.tm.archive.database.model.GroupRecord; +import org.tm.archive.database.model.GroupsV2UpdateMessageConverter; import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context; +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.groups.GroupDoesNotExistException; import org.tm.archive.groups.GroupId; @@ -35,6 +38,7 @@ import org.tm.archive.groups.GroupsV2Authorization; import org.tm.archive.groups.v2.ProfileKeySet; import org.tm.archive.jobmanager.Job; import org.tm.archive.jobs.AvatarGroupsV2DownloadJob; +import org.tm.archive.jobs.DirectoryRefreshJob; import org.tm.archive.jobs.LeaveGroupV2Job; import org.tm.archive.jobs.RequestGroupV2InfoJob; import org.tm.archive.jobs.RetrieveProfileJob; @@ -238,10 +242,10 @@ public class GroupsV2StateProcessor { updateLocalDatabaseGroupState(inputGroupState, newLocalState); if (localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { info("Inserting single update message for restore placeholder"); - profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null))); + profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null)), null); } else { info("Inserting force update messages"); - profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries()); + profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries(), null); } profileAndMessageHelper.persistLearnedProfileKeys(inputGroupState); @@ -259,7 +263,7 @@ public class GroupsV2StateProcessor { @Nullable DecryptedGroupChange signedGroupChange) throws IOException, GroupNotAMemberException { - return updateLocalGroupToRevision(revision, timestamp, groupDatabase.getGroup(groupId), signedGroupChange); + return updateLocalGroupToRevision(revision, timestamp, groupDatabase.getGroup(groupId), signedGroupChange, null); } /** @@ -271,7 +275,8 @@ public class GroupsV2StateProcessor { public GroupUpdateResult updateLocalGroupToRevision(final int revision, final long timestamp, @NonNull Optional localRecord, - @Nullable DecryptedGroupChange signedGroupChange) + @Nullable DecryptedGroupChange signedGroupChange, + @Nullable String serverGuid) throws IOException, GroupNotAMemberException { if (localIsAtLeast(localRecord, revision)) { @@ -287,7 +292,6 @@ public class GroupsV2StateProcessor { localState.revision + 1 == signedGroupChange.revision && revision == signedGroupChange.revision) { - if (notInGroupAndNotBeingAdded(localRecord, signedGroupChange) && notHavingInviteRevoked(signedGroupChange)) { warn("Ignoring P2P group change because we're not currently in the group and this change doesn't add us in. Falling back to a server fetch."); } else if (SignalStore.internalValues().gv2IgnoreP2PChanges()) { @@ -306,7 +310,7 @@ public class GroupsV2StateProcessor { if (inputGroupState == null) { try { - return updateLocalGroupFromServerPaged(revision, localState, timestamp, false); + return updateLocalGroupFromServerPaged(revision, localState, timestamp, false, serverGuid); } catch (GroupNotAMemberException e) { if (localState != null && signedGroupChange != null) { try { @@ -346,12 +350,16 @@ public class GroupsV2StateProcessor { updateLocalDatabaseGroupState(inputGroupState, newLocalState); if (localState != null && localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { info("Inserting single update message for restore placeholder"); - profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null))); + profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null)), null); } else { - profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries()); + profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries(), serverGuid); } profileAndMessageHelper.persistLearnedProfileKeys(inputGroupState); + if (!signedGroupChange.promotePendingPniAciMembers.isEmpty()) { + ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(false)); + } + GlobalGroupState remainingWork = advanceGroupStateResult.getNewGlobalGroupState(); if (remainingWork.getServerHistory().size() > 0) { info(String.format(Locale.US, "There are more revisions on the server for this group, scheduling for later, V[%d..%d]", newLocalState.revision + 1, remainingWork.getLatestRevisionNumber())); @@ -398,7 +406,7 @@ public class GroupsV2StateProcessor { /** * Using network, attempt to bring the local copy of the group up to the revision specified via paging. */ - private GroupUpdateResult updateLocalGroupFromServerPaged(int revision, DecryptedGroup localState, long timestamp, boolean forceIncludeFirst) throws IOException, GroupNotAMemberException { + private GroupUpdateResult updateLocalGroupFromServerPaged(int revision, DecryptedGroup localState, long timestamp, boolean forceIncludeFirst, @Nullable String serverGuid) throws IOException, GroupNotAMemberException { boolean latestRevisionOnly = revision == LATEST && (localState == null || localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION); info("Paging from server revision: " + (revision == LATEST ? "latest" : revision) + ", latestOnly: " + latestRevisionOnly); @@ -443,6 +451,7 @@ public class GroupsV2StateProcessor { ProfileKeySet profileKeys = new ProfileKeySet(); DecryptedGroup finalState = localState; GlobalGroupState finalGlobalGroupState = inputGroupState; + boolean performCdsLookup = false; boolean hasMore = true; @@ -456,7 +465,7 @@ public class GroupsV2StateProcessor { int requestRevision = (revision == LATEST) ? latestServerGroup.getRevision() : revision; if (newLocalRevision < requestRevision) { warn( "Paging again with force first snapshot enabled due to error processing changes. New local revision [" + newLocalRevision + "] hasn't reached our desired level [" + requestRevision + "]"); - return updateLocalGroupFromServerPaged(revision, localState, timestamp, true); + return updateLocalGroupFromServerPaged(revision, localState, timestamp, true, serverGuid); } } @@ -467,15 +476,20 @@ public class GroupsV2StateProcessor { updateLocalDatabaseGroupState(inputGroupState, newLocalState); if (localState == null || localState.revision != GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { - timestamp = profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries()); + timestamp = profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries(), serverGuid); } for (ServerGroupLogEntry entry : inputGroupState.getServerHistory()) { if (entry.getGroup() != null) { profileKeys.addKeysFromGroupState(entry.getGroup()); } + if (entry.getChange() != null) { profileKeys.addKeysFromGroupChange(entry.getChange()); + + if (!entry.getChange().promotePendingPniAciMembers.isEmpty()) { + performCdsLookup = true; + } } } @@ -491,11 +505,15 @@ public class GroupsV2StateProcessor { if (localState != null && localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { info("Inserting single update message for restore placeholder"); - profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(finalState, null))); + profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(finalState, null)), serverGuid); } profileAndMessageHelper.persistLearnedProfileKeys(profileKeys); + if (performCdsLookup) { + ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(false)); + } + if (finalGlobalGroupState.getServerHistory().size() > 0) { info(String.format(Locale.US, "There are more revisions on the server for this group, scheduling for later, V[%d..%d]", finalState.revision + 1, finalGlobalGroupState.getLatestRevisionNumber())); ApplicationDependencies.getJobManager().add(new RequestGroupV2InfoJob(groupId, finalGlobalGroupState.getLatestRevisionNumber())); @@ -558,8 +576,8 @@ public class GroupsV2StateProcessor { .deleteMembers(Collections.singletonList(serviceIds.getAci().toByteString())) .build(); - DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null); - OutgoingMessage leaveMessage = OutgoingMessage.groupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis()); + GV2UpdateDescription updateDescription = GroupProtoUtil.createOutgoingGroupV2UpdateDescription(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null); + OutgoingMessage leaveMessage = OutgoingMessage.groupUpdateMessage(groupRecipient, updateDescription, System.currentTimeMillis()); try { MessageTable mmsDatabase = SignalDatabase.messages(); @@ -735,7 +753,8 @@ public class GroupsV2StateProcessor { long insertUpdateMessages(long timestamp, @Nullable DecryptedGroup previousGroupState, - Collection processedLogEntries) + Collection processedLogEntries, + @Nullable String serverGuid) { for (LocalGroupLogEntry entry : processedLogEntries) { if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(entry.getChange()) && !DecryptedGroupUtil.changeIsEmpty(entry.getChange())) { @@ -746,7 +765,7 @@ public class GroupsV2StateProcessor { if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmpty(entry.getChange()) && previousGroupState != null) { Log.w(TAG, "Empty group update message seen. Not inserting."); } else { - storeMessage(GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(previousGroupState, entry.getChange(), entry.getGroup()), null), timestamp); + storeMessage(GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(previousGroupState, entry.getChange(), entry.getGroup()), null), timestamp, serverGuid); timestamp++; } } @@ -782,18 +801,23 @@ public class GroupsV2StateProcessor { } } - void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) { + void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp, @Nullable String serverGuid) { Optional editor = getEditor(decryptedGroupV2Context); boolean outgoing = !editor.isPresent() || aci.equals(editor.get()); + GV2UpdateDescription updateDescription = new GV2UpdateDescription.Builder() + .gv2ChangeDescription(decryptedGroupV2Context) + .groupChangeUpdate(GroupsV2UpdateMessageConverter.translateDecryptedChange(SignalStore.account().getServiceIds(), decryptedGroupV2Context)) + .build(); + if (outgoing) { try { MessageTable mmsDatabase = SignalDatabase.messages(); ThreadTable threadTable = SignalDatabase.threads(); RecipientId recipientId = recipientTable.getOrInsertFromGroupId(groupId); Recipient recipient = Recipient.resolved(recipientId); - OutgoingMessage outgoingMessage = OutgoingMessage.groupUpdateMessage(recipient, decryptedGroupV2Context, timestamp); + OutgoingMessage outgoingMessage = OutgoingMessage.groupUpdateMessage(recipient, updateDescription, timestamp); long threadId = threadTable.getOrCreateThreadIdFor(recipient); long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null); @@ -806,7 +830,7 @@ public class GroupsV2StateProcessor { try { MessageTable smsDatabase = SignalDatabase.messages(); RecipientId sender = RecipientId.from(editor.get()); - IncomingMessage groupMessage = IncomingMessage.groupUpdate(sender, timestamp, groupId, decryptedGroupV2Context); + IncomingMessage groupMessage = IncomingMessage.groupUpdate(sender, timestamp, groupId, decryptedGroupV2Context, serverGuid); Optional insertResult = smsDatabase.insertMessageInbox(groupMessage); if (insertResult.isPresent()) { diff --git a/app/src/main/java/org/tm/archive/invites/InviteActions.kt b/app/src/main/java/org/tm/archive/invites/InviteActions.kt index 4c77c0e9..e7b893e8 100644 --- a/app/src/main/java/org/tm/archive/invites/InviteActions.kt +++ b/app/src/main/java/org/tm/archive/invites/InviteActions.kt @@ -5,10 +5,7 @@ import android.content.Intent import android.widget.Toast import androidx.annotation.MainThread import org.tm.archive.R -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.recipients.Recipient import org.tm.archive.util.CommunicationActions -import org.tm.archive.util.Util /** * Handles 'invite to signal' actions. @@ -25,29 +22,18 @@ object InviteActions { @MainThread fun inviteUserToSignal( context: Context, - recipient: Recipient, - appendInviteToComposer: ((String) -> Unit)?, launchIntent: (Intent) -> Unit ) { val inviteText = context.getString( R.string.ConversationActivity_lets_switch_to_signal, context.getString(R.string.install_url) ) + val intent = CommunicationActions.createIntentToShareTextViaShareSheet(inviteText) - if (appendInviteToComposer != null && Util.isDefaultSmsProvider(context) && SignalStore.misc().smsExportPhase.isSmsSupported()) { - appendInviteToComposer(inviteText) - } else if (recipient.hasSmsAddress()) { - launchIntent( - CommunicationActions.createIntentToComposeSmsThroughDefaultApp(recipient, inviteText) - ) + if (intent.resolveActivity(context.packageManager) != null) { + launchIntent(Intent.createChooser(intent, context.getString(R.string.InviteActivity_invite_to_signal))) } else { - val intent = CommunicationActions.createIntentToShareTextViaShareSheet(inviteText) - - if (intent.resolveActivity(context.packageManager) != null) { - launchIntent(Intent.createChooser(intent, context.getString(R.string.InviteActivity_invite_to_signal))) - } else { - Toast.makeText(context, R.string.InviteActivity_no_app_to_share_to, Toast.LENGTH_LONG).show() - } + Toast.makeText(context, R.string.InviteActivity_no_app_to_share_to, Toast.LENGTH_LONG).show() } } } diff --git a/app/src/main/java/org/tm/archive/jobmanager/JobController.java b/app/src/main/java/org/tm/archive/jobmanager/JobController.java index cf7f9c9d..cfc0c9a9 100644 --- a/app/src/main/java/org/tm/archive/jobmanager/JobController.java +++ b/app/src/main/java/org/tm/archive/jobmanager/JobController.java @@ -76,6 +76,15 @@ class JobController { notifyAll(); } + @WorkerThread + void submitNewJobChains(@NonNull List>> chains) { + synchronized (this) { + for (List> chain : chains) { + submitNewJobChain(chain); + } + } + } + @WorkerThread void submitNewJobChain(@NonNull List> chain) { synchronized (this) { diff --git a/app/src/main/java/org/tm/archive/jobmanager/JobExtensions.kt b/app/src/main/java/org/tm/archive/jobmanager/JobExtensions.kt new file mode 100644 index 00000000..9554a985 --- /dev/null +++ b/app/src/main/java/org/tm/archive/jobmanager/JobExtensions.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.jobmanager + +import org.tm.archive.jobmanager.impl.BackoffUtil +import org.tm.archive.util.FeatureFlags + +/** + * Helper to calculate the default backoff interval for a [Job] given it's run attempt count. + */ +fun Job.defaultBackoffInterval(): Long = BackoffUtil.exponentialBackoff(runAttempt + 1, FeatureFlags.getDefaultMaxBackoff()) diff --git a/app/src/main/java/org/tm/archive/jobmanager/JobManager.java b/app/src/main/java/org/tm/archive/jobmanager/JobManager.java index c419c0be..68de5342 100644 --- a/app/src/main/java/org/tm/archive/jobmanager/JobManager.java +++ b/app/src/main/java/org/tm/archive/jobmanager/JobManager.java @@ -35,6 +35,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Allows the scheduling of durable jobs that will be run as early as possible. @@ -208,6 +209,24 @@ public class JobManager implements ConstraintObserver.Notifier { }); } + public void addAllChains(@NonNull List chains) { + if (chains.isEmpty()) { + return; + } + + for (Chain chain : chains) { + for (List jobList : chain.getJobListChain()) { + for (Job job : jobList) { + jobTracker.onStateChange(job, JobTracker.JobState.PENDING); + } + } + } + + runOnExecutor(() -> { + jobController.submitNewJobChains(chains.stream().map(Chain::getJobListChain).collect(Collectors.toList())); + }); + } + /** * Begins the creation of a job chain with a single job. * @see Chain diff --git a/app/src/main/java/org/tm/archive/jobs/AttachmentCompressionJob.java b/app/src/main/java/org/tm/archive/jobs/AttachmentCompressionJob.java index a55294ef..60f9162d 100644 --- a/app/src/main/java/org/tm/archive/jobs/AttachmentCompressionJob.java +++ b/app/src/main/java/org/tm/archive/jobs/AttachmentCompressionJob.java @@ -9,13 +9,8 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import androidx.media3.common.MimeTypes; -import com.google.common.io.ByteStreams; - import org.greenrobot.eventbus.EventBus; import org.signal.core.util.logging.Log; -import org.signal.libsignal.media.Mp4Sanitizer; -import org.signal.libsignal.media.ParseException; -import org.signal.libsignal.media.SanitizedMetadata; import org.tm.archive.R; import org.tm.archive.attachments.Attachment; import org.tm.archive.attachments.AttachmentId; @@ -45,17 +40,17 @@ import org.tm.archive.util.MediaUtil; import org.tm.archive.util.MemoryFileDescriptor.MemoryFileException; import org.tm.archive.video.InMemoryTranscoder; import org.tm.archive.video.StreamingTranscoder; -import org.tm.archive.video.TranscoderCancelationSignal; import org.tm.archive.video.TranscoderOptions; -import org.tm.archive.video.VideoSourceException; -import org.tm.archive.video.videoconverter.EncodingException; +import org.tm.archive.video.exceptions.VideoPostProcessingException; +import org.tm.archive.video.exceptions.VideoSourceException; +import org.tm.archive.video.interfaces.TranscoderCancelationSignal; +import org.tm.archive.video.postprocessing.Mp4FaststartPostProcessor; +import org.tm.archive.video.videoconverter.exceptions.EncodingException; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.io.SequenceInputStream; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -167,8 +162,7 @@ public final class AttachmentCompressionJob extends BaseJob { return; } - MediaConstraints mediaConstraints = mms ? MediaConstraints.getMmsMediaConstraints(mmsSubscriptionId) - : MediaConstraints.getPushMediaConstraints(SentMediaQuality.fromCode(transformProperties.sentMediaQuality)); + MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints(SentMediaQuality.fromCode(transformProperties.sentMediaQuality)); compress(database, mediaConstraints, databaseAttachment); } @@ -211,7 +205,7 @@ public final class AttachmentCompressionJob extends BaseJob { } else if (constraints.canResize(attachment)) { Log.i(TAG, "Compressing image."); try (MediaStream converted = compressImage(context, attachment, constraints)) { - attachmentDatabase.updateAttachmentData(attachment, converted, false); + attachmentDatabase.updateAttachmentData(attachment, converted); } attachmentDatabase.markAttachmentAsTransformed(attachmentId, false); } else if (constraints.isSatisfied(context, attachment)) { @@ -254,20 +248,22 @@ public final class AttachmentCompressionJob extends BaseJob { throw new UndeliverableMessageException("Cannot get media data source for attachment."); } - allowSkipOnFailure = !transformProperties.getVideoEdited(); TranscoderOptions options = null; - if (transformProperties.videoTrim) { - options = new TranscoderOptions(transformProperties.videoTrimStartTimeUs, transformProperties.videoTrimEndTimeUs); + if (transformProperties != null) { + allowSkipOnFailure = !transformProperties.getVideoEdited(); + if (transformProperties.videoTrim) { + options = new TranscoderOptions(transformProperties.videoTrimStartTimeUs, transformProperties.videoTrimEndTimeUs); + } } if (FeatureFlags.useStreamingVideoMuxer()) { - StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getCompressedVideoMaxSize(context)); + StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getVideoTranscodingSettings(), constraints.getCompressedVideoMaxSize(context), FeatureFlags.allowAudioRemuxing()); if (transcoder.isTranscodeRequired()) { Log.i(TAG, "Compressing with streaming muxer"); AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(); - File file = SignalDatabase.attachments().newFile(context); + File file = AttachmentTable.newDataFile(context); file.deleteOnExit(); boolean faststart = false; @@ -289,22 +285,32 @@ public final class AttachmentCompressionJob extends BaseJob { 100, 100)); - InputStream transcodedFileStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0); - SanitizedMetadata metadata = null; - try { - metadata = Mp4Sanitizer.sanitize(transcodedFileStream, file.length()); - } catch (ParseException e) { - Log.e(TAG, "Could not parse MP4 file.", e); + final Mp4FaststartPostProcessor postProcessor = new Mp4FaststartPostProcessor(() -> { + try { + return ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0); + } catch (IOException e) { + Log.w(TAG, "IOException thrown while creating CipherInputStream.", e); + throw new VideoPostProcessingException("Exception while opening InputStream!", e); + } + }); + + final long plaintextLength = ModernEncryptingPartOutputStream.getPlaintextLength(file.length()); + try (MediaStream mediaStream = new MediaStream(postProcessor.process(plaintextLength), MimeTypes.VIDEO_MP4, 0, 0, true)) { + attachmentDatabase.updateAttachmentData(attachment, mediaStream); + faststart = true; + } catch (VideoPostProcessingException e) { + Log.w(TAG, "Exception thrown during post processing.", e); + final Throwable cause = e.getCause(); + if (cause instanceof IOException) { + throw (IOException) cause; + } else if (cause instanceof EncodingException) { + throw (EncodingException) cause; + } } - if (metadata != null && metadata.getSanitizedMetadata() != null) { - try (MediaStream mediaStream = new MediaStream(new SequenceInputStream(new ByteArrayInputStream(metadata.getSanitizedMetadata()), ByteStreams.limit(ModernDecryptingPartInputStream.createFor(attachmentSecret, file, metadata.getDataOffset()), metadata.getDataLength())), MimeTypes.VIDEO_MP4, 0, 0, true)) { - attachmentDatabase.updateAttachmentData(attachment, mediaStream, true); - faststart = true; - } - } else { - try (MediaStream mediaStream = new MediaStream(ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0), MimeTypes.VIDEO_MP4, 0, 0)) { - attachmentDatabase.updateAttachmentData(attachment, mediaStream, true); + if (!faststart) { + try (MediaStream mediaStream = new MediaStream(ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0), MimeTypes.VIDEO_MP4, 0, 0, false)) { + attachmentDatabase.updateAttachmentData(attachment, mediaStream); } } } finally { @@ -320,7 +326,7 @@ public final class AttachmentCompressionJob extends BaseJob { Log.i(TAG, "Transcode was not required"); } } else { - try (InMemoryTranscoder transcoder = new InMemoryTranscoder(context, dataSource, options, constraints.getCompressedVideoMaxSize(context))) { + try (InMemoryTranscoder transcoder = new InMemoryTranscoder(context, dataSource, options, constraints.getVideoTranscodingSettings(), constraints.getCompressedVideoMaxSize(context))) { if (transcoder.isTranscodeRequired()) { Log.i(TAG, "Compressing with android in-memory muxer"); @@ -333,7 +339,7 @@ public final class AttachmentCompressionJob extends BaseJob { 100, percent)); }, cancelationSignal)) { - attachmentDatabase.updateAttachmentData(attachment, mediaStream, true); + attachmentDatabase.updateAttachmentData(attachment, mediaStream); attachmentDatabase.markAttachmentAsTransformed(attachment.attachmentId, mediaStream.getFaststart()); } @@ -360,6 +366,12 @@ public final class AttachmentCompressionJob extends BaseJob { } } catch (IOException | MmsException e) { throw new UndeliverableMessageException("Failed to transcode", e); + } catch (RuntimeException e) { + if (e.getCause() instanceof IOException) { + throw new UndeliverableMessageException("Failed to transcode", e); + } else { + throw e; + } } return attachment; } diff --git a/app/src/main/java/org/tm/archive/jobs/AttachmentDownloadJob.java b/app/src/main/java/org/tm/archive/jobs/AttachmentDownloadJob.java index 3bfe3875..45335238 100644 --- a/app/src/main/java/org/tm/archive/jobs/AttachmentDownloadJob.java +++ b/app/src/main/java/org/tm/archive/jobs/AttachmentDownloadJob.java @@ -12,7 +12,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.greenrobot.eventbus.EventBus; -import org.signal.core.util.Base64; import org.signal.core.util.Hex; import org.signal.core.util.logging.Log; import org.signal.libsignal.protocol.InvalidMacException; @@ -36,6 +35,7 @@ import org.tm.archive.releasechannel.ReleaseChannel; import org.tm.archive.s3.S3; import org.tm.archive.transport.RetryLaterException; import org.tm.archive.util.AttachmentUtil; +import org.signal.core.util.Base64; import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.Util; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; @@ -168,7 +168,7 @@ public final class AttachmentDownloadJob extends BaseJob { if (attachment.cdnNumber != ReleaseChannel.CDN_NUMBER) { retrieveAttachment(messageId, attachmentId, attachment); } else { - retrieveUrlAttachment(messageId, attachmentId, attachment); + retrieveAttachmentForReleaseChannel(messageId, attachmentId, attachment); } } @@ -216,7 +216,7 @@ public final class AttachmentDownloadJob extends BaseJob { return isCanceled(); } }); - database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream); + database.finalizeAttachmentAfterDownload(messageId, attachmentId, stream); } catch (RangeException e) { Log.w(TAG, "Range exception, file size " + attachmentFile.length(), e); if (attachmentFile.delete()) { @@ -278,9 +278,9 @@ public final class AttachmentDownloadJob extends BaseJob { } } - private void retrieveUrlAttachment(long messageId, - final AttachmentId attachmentId, - final Attachment attachment) + private void retrieveAttachmentForReleaseChannel(long messageId, + final AttachmentId attachmentId, + final Attachment attachment) throws IOException { try (Response response = S3.getObject(Objects.requireNonNull(attachment.fileName))) { @@ -289,7 +289,7 @@ public final class AttachmentDownloadJob extends BaseJob { if (body.contentLength() > FeatureFlags.maxAttachmentReceiveSizeBytes()) { throw new MmsException("Attachment too large, failing download"); } - SignalDatabase.attachments().insertAttachmentsForPlaceholder(messageId, attachmentId, Okio.buffer(body.source()).inputStream()); + SignalDatabase.attachments().finalizeAttachmentAfterDownload(messageId, attachmentId, Okio.buffer(body.source()).inputStream()); } } catch (MmsException e) { Log.w(TAG, "Experienced exception while trying to download an attachment.", e); diff --git a/app/src/main/java/org/tm/archive/jobs/AttachmentHashBackfillJob.kt b/app/src/main/java/org/tm/archive/jobs/AttachmentHashBackfillJob.kt new file mode 100644 index 00000000..b7e11fe6 --- /dev/null +++ b/app/src/main/java/org/tm/archive/jobs/AttachmentHashBackfillJob.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.jobs + +import org.signal.core.util.ThreadUtil +import org.signal.core.util.drain +import org.signal.core.util.logging.Log +import org.tm.archive.attachments.AttachmentId +import org.tm.archive.database.SignalDatabase +import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.jobmanager.Job +import org.tm.archive.jobmanager.defaultBackoffInterval +import java.io.File +import java.io.FileNotFoundException +import java.io.IOException +import java.security.DigestInputStream +import java.security.MessageDigest + +/** + * This job backfills hashes for attachments that were sent before we started hashing them. + * In order to avoid hammering the device with hash calculations and disk I/O, this job will + * calculate the hash for a single attachment and then reschedule itself to run again if necessary. + */ +class AttachmentHashBackfillJob private constructor(parameters: Parameters) : Job(parameters) { + + companion object { + val TAG = Log.tag(AttachmentHashBackfillJob::class.java) + + const val KEY = "AttachmentHashBackfillJob" + } + + private var activeFile: File? = null + + constructor() : this( + Parameters.Builder() + .setQueue(KEY) + .setMaxInstancesForFactory(2) + .setLifespan(Parameters.IMMORTAL) + .setMaxAttempts(10) + .build() + ) + + override fun serialize() = null + + override fun getFactoryKey() = KEY + + override fun run(): Result { + val (file: File?, attachmentId: AttachmentId?) = SignalDatabase.attachments.getUnhashedDataFile() ?: (null to null) + if (file == null || attachmentId == null) { + Log.i(TAG, "No more unhashed files! Task complete.") + return Result.success() + } + + activeFile = file + + if (!file.exists()) { + Log.w(TAG, "File does not exist! Clearing all usages.", true) + SignalDatabase.attachments.clearUsagesOfDataFile(file) + ApplicationDependencies.getJobManager().add(AttachmentHashBackfillJob()) + return Result.success() + } + + try { + val inputStream = SignalDatabase.attachments.getAttachmentStream(attachmentId, 0) + val messageDigest = MessageDigest.getInstance("SHA-256") + + DigestInputStream(inputStream, messageDigest).use { + it.drain() + } + + val hash = messageDigest.digest() + + SignalDatabase.attachments.setHashForDataFile(file, hash) + } catch (e: FileNotFoundException) { + Log.w(TAG, "File could not be found! Clearing all usages.", true) + SignalDatabase.attachments.clearUsagesOfDataFile(file) + } catch (e: IOException) { + Log.e(TAG, "Error hashing attachment. Retrying.", e) + + if (e.cause is FileNotFoundException) { + Log.w(TAG, "Underlying cause was a FileNotFoundException. Clearing all usages.", true) + SignalDatabase.attachments.clearUsagesOfDataFile(file) + } else { + return Result.retry(defaultBackoffInterval()) + } + } + + // Sleep just so we don't hammer the device with hash calculations and disk I/O + ThreadUtil.sleep(1000) + + ApplicationDependencies.getJobManager().add(AttachmentHashBackfillJob()) + return Result.success() + } + + override fun onFailure() { + activeFile?.let { file -> + Log.w(TAG, "Failed to calculate hash, marking as unhashable: $file", true) + SignalDatabase.attachments.markDataFileAsUnhashable(file) + } ?: Log.w(TAG, "Job failed, but no active file is set!") + + ApplicationDependencies.getJobManager().add(AttachmentHashBackfillJob()) + } + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): AttachmentHashBackfillJob { + return AttachmentHashBackfillJob(parameters) + } + } +} diff --git a/app/src/main/java/org/tm/archive/jobs/AttachmentUploadJob.kt b/app/src/main/java/org/tm/archive/jobs/AttachmentUploadJob.kt index 40443fa1..a9c64d6d 100644 --- a/app/src/main/java/org/tm/archive/jobs/AttachmentUploadJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/AttachmentUploadJob.kt @@ -42,6 +42,7 @@ import java.io.IOException import java.util.Objects import java.util.Optional import java.util.concurrent.TimeUnit +import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.milliseconds /** @@ -60,7 +61,7 @@ class AttachmentUploadJob private constructor( private val TAG = Log.tag(AttachmentUploadJob::class.java) - private val UPLOAD_REUSE_THRESHOLD = TimeUnit.DAYS.toMillis(3) + val UPLOAD_REUSE_THRESHOLD = 3.days.inWholeMilliseconds /** * Foreground notification shows while uploading attachments above this. @@ -162,7 +163,7 @@ class AttachmentUploadJob private constructor( buildAttachmentStream(databaseAttachment, notification, uploadSpec!!).use { localAttachment -> val remoteAttachment = messageSender.uploadAttachment(localAttachment) val attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.fastPreflightId).get() - SignalDatabase.attachments.updateAttachmentAfterUpload(databaseAttachment.attachmentId, attachment, remoteAttachment.uploadTimestamp) + SignalDatabase.attachments.finalizeAttachmentAfterUpload(databaseAttachment.attachmentId, attachment, remoteAttachment.uploadTimestamp) } } } catch (e: NonSuccessfulResumableUploadResponseCodeException) { diff --git a/app/src/main/java/org/tm/archive/jobs/CallLinkUpdateSendJob.kt b/app/src/main/java/org/tm/archive/jobs/CallLinkUpdateSendJob.kt index b49c6a37..37544abc 100644 --- a/app/src/main/java/org/tm/archive/jobs/CallLinkUpdateSendJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/CallLinkUpdateSendJob.kt @@ -26,7 +26,8 @@ import java.util.concurrent.TimeUnit */ class CallLinkUpdateSendJob private constructor( parameters: Parameters, - private val callLinkRoomId: CallLinkRoomId + private val callLinkRoomId: CallLinkRoomId, + private val callLinkUpdateType: CallLinkUpdate.Type ) : BaseJob(parameters) { companion object { @@ -35,7 +36,8 @@ class CallLinkUpdateSendJob private constructor( } constructor( - callLinkRoomId: CallLinkRoomId + callLinkRoomId: CallLinkRoomId, + callLinkUpdateType: CallLinkUpdate.Type = CallLinkUpdate.Type.UPDATE ) : this( Parameters.Builder() .setQueue("CallLinkUpdateSendJob") @@ -43,11 +45,18 @@ class CallLinkUpdateSendJob private constructor( .setMaxAttempts(Parameters.UNLIMITED) .addConstraint(NetworkConstraint.KEY) .build(), - callLinkRoomId + callLinkRoomId, + callLinkUpdateType ) override fun serialize(): ByteArray = CallLinkUpdateSendJobData.Builder() .callLinkRoomId(callLinkRoomId.serialize()) + .type( + when (callLinkUpdateType) { + CallLinkUpdate.Type.UPDATE -> CallLinkUpdateSendJobData.Type.UPDATE + CallLinkUpdate.Type.DELETE -> CallLinkUpdateSendJobData.Type.DELETE + } + ) .build() .encode() @@ -67,10 +76,17 @@ class CallLinkUpdateSendJob private constructor( return } - val callLinkUpdate = CallLinkUpdate(rootKey = callLink.credentials.linkKeyBytes.toByteString()) + val callLinkUpdate = CallLinkUpdate( + rootKey = callLink.credentials.linkKeyBytes.toByteString(), + type = callLinkUpdateType + ) ApplicationDependencies.getSignalServiceMessageSender() .sendSyncMessage(SignalServiceSyncMessage.forCallLinkUpdate(callLinkUpdate), Optional.empty()) + + if (callLinkUpdateType == CallLinkUpdate.Type.DELETE) { + SignalDatabase.callLinks.deleteCallLink(callLinkRoomId) + } } override fun onShouldRetry(e: Exception): Boolean { @@ -83,9 +99,16 @@ class CallLinkUpdateSendJob private constructor( class Factory : Job.Factory { override fun create(parameters: Parameters, serializedData: ByteArray?): CallLinkUpdateSendJob { + val jobData = CallLinkUpdateSendJobData.ADAPTER.decode(serializedData!!) + val type: CallLinkUpdate.Type = when (jobData.type) { + CallLinkUpdateSendJobData.Type.UPDATE, null -> CallLinkUpdate.Type.UPDATE + CallLinkUpdateSendJobData.Type.DELETE -> CallLinkUpdate.Type.DELETE + } + return CallLinkUpdateSendJob( parameters, - CallLinkRoomId.DatabaseSerializer.deserialize(CallLinkUpdateSendJobData.ADAPTER.decode(serializedData!!).callLinkRoomId) + CallLinkRoomId.DatabaseSerializer.deserialize(jobData.callLinkRoomId), + type ) } } diff --git a/app/src/main/java/org/tm/archive/jobs/CallLogEventSendJob.kt b/app/src/main/java/org/tm/archive/jobs/CallLogEventSendJob.kt index ee7c18c2..eacb734e 100644 --- a/app/src/main/java/org/tm/archive/jobs/CallLogEventSendJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/CallLogEventSendJob.kt @@ -5,10 +5,14 @@ package org.tm.archive.jobs +import androidx.annotation.WorkerThread +import okio.ByteString.Companion.toByteString +import org.tm.archive.database.CallTable import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.jobmanager.Job import org.tm.archive.jobmanager.impl.NetworkConstraint import org.tm.archive.jobs.protos.CallLogEventSendJobData +import org.tm.archive.recipients.Recipient import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException @@ -27,8 +31,9 @@ class CallLogEventSendJob private constructor( companion object { const val KEY = "CallLogEventSendJob" + @WorkerThread fun forClearHistory( - timestamp: Long + call: CallTable.Call ) = CallLogEventSendJob( Parameters.Builder() .setQueue("CallLogEventSendJob") @@ -37,10 +42,30 @@ class CallLogEventSendJob private constructor( .addConstraint(NetworkConstraint.KEY) .build(), SyncMessage.CallLogEvent( - timestamp = timestamp, + timestamp = call.timestamp, + callId = call.callId, + conversationId = Recipient.resolved(call.peer).requireCallConversationId().toByteString(), type = SyncMessage.CallLogEvent.Type.CLEAR ) ) + + @WorkerThread + fun forMarkedAsRead( + call: CallTable.Call + ) = CallLogEventSendJob( + Parameters.Builder() + .setQueue("CallLogEventSendJob") + .setLifespan(TimeUnit.DAYS.toMillis(1)) + .setMaxAttempts(Parameters.UNLIMITED) + .addConstraint(NetworkConstraint.KEY) + .build(), + SyncMessage.CallLogEvent( + timestamp = call.timestamp, + callId = call.callId, + conversationId = Recipient.resolved(call.peer).requireCallConversationId().toByteString(), + type = SyncMessage.CallLogEvent.Type.MARKED_AS_READ + ) + ) } override fun serialize(): ByteArray = CallLogEventSendJobData.Builder() diff --git a/app/src/main/java/org/tm/archive/jobs/ConversationShortcutUpdateJob.java b/app/src/main/java/org/tm/archive/jobs/ConversationShortcutUpdateJob.java index 0d5290d3..5839564b 100644 --- a/app/src/main/java/org/tm/archive/jobs/ConversationShortcutUpdateJob.java +++ b/app/src/main/java/org/tm/archive/jobs/ConversationShortcutUpdateJob.java @@ -69,7 +69,7 @@ public class ConversationShortcutUpdateJob extends BaseJob { int maxShortcuts = ConversationUtil.getMaxShortcuts(context); List ranked = new ArrayList<>(maxShortcuts); - try (ThreadTable.Reader reader = threadTable.readerFor(threadTable.getRecentConversationList(maxShortcuts, false, false, false, true, !Util.isDefaultSmsProvider(context), false))) { + try (ThreadTable.Reader reader = threadTable.readerFor(threadTable.getRecentConversationList(maxShortcuts, false, false, false, true, true, false))) { ThreadRecord record; while ((record = reader.getNext()) != null) { ranked.add(record.getRecipient().resolve()); diff --git a/app/src/main/java/org/tm/archive/jobs/FcmRefreshJob.java b/app/src/main/java/org/tm/archive/jobs/FcmRefreshJob.java index 2495d462..56aef4fc 100644 --- a/app/src/main/java/org/tm/archive/jobs/FcmRefreshJob.java +++ b/app/src/main/java/org/tm/archive/jobs/FcmRefreshJob.java @@ -103,7 +103,7 @@ public class FcmRefreshJob extends BaseJob { ApplicationDependencies.getSignalServiceAccountManager().setGcmId(token); SignalStore.account().setFcmToken(token.get()); - Log.i(TAG, "current FCM: " + FirebaseApp.getInstance().getOptions().getProjectId());//**TM_SA TODO remove this ASAP!**// +// Log.i(TAG, "current FCM: " + FirebaseApp.getInstance().getOptions().getProjectId());//**TM_SA } else { throw new RetryLaterException(new IOException("Failed to retrieve a token.")); } @@ -128,7 +128,7 @@ public class FcmRefreshJob extends BaseJob { builder.setSmallIcon(R.drawable.ic_notification); builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), - R.drawable.ic_action_warning_red)); + R.drawable.symbol_error_triangle_fill_32)); builder.setContentTitle(context.getString(R.string.GcmRefreshJob_Permanent_Signal_communication_failure)); builder.setContentText(context.getString(R.string.GcmRefreshJob_Signal_was_unable_to_register_with_Google_Play_Services)); builder.setTicker(context.getString(R.string.GcmRefreshJob_Permanent_Signal_communication_failure)); diff --git a/app/src/main/java/org/tm/archive/jobs/IndividualSendJob.java b/app/src/main/java/org/tm/archive/jobs/IndividualSendJob.java index 345c3ec7..441863b3 100644 --- a/app/src/main/java/org/tm/archive/jobs/IndividualSendJob.java +++ b/app/src/main/java/org/tm/archive/jobs/IndividualSendJob.java @@ -33,6 +33,7 @@ import org.tm.archive.service.ExpiringMessageManager; import org.tm.archive.transport.InsecureFallbackApprovalException; import org.tm.archive.transport.RetryLaterException; import org.tm.archive.transport.UndeliverableMessageException; +import org.tm.archive.util.SignalLocalMetrics; import org.tm.archive.util.Util; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents; @@ -140,6 +141,8 @@ public class IndividualSendJob extends PushSendJob { public void onPushSend() throws IOException, MmsException, NoSuchMessageException, UndeliverableMessageException, RetryLaterException { + SignalLocalMetrics.IndividualMessageSend.onJobStarted(messageId); + ExpiringMessageManager expirationManager = ApplicationDependencies.getExpiringMessageManager(); MessageTable database = SignalDatabase.messages(); OutgoingMessage message = database.getOutgoingMessage(messageId); @@ -216,10 +219,19 @@ public class IndividualSendJob extends PushSendJob { } catch (ProofRequiredException e) { handleProofRequiredException(context, e, SignalDatabase.threads().getRecipientForThreadId(threadId), threadId, messageId, true); } + + SignalLocalMetrics.IndividualMessageSend.onJobFinished(messageId); + } + + @Override + public void onRetry() { + SignalLocalMetrics.IndividualMessageSend.cancel(messageId); + super.onRetry(); } @Override public void onFailure() { + SignalLocalMetrics.IndividualMessageSend.cancel(messageId); SignalDatabase.messages().markAsSentFailed(messageId); notifyMediaMessageDeliveryFailed(context, messageId); } @@ -312,7 +324,8 @@ public class IndividualSendJob extends PushSendJob { SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId), false); return syncAccess.isPresent(); } else { - SendMessageResult result = messageSender.sendDataMessage(address, UnidentifiedAccessUtil.getAccessFor(context, messageRecipient), ContentHint.RESENDABLE, mediaMessage, IndividualSendEvents.EMPTY, message.isUrgent(), messageRecipient.needsPniSignature()); + SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId); + SendMessageResult result = messageSender.sendDataMessage(address, UnidentifiedAccessUtil.getAccessFor(context, messageRecipient), ContentHint.RESENDABLE, mediaMessage, new MetricEventListener(messageId), message.isUrgent(), messageRecipient.needsPniSignature()); SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId), message.isUrgent()); @@ -370,6 +383,28 @@ public class IndividualSendJob extends PushSendJob { JsonJobData data = JsonJobData.deserialize(serializedData); return data.getLong(KEY_MESSAGE_ID); } + private static class MetricEventListener implements SignalServiceMessageSender.IndividualSendEvents { + private final long messageId; + + private MetricEventListener(long messageId) { + this.messageId = messageId; + } + + @Override + public void onMessageEncrypted() { + SignalLocalMetrics.IndividualMessageSend.onMessageEncrypted(messageId); + } + + @Override + public void onMessageSent() { + SignalLocalMetrics.IndividualMessageSend.onMessageSent(messageId); + } + + @Override + public void onSyncMessageSent() { + SignalLocalMetrics.IndividualMessageSend.onSyncMessageSent(messageId); + } + } public static final class Factory implements Job.Factory { @Override diff --git a/app/src/main/java/org/tm/archive/jobs/JobManagerFactories.java b/app/src/main/java/org/tm/archive/jobs/JobManagerFactories.java index db147d10..5f40bb6f 100644 --- a/app/src/main/java/org/tm/archive/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/tm/archive/jobs/JobManagerFactories.java @@ -40,6 +40,7 @@ import org.tm.archive.migrations.AccountConsistencyMigrationJob; import org.tm.archive.migrations.AccountRecordMigrationJob; import org.tm.archive.migrations.ApplyUnknownFieldsToSelfMigrationJob; import org.tm.archive.migrations.AttachmentCleanupMigrationJob; +import org.tm.archive.migrations.AttachmentHashBackfillMigrationJob; import org.tm.archive.migrations.AttributesMigrationJob; import org.tm.archive.migrations.AvatarIdRemovalMigrationJob; import org.tm.archive.migrations.AvatarMigrationJob; @@ -63,6 +64,7 @@ import org.tm.archive.migrations.PinOptOutMigration; import org.tm.archive.migrations.PinReminderMigrationJob; import org.tm.archive.migrations.PniAccountInitializationMigrationJob; import org.tm.archive.migrations.PniMigrationJob; +import org.tm.archive.migrations.PnpLaunchMigrationJob; import org.tm.archive.migrations.PreKeysSyncMigrationJob; import org.tm.archive.migrations.ProfileMigrationJob; import org.tm.archive.migrations.ProfileSharingUpdateMigrationJob; @@ -100,6 +102,7 @@ public final class JobManagerFactories { put(AttachmentCompressionJob.KEY, new AttachmentCompressionJob.Factory()); put(AttachmentCopyJob.KEY, new AttachmentCopyJob.Factory()); put(AttachmentDownloadJob.KEY, new AttachmentDownloadJob.Factory()); + put(AttachmentHashBackfillJob.KEY, new AttachmentHashBackfillJob.Factory()); put(AttachmentMarkUploadedJob.KEY, new AttachmentMarkUploadedJob.Factory()); put(AttachmentUploadJob.KEY, new AttachmentUploadJob.Factory()); put(AutomaticSessionResetJob.KEY, new AutomaticSessionResetJob.Factory()); @@ -135,10 +138,10 @@ public final class JobManagerFactories { put(LeaveGroupV2Job.KEY, new LeaveGroupV2Job.Factory()); put(LeaveGroupV2WorkerJob.KEY, new LeaveGroupV2WorkerJob.Factory()); put(LegacyAttachmentUploadJob.KEY, new LegacyAttachmentUploadJob.Factory()); + put(LinkedDeviceInactiveCheckJob.KEY, new LinkedDeviceInactiveCheckJob.Factory()); put(LocalBackupJob.KEY, new LocalBackupJob.Factory()); put(LocalBackupJobApi29.KEY, new LocalBackupJobApi29.Factory()); put(MarkerJob.KEY, new MarkerJob.Factory()); - put(MmsSendJob.KEY, new MmsSendJob.Factory()); put(MultiDeviceBlockedUpdateJob.KEY, new MultiDeviceBlockedUpdateJob.Factory()); put(MultiDeviceCallLinkSyncJob.KEY, new MultiDeviceCallLinkSyncJob.Factory()); put(MultiDeviceConfigurationUpdateJob.KEY, new MultiDeviceConfigurationUpdateJob.Factory()); @@ -205,8 +208,6 @@ public final class JobManagerFactories { put(MultiDeviceStorySendSyncJob.KEY, new MultiDeviceStorySendSyncJob.Factory()); put(ResetSvrGuessCountJob.KEY, new ResetSvrGuessCountJob.Factory()); put(ServiceOutageDetectionJob.KEY, new ServiceOutageDetectionJob.Factory()); - put(SmsSendJob.KEY, new SmsSendJob.Factory()); - put(SmsSentJob.KEY, new SmsSentJob.Factory()); put(StickerDownloadJob.KEY, new StickerDownloadJob.Factory()); put(StickerPackDownloadJob.KEY, new StickerPackDownloadJob.Factory()); put(StorageAccountRestoreJob.KEY, new StorageAccountRestoreJob.Factory()); @@ -227,6 +228,7 @@ public final class JobManagerFactories { put(AccountRecordMigrationJob.KEY, new AccountRecordMigrationJob.Factory()); put(ApplyUnknownFieldsToSelfMigrationJob.KEY, new ApplyUnknownFieldsToSelfMigrationJob.Factory()); put(AttachmentCleanupMigrationJob.KEY, new AttachmentCleanupMigrationJob.Factory()); + put(AttachmentHashBackfillMigrationJob.KEY, new AttachmentHashBackfillMigrationJob.Factory()); put(AttributesMigrationJob.KEY, new AttributesMigrationJob.Factory()); put(AvatarIdRemovalMigrationJob.KEY, new AvatarIdRemovalMigrationJob.Factory()); put(AvatarMigrationJob.KEY, new AvatarMigrationJob.Factory()); @@ -249,6 +251,7 @@ public final class JobManagerFactories { put(PinReminderMigrationJob.KEY, new PinReminderMigrationJob.Factory()); put(PniAccountInitializationMigrationJob.KEY, new PniAccountInitializationMigrationJob.Factory()); put(PniMigrationJob.KEY, new PniMigrationJob.Factory()); + put(PnpLaunchMigrationJob.KEY, new PnpLaunchMigrationJob.Factory()); put(PreKeysSyncMigrationJob.KEY, new PreKeysSyncMigrationJob.Factory()); put(ProfileMigrationJob.KEY, new ProfileMigrationJob.Factory()); put(ProfileSharingUpdateMigrationJob.KEY, new ProfileSharingUpdateMigrationJob.Factory()); @@ -310,6 +313,9 @@ public final class JobManagerFactories { put("StoryReadStateMigrationJob", new PassingMigrationJob.Factory()); put("GroupV1MigrationJob", new FailingJob.Factory()); put("NewRegistrationUsernameSyncJob", new FailingJob.Factory()); + put("SmsSendJob", new FailingJob.Factory()); + put("SmsSentJob", new FailingJob.Factory()); + put("MmsSendJobV2", new FailingJob.Factory()); }}; } diff --git a/app/src/main/java/org/tm/archive/jobs/LegacyAttachmentUploadJob.java b/app/src/main/java/org/tm/archive/jobs/LegacyAttachmentUploadJob.java index cdb4e7b5..213ca7c4 100644 --- a/app/src/main/java/org/tm/archive/jobs/LegacyAttachmentUploadJob.java +++ b/app/src/main/java/org/tm/archive/jobs/LegacyAttachmentUploadJob.java @@ -139,7 +139,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob { SignalServiceAttachmentPointer remoteAttachment = messageSender.uploadAttachment(localAttachment); Attachment attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.fastPreflightId).get(); - database.updateAttachmentAfterUpload(databaseAttachment.attachmentId, attachment, remoteAttachment.getUploadTimestamp()); + database.finalizeAttachmentAfterUpload(databaseAttachment.attachmentId, attachment, remoteAttachment.getUploadTimestamp()); } } catch (NonSuccessfulResumableUploadResponseCodeException e) { if (e.getCode() == 400) { diff --git a/app/src/main/java/org/tm/archive/jobs/LinkedDeviceInactiveCheckJob.kt b/app/src/main/java/org/tm/archive/jobs/LinkedDeviceInactiveCheckJob.kt new file mode 100644 index 00000000..eeca49cb --- /dev/null +++ b/app/src/main/java/org/tm/archive/jobs/LinkedDeviceInactiveCheckJob.kt @@ -0,0 +1,117 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.jobs + +import org.signal.core.util.Base64 +import org.signal.core.util.logging.Log +import org.signal.core.util.roundedString +import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.devicelist.protos.DeviceName +import org.tm.archive.jobmanager.Job +import org.tm.archive.jobmanager.impl.NetworkConstraint +import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.keyvalue.protos.LeastActiveLinkedDevice +import org.tm.archive.registration.secondary.DeviceNameCipher +import org.whispersystems.signalservice.api.push.SignalServiceAddress +import java.io.IOException +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.DurationUnit + +/** + * Designed as a routine check to keep an eye on how active our linked devices are. + */ +class LinkedDeviceInactiveCheckJob private constructor( + parameters: Parameters = Parameters.Builder() + .setQueue("LinkedDeviceInactiveCheckJob") + .setMaxInstancesForFactory(2) + .setLifespan(30.days.inWholeMilliseconds) + .setMaxAttempts(Parameters.UNLIMITED) + .addConstraint(NetworkConstraint.KEY) + .build() +) : Job(parameters) { + + companion object { + private val TAG = Log.tag(LinkedDeviceInactiveCheckJob::class.java) + const val KEY = "LinkedDeviceInactiveCheckJob" + + @JvmStatic + fun enqueue() { + ApplicationDependencies.getJobManager().add(LinkedDeviceInactiveCheckJob()) + } + + @JvmStatic + fun enqueueIfNecessary() { + val timeSinceLastCheck = System.currentTimeMillis() - SignalStore.misc().linkedDeviceLastActiveCheckTime + if (timeSinceLastCheck > 1.days.inWholeMilliseconds || timeSinceLastCheck < 0) { + ApplicationDependencies.getJobManager().add(LinkedDeviceInactiveCheckJob()) + } + } + } + + override fun serialize(): ByteArray? = null + + override fun getFactoryKey(): String = KEY + + override fun run(): Result { + val devices = try { + ApplicationDependencies.getSignalServiceAccountManager().devices + } catch (e: IOException) { + return Result.retry(defaultBackoff()) + } + + if (devices.isEmpty()) { + Log.i(TAG, "No linked devices found.") + + SignalStore.misc().hasLinkedDevices = false + SignalStore.misc().leastActiveLinkedDevice = null + SignalStore.misc().linkedDeviceLastActiveCheckTime = System.currentTimeMillis() + + return Result.success() + } + + val leastActiveDevice: LeastActiveLinkedDevice? = devices + .filter { it.id != SignalServiceAddress.DEFAULT_DEVICE_ID } + .filter { it.name != null } + .minBy { it.lastSeen } + .let { + val nameProto = DeviceName.ADAPTER.decode(Base64.decode(it.getName())) + val decryptedBytes = DeviceNameCipher.decryptDeviceName(nameProto, ApplicationDependencies.getProtocolStore().aci().identityKeyPair) ?: return@let null + val name = String(decryptedBytes) + + LeastActiveLinkedDevice( + name = name, + lastActiveTimestamp = it.lastSeen + ) + } + + if (leastActiveDevice == null) { + Log.w(TAG, "Failed to decrypt linked device name.") + SignalStore.misc().hasLinkedDevices = true + SignalStore.misc().leastActiveLinkedDevice = null + SignalStore.misc().linkedDeviceLastActiveCheckTime = System.currentTimeMillis() + return Result.success() + } + + val timeSinceActive = System.currentTimeMillis() - leastActiveDevice.lastActiveTimestamp + Log.i(TAG, "Least active linked device was last active ${timeSinceActive.milliseconds.toDouble(DurationUnit.DAYS).roundedString(2)} days ago ($timeSinceActive ms).") + + SignalStore.misc().hasLinkedDevices = true + SignalStore.misc().leastActiveLinkedDevice = leastActiveDevice + SignalStore.misc().linkedDeviceLastActiveCheckTime = System.currentTimeMillis() + + return Result.success() + } + + override fun onFailure() { + } + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): LinkedDeviceInactiveCheckJob { + return LinkedDeviceInactiveCheckJob(parameters) + } + } +} diff --git a/app/src/main/java/org/tm/archive/jobs/MmsSendJob.java b/app/src/main/java/org/tm/archive/jobs/MmsSendJob.java deleted file mode 100644 index 93e8ed83..00000000 --- a/app/src/main/java/org/tm/archive/jobs/MmsSendJob.java +++ /dev/null @@ -1,371 +0,0 @@ -package org.tm.archive.jobs; - -import android.content.Context; -import android.text.TextUtils; -import android.webkit.MimeTypeMap; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.WorkerThread; - -import com.android.mms.dom.smil.parser.SmilXmlSerializer; -import com.annimon.stream.Stream; -import com.google.android.mms.ContentType; -import com.google.android.mms.InvalidHeaderValueException; -import com.google.android.mms.pdu_alt.CharacterSets; -import com.google.android.mms.pdu_alt.EncodedStringValue; -import com.google.android.mms.pdu_alt.PduBody; -import com.google.android.mms.pdu_alt.PduComposer; -import com.google.android.mms.pdu_alt.PduHeaders; -import com.google.android.mms.pdu_alt.PduPart; -import com.google.android.mms.pdu_alt.SendConf; -import com.google.android.mms.pdu_alt.SendReq; -import com.google.android.mms.smil.SmilHelper; -import com.klinker.android.send_message.Utils; - -import org.signal.core.util.Hex; -import org.signal.core.util.StreamUtil; -import org.signal.core.util.logging.Log; -import org.tm.archive.attachments.Attachment; -import org.tm.archive.attachments.DatabaseAttachment; -import org.tm.archive.database.GroupTable; -import org.tm.archive.database.MessageTable; -import org.tm.archive.database.NoSuchMessageException; -import org.tm.archive.database.SignalDatabase; -import org.tm.archive.database.ThreadTable; -import org.tm.archive.dependencies.ApplicationDependencies; -import org.tm.archive.jobmanager.JsonJobData; -import org.tm.archive.jobmanager.Job; -import org.tm.archive.jobmanager.JobLogger; -import org.tm.archive.jobmanager.JobManager; -import org.tm.archive.jobmanager.impl.NetworkConstraint; -import org.tm.archive.keyvalue.SignalStore; -import org.tm.archive.mms.CompatMmsConnection; -import org.tm.archive.mms.MediaConstraints; -import org.tm.archive.mms.MmsException; -import org.tm.archive.mms.MmsSendResult; -import org.tm.archive.mms.OutgoingMessage; -import org.tm.archive.mms.PartAuthority; -import org.tm.archive.notifications.v2.ConversationId; -import org.tm.archive.phonenumbers.NumberUtil; -import org.tm.archive.recipients.Recipient; -import org.tm.archive.transport.InsecureFallbackApprovalException; -import org.tm.archive.transport.UndeliverableMessageException; -import org.tm.archive.util.Util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.List; - -public final class MmsSendJob extends SendJob { - - public static final String KEY = "MmsSendJobV2"; - - private static final String TAG = Log.tag(MmsSendJob.class); - - private static final String KEY_MESSAGE_ID = "message_id"; - - private final long messageId; - - private MmsSendJob(long messageId) { - this(new Job.Parameters.Builder() - .setQueue("mms-operation") - .addConstraint(NetworkConstraint.KEY) - .setMaxAttempts(15) - .build(), - messageId); - } - - /** Enqueues compression jobs for attachments and finally the MMS send job. */ - @WorkerThread - public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId) { - MessageTable database = SignalDatabase.messages(); - OutgoingMessage message; - - try { - message = database.getOutgoingMessage(messageId); - } catch (MmsException | NoSuchMessageException e) { - throw new AssertionError(e); - } - - List compressionJobs = Stream.of(message.getAttachments()) - .map(a -> (Job) AttachmentCompressionJob.fromAttachment((DatabaseAttachment) a, true, -1)) - .toList(); - - MmsSendJob sendJob = new MmsSendJob(messageId); - - jobManager.startChain(compressionJobs) - .then(sendJob) - .enqueue(); - } - - private MmsSendJob(@NonNull Job.Parameters parameters, long messageId) { - super(parameters); - this.messageId = messageId; - } - - @Override - public @Nullable byte[] serialize() { - return new JsonJobData.Builder().putLong(KEY_MESSAGE_ID, messageId).serialize(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onAdded() { - SignalDatabase.messages().markAsSending(messageId); - } - - @Override - public void onSend() throws MmsException, NoSuchMessageException, IOException { - MessageTable database = SignalDatabase.messages(); - OutgoingMessage message = database.getOutgoingMessage(messageId); - - if (database.isSent(messageId)) { - Log.w(TAG, "Message " + messageId + " was already sent. Ignoring."); - return; - } - - try { - Log.i(TAG, "Sending message: " + messageId); - - SendReq pdu = constructSendPdu(message); - - validateDestinations(message, pdu); - - final byte[] pduBytes = getPduBytes(pdu); - final SendConf sendConf = new CompatMmsConnection(context).send(pduBytes, -1); - final MmsSendResult result = getSendResult(sendConf, pdu); - - database.markAsSent(messageId, false); - markAttachmentsUploaded(messageId, message); - - Log.i(TAG, "Sent message: " + messageId); - } catch (UndeliverableMessageException | IOException e) { - Log.w(TAG, e); - database.markAsSentFailed(messageId); - notifyMediaMessageDeliveryFailed(context, messageId); - } catch (InsecureFallbackApprovalException e) { - Log.w(TAG, e); - database.markAsPendingInsecureSmsFallback(messageId); - notifyMediaMessageDeliveryFailed(context, messageId); - } - } - - @Override - public boolean onShouldRetry(@NonNull Exception exception) { - return false; - } - - @Override - public void onFailure() { - Log.i(TAG, JobLogger.format(this, "onFailure() messageId: " + messageId)); - SignalDatabase.messages().markAsSentFailed(messageId); - notifyMediaMessageDeliveryFailed(context, messageId); - } - - private byte[] getPduBytes(SendReq message) - throws IOException, UndeliverableMessageException, InsecureFallbackApprovalException - { - byte[] pduBytes = new PduComposer(context, message).make(); - - if (pduBytes == null) { - throw new UndeliverableMessageException("PDU composition failed, null payload"); - } - - return pduBytes; - } - - private MmsSendResult getSendResult(SendConf conf, SendReq message) - throws UndeliverableMessageException - { - if (conf == null) { - throw new UndeliverableMessageException("No M-Send.conf received in response to send."); - } else if (conf.getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) { - throw new UndeliverableMessageException("Got bad response: " + conf.getResponseStatus()); - } else if (isInconsistentResponse(message, conf)) { - throw new UndeliverableMessageException("Mismatched response!"); - } else { - return new MmsSendResult(conf.getMessageId(), conf.getResponseStatus()); - } - } - - private boolean isInconsistentResponse(SendReq message, SendConf response) { - Log.i(TAG, "Comparing: " + Hex.toString(message.getTransactionId())); - Log.i(TAG, "With: " + Hex.toString(response.getTransactionId())); - return !Arrays.equals(message.getTransactionId(), response.getTransactionId()); - } - - private void validateDestinations(EncodedStringValue[] destinations) throws UndeliverableMessageException { - if (destinations == null) return; - - for (EncodedStringValue destination : destinations) { - if (destination == null || !NumberUtil.isValidSmsOrEmail(destination.getString())) { - throw new UndeliverableMessageException("Invalid destination: " + - (destination == null ? null : destination.getString())); - } - } - } - - private void validateDestinations(OutgoingMessage media, SendReq message) throws UndeliverableMessageException { - validateDestinations(message.getTo()); - validateDestinations(message.getCc()); - validateDestinations(message.getBcc()); - - if (message.getTo() == null && message.getCc() == null && message.getBcc() == null) { - throw new UndeliverableMessageException("No to, cc, or bcc specified!"); - } - - if (media.isSecure()) { - throw new UndeliverableMessageException("Attempt to send encrypted MMS?"); - } - } - - private SendReq constructSendPdu(OutgoingMessage message) - throws UndeliverableMessageException - { - SendReq req = new SendReq(); - String lineNumber = getMyNumber(context); - MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(-1); - List scaledAttachments = message.getAttachments(); - - if (!TextUtils.isEmpty(lineNumber)) { - req.setFrom(new EncodedStringValue(lineNumber)); - } else { - req.setFrom(new EncodedStringValue(SignalStore.account().getE164())); - } - - if (message.getThreadRecipient().isMmsGroup()) { - List members = SignalDatabase.groups().getGroupMembers(message.getThreadRecipient().requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); - - for (Recipient member : members) { - if (!member.hasSmsAddress()) { - throw new UndeliverableMessageException("One of the group recipients did not have an SMS address! " + member.getId()); - } - - if (message.getDistributionType() == ThreadTable.DistributionTypes.BROADCAST) { - req.addBcc(new EncodedStringValue(member.requireSmsAddress())); - } else { - req.addTo(new EncodedStringValue(member.requireSmsAddress())); - } - } - } else { - if (!message.getThreadRecipient().hasSmsAddress()) { - throw new UndeliverableMessageException("Recipient did not have an SMS address! " + message.getThreadRecipient().getId()); - } - - req.addTo(new EncodedStringValue(message.getThreadRecipient().requireSmsAddress())); - } - - req.setDate(System.currentTimeMillis() / 1000); - - PduBody body = new PduBody(); - int size = 0; - - if (!TextUtils.isEmpty(message.getBody())) { - PduPart part = new PduPart(); - String name = String.valueOf(System.currentTimeMillis()); - part.setData(Util.toUtf8Bytes(message.getBody())); - part.setCharset(CharacterSets.UTF_8); - part.setContentType(ContentType.TEXT_PLAIN.getBytes()); - part.setContentId(name.getBytes()); - part.setContentLocation((name + ".txt").getBytes()); - part.setName((name + ".txt").getBytes()); - - body.addPart(part); - size += getPartSize(part); - } - - for (Attachment attachment : scaledAttachments) { - try { - if (attachment.getUri() == null) throw new IOException("Assertion failed, attachment for outgoing MMS has no data!"); - - String fileName = attachment.fileName; - PduPart part = new PduPart(); - - if (fileName == null) { - fileName = String.valueOf(Math.abs(new SecureRandom().nextLong())); - String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(attachment.contentType); - - if (fileExtension != null) fileName = fileName + "." + fileExtension; - } - - if (attachment.contentType.startsWith("text")) { - part.setCharset(CharacterSets.UTF_8); - } - - part.setContentType(attachment.contentType.getBytes()); - part.setContentLocation(fileName.getBytes()); - part.setName(fileName.getBytes()); - - int index = fileName.lastIndexOf("."); - String contentId = (index == -1) ? fileName : fileName.substring(0, index); - part.setContentId(contentId.getBytes()); - part.setData(StreamUtil.readFully(PartAuthority.getAttachmentStream(context, attachment.getUri()))); - - body.addPart(part); - size += getPartSize(part); - } catch (IOException e) { - Log.w(TAG, e); - } - } - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - SmilXmlSerializer.serialize(SmilHelper.createSmilDocument(body), out); - PduPart smilPart = new PduPart(); - smilPart.setContentId("smil".getBytes()); - smilPart.setContentLocation("smil.xml".getBytes()); - smilPart.setContentType(ContentType.APP_SMIL.getBytes()); - smilPart.setData(out.toByteArray()); - body.addPart(0, smilPart); - - req.setBody(body); - req.setMessageSize(size); - req.setMessageClass(PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes()); - req.setExpiry(7 * 24 * 60 * 60); - - try { - req.setPriority(PduHeaders.PRIORITY_NORMAL); - req.setDeliveryReport(PduHeaders.VALUE_NO); - req.setReadReport(PduHeaders.VALUE_NO); - } catch (InvalidHeaderValueException e) {} - - return req; - } - - private long getPartSize(PduPart part) { - return part.getName().length + part.getContentLocation().length + - part.getContentType().length + part.getData().length + - part.getContentId().length; - } - - private void notifyMediaMessageDeliveryFailed(Context context, long messageId) { - long threadId = SignalDatabase.messages().getThreadIdForMessage(messageId); - Recipient recipient = SignalDatabase.threads().getRecipientForThreadId(threadId); - - if (recipient != null) { - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, recipient, ConversationId.forConversation(threadId)); - } - } - - private String getMyNumber(Context context) throws UndeliverableMessageException { - try { - return Utils.getMyPhoneNumber(context); - } catch (SecurityException e) { - throw new UndeliverableMessageException(e); - } - } - - public static class Factory implements Job.Factory { - @Override - public @NonNull MmsSendJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) { - JsonJobData data = JsonJobData.deserialize(serializedData); - return new MmsSendJob(parameters, data.getLong(KEY_MESSAGE_ID)); - } - } -} diff --git a/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactSyncJob.kt b/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactSyncJob.kt index 848cbde4..62be1607 100644 --- a/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactSyncJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactSyncJob.kt @@ -76,7 +76,11 @@ class MultiDeviceContactSyncJob(parameters: Parameters, private val attachmentPo var contact: DeviceContact? = deviceContacts.read() while (contact != null) { - val recipient = Recipient.externalPush(SignalServiceAddress(contact.address.serviceId, contact.address.number.orElse(null))) + val recipient = if (contact.aci.isPresent) { + Recipient.externalPush(SignalServiceAddress(contact.aci.get(), contact.e164.orElse(null))) + } else { + Recipient.external(context, contact.e164.get()) + } if (recipient.isSelf) { contact = deviceContacts.read() @@ -118,8 +122,6 @@ class MultiDeviceContactSyncJob(parameters: Parameters, private val attachmentPo } } - recipients.setBlocked(recipient.id, contact.isBlocked) - val threadRecord = threads.getThreadRecord(threads.getThreadIdFor(recipient.id)) if (threadRecord != null && contact.isArchived != threadRecord.isArchived) { if (contact.isArchived) { diff --git a/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactUpdateJob.java b/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactUpdateJob.java index 9038ba2d..3044457a 100644 --- a/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactUpdateJob.java +++ b/app/src/main/java/org/tm/archive/jobs/MultiDeviceContactUpdateJob.java @@ -151,18 +151,23 @@ public class MultiDeviceContactUpdateJob extends BaseJob { return; } + if (!recipient.hasE164() && !recipient.hasAci()) { + Log.w(TAG, recipientId + " has no valid identifier!"); + return; + } + Optional identityRecord = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecord(recipient.getId()); Optional verifiedMessage = getVerifiedMessage(recipient, identityRecord); Map inboxPositions = SignalDatabase.threads().getInboxPositions(); Set archived = SignalDatabase.threads().getArchivedRecipients(); - out.write(new DeviceContact(RecipientUtil.toSignalServiceAddress(context, recipient), + out.write(new DeviceContact(recipient.getAci(), + recipient.getE164(), Optional.ofNullable(recipient.isGroup() || recipient.isSystemContact() ? recipient.getDisplayName(context) : null), getSystemAvatar(recipient.getContactUri()), Optional.of(ChatColorsMapper.getMaterialColor(recipient.getChatColors()).serialize()), verifiedMessage, ProfileKeyUtil.profileKeyOptional(recipient.getProfileKey()), - recipient.isBlocked(), recipient.getExpiresInSeconds() > 0 ? Optional.of(recipient.getExpiresInSeconds()) : Optional.empty(), Optional.ofNullable(inboxPositions.get(recipientId)), @@ -222,13 +227,13 @@ public class MultiDeviceContactUpdateJob extends BaseJob { Optional expireTimer = recipient.getExpiresInSeconds() > 0 ? Optional.of(recipient.getExpiresInSeconds()) : Optional.empty(); Optional inboxPosition = Optional.ofNullable(inboxPositions.get(recipient.getId())); - out.write(new DeviceContact(RecipientUtil.toSignalServiceAddress(context, recipient), + out.write(new DeviceContact(recipient.getAci(), + recipient.getE164(), name, getSystemAvatar(recipient.getContactUri()), Optional.of(ChatColorsMapper.getMaterialColor(recipient.getChatColors()).serialize()), verified, profileKey, - blocked, expireTimer, inboxPosition, archived.contains(recipient.getId()))); @@ -239,13 +244,13 @@ public class MultiDeviceContactUpdateJob extends BaseJob { byte[] profileKey = self.getProfileKey(); if (profileKey != null) { - out.write(new DeviceContact(RecipientUtil.toSignalServiceAddress(context, self), + out.write(new DeviceContact(Optional.of(SignalStore.account().getAci()), + Optional.of(SignalStore.account().getE164()), Optional.empty(), Optional.empty(), Optional.of(ChatColorsMapper.getMaterialColor(self.getChatColors()).serialize()), Optional.empty(), ProfileKeyUtil.profileKeyOptionalOrThrow(self.getProfileKey()), - false, self.getExpiresInSeconds() > 0 ? Optional.of(self.getExpiresInSeconds()) : Optional.empty(), Optional.ofNullable(inboxPositions.get(self.getId())), archived.contains(self.getId()))); diff --git a/app/src/main/java/org/tm/archive/jobs/MultiDeviceMessageRequestResponseJob.java b/app/src/main/java/org/tm/archive/jobs/MultiDeviceMessageRequestResponseJob.java index 68fcce78..e29f21af 100644 --- a/app/src/main/java/org/tm/archive/jobs/MultiDeviceMessageRequestResponseJob.java +++ b/app/src/main/java/org/tm/archive/jobs/MultiDeviceMessageRequestResponseJob.java @@ -54,7 +54,11 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob { } public static @NonNull MultiDeviceMessageRequestResponseJob forBlockAndReportSpam(@NonNull RecipientId threadRecipient) { - return new MultiDeviceMessageRequestResponseJob(threadRecipient, Type.BLOCK); + return new MultiDeviceMessageRequestResponseJob(threadRecipient, Type.BLOCK_AND_SPAM); + } + + public static @NonNull MultiDeviceMessageRequestResponseJob forReportSpam(@NonNull RecipientId threadRecipient) { + return new MultiDeviceMessageRequestResponseJob(threadRecipient, Type.SPAM); } private MultiDeviceMessageRequestResponseJob(@NonNull RecipientId threadRecipient, @NonNull Type type) { @@ -135,6 +139,10 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob { return MessageRequestResponseMessage.Type.BLOCK; case BLOCK_AND_DELETE: return MessageRequestResponseMessage.Type.BLOCK_AND_DELETE; + case SPAM: + return MessageRequestResponseMessage.Type.SPAM; + case BLOCK_AND_SPAM: + return MessageRequestResponseMessage.Type.BLOCK_AND_SPAM; default: return MessageRequestResponseMessage.Type.UNKNOWN; } @@ -151,7 +159,7 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob { } private enum Type { - UNKNOWN(0), ACCEPT(1), DELETE(2), BLOCK(3), BLOCK_AND_DELETE(4); + UNKNOWN(0), ACCEPT(1), DELETE(2), BLOCK(3), BLOCK_AND_DELETE(4), SPAM(5), BLOCK_AND_SPAM(6); private final int value; diff --git a/app/src/main/java/org/tm/archive/jobs/MultiDeviceProfileKeyUpdateJob.java b/app/src/main/java/org/tm/archive/jobs/MultiDeviceProfileKeyUpdateJob.java index 3f4c7237..cb77f8c2 100644 --- a/app/src/main/java/org/tm/archive/jobs/MultiDeviceProfileKeyUpdateJob.java +++ b/app/src/main/java/org/tm/archive/jobs/MultiDeviceProfileKeyUpdateJob.java @@ -11,6 +11,7 @@ import org.tm.archive.crypto.UnidentifiedAccessUtil; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobmanager.Job; import org.tm.archive.jobmanager.impl.NetworkConstraint; +import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.net.NotPushRegisteredException; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientUtil; @@ -76,13 +77,13 @@ public class MultiDeviceProfileKeyUpdateJob extends BaseJob { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DeviceContactsOutputStream out = new DeviceContactsOutputStream(baos); - out.write(new DeviceContact(RecipientUtil.toSignalServiceAddress(context, Recipient.self()), + out.write(new DeviceContact(Optional.ofNullable(SignalStore.account().getAci()), + Optional.ofNullable(SignalStore.account().getE164()), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), profileKey, - false, Optional.empty(), Optional.empty(), false)); diff --git a/app/src/main/java/org/tm/archive/jobs/PnpInitializeDevicesJob.kt b/app/src/main/java/org/tm/archive/jobs/PnpInitializeDevicesJob.kt index e446808e..9c9ea1f1 100644 --- a/app/src/main/java/org/tm/archive/jobs/PnpInitializeDevicesJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/PnpInitializeDevicesJob.kt @@ -20,7 +20,6 @@ import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.jobmanager.Job import org.tm.archive.jobmanager.impl.NetworkConstraint import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.recipients.Recipient import org.tm.archive.registration.VerifyResponse import org.tm.archive.registration.VerifyResponseWithoutKbs import org.tm.archive.util.TextSecurePreferences @@ -49,7 +48,7 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base @JvmStatic fun enqueueIfNecessary() { - if (SignalStore.misc().hasPniInitializedDevices() || !SignalStore.account().isRegistered || SignalStore.account().aci == null || Recipient.self().pnpCapability != Recipient.Capability.SUPPORTED) { + if (SignalStore.misc().hasPniInitializedDevices || !SignalStore.account().isRegistered || SignalStore.account().aci == null) { return } @@ -71,10 +70,6 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base @Throws(Exception::class) public override fun onRun() { - if (Recipient.self().pnpCapability != Recipient.Capability.SUPPORTED) { - throw IllegalStateException("This should only be run if you have the capability!") - } - if (!SignalStore.account().isRegistered || SignalStore.account().aci == null) { Log.w(TAG, "Not registered! Skipping, as it wouldn't do anything.") return @@ -82,19 +77,19 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base if (!TextSecurePreferences.isMultiDevice(context)) { Log.i(TAG, "Not multi device, aborting...") - SignalStore.misc().setPniInitializedDevices(true) + SignalStore.misc().hasPniInitializedDevices = true return } if (SignalStore.account().isLinkedDevice) { Log.i(TAG, "Not primary device, aborting...") - SignalStore.misc().setPniInitializedDevices(true) + SignalStore.misc().hasPniInitializedDevices = true return } ChangeNumberRepository.CHANGE_NUMBER_LOCK.lock() try { - if (SignalStore.misc().hasPniInitializedDevices()) { + if (SignalStore.misc().hasPniInitializedDevices) { Log.w(TAG, "We found out that things have been initialized after we got the lock! No need to do anything else.") return } @@ -103,10 +98,11 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base try { Log.i(TAG, "Initializing PNI for linked devices") - initializeDevices(e164) + val result: VerifyResponseWithoutKbs = initializeDevices(e164) .map(::VerifyResponseWithoutKbs) .safeBlockingGet() - .resultOrThrow + + result.error?.let { throw it } } catch (e: InterruptedException) { throw IOException("Retry", e) } catch (t: Throwable) { @@ -114,7 +110,7 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base throw t } - SignalStore.misc().setPniInitializedDevices(true) + SignalStore.misc().hasPniInitializedDevices = true } finally { ChangeNumberRepository.CHANGE_NUMBER_LOCK.unlock() } @@ -189,7 +185,7 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base val lastResortKyberPreKeyRecord: KyberPreKeyRecord = if (deviceId == primaryDeviceId) { pniProtocolStore.loadKyberPreKey(SignalStore.account().pniPreKeys.lastResortKyberPreKeyId) } else { - PreKeyUtil.generateLastRestortKyberPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) + PreKeyUtil.generateLastResortKyberPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) } devicePniLastResortKyberPreKeys[deviceId] = KyberPreKeyEntity(lastResortKyberPreKeyRecord.id, lastResortKyberPreKeyRecord.keyPair.publicKey, lastResortKyberPreKeyRecord.signature) diff --git a/app/src/main/java/org/tm/archive/jobs/PreKeysSyncJob.kt b/app/src/main/java/org/tm/archive/jobs/PreKeysSyncJob.kt index b2e42c60..742ef03c 100644 --- a/app/src/main/java/org/tm/archive/jobs/PreKeysSyncJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/PreKeysSyncJob.kt @@ -2,6 +2,7 @@ package org.tm.archive.jobs import androidx.annotation.VisibleForTesting import org.signal.core.util.logging.Log +import org.signal.core.util.roundedString import org.signal.libsignal.protocol.state.KyberPreKeyRecord import org.signal.libsignal.protocol.state.PreKeyRecord import org.signal.libsignal.protocol.state.SignalProtocolStore @@ -11,7 +12,10 @@ import org.tm.archive.crypto.storage.PreKeyMetadataStore import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.jobmanager.Job import org.tm.archive.jobmanager.impl.NetworkConstraint +import org.tm.archive.jobs.protos.PreKeysSyncJobData import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.util.FeatureFlags +import org.whispersystems.signalservice.api.NetworkResult import org.whispersystems.signalservice.api.SignalServiceAccountDataStore import org.whispersystems.signalservice.api.account.PreKeyUpload import org.whispersystems.signalservice.api.push.ServiceId @@ -19,7 +23,9 @@ import org.whispersystems.signalservice.api.push.ServiceIdType import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException import org.whispersystems.signalservice.internal.push.OneTimePreKeyCounts +import java.io.IOException import java.util.concurrent.TimeUnit +import kotlin.jvm.Throws import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.milliseconds import kotlin.time.DurationUnit @@ -34,7 +40,10 @@ import kotlin.time.DurationUnit * It will also rotate/create last-resort kyber prekeys for both ACI and PNI identities, as well as ensure * that the user has a sufficient number of one-time kyber prekeys available on the service. */ -class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(parameters) { +class PreKeysSyncJob private constructor( + parameters: Parameters, + private val forceRotationRequested: Boolean +) : BaseJob(parameters) { companion object { const val KEY = "PreKeysSyncJob" @@ -52,9 +61,13 @@ class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(param @JvmField val MAXIMUM_ALLOWED_SIGNED_PREKEY_AGE = 14.days.inWholeMilliseconds + /** + * @param forceRotationRequested If true, this will force the rotation of all keys, provided we haven't already done a forced refresh recently. + */ + @JvmOverloads @JvmStatic - fun create(): PreKeysSyncJob { - return PreKeysSyncJob() + fun create(forceRotationRequested: Boolean = false): PreKeysSyncJob { + return PreKeysSyncJob(forceRotationRequested) } @JvmStatic @@ -87,19 +100,22 @@ class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(param } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - constructor() : this( + constructor(forceRotation: Boolean = false) : this( Parameters.Builder() .setQueue("PreKeysSyncJob") .addConstraint(NetworkConstraint.KEY) .setMaxInstancesForFactory(1) .setMaxAttempts(Parameters.UNLIMITED) .setLifespan(TimeUnit.DAYS.toMillis(30)) - .build() + .build(), + forceRotation ) override fun getFactoryKey(): String = KEY - override fun serialize(): ByteArray? = null + override fun serialize(): ByteArray { + return PreKeysSyncJobData(forceRotationRequested).encode() + } override fun onRun() { if (!SignalStore.account().isRegistered || SignalStore.account().aci == null || SignalStore.account().pni == null) { @@ -107,12 +123,43 @@ class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(param return } - syncPreKeys(ServiceIdType.ACI, SignalStore.account().aci, ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys) - syncPreKeys(ServiceIdType.PNI, SignalStore.account().pni, ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys) + val forceRotation = if (forceRotationRequested) { + warn(TAG, "Forced rotation was requested.") + warn(TAG, ServiceIdType.ACI, "Active Signed EC: ${SignalStore.account().aciPreKeys.activeSignedPreKeyId}, Last Resort Kyber: ${SignalStore.account().aciPreKeys.lastResortKyberPreKeyId}") + warn(TAG, ServiceIdType.PNI, "Active Signed EC: ${SignalStore.account().pniPreKeys.activeSignedPreKeyId}, Last Resort Kyber: ${SignalStore.account().pniPreKeys.lastResortKyberPreKeyId}") + + if (!checkPreKeyConsistency(ServiceIdType.ACI, ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys)) { + warn(TAG, ServiceIdType.ACI, "Prekey consistency check failed! Must rotate keys!") + true + } else if (!checkPreKeyConsistency(ServiceIdType.PNI, ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys)) { + warn(TAG, ServiceIdType.PNI, "Prekey consistency check failed! Must rotate keys! (ACI consistency check must have passed)") + true + } else { + warn(TAG, "Forced rotation was requested, but the consistency checks passed!") + val timeSinceLastForcedRotation = System.currentTimeMillis() - SignalStore.misc().lastForcedPreKeyRefresh + // We check < 0 in case someone changed their clock and had a bad value set + timeSinceLastForcedRotation > FeatureFlags.preKeyForceRefreshInterval() || timeSinceLastForcedRotation < 0 + } + } else { + false + } + + if (forceRotation) { + warn(TAG, "Forcing prekey rotation.") + } else if (forceRotationRequested) { + warn(TAG, "Forced prekey rotation was requested, but we already did a forced refresh ${System.currentTimeMillis() - SignalStore.misc().lastForcedPreKeyRefresh} ms ago. Ignoring.") + } + + syncPreKeys(ServiceIdType.ACI, SignalStore.account().aci, ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys, forceRotation) + syncPreKeys(ServiceIdType.PNI, SignalStore.account().pni, ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys, forceRotation) SignalStore.misc().lastFullPrekeyRefreshTime = System.currentTimeMillis() + + if (forceRotation) { + SignalStore.misc().lastForcedPreKeyRefresh = System.currentTimeMillis() + } } - private fun syncPreKeys(serviceIdType: ServiceIdType, serviceId: ServiceId?, protocolStore: SignalServiceAccountDataStore, metadataStore: PreKeyMetadataStore) { + private fun syncPreKeys(serviceIdType: ServiceIdType, serviceId: ServiceId?, protocolStore: SignalServiceAccountDataStore, metadataStore: PreKeyMetadataStore, forceRotation: Boolean) { if (serviceId == null) { warn(TAG, serviceIdType, "AccountId not set!") return @@ -121,20 +168,20 @@ class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(param val accountManager = ApplicationDependencies.getSignalServiceAccountManager() val availablePreKeyCounts: OneTimePreKeyCounts = accountManager.getPreKeyCounts(serviceIdType) - val signedPreKeyToUpload: SignedPreKeyRecord? = signedPreKeyUploadIfNeeded(serviceIdType, protocolStore, metadataStore) + val signedPreKeyToUpload: SignedPreKeyRecord? = signedPreKeyUploadIfNeeded(serviceIdType, protocolStore, metadataStore, forceRotation) - val oneTimeEcPreKeysToUpload: List? = if (availablePreKeyCounts.ecCount < ONE_TIME_PREKEY_MINIMUM) { - log(serviceIdType, "There are ${availablePreKeyCounts.ecCount} one-time EC prekeys available, which is less than our threshold. Need more.") + val oneTimeEcPreKeysToUpload: List? = if (forceRotation || availablePreKeyCounts.ecCount < ONE_TIME_PREKEY_MINIMUM) { + log(serviceIdType, "There are ${availablePreKeyCounts.ecCount} one-time EC prekeys available, which is less than our threshold. Need more. (Forced: $forceRotation)") PreKeyUtil.generateAndStoreOneTimeEcPreKeys(protocolStore, metadataStore) } else { log(serviceIdType, "There are ${availablePreKeyCounts.ecCount} one-time EC prekeys available, which is enough.") null } - val lastResortKyberPreKeyToUpload: KyberPreKeyRecord? = lastResortKyberPreKeyUploadIfNeeded(serviceIdType, protocolStore, metadataStore) + val lastResortKyberPreKeyToUpload: KyberPreKeyRecord? = lastResortKyberPreKeyUploadIfNeeded(serviceIdType, protocolStore, metadataStore, forceRotation) - val oneTimeKyberPreKeysToUpload: List? = if (availablePreKeyCounts.kyberCount < ONE_TIME_PREKEY_MINIMUM) { - log(serviceIdType, "There are ${availablePreKeyCounts.kyberCount} one-time kyber prekeys available, which is less than our threshold. Need more.") + val oneTimeKyberPreKeysToUpload: List? = if (forceRotation || availablePreKeyCounts.kyberCount < ONE_TIME_PREKEY_MINIMUM) { + log(serviceIdType, "There are ${availablePreKeyCounts.kyberCount} one-time kyber prekeys available, which is less than our threshold. Need more. (Forced: $forceRotation)") PreKeyUtil.generateAndStoreOneTimeKyberPreKeys(protocolStore, metadataStore) } else { log(serviceIdType, "There are ${availablePreKeyCounts.kyberCount} one-time kyber prekeys available, which is enough.") @@ -183,32 +230,55 @@ class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(param PreKeyUtil.cleanOneTimePreKeys(protocolStore) } - private fun signedPreKeyUploadIfNeeded(serviceIdType: ServiceIdType, protocolStore: SignalProtocolStore, metadataStore: PreKeyMetadataStore): SignedPreKeyRecord? { + private fun signedPreKeyUploadIfNeeded(serviceIdType: ServiceIdType, protocolStore: SignalProtocolStore, metadataStore: PreKeyMetadataStore, forceRotation: Boolean): SignedPreKeyRecord? { val signedPreKeyRegistered = metadataStore.isSignedPreKeyRegistered && metadataStore.activeSignedPreKeyId >= 0 val timeSinceLastSignedPreKeyRotation = System.currentTimeMillis() - metadataStore.lastSignedPreKeyRotationTime - return if (!signedPreKeyRegistered || timeSinceLastSignedPreKeyRotation >= REFRESH_INTERVAL || timeSinceLastSignedPreKeyRotation < 0) { - log(serviceIdType, "Rotating signed prekey. SignedPreKeyRegistered: $signedPreKeyRegistered, TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS)} days)") + return if (forceRotation || !signedPreKeyRegistered || timeSinceLastSignedPreKeyRotation >= REFRESH_INTERVAL || timeSinceLastSignedPreKeyRotation < 0) { + log(serviceIdType, "Rotating signed prekey. ForceRotation: $forceRotation, SignedPreKeyRegistered: $signedPreKeyRegistered, TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS).roundedString(2)} days)") PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore) } else { - log(serviceIdType, "No need to rotate signed prekey. TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS)} days)") + log(serviceIdType, "No need to rotate signed prekey. TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS).roundedString(2)} days)") null } } - private fun lastResortKyberPreKeyUploadIfNeeded(serviceIdType: ServiceIdType, protocolStore: SignalServiceAccountDataStore, metadataStore: PreKeyMetadataStore): KyberPreKeyRecord? { + private fun lastResortKyberPreKeyUploadIfNeeded(serviceIdType: ServiceIdType, protocolStore: SignalServiceAccountDataStore, metadataStore: PreKeyMetadataStore, forceRotation: Boolean): KyberPreKeyRecord? { val lastResortRegistered = metadataStore.lastResortKyberPreKeyId >= 0 val timeSinceLastSignedPreKeyRotation = System.currentTimeMillis() - metadataStore.lastResortKyberPreKeyRotationTime - return if (!lastResortRegistered || timeSinceLastSignedPreKeyRotation >= REFRESH_INTERVAL || timeSinceLastSignedPreKeyRotation < 0) { - log(serviceIdType, "Rotating last-resort kyber prekey. TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS)} days)") + return if (forceRotation || !lastResortRegistered || timeSinceLastSignedPreKeyRotation >= REFRESH_INTERVAL || timeSinceLastSignedPreKeyRotation < 0) { + log(serviceIdType, "Rotating last-resort kyber prekey. ForceRotation: $forceRotation, TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS).roundedString(2)} days)") PreKeyUtil.generateAndStoreLastResortKyberPreKey(protocolStore, metadataStore) } else { - log(serviceIdType, "No need to rotate last-resort kyber prekey. TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS)} days)") + log(serviceIdType, "No need to rotate last-resort kyber prekey. TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS).roundedString(2)} days)") null } } + @Throws(IOException::class) + private fun checkPreKeyConsistency(serviceIdType: ServiceIdType, protocolStore: SignalServiceAccountDataStore, metadataStore: PreKeyMetadataStore): Boolean { + val result: NetworkResult = ApplicationDependencies.getSignalServiceAccountManager().keysApi.checkRepeatedUseKeys( + serviceIdType = serviceIdType, + identityKey = protocolStore.identityKeyPair.publicKey, + signedPreKeyId = metadataStore.activeSignedPreKeyId, + signedPreKey = protocolStore.loadSignedPreKey(metadataStore.activeSignedPreKeyId).keyPair.publicKey, + lastResortKyberKeyId = metadataStore.lastResortKyberPreKeyId, + lastResortKyberKey = protocolStore.loadKyberPreKey(metadataStore.lastResortKyberPreKeyId).keyPair.publicKey + ) + + return when (result) { + is NetworkResult.Success -> true + is NetworkResult.NetworkError -> throw result.throwable ?: PushNetworkException("Network error") + is NetworkResult.ApplicationError -> throw result.throwable + is NetworkResult.StatusCodeError -> if (result.code == 409) { + false + } else { + throw NonSuccessfulResponseCodeException(result.code) + } + } + } + override fun onShouldRetry(e: Exception): Boolean { return when (e) { is NonSuccessfulResponseCodeException -> false @@ -225,7 +295,15 @@ class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(param class Factory : Job.Factory { override fun create(parameters: Parameters, serializedData: ByteArray?): PreKeysSyncJob { - return PreKeysSyncJob(parameters) + return try { + serializedData?.let { + val data = PreKeysSyncJobData.ADAPTER.decode(serializedData) + PreKeysSyncJob(parameters, data.forceRefreshRequested) + } ?: PreKeysSyncJob(parameters, forceRotationRequested = false) + } catch (e: IOException) { + Log.w(TAG, "Error deserializing PreKeysSyncJob", e) + PreKeysSyncJob(parameters, forceRotationRequested = false) + } } } } diff --git a/app/src/main/java/org/tm/archive/jobs/PushGroupSendJob.java b/app/src/main/java/org/tm/archive/jobs/PushGroupSendJob.java index 17611a19..12e4832c 100644 --- a/app/src/main/java/org/tm/archive/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/tm/archive/jobs/PushGroupSendJob.java @@ -492,7 +492,11 @@ public final class PushGroupSendJob extends PushSendJob { } else if (!networkFailures.isEmpty()) { long retryAfter = results.stream() .filter(r -> r.getRateLimitFailure() != null) - .map(r -> r.getRateLimitFailure().getRetryAfterMilliseconds().orElse(-1L)) + .map(r -> { + long milliseconds = r.getRateLimitFailure().getRetryAfterMilliseconds().orElse(-1L); + return (milliseconds > 0) ? milliseconds : -1L; + } + ) .max(Long::compare) .orElse(-1L); Log.w(TAG, "Retrying because there were " + networkFailures.size() + " network failures. retryAfter: " + retryAfter); diff --git a/app/src/main/java/org/tm/archive/jobs/PushSendJob.java b/app/src/main/java/org/tm/archive/jobs/PushSendJob.java index e66c5797..dabff936 100644 --- a/app/src/main/java/org/tm/archive/jobs/PushSendJob.java +++ b/app/src/main/java/org/tm/archive/jobs/PushSendJob.java @@ -594,8 +594,13 @@ public abstract class PushSendJob extends SendJob { SignalDatabase.messages().markAsRateLimited(messageId); } - if (proofRequired.getOptions().contains(ProofRequiredException.Option.RECAPTCHA)) { - Log.i(TAG, "[Proof Required] ReCAPTCHA required."); + final Optional captchaRequired = + proofRequired.getOptions().stream() + .filter(option -> option.equals(ProofRequiredException.Option.RECAPTCHA) || option.equals(ProofRequiredException.Option.CAPTCHA)) + .findFirst(); + + if (captchaRequired.isPresent()) { + Log.i(TAG, "[Proof Required] " + captchaRequired.get() + " required."); SignalStore.rateLimit().markNeedsRecaptcha(proofRequired.getToken()); if (recipient != null) { diff --git a/app/src/main/java/org/tm/archive/jobs/RefreshAttributesJob.java b/app/src/main/java/org/tm/archive/jobs/RefreshAttributesJob.java index 3efdd6fb..d245044c 100644 --- a/app/src/main/java/org/tm/archive/jobs/RefreshAttributesJob.java +++ b/app/src/main/java/org/tm/archive/jobs/RefreshAttributesJob.java @@ -12,6 +12,8 @@ import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobmanager.JsonJobData; import org.tm.archive.jobmanager.Job; import org.tm.archive.jobmanager.impl.NetworkConstraint; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode; import org.tm.archive.keyvalue.SvrValues; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.registration.RegistrationRepository; @@ -97,7 +99,7 @@ public class RefreshAttributesJob extends BaseJob { registrationLockV2 = svrValues.getRegistrationLockToken(); } - boolean phoneNumberDiscoverable = SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode().isDiscoverable(); + boolean phoneNumberDiscoverable = SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode() == PhoneNumberDiscoverabilityMode.DISCOVERABLE; String deviceName = SignalStore.account().getDeviceName(); byte[] encryptedDeviceName = (deviceName == null) ? null : DeviceNameCipher.encryptDeviceName(deviceName.getBytes(StandardCharsets.UTF_8), SignalStore.account().getAciIdentityKey()); diff --git a/app/src/main/java/org/tm/archive/jobs/RefreshOwnProfileJob.java b/app/src/main/java/org/tm/archive/jobs/RefreshOwnProfileJob.java index af6b881a..f7dc2a9c 100644 --- a/app/src/main/java/org/tm/archive/jobs/RefreshOwnProfileJob.java +++ b/app/src/main/java/org/tm/archive/jobs/RefreshOwnProfileJob.java @@ -155,9 +155,7 @@ public class RefreshOwnProfileJob extends BaseJob { StoryOnboardingDownloadJob.Companion.enqueueIfNeeded(); - if (FeatureFlags.usernames()) { - checkUsernameIsInSync(); - } + checkUsernameIsInSync(); } private void setExpiringProfileKeyCredential(@NonNull Recipient recipient, diff --git a/app/src/main/java/org/tm/archive/jobs/ReportSpamJob.java b/app/src/main/java/org/tm/archive/jobs/ReportSpamJob.java index 9ba7ed48..760869a2 100644 --- a/app/src/main/java/org/tm/archive/jobs/ReportSpamJob.java +++ b/app/src/main/java/org/tm/archive/jobs/ReportSpamJob.java @@ -20,6 +20,7 @@ import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulRespons import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -72,9 +73,28 @@ public class ReportSpamJob extends BaseJob { return; } - int count = 0; - List reportSpamData = SignalDatabase.messages().getReportSpamMessageServerData(threadId, timestamp, MAX_MESSAGE_COUNT); - SignalServiceAccountManager signalServiceAccountManager = ApplicationDependencies.getSignalServiceAccountManager(); + Recipient threadRecipient = SignalDatabase.threads().getRecipientForThreadId(threadId); + if (threadRecipient == null) { + Log.w(TAG, "No recipient for thread"); + return; + } + + List reportSpamData; + + if (threadRecipient.isGroup()) { + Recipient inviter = SignalDatabase.groups().getGroupInviter(threadRecipient.requireGroupId()); + if (inviter == null) { + Log.w(TAG, "Unable to determine inviter to report"); + return; + } + + reportSpamData = SignalDatabase.messages().getGroupReportSpamMessageServerData(threadId, inviter.getId(), timestamp, MAX_MESSAGE_COUNT); + } else { + reportSpamData = SignalDatabase.messages().getReportSpamMessageServerData(threadId, timestamp, MAX_MESSAGE_COUNT); + } + + int count = 0; + SignalServiceAccountManager signalServiceAccountManager = ApplicationDependencies.getSignalServiceAccountManager(); for (ReportSpamData data : reportSpamData) { RecipientId recipientId = data.getRecipientId(); @@ -88,7 +108,7 @@ public class ReportSpamJob extends BaseJob { if (reportingTokenBytes != null) { reportingTokenEncoded = Base64.encodeWithPadding(reportingTokenBytes); } - + signalServiceAccountManager.reportSpam(serviceId.get(), data.getServerGuid(), reportingTokenEncoded); count++; } else { diff --git a/app/src/main/java/org/tm/archive/jobs/ResendMessageJob.java b/app/src/main/java/org/tm/archive/jobs/ResendMessageJob.java index 0dde59d7..e85a71b5 100644 --- a/app/src/main/java/org/tm/archive/jobs/ResendMessageJob.java +++ b/app/src/main/java/org/tm/archive/jobs/ResendMessageJob.java @@ -131,6 +131,8 @@ public class ResendMessageJob extends BaseJob { ThreadUtil.sleep(10000); } + Log.i(TAG, "[" + sentTimestamp + " ] Resending message to " + recipientId + " (urgent: " + urgent + ", contentHint: " + contentHint.name() + ", groupId: " + groupId + ", distributionId: " + distributionId + ")"); + SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender(); Recipient recipient = Recipient.resolved(recipientId); @@ -174,7 +176,20 @@ public class ResendMessageJob extends BaseJob { contentToSend = contentToSend.newBuilder().senderKeyDistributionMessage(distributionBytes).build(); } - SendMessageResult result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId), urgent); + SendMessageResult result; + + try { + result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId), urgent); + } catch (IllegalStateException e) { + Log.w(TAG, "Failed to resend content. Archiving session and trying again.", e); + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSessions(recipientId, SignalServiceAddress.DEFAULT_DEVICE_ID); + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSiblingSessions(recipient.requireServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID)); + ApplicationDependencies.getProtocolStore().pni().sessions().archiveSessions(recipientId, SignalServiceAddress.DEFAULT_DEVICE_ID); + ApplicationDependencies.getProtocolStore().pni().sessions().archiveSiblingSessions(recipient.requireServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID)); + SignalDatabase.senderKeyShared().deleteAllFor(recipientId); + + result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId), urgent); + } if (result.isSuccess() && distributionId != null) { List addresses = result.getSuccess() diff --git a/app/src/main/java/org/tm/archive/jobs/RetrieveProfileAvatarJob.java b/app/src/main/java/org/tm/archive/jobs/RetrieveProfileAvatarJob.java index 6195657c..be81b7fb 100644 --- a/app/src/main/java/org/tm/archive/jobs/RetrieveProfileAvatarJob.java +++ b/app/src/main/java/org/tm/archive/jobs/RetrieveProfileAvatarJob.java @@ -127,7 +127,7 @@ public class RetrieveProfileAvatarJob extends BaseJob { AvatarHelper.setAvatar(context, recipient.getId(), avatarStream); if (recipient.isSelf()) { - SignalStore.misc().markHasEverHadAnAvatar(); + SignalStore.misc().setHasEverHadAnAvatar(true); } } catch (AssertionError e) { throw new IOException("Failed to copy stream. Likely a Conscrypt issue.", e); diff --git a/app/src/main/java/org/tm/archive/jobs/RetrieveProfileJob.kt b/app/src/main/java/org/tm/archive/jobs/RetrieveProfileJob.kt index 3bf07cbd..4fdae1ed 100644 --- a/app/src/main/java/org/tm/archive/jobs/RetrieveProfileJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/RetrieveProfileJob.kt @@ -54,6 +54,12 @@ class RetrieveProfileJob private constructor(parameters: Parameters, private val constructor(recipientIds: Set) : this( Parameters.Builder() .addConstraint(NetworkConstraint.KEY) + .apply { + if (recipientIds.size < 5) { + setQueue(recipientIds.map { it.toLong() }.sorted().joinToString(separator = "_", prefix = QUEUE_PREFIX)) + setMaxInstancesForQueue(2) + } + } .setMaxAttempts(3) .build(), recipientIds.toMutableSet() @@ -159,9 +165,15 @@ class RetrieveProfileJob private constructor(parameters: Parameters, private val SignalDatabase.recipients.markProfilesFetched(successIds, System.currentTimeMillis()) stopwatch.split("mark-fetched") - if (operationState.unregistered.isNotEmpty() || newlyRegisteredIds.isNotEmpty()) { - Log.i(TAG, "Marking " + newlyRegisteredIds.size + " users as registered and " + operationState.unregistered.size + " users as unregistered.") - SignalDatabase.recipients.bulkUpdatedRegisteredStatus(newlyRegisteredIds, operationState.unregistered) + if (newlyRegisteredIds.isNotEmpty()) { + Log.i(TAG, "Marking " + newlyRegisteredIds.size + " users as registered.") + SignalDatabase.recipients.bulkUpdatedRegisteredStatus(newlyRegisteredIds, emptySet()) + } + if (operationState.unregistered.isNotEmpty()) { + Log.i(TAG, "Marking " + operationState.unregistered.size + " users as unregistered.") + for (recipientId in operationState.unregistered) { + SignalDatabase.recipients.markUnregistered(recipientId) + } } stopwatch.split("registered-update") @@ -358,6 +370,16 @@ class RetrieveProfileJob private constructor(parameters: Parameters, private val val remoteProfileName = ProfileName.fromSerialized(plaintextProfileName) val localProfileName = recipient.profileName + if (localProfileName.isEmpty && + !recipient.isSystemContact && + recipient.isProfileSharing && + !recipient.isGroup && + !recipient.isSelf + ) { + Log.i(TAG, "Learned profile name for first time, insert event") + SignalDatabase.messages.insertLearnedProfileNameChangeMessage(recipient, recipient.getDisplayName(context)) + } + if (remoteProfileName != localProfileName) { Log.i(TAG, "Profile name updated. Writing new value.") SignalDatabase.recipients.setProfileName(recipient.id, remoteProfileName) @@ -378,9 +400,12 @@ class RetrieveProfileJob private constructor(parameters: Parameters, private val } if (writeChangeEvent || localDisplayName.isEmpty()) { + ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners() val threadId = SignalDatabase.threads.getThreadIdFor(recipient.id) if (threadId != null) { - ApplicationDependencies.getMessageNotifier().updateNotification(context, forConversation(threadId)) + SignalDatabase.runPostSuccessfulTransaction { + ApplicationDependencies.getMessageNotifier().updateNotification(context, forConversation(threadId)) + } } } @@ -481,6 +506,7 @@ class RetrieveProfileJob private constructor(parameters: Parameters, private val private val TAG = Log.tag(RetrieveProfileJob::class.java) private const val KEY_RECIPIENTS = "recipients" private const val DEDUPE_KEY_RETRIEVE_AVATAR = KEY + "_RETRIEVE_PROFILE_AVATAR" + private const val QUEUE_PREFIX = "RetrieveProfileJob_" /** * Submits the necessary job to refresh the profile of the requested recipient. Works for any diff --git a/app/src/main/java/org/tm/archive/jobs/SendRetryReceiptJob.java b/app/src/main/java/org/tm/archive/jobs/SendRetryReceiptJob.java index 00ab818e..356347b2 100644 --- a/app/src/main/java/org/tm/archive/jobs/SendRetryReceiptJob.java +++ b/app/src/main/java/org/tm/archive/jobs/SendRetryReceiptJob.java @@ -5,6 +5,7 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.libsignal.protocol.InvalidMessageException; +import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.message.DecryptionErrorMessage; import org.tm.archive.crypto.UnidentifiedAccessUtil; import org.tm.archive.dependencies.ApplicationDependencies; @@ -119,7 +120,7 @@ public final class SendRetryReceiptJob extends BaseJob { } return new SendRetryReceiptJob(recipientId, groupId, errorMessage, parameters); - } catch (InvalidMessageException e) { + } catch (InvalidKeyException | InvalidMessageException e) { throw new AssertionError(e); } } diff --git a/app/src/main/java/org/tm/archive/jobs/SendViewedReceiptJob.java b/app/src/main/java/org/tm/archive/jobs/SendViewedReceiptJob.java index 727756c4..76f55dc1 100644 --- a/app/src/main/java/org/tm/archive/jobs/SendViewedReceiptJob.java +++ b/app/src/main/java/org/tm/archive/jobs/SendViewedReceiptJob.java @@ -196,6 +196,11 @@ public class SendViewedReceiptJob extends BaseJob { return; } + if (recipient.isReleaseNotes()) { + Log.w(TAG, "Refusing to send receipts to release channel"); + return; + } + SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender(); SignalServiceAddress remoteAddress = RecipientUtil.toSignalServiceAddress(context, recipient); SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED, diff --git a/app/src/main/java/org/tm/archive/jobs/SmsSendJob.java b/app/src/main/java/org/tm/archive/jobs/SmsSendJob.java deleted file mode 100644 index 57042d96..00000000 --- a/app/src/main/java/org/tm/archive/jobs/SmsSendJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package org.tm.archive.jobs; - -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.telephony.PhoneNumberUtils; -import android.telephony.SmsManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.signal.core.util.PendingIntentFlags; -import org.signal.core.util.logging.Log; -import org.tm.archive.database.MessageTable; -import org.tm.archive.database.NoSuchMessageException; -import org.tm.archive.database.SignalDatabase; -import org.tm.archive.database.model.MessageRecord; -import org.tm.archive.dependencies.ApplicationDependencies; -import org.tm.archive.jobmanager.JsonJobData; -import org.tm.archive.jobmanager.Job; -import org.tm.archive.jobmanager.impl.NetworkOrCellServiceConstraint; -import org.tm.archive.keyvalue.SignalStore; -import org.tm.archive.notifications.v2.ConversationId; -import org.tm.archive.phonenumbers.NumberUtil; -import org.tm.archive.recipients.Recipient; -import org.tm.archive.service.SmsDeliveryListener; -import org.tm.archive.transport.UndeliverableMessageException; - -import java.util.ArrayList; - -public class SmsSendJob extends SendJob { - - public static final String KEY = "SmsSendJob"; - - private static final String TAG = Log.tag(SmsSendJob.class); - private static final int MAX_ATTEMPTS = 15; - private static final String KEY_MESSAGE_ID = "message_id"; - private static final String KEY_RUN_ATTEMPT = "run_attempt"; - - private final long messageId; - private final int runAttempt; - - public SmsSendJob(long messageId, @NonNull Recipient destination) { - this(messageId, destination, 0); - } - - public SmsSendJob(long messageId, @NonNull Recipient destination, int runAttempt) { - this(constructParameters(destination), messageId, runAttempt); - } - - private SmsSendJob(@NonNull Job.Parameters parameters, long messageId, int runAttempt) { - super(parameters); - - this.messageId = messageId; - this.runAttempt = runAttempt; - } - - @Override - public @Nullable byte[] serialize() { - return new JsonJobData.Builder().putLong(KEY_MESSAGE_ID, messageId) - .putInt(KEY_RUN_ATTEMPT, runAttempt) - .serialize(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onAdded() { - SignalDatabase.messages().markAsSending(messageId); - } - - @Override - public void onSend() throws NoSuchMessageException, TooManyRetriesException, UndeliverableMessageException { - if (runAttempt >= MAX_ATTEMPTS) { - warn(TAG, "Hit the retry limit. Failing."); - throw new TooManyRetriesException(); - } - - MessageTable database = SignalDatabase.messages(); - MessageRecord record = database.getMessageRecord(messageId); - - if (!record.isPending() && !record.isFailed()) { - warn(TAG, "Message " + messageId + " was already sent. Ignoring."); - return; - } - - if (!record.getToRecipient().hasSmsAddress()) { - throw new UndeliverableMessageException("Recipient didn't have an SMS address! " + record.getToRecipient().getId()); - } - - try { - log(TAG, String.valueOf(record.getDateSent()), "Sending message: " + messageId + " (attempt " + runAttempt + ")"); - deliver(record); - log(TAG, String.valueOf(record.getDateSent()), "Sent message: " + messageId); - } catch (UndeliverableMessageException ude) { - warn(TAG, ude); - SignalDatabase.messages().markAsSentFailed(record.getId()); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getToRecipient(), ConversationId.fromMessageRecord(record)); - } - } - - @Override - public boolean onShouldRetry(@NonNull Exception throwable) { - return false; - } - - @Override - public void onFailure() { - warn(TAG, "onFailure() messageId: " + messageId); - long threadId = SignalDatabase.messages().getThreadIdForMessage(messageId); - Recipient recipient = SignalDatabase.threads().getRecipientForThreadId(threadId); - - SignalDatabase.messages().markAsSentFailed(messageId); - - if (threadId != -1 && recipient != null) { - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, recipient, ConversationId.forConversation(threadId)); - } else { - Log.w(TAG, "Could not find message! threadId: " + threadId + ", recipient: " + (recipient != null ? recipient.getId().toString() : "null")); - } - } - - private void deliver(MessageRecord message) - throws UndeliverableMessageException - { - if (message.isSecure() || message.isKeyExchange() || message.isEndSession()) { - throw new UndeliverableMessageException("Trying to send a secure SMS?"); - } - - String recipient = message.getToRecipient().requireSmsAddress(); - - // See issue #1516 for bug report, and discussion on commits related to #4833 for problems - // related to the original fix to #1516. This still may not be a correct fix if networks allow - // SMS/MMS sending to alphanumeric recipients other than email addresses, but should also - // help to fix issue #3099. - if (!NumberUtil.isValidEmail(recipient)) { - recipient = PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(recipient)); - } - - if (!NumberUtil.isValidSmsOrEmail(recipient)) { - throw new UndeliverableMessageException("Not a valid SMS destination! " + recipient); - } - - SmsManager smsManager = getSmsManagerFor(message.getSubscriptionId()); - ArrayList messages = smsManager.divideMessage(message.getBody()); - ArrayList sentIntents = constructSentIntents(message.getId(), message.getType(), messages); - ArrayList deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages); - - // NOTE 11/04/14 -- There's apparently a bug where for some unknown recipients - // and messages, this will throw an NPE. We have no idea why, so we're just - // catching it and marking the message as a failure. That way at least it doesn't - // repeatedly crash every time you start the app. - try { - smsManager.sendMultipartTextMessage(recipient, null, messages, sentIntents, deliveredIntents); - } catch (NullPointerException | IllegalArgumentException npe) { - warn(TAG, npe); - log(TAG, String.valueOf(message.getDateSent()), "Recipient: " + recipient); - log(TAG, String.valueOf(message.getDateSent()), "Message Parts: " + messages.size()); - - try { - for (int i=0;i constructSentIntents(long messageId, long type, ArrayList messages) - { - ArrayList sentIntents = new ArrayList<>(messages.size()); - boolean isMultipart = messages.size() > 1; - - for (String ignored : messages) { - sentIntents.add(PendingIntent.getBroadcast(context, 0, - constructSentIntent(context, messageId, type, isMultipart), - PendingIntentFlags.mutable())); - } - - return sentIntents; - } - - private ArrayList constructDeliveredIntents(long messageId, long type, ArrayList messages) { - if (!SignalStore.settings().isSmsDeliveryReportsEnabled()) { - return null; - } - - ArrayList deliveredIntents = new ArrayList<>(messages.size()); - boolean isMultipart = messages.size() > 1; - - for (String ignored : messages) { - deliveredIntents.add(PendingIntent.getBroadcast(context, 0, - constructDeliveredIntent(context, messageId, type, isMultipart), - PendingIntentFlags.mutable())); - } - - return deliveredIntents; - } - - private Intent constructSentIntent(Context context, long messageId, long type, boolean isMultipart) { - Intent pending = new Intent(SmsDeliveryListener.SENT_SMS_ACTION, - Uri.parse("custom://" + messageId + System.currentTimeMillis()), - context, SmsDeliveryListener.class); - - pending.putExtra("type", type); - pending.putExtra("message_id", messageId); - pending.putExtra("run_attempt", Math.max(runAttempt, getRunAttempt())); - pending.putExtra("is_multipart", isMultipart); - - return pending; - } - - private Intent constructDeliveredIntent(Context context, long messageId, long type, boolean isMultipart) { - Intent pending = new Intent(SmsDeliveryListener.DELIVERED_SMS_ACTION, - Uri.parse("custom://" + messageId + System.currentTimeMillis()), - context, SmsDeliveryListener.class); - pending.putExtra("type", type); - pending.putExtra("message_id", messageId); - pending.putExtra("is_multipart", isMultipart); - - return pending; - } - - private SmsManager getSmsManagerFor(int subscriptionId) { - if (Build.VERSION.SDK_INT >= 22 && subscriptionId != -1) { - return SmsManager.getSmsManagerForSubscriptionId(subscriptionId); - } else { - return SmsManager.getDefault(); - } - } - - private static Job.Parameters constructParameters(@NonNull Recipient destination) { - return new Job.Parameters.Builder() - .setMaxAttempts(MAX_ATTEMPTS) - .setQueue(destination.getId().toQueueKey() + "::SMS") - .addConstraint(NetworkOrCellServiceConstraint.KEY) - .build(); - } - - private static class TooManyRetriesException extends Exception { } - - public static class Factory implements Job.Factory { - @Override - public @NonNull SmsSendJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) { - JsonJobData data = JsonJobData.deserialize(serializedData); - return new SmsSendJob(parameters, data.getLong(KEY_MESSAGE_ID), data.getInt(KEY_RUN_ATTEMPT)); - } - } -} diff --git a/app/src/main/java/org/tm/archive/jobs/SmsSentJob.java b/app/src/main/java/org/tm/archive/jobs/SmsSentJob.java deleted file mode 100644 index 5ede1f8e..00000000 --- a/app/src/main/java/org/tm/archive/jobs/SmsSentJob.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.tm.archive.jobs; - -import android.app.Activity; -import android.telephony.SmsManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.signal.core.util.logging.Log; -import org.tm.archive.database.MessageTable; -import org.tm.archive.database.NoSuchMessageException; -import org.tm.archive.database.SignalDatabase; -import org.tm.archive.database.model.MessageRecord; -import org.tm.archive.dependencies.ApplicationDependencies; -import org.tm.archive.jobmanager.JsonJobData; -import org.tm.archive.jobmanager.Job; -import org.tm.archive.notifications.v2.ConversationId; -import org.tm.archive.service.SmsDeliveryListener; - -public class SmsSentJob extends BaseJob { - - public static final String KEY = "SmsSentJob"; - - private static final String TAG = Log.tag(SmsSentJob.class); - - private static final String KEY_MESSAGE_ID = "message_id"; - private static final String KEY_IS_MULTIPART = "is_multipart"; - private static final String KEY_ACTION = "action"; - private static final String KEY_RESULT = "result"; - private static final String KEY_RUN_ATTEMPT = "run_attempt"; - - private final long messageId; - private final boolean isMultipart; - private final String action; - private final int result; - private final int runAttempt; - - public SmsSentJob(long messageId, boolean isMultipart, String action, int result, int runAttempt) { - this(new Job.Parameters.Builder().build(), - messageId, - isMultipart, - action, - result, - runAttempt); - } - - private SmsSentJob(@NonNull Job.Parameters parameters, long messageId, boolean isMultipart, String action, int result, int runAttempt) { - super(parameters); - - this.messageId = messageId; - this.isMultipart = isMultipart; - this.action = action; - this.result = result; - this.runAttempt = runAttempt; - } - - @Override - public @Nullable byte[] serialize() { - return new JsonJobData.Builder().putLong(KEY_MESSAGE_ID, messageId) - .putBoolean(KEY_IS_MULTIPART, isMultipart) - .putString(KEY_ACTION, action) - .putInt(KEY_RESULT, result) - .putInt(KEY_RUN_ATTEMPT, runAttempt) - .serialize(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onRun() { - Log.i(TAG, "Got SMS callback: " + action + " , " + result); - - switch (action) { - case SmsDeliveryListener.SENT_SMS_ACTION: - handleSentResult(messageId, result); - break; - case SmsDeliveryListener.DELIVERED_SMS_ACTION: - handleDeliveredResult(messageId, result); - break; - } - } - - @Override - public boolean onShouldRetry(@NonNull Exception throwable) { - return false; - } - - @Override - public void onFailure() { - } - - private void handleDeliveredResult(long messageId, int result) { - SignalDatabase.messages().markSmsStatus(messageId, result); - } - - private void handleSentResult(long messageId, int result) { - try { - MessageTable database = SignalDatabase.messages(); - MessageRecord record = database.getMessageRecord(messageId); - - switch (result) { - case Activity.RESULT_OK: - database.markAsSent(messageId, false); - break; - case SmsManager.RESULT_ERROR_NO_SERVICE: - case SmsManager.RESULT_ERROR_RADIO_OFF: - if (isMultipart) { - Log.w(TAG, "Service connectivity problem, but not retrying due to multipart"); - database.markAsSentFailed(messageId); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getToRecipient(), ConversationId.forConversation(record.getThreadId())); - } else { - Log.w(TAG, "Service connectivity problem, requeuing..."); - ApplicationDependencies.getJobManager().add(new SmsSendJob(messageId, record.getToRecipient(), runAttempt + 1)); - } - break; - default: - database.markAsSentFailed(messageId); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getToRecipient(), ConversationId.forConversation(record.getThreadId())); - } - } catch (NoSuchMessageException e) { - Log.w(TAG, e); - } - } - - public static final class Factory implements Job.Factory { - @Override - public @NonNull SmsSentJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) { - JsonJobData data = JsonJobData.deserialize(serializedData); - - return new SmsSentJob(parameters, - data.getLong(KEY_MESSAGE_ID), - data.getBooleanOrDefault(KEY_IS_MULTIPART, true), - data.getString(KEY_ACTION), - data.getInt(KEY_RESULT), - data.getInt(KEY_RUN_ATTEMPT)); - } - } -} diff --git a/app/src/main/java/org/tm/archive/jobs/StorageSyncJob.java b/app/src/main/java/org/tm/archive/jobs/StorageSyncJob.java index b34d7a4f..733c463a 100644 --- a/app/src/main/java/org/tm/archive/jobs/StorageSyncJob.java +++ b/app/src/main/java/org/tm/archive/jobs/StorageSyncJob.java @@ -426,10 +426,7 @@ public class StorageSyncJob extends BaseJob { new GroupV1RecordProcessor(context).process(records.gv1, StorageSyncHelper.KEY_GENERATOR); new GroupV2RecordProcessor(context).process(records.gv2, StorageSyncHelper.KEY_GENERATOR); new AccountRecordProcessor(context, freshSelf()).process(records.account, StorageSyncHelper.KEY_GENERATOR); - - if (getKnownTypes().contains(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST.getValue())) { - new StoryDistributionListRecordProcessor().process(records.storyDistributionLists, StorageSyncHelper.KEY_GENERATOR); - } + new StoryDistributionListRecordProcessor().process(records.storyDistributionLists, StorageSyncHelper.KEY_GENERATOR); } private static @NonNull List getAllLocalStorageIds(@NonNull Recipient self) { diff --git a/app/src/main/java/org/tm/archive/jobs/SyncSystemContactLinksJob.kt b/app/src/main/java/org/tm/archive/jobs/SyncSystemContactLinksJob.kt index 4180eb8b..1598c328 100644 --- a/app/src/main/java/org/tm/archive/jobs/SyncSystemContactLinksJob.kt +++ b/app/src/main/java/org/tm/archive/jobs/SyncSystemContactLinksJob.kt @@ -44,9 +44,9 @@ class SyncSystemContactLinksJob private constructor(parameters: Parameters) : Ba val stopwatch = Stopwatch("contact-links") - val registeredE164s: Set = SignalDatabase.recipients.getRegisteredE164s() + val e164sForLinking: Set = SignalDatabase.recipients.getE164sForSystemContactLinks() - if (registeredE164s.isEmpty()) { + if (e164sForLinking.isEmpty()) { Log.w(TAG, "No registeredE164s. Skipping.") return } @@ -66,7 +66,7 @@ class SyncSystemContactLinksJob private constructor(parameters: Parameters) : Ba SystemContactsRepository.addMessageAndCallLinksToContacts( context = context, config = buildContactLinkConfiguration(context, account), - targetE164s = registeredE164s, + targetE164s = e164sForLinking, removeIfMissing = true ) stopwatch.split("add-links") diff --git a/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerFragment.kt b/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerFragment.kt index 6849513b..987078da 100644 --- a/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerFragment.kt +++ b/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerFragment.kt @@ -4,6 +4,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.Window +import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import org.tm.archive.R @@ -57,10 +59,12 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme } override fun onHiddenChanged(hidden: Boolean) { - if (hidden) { - WindowUtil.setNavigationBarColor(requireActivity(), ThemeUtil.getThemedColor(requireContext(), android.R.attr.navigationBarColor)) - } else { - WindowUtil.setNavigationBarColor(requireActivity(), ThemeUtil.getThemedColor(requireContext(), R.attr.mediaKeyboardBottomBarBackgroundColor)) + getWindow()?.let { window -> + if (hidden) { + WindowUtil.setNavigationBarColor(requireContext(), window, ThemeUtil.getThemedColor(requireContext(), android.R.attr.navigationBarColor)) + } else { + WindowUtil.setNavigationBarColor(requireContext(), window, ThemeUtil.getThemedColor(requireContext(), R.attr.mediaKeyboardBottomBarBackgroundColor)) + } } } @@ -70,6 +74,19 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme viewModel.page().value?.let(this::onPageSelected) } + private fun getWindow(): Window? { + var parent: Fragment? = parentFragment + while (parent != null) { + if (parent is DialogFragment) { + return parent.dialog?.window + } + + parent = parent.parentFragment + } + + return activity?.window + } + private fun onPageSelected(page: KeyboardPage) { emojiButton.isSelected = page == KeyboardPage.EMOJI stickerButton.isSelected = page == KeyboardPage.STICKER diff --git a/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerViewModel.kt b/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerViewModel.kt index 682f0857..a9ff9e13 100644 --- a/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerViewModel.kt +++ b/app/src/main/java/org/tm/archive/keyboard/KeyboardPagerViewModel.kt @@ -7,6 +7,7 @@ import org.signal.core.util.ThreadUtil import org.tm.archive.keyvalue.SignalStore import org.tm.archive.stickers.StickerSearchRepository import org.tm.archive.util.DefaultValueLiveData +import org.tm.archive.util.FeatureFlags class KeyboardPagerViewModel : ViewModel() { @@ -18,6 +19,11 @@ class KeyboardPagerViewModel : ViewModel() { if (SignalStore.settings().isPreferSystemEmoji) { startingPages.remove(KeyboardPage.EMOJI) } + + if (!FeatureFlags.gifSearchAvailable()) { + startingPages.remove(KeyboardPage.GIF) + } + pages = DefaultValueLiveData(startingPages) page = DefaultValueLiveData(startingPages.first()) diff --git a/app/src/main/java/org/tm/archive/keyboard/KeyboardUtil.kt b/app/src/main/java/org/tm/archive/keyboard/KeyboardUtil.kt index fe0cea7b..b04f175f 100644 --- a/app/src/main/java/org/tm/archive/keyboard/KeyboardUtil.kt +++ b/app/src/main/java/org/tm/archive/keyboard/KeyboardUtil.kt @@ -9,9 +9,9 @@ import android.graphics.Bitmap import android.graphics.Color import android.net.Uri import androidx.annotation.WorkerThread +import com.bumptech.glide.RequestManager import com.bumptech.glide.load.engine.DiskCacheStrategy import org.tm.archive.mms.DecryptableStreamUriLoader -import org.tm.archive.mms.GlideRequests import java.util.concurrent.ExecutionException import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException @@ -19,9 +19,9 @@ import java.util.concurrent.TimeoutException object KeyboardUtil { @WorkerThread - fun getImageDetails(glideRequests: GlideRequests, uri: Uri): ImageDetails? { + fun getImageDetails(requestManager: RequestManager, uri: Uri): ImageDetails? { return try { - val bitmap: Bitmap = glideRequests.asBitmap() + val bitmap: Bitmap = requestManager.asBitmap() .load(DecryptableStreamUriLoader.DecryptableUri(uri)) .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) diff --git a/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerListAdapter.kt b/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerListAdapter.kt index 34fa435f..cc4715b5 100644 --- a/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerListAdapter.kt +++ b/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerListAdapter.kt @@ -4,19 +4,19 @@ import android.content.Context import android.view.View import android.widget.ImageView import android.widget.TextView +import com.bumptech.glide.RequestManager import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import org.tm.archive.R import org.tm.archive.database.model.StickerRecord import org.tm.archive.glide.cache.ApngOptions import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri -import org.tm.archive.mms.GlideRequests import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingModel import org.tm.archive.util.adapter.mapping.MappingViewHolder class KeyboardStickerListAdapter( - private val glideRequests: GlideRequests, + private val requestManager: RequestManager, private val eventListener: EventListener?, private val allowApngAnimation: Boolean ) : MappingAdapter() { @@ -44,7 +44,7 @@ class KeyboardStickerListAdapter( private val image: ImageView = findViewById(R.id.sticker_keyboard_page_image) override fun bind(model: Sticker) { - glideRequests.load(model.uri) + requestManager.load(model.uri) .set(ApngOptions.ANIMATE, allowApngAnimation) .transition(DrawableTransitionOptions.withCrossFade()) .into(image) diff --git a/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerPackListAdapter.kt b/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerPackListAdapter.kt index abef4d03..5c27aa88 100644 --- a/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerPackListAdapter.kt +++ b/app/src/main/java/org/tm/archive/keyboard/sticker/KeyboardStickerPackListAdapter.kt @@ -4,16 +4,16 @@ import android.content.res.ColorStateList import android.view.View import android.widget.ImageView import androidx.core.widget.ImageViewCompat +import com.bumptech.glide.RequestManager import org.tm.archive.R import org.tm.archive.glide.cache.ApngOptions import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri -import org.tm.archive.mms.GlideRequests import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingModel import org.tm.archive.util.adapter.mapping.MappingViewHolder -class KeyboardStickerPackListAdapter(private val glideRequests: GlideRequests, private val allowApngAnimation: Boolean, private val onTabSelected: (StickerPack) -> Unit) : MappingAdapter() { +class KeyboardStickerPackListAdapter(private val requestManager: RequestManager, private val allowApngAnimation: Boolean, private val onTabSelected: (StickerPack) -> Unit) : MappingAdapter() { init { registerFactory(StickerPack::class.java, LayoutFactory(::StickerPackViewHolder, R.layout.keyboard_pager_category_icon)) @@ -47,7 +47,7 @@ class KeyboardStickerPackListAdapter(private val glideRequests: GlideRequests, p if (model.loadImage) { ImageViewCompat.setImageTintList(icon, null) icon.alpha = if (model.selected) 1f else 0.5f - glideRequests.load(model.uri) + requestManager.load(model.uri) .set(ApngOptions.ANIMATE, allowApngAnimation) .into(icon) } else { diff --git a/app/src/main/java/org/tm/archive/keyboard/sticker/StickerKeyboardPageFragment.kt b/app/src/main/java/org/tm/archive/keyboard/sticker/StickerKeyboardPageFragment.kt index 105a0c32..f708b285 100644 --- a/app/src/main/java/org/tm/archive/keyboard/sticker/StickerKeyboardPageFragment.kt +++ b/app/src/main/java/org/tm/archive/keyboard/sticker/StickerKeyboardPageFragment.kt @@ -9,6 +9,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.SmoothScroller +import com.bumptech.glide.Glide import com.google.android.material.appbar.AppBarLayout import org.signal.libsignal.protocol.util.Pair import org.tm.archive.LoggingFragment @@ -16,7 +17,6 @@ import org.tm.archive.R import org.tm.archive.database.DatabaseObserver import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.keyboard.emoji.KeyboardPageSearchView -import org.tm.archive.mms.GlideApp import org.tm.archive.stickers.StickerEventListener import org.tm.archive.stickers.StickerRolloverTouchListener import org.tm.archive.stickers.StickerRolloverTouchListener.RolloverStickerRetriever @@ -57,8 +57,8 @@ open class StickerKeyboardPageFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val glideRequests = GlideApp.with(this) - stickerListAdapter = KeyboardStickerListAdapter(glideRequests, this, DeviceProperties.shouldAllowApngStickerAnimation(requireContext())) + val requestManager = Glide.with(this) + stickerListAdapter = KeyboardStickerListAdapter(requestManager, this, DeviceProperties.shouldAllowApngStickerAnimation(requireContext())) layoutManager = GridLayoutManager(requireContext(), 2).apply { spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { @@ -70,7 +70,7 @@ open class StickerKeyboardPageFragment : } } } - listTouchListener = StickerRolloverTouchListener(requireContext(), glideRequests, this, this) + listTouchListener = StickerRolloverTouchListener(requireContext(), requestManager, this, this) stickerList = view.findViewById(R.id.sticker_keyboard_list) stickerList.layoutManager = layoutManager @@ -81,7 +81,7 @@ open class StickerKeyboardPageFragment : stickerPacksRecycler = view.findViewById(R.id.sticker_packs_recycler) - stickerPacksAdapter = KeyboardStickerPackListAdapter(glideRequests, DeviceProperties.shouldAllowApngStickerAnimation(requireContext()), this::onTabSelected) + stickerPacksAdapter = KeyboardStickerPackListAdapter(requestManager, DeviceProperties.shouldAllowApngStickerAnimation(requireContext()), this::onTabSelected) stickerPacksRecycler.adapter = stickerPacksAdapter appBarLayout = view.findViewById(R.id.sticker_keyboard_search_appbar) diff --git a/app/src/main/java/org/tm/archive/keyboard/sticker/StickerSearchDialogFragment.kt b/app/src/main/java/org/tm/archive/keyboard/sticker/StickerSearchDialogFragment.kt index 3605b3a0..7d340dee 100644 --- a/app/src/main/java/org/tm/archive/keyboard/sticker/StickerSearchDialogFragment.kt +++ b/app/src/main/java/org/tm/archive/keyboard/sticker/StickerSearchDialogFragment.kt @@ -10,9 +10,9 @@ import androidx.fragment.app.FragmentManager import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import org.tm.archive.R import org.tm.archive.keyboard.emoji.KeyboardPageSearchView -import org.tm.archive.mms.GlideApp import org.tm.archive.stickers.StickerEventListener import org.tm.archive.util.DeviceProperties import org.tm.archive.util.InsetItemDecoration @@ -47,7 +47,7 @@ class StickerSearchDialogFragment : DialogFragment(), KeyboardStickerListAdapter list = view.findViewById(R.id.sticker_search_list) noResults = view.findViewById(R.id.sticker_search_no_results) - adapter = KeyboardStickerListAdapter(GlideApp.with(this), this, DeviceProperties.shouldAllowApngStickerAnimation(requireContext())) + adapter = KeyboardStickerListAdapter(Glide.with(this), this, DeviceProperties.shouldAllowApngStickerAnimation(requireContext())) layoutManager = GridLayoutManager(requireContext(), 2) list.layoutManager = layoutManager diff --git a/app/src/main/java/org/tm/archive/keyvalue/MiscellaneousValues.java b/app/src/main/java/org/tm/archive/keyvalue/MiscellaneousValues.java deleted file mode 100644 index 7a5dcbe8..00000000 --- a/app/src/main/java/org/tm/archive/keyvalue/MiscellaneousValues.java +++ /dev/null @@ -1,349 +0,0 @@ -package org.tm.archive.keyvalue; - -import android.preference.PreferenceManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.archiver.annotation.TeleMessageUnfinalize; -import org.tm.archive.components.settings.app.usernamelinks.UsernameQrCodeColorScheme; -import org.tm.archive.database.model.databaseprotos.PendingChangeNumberMetadata; -import org.tm.archive.dependencies.ApplicationDependencies; -import org.tm.archive.jobmanager.impl.ChangeNumberConstraintObserver; - -import java.util.Collections; -import java.util.List; - -@TeleMessageUnfinalize -public class MiscellaneousValues extends SignalStoreValues { - - private static final String LAST_PREKEY_REFRESH_TIME = "last_prekey_refresh_time"; - private static final String MESSAGE_REQUEST_ENABLE_TIME = "message_request_enable_time"; - private static final String LAST_PROFILE_REFRESH_TIME = "misc.last_profile_refresh_time"; - private static final String USERNAME_SHOW_REMINDER = "username.show.reminder"; - private static final String CLIENT_DEPRECATED = "misc.client_deprecated"; - private static final String OLD_DEVICE_TRANSFER_LOCKED = "misc.old_device.transfer.locked"; - private static final String HAS_EVER_HAD_AN_AVATAR = "misc.has.ever.had.an.avatar"; - private static final String CHANGE_NUMBER_LOCK = "misc.change_number.lock"; - private static final String PENDING_CHANGE_NUMBER_METADATA = "misc.pending_change_number.metadata"; - private static final String CENSORSHIP_LAST_CHECK_TIME = "misc.censorship.last_check_time"; - private static final String CENSORSHIP_SERVICE_REACHABLE = "misc.censorship.service_reachable"; - private static final String LAST_GV2_PROFILE_CHECK_TIME = "misc.last_gv2_profile_check_time"; - private static final String CDS_TOKEN = "misc.cds_token"; - private static final String CDS_BLOCKED_UNTIL = "misc.cds_blocked_until"; - private static final String LAST_FOREGROUND_TIME = "misc.last_foreground_time"; - private static final String PNI_INITIALIZED_DEVICES = "misc.pni_initialized_devices"; - private static final String LINKED_DEVICES_REMINDER = "misc.linked_devices_reminder"; - private static final String HAS_LINKED_DEVICES = "misc.linked_devices_present"; - private static final String USERNAME_QR_CODE_COLOR = "mis.username_qr_color_scheme"; - private static final String KEYBOARD_LANDSCAPE_HEIGHT = "misc.keyboard.landscape_height"; - private static final String KEYBOARD_PORTRAIT_HEIGHT = "misc.keyboard.protrait_height"; - private static final String LAST_CONSISTENCY_CHECK_TIME = "misc.last_consistency_check_time"; - private static final String SERVER_TIME_OFFSET = "misc.server_time_offset"; - private static final String LAST_SERVER_TIME_OFFSET_UPDATE = "misc.last_server_time_offset_update"; - private static final String NEEDS_USERNAME_RESTORE = "misc.needs_username_restore"; - - MiscellaneousValues(@NonNull KeyValueStore store) { - super(store); - } - - @Override - void onFirstEverAppLaunch() { - putLong(MESSAGE_REQUEST_ENABLE_TIME, 0); - putBoolean(NEEDS_USERNAME_RESTORE, true); - } - - @Override - @NonNull List getKeysToIncludeInBackup() { - return Collections.emptyList(); - } - - /** - * Represents the last time a _full_ prekey refreshed finished. That means signed+one-time prekeys for both ACI and PNI. - */ - public long getLastFullPrekeyRefreshTime() { - return getLong(LAST_PREKEY_REFRESH_TIME, 0); - } - - public void setLastFullPrekeyRefreshTime(long time) { - putLong(LAST_PREKEY_REFRESH_TIME, time); - } - - public long getMessageRequestEnableTime() { - return getLong(MESSAGE_REQUEST_ENABLE_TIME, 0); - } - - public long getLastProfileRefreshTime() { - return getLong(LAST_PROFILE_REFRESH_TIME, 0); - } - - public void setLastProfileRefreshTime(long time) { - putLong(LAST_PROFILE_REFRESH_TIME, time); - } - - public void hideUsernameReminder() { - putBoolean(USERNAME_SHOW_REMINDER, false); - } - - public boolean shouldShowUsernameReminder() { - return getBoolean(USERNAME_SHOW_REMINDER, true); - } - - public boolean isClientDeprecated() { - return getBoolean(CLIENT_DEPRECATED, false); - } - - public void markClientDeprecated() { - putBoolean(CLIENT_DEPRECATED, true); - } - - public void clearClientDeprecated() { - putBoolean(CLIENT_DEPRECATED, false); - } - - public boolean isOldDeviceTransferLocked() { - return getBoolean(OLD_DEVICE_TRANSFER_LOCKED, false); - } - - public void markOldDeviceTransferLocked() { - putBoolean(OLD_DEVICE_TRANSFER_LOCKED, true); - } - - public void clearOldDeviceTransferLocked() { - putBoolean(OLD_DEVICE_TRANSFER_LOCKED, false); - } - - public boolean hasEverHadAnAvatar() { - return getBoolean(HAS_EVER_HAD_AN_AVATAR, false); - } - - public void markHasEverHadAnAvatar() { - putBoolean(HAS_EVER_HAD_AN_AVATAR, true); - } - - public boolean isChangeNumberLocked() { - return getBoolean(CHANGE_NUMBER_LOCK, false); - } - - public void lockChangeNumber() { - putBoolean(CHANGE_NUMBER_LOCK, true); - ChangeNumberConstraintObserver.INSTANCE.onChange(); - } - - public void unlockChangeNumber() { - putBoolean(CHANGE_NUMBER_LOCK, false); - ChangeNumberConstraintObserver.INSTANCE.onChange(); - } - - public @Nullable PendingChangeNumberMetadata getPendingChangeNumberMetadata() { - return getObject(PENDING_CHANGE_NUMBER_METADATA, null, PendingChangeNumberMetadataSerializer.INSTANCE); - } - - /** Store pending new PNI data to be applied after successful change number */ - public void setPendingChangeNumberMetadata(@NonNull PendingChangeNumberMetadata metadata) { - putObject(PENDING_CHANGE_NUMBER_METADATA, metadata, PendingChangeNumberMetadataSerializer.INSTANCE); - } - - /** Clear pending new PNI data after confirmed successful or failed change number */ - public void clearPendingChangeNumberMetadata() { - remove(PENDING_CHANGE_NUMBER_METADATA); - } - - public long getLastCensorshipServiceReachabilityCheckTime() { - return getLong(CENSORSHIP_LAST_CHECK_TIME, 0); - } - - public void setLastCensorshipServiceReachabilityCheckTime(long value) { - putLong(CENSORSHIP_LAST_CHECK_TIME, value); - } - - public boolean isServiceReachableWithoutCircumvention() { - return getBoolean(CENSORSHIP_SERVICE_REACHABLE, false); - } - - public void setServiceReachableWithoutCircumvention(boolean value) { - putBoolean(CENSORSHIP_SERVICE_REACHABLE, value); - } - - public long getLastGv2ProfileCheckTime() { - return getLong(LAST_GV2_PROFILE_CHECK_TIME, 0); - } - - public void setLastGv2ProfileCheckTime(long value) { - putLong(LAST_GV2_PROFILE_CHECK_TIME, value); - } - - public @Nullable byte[] getCdsToken() { - return getBlob(CDS_TOKEN, null); - } - - public void setCdsToken(@Nullable byte[] token) { - getStore().beginWrite() - .putBlob(CDS_TOKEN, token) - .commit(); - } - - /** - * Marks the time at which we think the next CDS request will succeed. This should be taken from the service response. - */ - public void setCdsBlockedUtil(long time) { - putLong(CDS_BLOCKED_UNTIL, time); - } - - /** - * Indicates that a CDS request will never succeed at the current contact count. - */ - public void markCdsPermanentlyBlocked() { - putLong(CDS_BLOCKED_UNTIL, Long.MAX_VALUE); - } - - /** - * Clears any rate limiting state related to CDS. - */ - public void clearCdsBlocked() { - setCdsBlockedUtil(0); - } - - /** - * Whether or not we expect the next CDS request to succeed. - */ - public boolean isCdsBlocked() { - return getCdsBlockedUtil() > 0; - } - - /** - * This represents the next time we think we'll be able to make a successful CDS request. If it is before this time, we expect the request will fail - * (assuming the user still has the same number of new E164s). - */ - public long getCdsBlockedUtil() { - return getLong(CDS_BLOCKED_UNTIL, 0); - } - - public long getLastForegroundTime() { - return getLong(LAST_FOREGROUND_TIME, 0); - } - - public void setLastForegroundTime(long time) { - putLong(LAST_FOREGROUND_TIME, time); - } - - public boolean hasPniInitializedDevices() { - return getBoolean(PNI_INITIALIZED_DEVICES, false); - } - - public void setPniInitializedDevices(boolean value) { - putBoolean(PNI_INITIALIZED_DEVICES, value); - } - - public @NonNull SmsExportPhase getSmsExportPhase() { - return SmsExportPhase.getCurrentPhase(); - } - - public void setHasLinkedDevices(boolean value) { - putBoolean(HAS_LINKED_DEVICES, value); - } - - public boolean getHasLinkedDevices() { - return getBoolean(HAS_LINKED_DEVICES, false); - } - - public void setShouldShowLinkedDevicesReminder(boolean value) { - putBoolean(LINKED_DEVICES_REMINDER, value); - } - - public boolean getShouldShowLinkedDevicesReminder() { - return getBoolean(LINKED_DEVICES_REMINDER, false); - } - - /** The color the user saved for rendering their shareable username QR code. */ - public @NonNull UsernameQrCodeColorScheme getUsernameQrCodeColorScheme() { - String serialized = getString(USERNAME_QR_CODE_COLOR, null); - return UsernameQrCodeColorScheme.deserialize(serialized); - } - - public void setUsernameQrCodeColorScheme(@NonNull UsernameQrCodeColorScheme color) { - putString(USERNAME_QR_CODE_COLOR, color.serialize()); - } - - public int getKeyboardLandscapeHeight() { - int height = (int) getLong(KEYBOARD_LANDSCAPE_HEIGHT, 0); - if (height == 0) { - //noinspection deprecation - height = PreferenceManager.getDefaultSharedPreferences(ApplicationDependencies.getApplication()) - .getInt("keyboard_height_landscape", 0); - - if (height > 0) { - setKeyboardLandscapeHeight(height); - } - } - return height; - } - - public void setKeyboardLandscapeHeight(int height) { - putLong(KEYBOARD_LANDSCAPE_HEIGHT, height); - } - - public int getKeyboardPortraitHeight() { - int height = (int) getInteger(KEYBOARD_PORTRAIT_HEIGHT, 0); - if (height == 0) { - //noinspection deprecation - height = PreferenceManager.getDefaultSharedPreferences(ApplicationDependencies.getApplication()) - .getInt("keyboard_height_portrait", 0); - - if (height > 0) { - setKeyboardPortraitHeight(height); - } - } - return height; - } - - public void setKeyboardPortraitHeight(int height) { - putInteger(KEYBOARD_PORTRAIT_HEIGHT, height); - } - - public long getLastConsistencyCheckTime() { - return getLong(LAST_CONSISTENCY_CHECK_TIME, 0); - } - - public void setLastConsistencyCheckTime(long time) { - putLong(LAST_CONSISTENCY_CHECK_TIME, time); - } - - /** - * Sets the last-known server time. - */ - public void setLastKnownServerTime(long serverTime, long currentTime) { - getStore() - .beginWrite() - .putLong(SERVER_TIME_OFFSET, currentTime - serverTime) - .putLong(LAST_SERVER_TIME_OFFSET_UPDATE, System.currentTimeMillis()) - .apply(); - } - - /** - * The last-known offset between our local clock and the server. To get an estimate of the server time, take your current time and subtract this offset. e.g. - * - * estimatedServerTime = System.currentTimeMillis() - SignalStore.misc().getLastKnownServerTimeOffset() - */ - public long getLastKnownServerTimeOffset() { - return getLong(SERVER_TIME_OFFSET, 0); - } - - /** - * The last time (using our local clock) we updated the server time offset returned by {@link #getLastKnownServerTimeOffset()}}. - */ - public long getLastKnownServerTimeOffsetUpdateTime() { - return getLong(LAST_SERVER_TIME_OFFSET_UPDATE, 0); - } - - /** - * Whether or not we should attempt to restore the user's username and link. - */ - public boolean needsUsernameRestore() { - return getBoolean(NEEDS_USERNAME_RESTORE, false); - } - - public void setNeedsUsernameRestore(boolean value) { - putBoolean(NEEDS_USERNAME_RESTORE, value); - } -} diff --git a/app/src/main/java/org/tm/archive/keyvalue/MiscellaneousValues.kt b/app/src/main/java/org/tm/archive/keyvalue/MiscellaneousValues.kt new file mode 100644 index 00000000..c4b80c77 --- /dev/null +++ b/app/src/main/java/org/tm/archive/keyvalue/MiscellaneousValues.kt @@ -0,0 +1,240 @@ +package org.tm.archive.keyvalue + +import org.archiver.annotation.TeleMessageUnfinalize +import org.tm.archive.components.settings.app.usernamelinks.UsernameQrCodeColorScheme +import org.tm.archive.database.model.databaseprotos.PendingChangeNumberMetadata +import org.tm.archive.jobmanager.impl.ChangeNumberConstraintObserver +import org.tm.archive.keyvalue.protos.LeastActiveLinkedDevice + +open class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) {//**TM_SA**//make open + companion object { + private const val LAST_PREKEY_REFRESH_TIME = "last_prekey_refresh_time" + private const val MESSAGE_REQUEST_ENABLE_TIME = "message_request_enable_time" + private const val LAST_PROFILE_REFRESH_TIME = "misc.last_profile_refresh_time" + private const val CLIENT_DEPRECATED = "misc.client_deprecated" + private const val OLD_DEVICE_TRANSFER_LOCKED = "misc.old_device.transfer.locked" + private const val HAS_EVER_HAD_AN_AVATAR = "misc.has.ever.had.an.avatar" + private const val CHANGE_NUMBER_LOCK = "misc.change_number.lock" + private const val PENDING_CHANGE_NUMBER_METADATA = "misc.pending_change_number.metadata" + private const val CENSORSHIP_LAST_CHECK_TIME = "misc.censorship.last_check_time" + private const val CENSORSHIP_SERVICE_REACHABLE = "misc.censorship.service_reachable" + private const val LAST_GV2_PROFILE_CHECK_TIME = "misc.last_gv2_profile_check_time" + private const val CDS_TOKEN = "misc.cds_token" + private const val CDS_BLOCKED_UNTIL = "misc.cds_blocked_until" + private const val LAST_FOREGROUND_TIME = "misc.last_foreground_time" + private const val PNI_INITIALIZED_DEVICES = "misc.pni_initialized_devices" + private const val LINKED_DEVICES_REMINDER = "misc.linked_devices_reminder" + private const val HAS_LINKED_DEVICES = "misc.linked_devices_present" + private const val USERNAME_QR_CODE_COLOR = "mis.username_qr_color_scheme" + private const val KEYBOARD_LANDSCAPE_HEIGHT = "misc.keyboard.landscape_height" + private const val KEYBOARD_PORTRAIT_HEIGHT = "misc.keyboard.protrait_height" + private const val LAST_CONSISTENCY_CHECK_TIME = "misc.last_consistency_check_time" + private const val SERVER_TIME_OFFSET = "misc.server_time_offset" + private const val LAST_SERVER_TIME_OFFSET_UPDATE = "misc.last_server_time_offset_update" + private const val NEEDS_USERNAME_RESTORE = "misc.needs_username_restore" + private const val LAST_FORCED_PREKEY_REFRESH = "misc.last_forced_prekey_refresh" + private const val LAST_CDS_FOREGROUND_SYNC = "misc.last_cds_foreground_sync" + private const val LINKED_DEVICE_LAST_ACTIVE_CHECK_TIME = "misc.linked_device.last_active_check_time" + private const val LEAST_ACTIVE_LINKED_DEVICE = "misc.linked_device.least_active" + } + + public override fun onFirstEverAppLaunch() { + putLong(MESSAGE_REQUEST_ENABLE_TIME, 0) + putBoolean(NEEDS_USERNAME_RESTORE, true) + } + + public override fun getKeysToIncludeInBackup(): List { + return emptyList() + } + + /** + * Represents the last time a _full_ prekey refreshed finished. That means signed+one-time prekeys for both ACI and PNI. + */ + var lastFullPrekeyRefreshTime by longValue(LAST_PREKEY_REFRESH_TIME, 0) + + val messageRequestEnableTime by longValue(MESSAGE_REQUEST_ENABLE_TIME, 0) + + /** + * Get the last time we successfully completed a forced prekey refresh. + */ + var lastForcedPreKeyRefresh by longValue(LAST_FORCED_PREKEY_REFRESH, 0) + + /** + * The last time we completed a routine profile refresh. + */ + var lastProfileRefreshTime by longValue(LAST_PROFILE_REFRESH_TIME, 0) + + /** + * Whether or not the client is currently in a 'deprecated' state, disallowing network access. + */ + open var isClientDeprecated: Boolean by booleanValue(CLIENT_DEPRECATED, false)//**TM_SA**//make open + + /** + * Whether or not we've locked the device after they've transferred to a new one. + */ + var isOldDeviceTransferLocked by booleanValue(OLD_DEVICE_TRANSFER_LOCKED, false) + + /** + * Whether or not the user has ever had an avatar. + */ + var hasEverHadAnAvatar by booleanValue(HAS_EVER_HAD_AN_AVATAR, false) + + val isChangeNumberLocked: Boolean by booleanValue(CHANGE_NUMBER_LOCK, false) + + fun lockChangeNumber() { + putBoolean(CHANGE_NUMBER_LOCK, true) + ChangeNumberConstraintObserver.onChange() + } + + fun unlockChangeNumber() { + putBoolean(CHANGE_NUMBER_LOCK, false) + ChangeNumberConstraintObserver.onChange() + } + + val pendingChangeNumberMetadata: PendingChangeNumberMetadata? + get() = getObject(PENDING_CHANGE_NUMBER_METADATA, null, PendingChangeNumberMetadataSerializer) + + /** Store pending new PNI data to be applied after successful change number */ + fun setPendingChangeNumberMetadata(metadata: PendingChangeNumberMetadata) { + putObject(PENDING_CHANGE_NUMBER_METADATA, metadata, PendingChangeNumberMetadataSerializer) + } + + /** Clear pending new PNI data after confirmed successful or failed change number */ + fun clearPendingChangeNumberMetadata() { + remove(PENDING_CHANGE_NUMBER_METADATA) + } + + /** + * The last time we checked if the service was reachable without censorship circumvention. + */ + var lastCensorshipServiceReachabilityCheckTime by longValue(CENSORSHIP_LAST_CHECK_TIME, 0) + + /** + * Whether or not the service is reachable without censorship circumvention. + */ + var isServiceReachableWithoutCircumvention by booleanValue(CENSORSHIP_SERVICE_REACHABLE, false) + + /** + * The last time we did a routing check to see if our GV2 groups have the latest version of our profile key. + */ + var lastGv2ProfileCheckTime by longValue(LAST_GV2_PROFILE_CHECK_TIME, 0) + + /** + * The CDS token that is used for rate-limiting. + */ + var cdsToken by nullableBlobValue(CDS_TOKEN, null) + + /** + * Indicates that a CDS request will never succeed at the current contact count. + */ + fun markCdsPermanentlyBlocked() { + putLong(CDS_BLOCKED_UNTIL, Long.MAX_VALUE) + } + + /** + * Clears any rate limiting state related to CDS. + */ + fun clearCdsBlocked() { + cdsBlockedUtil = 0 + } + + /** Whether or not we expect the next CDS request to succeed.*/ + val isCdsBlocked: Boolean + get() = cdsBlockedUtil > 0 + + /** + * This represents the next time we think we'll be able to make a successful CDS request. If it is before this time, we expect the request will fail + * (assuming the user still has the same number of new E164s). + */ + var cdsBlockedUtil by longValue(CDS_BLOCKED_UNTIL, 0) + + /** + * The last time the user foregrounded the app. + */ + var lastForegroundTime by longValue(LAST_FOREGROUND_TIME, 0) + + /** + * Whether or not we've done the initial "PNP Hello World" dance. + */ + var hasPniInitializedDevices by booleanValue(PNI_INITIALIZED_DEVICES, false) + + /** + * Whether or not the user has linked devices. + */ + var hasLinkedDevices by booleanValue(HAS_LINKED_DEVICES, false) + + /** + * Whether or not we should show a reminder for the user to relink their devices after re-registering. + */ + var shouldShowLinkedDevicesReminder by booleanValue(LINKED_DEVICES_REMINDER, false) + + /** + * The color the user saved for rendering their shareable username QR code. + */ + var usernameQrCodeColorScheme: UsernameQrCodeColorScheme + get() { + val serialized = getString(USERNAME_QR_CODE_COLOR, null) + return UsernameQrCodeColorScheme.deserialize(serialized) + } + set(color) { + putString(USERNAME_QR_CODE_COLOR, color.serialize()) + } + + /** + * Cached landscape keyboard height. + */ + var keyboardLandscapeHeight by integerValue(KEYBOARD_LANDSCAPE_HEIGHT, 0) + + /** + * Cached portrait keyboard height. + */ + var keyboardPortraitHeight by integerValue(KEYBOARD_PORTRAIT_HEIGHT, 0) + + /** + * The last time we ran an account consistency check via [org.tm.archive.jobs.AccountConsistencyWorkerJob] + */ + var lastConsistencyCheckTime by longValue(LAST_CONSISTENCY_CHECK_TIME, 0) + + /** + * The last-known offset between our local clock and the server. To get an estimate of the server time, take your current time and subtract this offset. e.g. + * + * estimatedServerTime = System.currentTimeMillis() - SignalStore.misc().getLastKnownServerTimeOffset() + */ + val lastKnownServerTimeOffset by longValue(SERVER_TIME_OFFSET, 0) + + /** + * The last time (using our local clock) we updated the server time offset returned by [.getLastKnownServerTimeOffset]}. + */ + val lastKnownServerTimeOffsetUpdateTime by longValue(LAST_SERVER_TIME_OFFSET_UPDATE, 0) + + /** + * Sets the last-known server time. + */ + fun setLastKnownServerTime(serverTime: Long, currentTime: Long) { + store + .beginWrite() + .putLong(SERVER_TIME_OFFSET, currentTime - serverTime) + .putLong(LAST_SERVER_TIME_OFFSET_UPDATE, System.currentTimeMillis()) + .apply() + } + + /** + * Whether or not we should attempt to restore the user's username and link. + */ + var needsUsernameRestore by booleanValue(NEEDS_USERNAME_RESTORE, false) + + /** + * How long it's been since the last foreground CDS sync, which we do in response to new threads being created. + */ + var lastCdsForegroundSyncTime by longValue(LAST_CDS_FOREGROUND_SYNC, 0) + + /** + * The last time we checked for linked device activity. + */ + var linkedDeviceLastActiveCheckTime by longValue(LINKED_DEVICE_LAST_ACTIVE_CHECK_TIME, 0) + + /** + * Details about the least-active linked device. + */ + var leastActiveLinkedDevice: LeastActiveLinkedDevice? by protoValue(LEAST_ACTIVE_LINKED_DEVICE, LeastActiveLinkedDevice.ADAPTER) +} diff --git a/app/src/main/java/org/tm/archive/keyvalue/PhoneNumberPrivacyValues.java b/app/src/main/java/org/tm/archive/keyvalue/PhoneNumberPrivacyValues.java index 175d47ce..de5125c3 100644 --- a/app/src/main/java/org/tm/archive/keyvalue/PhoneNumberPrivacyValues.java +++ b/app/src/main/java/org/tm/archive/keyvalue/PhoneNumberPrivacyValues.java @@ -9,9 +9,9 @@ import java.util.List; public final class PhoneNumberPrivacyValues extends SignalStoreValues { - public static final String SHARING_MODE = "phoneNumberPrivacy.sharingMode"; - public static final String LISTING_MODE = "phoneNumberPrivacy.listingMode"; - public static final String LISTING_TIMESTAMP = "phoneNumberPrivacy.listingMode.timestamp"; + public static final String SHARING_MODE = "phoneNumberPrivacy.sharingMode"; + public static final String DISCOVERABILITY_MODE = "phoneNumberPrivacy.listingMode"; + public static final String DISCOVERABILITY_TIMESTAMP = "phoneNumberPrivacy.listingMode.timestamp"; private static final Collection ACI_AND_E164_CERTIFICATE = Collections.singletonList(CertificateType.ACI_AND_E164); private static final Collection ACI_ONLY_CERTIFICATE = Collections.singletonList(CertificateType.ACI_ONLY); @@ -23,15 +23,14 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues { @Override void onFirstEverAppLaunch() { - // TODO [ALAN] PhoneNumberPrivacy: During registration, set the attribute to so that new registrations start out as not listed - //getStore().beginWrite() - // .putInteger(LISTING_MODE, PhoneNumberListingMode.UNLISTED.serialize()) - // .apply(); + getStore().beginWrite() + .putInteger(DISCOVERABILITY_MODE, PhoneNumberDiscoverabilityMode.UNDECIDED.serialize()) + .apply(); } @Override @NonNull List getKeysToIncludeInBackup() { - return Arrays.asList(SHARING_MODE, LISTING_MODE, LISTING_TIMESTAMP); + return Arrays.asList(SHARING_MODE, DISCOVERABILITY_MODE, DISCOVERABILITY_TIMESTAMP); } /** @@ -43,10 +42,9 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues { } public boolean isPhoneNumberSharingEnabled() { - // TODO [pnp] When we launch usernames, the default should return false return switch (getPhoneNumberSharingMode()) { - case DEFAULT, EVERYBODY -> true; - case NOBODY -> false; + case EVERYBODY -> true; + case DEFAULT, NOBODY -> false; }; } @@ -54,24 +52,21 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues { putInteger(SHARING_MODE, phoneNumberSharingMode.serialize()); } - public boolean isDiscoverableByPhoneNumber() { - return getPhoneNumberListingMode() == PhoneNumberPrivacyValues.PhoneNumberListingMode.LISTED; + public @NonNull PhoneNumberDiscoverabilityMode getPhoneNumberDiscoverabilityMode() { + // The default for existing users is to be discoverable, but new users are set to UNDECIDED in onFirstEverAppLaunch + return PhoneNumberDiscoverabilityMode.deserialize(getInteger(DISCOVERABILITY_MODE, PhoneNumberDiscoverabilityMode.DISCOVERABLE.serialize())); } - public @NonNull PhoneNumberListingMode getPhoneNumberListingMode() { - return PhoneNumberListingMode.deserialize(getInteger(LISTING_MODE, PhoneNumberListingMode.LISTED.serialize())); - } - - public void setPhoneNumberListingMode(@NonNull PhoneNumberListingMode phoneNumberListingMode) { + public void setPhoneNumberDiscoverabilityMode(@NonNull PhoneNumberDiscoverabilityMode phoneNumberDiscoverabilityMode) { getStore() .beginWrite() - .putInteger(LISTING_MODE, phoneNumberListingMode.serialize()) - .putLong(LISTING_TIMESTAMP, System.currentTimeMillis()) + .putInteger(DISCOVERABILITY_MODE, phoneNumberDiscoverabilityMode.serialize()) + .putLong(DISCOVERABILITY_TIMESTAMP, System.currentTimeMillis()) .apply(); } - public long getPhoneNumberListingModeTimestamp() { - return getLong(LISTING_TIMESTAMP, 0); + public long getPhoneNumberDiscoverabilityModeTimestamp() { + return getLong(DISCOVERABILITY_TIMESTAMP, 0); } /** @@ -119,30 +114,24 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues { } } - public enum PhoneNumberListingMode { - LISTED(0), - UNLISTED(1); + public enum PhoneNumberDiscoverabilityMode { + DISCOVERABLE(0), + NOT_DISCOVERABLE(1), + /** The user is going through registration and has not yet chosen a discoverability setting */ + UNDECIDED(2); private final int code; - PhoneNumberListingMode(int code) { + PhoneNumberDiscoverabilityMode(int code) { this.code = code; } - public boolean isDiscoverable() { - return this == LISTED; - } - - public boolean isUnlisted() { - return this == UNLISTED; - } - public int serialize() { return code; } - public static PhoneNumberListingMode deserialize(int code) { - for (PhoneNumberListingMode value : PhoneNumberListingMode.values()) { + public static PhoneNumberDiscoverabilityMode deserialize(int code) { + for (PhoneNumberDiscoverabilityMode value : PhoneNumberDiscoverabilityMode.values()) { if (value.code == code) { return value; } diff --git a/app/src/main/java/org/tm/archive/keyvalue/PinValues.java b/app/src/main/java/org/tm/archive/keyvalue/PinValues.java index a96a7399..aea44171 100644 --- a/app/src/main/java/org/tm/archive/keyvalue/PinValues.java +++ b/app/src/main/java/org/tm/archive/keyvalue/PinValues.java @@ -98,7 +98,19 @@ public final class PinValues extends SignalStoreValues { } public @NonNull PinKeyboardType getKeyboardType() { - return PinKeyboardType.fromCode(getStore().getString(KEYBOARD_TYPE, null)); + String pin = SignalStore.svr().getPin(); + + if (pin == null) { + return PinKeyboardType.fromCode(getStore().getString(KEYBOARD_TYPE, null)); + } + + for (char c : pin.toCharArray()) { + if (!Character.isDigit(c)) { + return PinKeyboardType.ALPHA_NUMERIC; + } + } + + return PinKeyboardType.NUMERIC; } public void setNextReminderIntervalToAtMost(long maxInterval) { diff --git a/app/src/main/java/org/tm/archive/keyvalue/SettingsValues.java b/app/src/main/java/org/tm/archive/keyvalue/SettingsValues.java index 57214deb..0912ce8e 100644 --- a/app/src/main/java/org/tm/archive/keyvalue/SettingsValues.java +++ b/app/src/main/java/org/tm/archive/keyvalue/SettingsValues.java @@ -65,7 +65,6 @@ public final class SettingsValues extends SignalStoreValues { public static final String CALL_RINGTONE = "settings.call.ringtone"; public static final String CALL_VIBRATE_ENABLED = "settings.call.vibrate.enabled"; public static final String NOTIFY_WHEN_CONTACT_JOINS_SIGNAL = "settings.notify.when.contact.joins.signal"; - private static final String DEFAULT_SMS = "settings.default_sms"; private static final String UNIVERSAL_EXPIRE_TIMER = "settings.universal.expire.timer"; private static final String SENT_MEDIA_QUALITY = "settings.sentMediaQuality"; private static final String CENSORSHIP_CIRCUMVENTION_ENABLED = "settings.censorshipCircumventionEnabled"; @@ -411,26 +410,6 @@ public final class SettingsValues extends SignalStoreValues { putBoolean(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, notifyWhenContactJoinsSignal); } - /** - * We need to keep track of when the default status changes so we can sync to storage service. - * So call this when you think it might have changed, but *don't* rely on it for knowing if we - * *are* the default SMS. For that, continue to use - * {@link org.tm.archive.util.Util#isDefaultSmsProvider(Context)}. - */ - public void setDefaultSms(boolean value) { - boolean lastKnown = getBoolean(DEFAULT_SMS, false); - - if (value != lastKnown && SignalStore.registrationValues().isRegistrationComplete()) { - Log.i(TAG, "Default SMS state changed! Scheduling a storage sync."); - putBoolean(DEFAULT_SMS, value); - - SignalExecutors.BOUNDED.execute(() -> { - SignalDatabase.recipients().markNeedsSync(Recipient.self().getId()); - StorageSyncHelper.scheduleSyncForDataChange(); - }); - } - } - public void setUniversalExpireTimer(int seconds) { putInteger(UNIVERSAL_EXPIRE_TIMER, seconds); } diff --git a/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValueDelegates.kt b/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValueDelegates.kt index 4aef02cc..3feba025 100644 --- a/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValueDelegates.kt +++ b/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValueDelegates.kt @@ -28,6 +28,10 @@ internal fun SignalStoreValues.blobValue(key: String, default: ByteArray): Signa return BlobValue(key, default, this.store) } +internal fun SignalStoreValues.nullableBlobValue(key: String, default: ByteArray?): SignalStoreValueDelegate { + return NullableBlobValue(key, default, this.store) +} + internal fun SignalStoreValues.enumValue(key: String, default: T, serializer: LongSerializer): SignalStoreValueDelegate { return KeyValueEnumValue(key, default, serializer, this.store) } @@ -114,6 +118,16 @@ private class BlobValue(private val key: String, private val default: ByteArray, } } +private class NullableBlobValue(private val key: String, private val default: ByteArray?, store: KeyValueStore) : SignalStoreValueDelegate(store) { + override fun getValue(values: KeyValueStore): ByteArray? { + return values.getBlob(key, default) + } + + override fun setValue(values: KeyValueStore, value: ByteArray?) { + values.beginWrite().putBlob(key, value).apply() + } +} + private class KeyValueProtoValue( private val key: String, private val adapter: ProtoAdapter, diff --git a/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValues.java b/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValues.java index a4d8fad4..1c00c07d 100644 --- a/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValues.java +++ b/app/src/main/java/org/tm/archive/keyvalue/SignalStoreValues.java @@ -12,7 +12,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -abstract class SignalStoreValues { +public abstract class SignalStoreValues {//**TM_SA**//make public private final KeyValueStore store; diff --git a/app/src/main/java/org/tm/archive/keyvalue/SmsExportPhase.kt b/app/src/main/java/org/tm/archive/keyvalue/SmsExportPhase.kt deleted file mode 100644 index 1cdbaa53..00000000 --- a/app/src/main/java/org/tm/archive/keyvalue/SmsExportPhase.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.tm.archive.keyvalue - -enum class SmsExportPhase(val duration: Long) { - PHASE_3(0); - - fun allowSmsFeatures(): Boolean { - return false - } - - fun isSmsSupported(): Boolean { - return false - } - - fun isBlockingUi(): Boolean { - return true - } - - companion object { - @JvmStatic - fun getCurrentPhase(): SmsExportPhase { - return PHASE_3 - } - } -} diff --git a/app/src/main/java/org/tm/archive/keyvalue/UiHints.java b/app/src/main/java/org/tm/archive/keyvalue/UiHints.java index 726e86e2..20792b39 100644 --- a/app/src/main/java/org/tm/archive/keyvalue/UiHints.java +++ b/app/src/main/java/org/tm/archive/keyvalue/UiHints.java @@ -14,7 +14,6 @@ public class UiHints extends SignalStoreValues { private static final String HAS_SET_OR_SKIPPED_USERNAME_CREATION = "uihints.has_set_or_skipped_username_creation"; private static final String NEVER_DISPLAY_PULL_TO_FILTER_TIP = "uihints.never_display_pull_to_filter_tip"; private static final String HAS_SEEN_SCHEDULED_MESSAGES_INFO_ONCE = "uihints.has_seen_scheduled_messages_info_once"; - private static final String HAS_SEEN_USERNAME_EDUCATION = "uihints.has_seen_username_education"; private static final String HAS_SEEN_TEXT_FORMATTING_ALERT = "uihints.text_formatting.has_seen_alert"; private static final String HAS_NOT_SEEN_EDIT_MESSAGE_BETA_ALERT = "uihints.edit_message.has_not_seen_beta_alert"; private static final String HAS_SEEN_SAFETY_NUMBER_NUX = "uihints.has_seen_safety_number_nux"; @@ -23,6 +22,7 @@ public class UiHints extends SignalStoreValues { private static final String DISMISSED_BATTERY_SAVER_PROMPT = "uihints.declined_battery_saver_prompt"; private static final String LAST_BATTERY_SAVER_PROMPT = "uihints.last_battery_saver_prompt"; private static final String LAST_CRASH_PROMPT = "uihints.last_crash_prompt"; + private static final String HAS_COMPLETED_USERNAME_ONBOARDING = "uihints.has_completed_username_onboarding"; UiHints(@NonNull KeyValueStore store) { super(store); @@ -35,7 +35,7 @@ public class UiHints extends SignalStoreValues { @Override @NonNull List getKeysToIncludeInBackup() { - return Arrays.asList(NEVER_DISPLAY_PULL_TO_FILTER_TIP, HAS_SEEN_USERNAME_EDUCATION, HAS_SEEN_TEXT_FORMATTING_ALERT); + return Arrays.asList(NEVER_DISPLAY_PULL_TO_FILTER_TIP, HAS_COMPLETED_USERNAME_ONBOARDING, HAS_SEEN_TEXT_FORMATTING_ALERT); } public void markHasSeenGroupSettingsMenuToast() { @@ -70,19 +70,14 @@ public class UiHints extends SignalStoreValues { putBoolean(HAS_SET_OR_SKIPPED_USERNAME_CREATION, true); } - public void markHasSeenUsernameEducation() { - putBoolean(HAS_SEEN_USERNAME_EDUCATION, true); + public void setHasCompletedUsernameOnboarding(boolean value) { + putBoolean(HAS_COMPLETED_USERNAME_ONBOARDING, value); } - public boolean hasSeenUsernameEducation() { - return getBoolean(HAS_SEEN_USERNAME_EDUCATION, false); + public boolean hasCompletedUsernameOnboarding() { + return getBoolean(HAS_COMPLETED_USERNAME_ONBOARDING, false); } - public void clearHasSeenUsernameEducation() { - putBoolean(HAS_SEEN_USERNAME_EDUCATION, false); - } - - public void resetNeverDisplayPullToRefreshCount() { putInteger(NEVER_DISPLAY_PULL_TO_FILTER_TIP, 0); } diff --git a/app/src/main/java/org/tm/archive/linkpreview/LinkPreviewRepository.java b/app/src/main/java/org/tm/archive/linkpreview/LinkPreviewRepository.java index fb5a3e2c..051d3ae1 100644 --- a/app/src/main/java/org/tm/archive/linkpreview/LinkPreviewRepository.java +++ b/app/src/main/java/org/tm/archive/linkpreview/LinkPreviewRepository.java @@ -9,6 +9,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.util.Consumer; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.signal.core.util.Hex; @@ -35,7 +36,6 @@ import org.tm.archive.groups.v2.GroupInviteLinkUrl; import org.tm.archive.jobs.AvatarGroupsV2DownloadJob; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.linkpreview.LinkPreviewUtil.OpenGraph; -import org.tm.archive.mms.GlideApp; import org.tm.archive.mms.PushMediaConstraints; import org.tm.archive.net.CallRequestController; import org.tm.archive.net.CompositeRequestController; @@ -190,7 +190,15 @@ public class LinkPreviewRepository { return; } - String body = OkHttpUtil.readAsString(response.body(), FAILSAFE_MAX_TEXT_SIZE); + String body; + try { + body = OkHttpUtil.readAsString(response.body(), FAILSAFE_MAX_TEXT_SIZE); + } catch (IOException e) { + Log.w(TAG, "Failed to read body", e); + callback.accept(Metadata.empty()); + return; + } + OpenGraph openGraph = LinkPreviewUtil.parseOpenGraphFields(body); Optional title = openGraph.getTitle(); Optional description = openGraph.getDescription(); @@ -236,7 +244,7 @@ public class LinkPreviewRepository { bitmap, maxDimension, mediaConfig.getMaxImageFileSize(), - mediaConfig.getQualitySetting() + mediaConfig.getImageQualitySetting() ); if (result != null) { @@ -279,7 +287,7 @@ public class LinkPreviewRepository { Optional cover = OptionalUtil.or(manifest.getCover(), firstSticker); if (cover.isPresent()) { - Bitmap bitmap = GlideApp.with(context).asBitmap() + Bitmap bitmap = Glide.with(context).asBitmap() .load(new StickerRemoteUri(packIdString, packKeyString, cover.get().getId())) .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) diff --git a/app/src/main/java/org/tm/archive/lock/v2/ConfirmSvrPinFragment.kt b/app/src/main/java/org/tm/archive/lock/v2/ConfirmSvrPinFragment.kt index 8d0a9628..5b49b686 100644 --- a/app/src/main/java/org/tm/archive/lock/v2/ConfirmSvrPinFragment.kt +++ b/app/src/main/java/org/tm/archive/lock/v2/ConfirmSvrPinFragment.kt @@ -107,7 +107,7 @@ internal class ConfirmSvrPinFragment : BaseSvrPinFragment + .setPositiveButton(android.R.string.ok) { d: DialogInterface, w: Int -> d.dismiss() markMegaphoneSeenIfNecessary() requireActivity().setResult(Activity.RESULT_CANCELED) diff --git a/app/src/main/java/org/tm/archive/logsubmit/LogSectionCapabilities.java b/app/src/main/java/org/tm/archive/logsubmit/LogSectionCapabilities.java index 43f0265b..7a06b724 100644 --- a/app/src/main/java/org/tm/archive/logsubmit/LogSectionCapabilities.java +++ b/app/src/main/java/org/tm/archive/logsubmit/LogSectionCapabilities.java @@ -34,21 +34,12 @@ public final class LogSectionCapabilities implements LogSection { RecipientRecord.Capabilities globalCapabilities = SignalDatabase.recipients().getCapabilities(self.getId()); StringBuilder builder = new StringBuilder().append("-- Local").append("\n") - .append("Sender Key : ").append(localCapabilities.getSenderKey()).append("\n") - .append("Announcement Groups: ").append(localCapabilities.getAnnouncementGroup()).append("\n") - .append("Change Number : ").append(localCapabilities.getChangeNumber()).append("\n") - .append("Stories : ").append(localCapabilities.getStories()).append("\n") - .append("Gift Badges : ").append(localCapabilities.getGiftBadges()).append("\n") + .append("PNP/PNI: ").append(localCapabilities.getPni()).append("\n") .append("\n") .append("-- Global").append("\n"); if (globalCapabilities != null) { - builder.append("GV1 Migration : ").append(globalCapabilities.getGroupsV1MigrationCapability()).append("\n") - .append("Sender Key : ").append(globalCapabilities.getSenderKeyCapability()).append("\n") - .append("Announcement Groups: ").append(globalCapabilities.getAnnouncementGroupCapability()).append("\n") - .append("Change Number : ").append(globalCapabilities.getChangeNumberCapability()).append("\n") - .append("Stories : ").append(globalCapabilities.getStoriesCapability()).append("\n") - .append("Gift Badges : ").append(globalCapabilities.getGiftBadgesCapability()).append("\n"); + builder.append("PNP/PNI: ").append(globalCapabilities.getPnpCapability()).append("\n"); } else { builder.append("Self not found!"); } diff --git a/app/src/main/java/org/tm/archive/logsubmit/LogSectionKeyPreferences.java b/app/src/main/java/org/tm/archive/logsubmit/LogSectionKeyPreferences.java index 05a66eca..cdfc3a96 100644 --- a/app/src/main/java/org/tm/archive/logsubmit/LogSectionKeyPreferences.java +++ b/app/src/main/java/org/tm/archive/logsubmit/LogSectionKeyPreferences.java @@ -19,22 +19,24 @@ final class LogSectionKeyPreferences implements LogSection { @Override public @NonNull CharSequence getContent(@NonNull Context context) { - return new StringBuilder().append("Screen Lock : ").append(TextSecurePreferences.isScreenLockEnabled(context)).append("\n") - .append("Screen Lock Timeout : ").append(TextSecurePreferences.getScreenLockTimeout(context)).append("\n") - .append("Password Disabled : ").append(TextSecurePreferences.isPasswordDisabled(context)).append("\n") - .append("Prefer Contact Photos: ").append(SignalStore.settings().isPreferSystemContactPhotos()).append("\n") - .append("Call Data Mode : ").append(SignalStore.settings().getCallDataMode()).append("\n") - .append("Media Quality : ").append(SignalStore.settings().getSentMediaQuality()).append("\n") - .append("Client Deprecated : ").append(SignalStore.misc().isClientDeprecated()).append("\n") - .append("Push Registered : ").append(SignalStore.account().isRegistered()).append("\n") - .append("Unauthorized Received: ").append(TextSecurePreferences.isUnauthorizedReceived(context)).append("\n") - .append("self.isRegistered() : ").append(SignalStore.account().getAci() == null ? "false" : Recipient.self().isRegistered()).append("\n") - .append("Thread Trimming : ").append(getThreadTrimmingString()).append("\n") - .append("Censorship Setting : ").append(SignalStore.settings().getCensorshipCircumventionEnabled()).append("\n") - .append("Network Reachable : ").append(SignalStore.misc().isServiceReachableWithoutCircumvention()).append(", last checked: ").append(SignalStore.misc().getLastCensorshipServiceReachabilityCheckTime()).append("\n") - .append("Wifi Download : ").append(Util.join(TextSecurePreferences.getWifiMediaDownloadAllowed(context), ",")).append("\n") - .append("Roaming Download : ").append(Util.join(TextSecurePreferences.getRoamingMediaDownloadAllowed(context), ",")).append("\n") - .append("Mobile Download : ").append(Util.join(TextSecurePreferences.getMobileMediaDownloadAllowed(context), ",")).append("\n"); + return new StringBuilder().append("Screen Lock : ").append(TextSecurePreferences.isScreenLockEnabled(context)).append("\n") + .append("Screen Lock Timeout : ").append(TextSecurePreferences.getScreenLockTimeout(context)).append("\n") + .append("Password Disabled : ").append(TextSecurePreferences.isPasswordDisabled(context)).append("\n") + .append("Prefer Contact Photos : ").append(SignalStore.settings().isPreferSystemContactPhotos()).append("\n") + .append("Call Data Mode : ").append(SignalStore.settings().getCallDataMode()).append("\n") + .append("Media Quality : ").append(SignalStore.settings().getSentMediaQuality()).append("\n") + .append("Client Deprecated : ").append(SignalStore.misc().isClientDeprecated()).append("\n") + .append("Push Registered : ").append(SignalStore.account().isRegistered()).append("\n") + .append("Unauthorized Received : ").append(TextSecurePreferences.isUnauthorizedReceived(context)).append("\n") + .append("self.isRegistered() : ").append(SignalStore.account().getAci() == null ? "false" : Recipient.self().isRegistered()).append("\n") + .append("Thread Trimming : ").append(getThreadTrimmingString()).append("\n") + .append("Censorship Setting : ").append(SignalStore.settings().getCensorshipCircumventionEnabled()).append("\n") + .append("Network Reachable : ").append(SignalStore.misc().isServiceReachableWithoutCircumvention()).append(", last checked: ").append(SignalStore.misc().getLastCensorshipServiceReachabilityCheckTime()).append("\n") + .append("Wifi Download : ").append(Util.join(TextSecurePreferences.getWifiMediaDownloadAllowed(context), ",")).append("\n") + .append("Roaming Download : ").append(Util.join(TextSecurePreferences.getRoamingMediaDownloadAllowed(context), ",")).append("\n") + .append("Mobile Download : ").append(Util.join(TextSecurePreferences.getMobileMediaDownloadAllowed(context), ",")).append("\n") + .append("Phone Number Sharing : ").append(SignalStore.phoneNumberPrivacy().isPhoneNumberSharingEnabled()).append(" (").append(SignalStore.phoneNumberPrivacy().getPhoneNumberSharingMode()).append(")\n") + .append("Phone Number Discoverable: ").append(SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode()).append("\n"); } private static String getThreadTrimmingString() { diff --git a/app/src/main/java/org/tm/archive/logsubmit/LogSectionSMS.kt b/app/src/main/java/org/tm/archive/logsubmit/LogSectionSMS.kt deleted file mode 100644 index 3e799ed9..00000000 --- a/app/src/main/java/org/tm/archive/logsubmit/LogSectionSMS.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.tm.archive.logsubmit - -import android.content.Context -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.util.Util - -/** - * Prints off the current SMS settings - */ - -class LogSectionSMS : LogSection { - override fun getTitle(): String = "SMS" - - override fun getContent(context: Context): CharSequence { - val isDefaultSMS = Util.isDefaultSmsProvider(context) - val settings = SignalStore.settings() - val output = StringBuilder() - - output.append("Default SMS : ${isDefaultSMS}\n") - output.append("SMS delivery reports : ${settings.isSmsDeliveryReportsEnabled}\n") - output.append("WiFi SMS : ${settings.isWifiCallingCompatibilityModeEnabled}\n") - - return output - } -} diff --git a/app/src/main/java/org/tm/archive/logsubmit/LogSectionSystemInfo.java b/app/src/main/java/org/tm/archive/logsubmit/LogSectionSystemInfo.java index 9df0201a..77375da5 100644 --- a/app/src/main/java/org/tm/archive/logsubmit/LogSectionSystemInfo.java +++ b/app/src/main/java/org/tm/archive/logsubmit/LogSectionSystemInfo.java @@ -91,6 +91,7 @@ public class LogSectionSystemInfo implements LogSection { builder.append("User-Agent : ").append(StandardUserAgentInterceptor.USER_AGENT).append("\n"); builder.append("SlowNotifications : ").append(SlowNotificationHeuristics.isHavingDelayedNotifications()).append("\n"); builder.append("PotentiallyBattery: ").append(SlowNotificationHeuristics.isPotentiallyCausedByBatteryOptimizations()).append("\n"); + builder.append("APNG Animation : ").append(DeviceProperties.shouldAllowApngStickerAnimation(context)).append("\n"); if (BuildConfig.MANAGES_APP_UPDATES) { builder.append("ApkManifestUrl : ").append(BuildConfig.APK_UPDATE_MANIFEST_URL).append("\n"); } diff --git a/app/src/main/java/org/tm/archive/logsubmit/SubmitDebugLogRepository.java b/app/src/main/java/org/tm/archive/logsubmit/SubmitDebugLogRepository.java index 08f5d0ae..c34b47e3 100644 --- a/app/src/main/java/org/tm/archive/logsubmit/SubmitDebugLogRepository.java +++ b/app/src/main/java/org/tm/archive/logsubmit/SubmitDebugLogRepository.java @@ -86,7 +86,6 @@ public class SubmitDebugLogRepository { add(new LogSectionNotificationProfiles()); add(new LogSectionExoPlayerPool()); add(new LogSectionKeyPreferences()); - add(new LogSectionSMS()); add(new LogSectionStories()); add(new LogSectionBadges()); add(new LogSectionPermissions()); diff --git a/app/src/main/java/org/tm/archive/longmessage/LongMessageFragment.java b/app/src/main/java/org/tm/archive/longmessage/LongMessageFragment.java index abbd0f44..be7c8db7 100644 --- a/app/src/main/java/org/tm/archive/longmessage/LongMessageFragment.java +++ b/app/src/main/java/org/tm/archive/longmessage/LongMessageFragment.java @@ -3,8 +3,6 @@ package org.tm.archive.longmessage; import android.graphics.PorterDuff; import android.os.Bundle; import android.text.SpannableString; -import android.text.style.URLSpan; -import android.text.util.Linkify; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; @@ -13,21 +11,19 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; -import androidx.core.text.util.LinkifyCompat; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProvider; -import com.annimon.stream.Stream; - import org.tm.archive.R; import org.tm.archive.components.ConversationItemFooter; import org.tm.archive.components.FullScreenDialogFragment; import org.tm.archive.components.emoji.EmojiTextView; import org.tm.archive.conversation.ConversationItemDisplayMode; import org.tm.archive.conversation.colors.ColorizerView; +import org.tm.archive.conversation.v2.items.V2ConversationItemUtils; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.Recipient; -import org.tm.archive.util.LinkUtil; +import org.tm.archive.util.CommunicationActions; import org.tm.archive.util.LongClickMovementMethod; import org.tm.archive.util.Projection; import org.tm.archive.util.ThemeUtil; @@ -126,11 +122,14 @@ public class LongMessageFragment extends FullScreenDialogFragment { EmojiTextView text = bubble.findViewById(R.id.longmessage_text); ConversationItemFooter footer = bubble.findViewById(R.id.longmessage_footer); - CharSequence trimmedBody = getTrimmedBody(message.get().getFullBody(requireContext())); - SpannableString styledBody = linkifyMessageBody(new SpannableString(trimmedBody)); + SpannableString body = new SpannableString(getTrimmedBody(message.get().getFullBody(requireContext()))); + V2ConversationItemUtils.linkifyUrlLinks(body, + true, + url -> CommunicationActions.handlePotentialGroupLinkUrl(requireActivity(), url) || + CommunicationActions.handlePotentialProxyLinkUrl(requireActivity(), url)); bubble.setVisibility(View.VISIBLE); - text.setText(styledBody); + text.setText(body); text.setMovementMethod(LongClickMovementMethod.getInstance(getContext())); text.setTextSize(TypedValue.COMPLEX_UNIT_SP, SignalStore.settings().getMessageFontSize()); if (!message.get().getMessageRecord().isOutgoing()) { @@ -147,18 +146,6 @@ public class LongMessageFragment extends FullScreenDialogFragment { : text.subSequence(0, MAX_DISPLAY_LENGTH); } - private SpannableString linkifyMessageBody(SpannableString messageBody) { - int linkPattern = Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS; - boolean hasLinks = LinkifyCompat.addLinks(messageBody, linkPattern); - - if (hasLinks) { - Stream.of(messageBody.getSpans(0, messageBody.length(), URLSpan.class)) - .filterNot(url -> LinkUtil.isLegalUrl(url.getURL())) - .forEach(messageBody::removeSpan); - } - return messageBody; - } - private final class BubbleLayoutListener implements View.OnLayoutChangeListener { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { diff --git a/app/src/main/java/org/tm/archive/maps/PlacePickerActivity.java b/app/src/main/java/org/tm/archive/maps/PlacePickerActivity.java index a8fde950..3aa761a5 100644 --- a/app/src/main/java/org/tm/archive/maps/PlacePickerActivity.java +++ b/app/src/main/java/org/tm/archive/maps/PlacePickerActivity.java @@ -32,6 +32,7 @@ import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MapStyleOptions; +import org.signal.core.util.concurrent.ListenableFuture; import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.components.location.SignalMapView; @@ -40,7 +41,6 @@ import org.tm.archive.util.BitmapUtil; import org.tm.archive.util.DynamicNoActionBarTheme; import org.tm.archive.util.DynamicTheme; import org.tm.archive.util.MediaUtil; -import org.tm.archive.util.concurrent.ListenableFuture; import org.tm.archive.util.views.SimpleProgressDialog; import java.io.IOException; diff --git a/app/src/main/java/org/tm/archive/media/DecryptableUriMediaInput.java b/app/src/main/java/org/tm/archive/media/DecryptableUriMediaInput.java deleted file mode 100644 index abcc219f..00000000 --- a/app/src/main/java/org/tm/archive/media/DecryptableUriMediaInput.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.tm.archive.media; - -import android.content.Context; -import android.media.MediaDataSource; -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; - -import org.tm.archive.attachments.AttachmentId; -import org.tm.archive.database.SignalDatabase; -import org.tm.archive.mms.PartAuthority; -import org.tm.archive.mms.PartUriParser; -import org.tm.archive.providers.BlobProvider; - -import java.io.IOException; - -@RequiresApi(api = 23) -public final class DecryptableUriMediaInput { - - private DecryptableUriMediaInput() { - } - - public static @NonNull MediaInput createForUri(@NonNull Context context, @NonNull Uri uri) throws IOException { - - if (BlobProvider.isAuthority(uri)) { - return new MediaInput.MediaDataSourceMediaInput(BlobProvider.getInstance().getMediaDataSource(context, uri)); - } - - if (PartAuthority.isLocalUri(uri)) { - return createForAttachmentUri(context, uri); - } - - return new MediaInput.UriMediaInput(context, uri); - } - - private static @NonNull MediaInput createForAttachmentUri(@NonNull Context context, @NonNull Uri uri) { - AttachmentId partId = new PartUriParser(uri).getPartId(); - - if (!partId.isValid()) { - throw new AssertionError(); - } - - MediaDataSource mediaDataSource = SignalDatabase.attachments().mediaDataSourceFor(partId, true); - - if (mediaDataSource == null) { - throw new AssertionError(); - } - - return new MediaInput.MediaDataSourceMediaInput(mediaDataSource); - } -} diff --git a/app/src/main/java/org/tm/archive/media/DecryptableUriMediaInput.kt b/app/src/main/java/org/tm/archive/media/DecryptableUriMediaInput.kt new file mode 100644 index 00000000..63acb7b4 --- /dev/null +++ b/app/src/main/java/org/tm/archive/media/DecryptableUriMediaInput.kt @@ -0,0 +1,40 @@ +package org.tm.archive.media + +import android.content.Context +import android.net.Uri +import androidx.annotation.RequiresApi +import org.tm.archive.database.SignalDatabase.Companion.attachments +import org.tm.archive.mms.PartAuthority +import org.tm.archive.mms.PartUriParser +import org.tm.archive.providers.BlobProvider +import org.tm.archive.video.interfaces.MediaInput +import org.tm.archive.video.videoconverter.mediadatasource.MediaDataSourceMediaInput +import java.io.IOException + +/** + * A media input source that is decrypted on the fly. + */ +@RequiresApi(api = 23) +object DecryptableUriMediaInput { + @JvmStatic + @Throws(IOException::class) + fun createForUri(context: Context, uri: Uri): MediaInput { + if (BlobProvider.isAuthority(uri)) { + return MediaDataSourceMediaInput(BlobProvider.getInstance().getMediaDataSource(context, uri)) + } + return if (PartAuthority.isLocalUri(uri)) { + createForAttachmentUri(uri) + } else { + UriMediaInput(context, uri) + } + } + + private fun createForAttachmentUri(uri: Uri): MediaInput { + val partId = PartUriParser(uri).partId + if (!partId.isValid) { + throw AssertionError() + } + val mediaDataSource = attachments.mediaDataSourceFor(partId, true) ?: throw AssertionError() + return MediaDataSourceMediaInput(mediaDataSource) + } +} diff --git a/app/src/main/java/org/tm/archive/media/FileMediaInput.kt b/app/src/main/java/org/tm/archive/media/FileMediaInput.kt new file mode 100644 index 00000000..97ef693c --- /dev/null +++ b/app/src/main/java/org/tm/archive/media/FileMediaInput.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ +package org.tm.archive.media + +import android.media.MediaExtractor +import org.tm.archive.video.interfaces.MediaInput +import java.io.File +import java.io.IOException + +/** + * A media input source that the system reads directly from the file. + */ +class FileMediaInput(private val file: File) : MediaInput { + @Throws(IOException::class) + override fun createExtractor(): MediaExtractor { + val extractor = MediaExtractor() + extractor.setDataSource(file.absolutePath) + return extractor + } + + override fun hasSameInput(other: MediaInput): Boolean { + return other is FileMediaInput && other.file == this.file + } + + override fun close() {} +} diff --git a/app/src/main/java/org/tm/archive/media/MediaInput.java b/app/src/main/java/org/tm/archive/media/MediaInput.java deleted file mode 100644 index fa33b205..00000000 --- a/app/src/main/java/org/tm/archive/media/MediaInput.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.tm.archive.media; - -import android.content.Context; -import android.media.MediaDataSource; -import android.media.MediaExtractor; -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; - -public abstract class MediaInput implements Closeable { - - @NonNull - public abstract MediaExtractor createExtractor() throws IOException; - - public static class FileMediaInput extends MediaInput { - - private final File file; - - public FileMediaInput(@NonNull File file) { - this.file = file; - } - - @Override - public @NonNull MediaExtractor createExtractor() throws IOException { - final MediaExtractor extractor = new MediaExtractor(); - extractor.setDataSource(file.getAbsolutePath()); - return extractor; - } - - @Override - public void close() { - } - } - - public static class UriMediaInput extends MediaInput { - - private final Uri uri; - private final Context context; - - public UriMediaInput(@NonNull Context context, @NonNull Uri uri) { - this.uri = uri; - this.context = context; - } - - @Override - public @NonNull MediaExtractor createExtractor() throws IOException { - final MediaExtractor extractor = new MediaExtractor(); - extractor.setDataSource(context, uri, null); - return extractor; - } - - @Override - public void close() { - } - } - - @RequiresApi(23) - public static class MediaDataSourceMediaInput extends MediaInput { - - private final MediaDataSource mediaDataSource; - - public MediaDataSourceMediaInput(@NonNull MediaDataSource mediaDataSource) { - this.mediaDataSource = mediaDataSource; - } - - @Override - public @NonNull MediaExtractor createExtractor() throws IOException { - final MediaExtractor extractor = new MediaExtractor(); - extractor.setDataSource(mediaDataSource); - return extractor; - } - - @Override - public void close() throws IOException { - mediaDataSource.close(); - } - } -} diff --git a/app/src/main/java/org/tm/archive/media/UriMediaInput.kt b/app/src/main/java/org/tm/archive/media/UriMediaInput.kt new file mode 100644 index 00000000..626dfb8f --- /dev/null +++ b/app/src/main/java/org/tm/archive/media/UriMediaInput.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ +package org.tm.archive.media + +import android.content.Context +import android.media.MediaExtractor +import android.net.Uri +import org.tm.archive.video.interfaces.MediaInput +import java.io.IOException + +/** + * A media input source defined by a [Uri] that the system can parse and access. + */ +class UriMediaInput(private val context: Context, private val uri: Uri) : MediaInput { + @Throws(IOException::class) + override fun createExtractor(): MediaExtractor { + val extractor = MediaExtractor() + extractor.setDataSource(context, uri, null) + return extractor + } + + override fun hasSameInput(other: MediaInput): Boolean { + return other is UriMediaInput && other.uri == this.uri + } + + override fun close() = Unit +} diff --git a/app/src/main/java/org/tm/archive/mediaoverview/MediaGalleryAllAdapter.java b/app/src/main/java/org/tm/archive/mediaoverview/MediaGalleryAllAdapter.java index 0930fddb..8bfd7416 100644 --- a/app/src/main/java/org/tm/archive/mediaoverview/MediaGalleryAllAdapter.java +++ b/app/src/main/java/org/tm/archive/mediaoverview/MediaGalleryAllAdapter.java @@ -32,6 +32,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.annimon.stream.Collectors; import com.annimon.stream.Stream; +import com.bumptech.glide.RequestManager; import com.codewaves.stickyheadergrid.StickyHeaderGridAdapter; import org.signal.libsignal.protocol.util.Pair; @@ -45,7 +46,6 @@ import org.tm.archive.database.MediaTable.MediaRecord; import org.tm.archive.database.loaders.GroupedThreadMediaLoader.GroupedThreadMedia; import org.tm.archive.mediapreview.MediaPreviewCache; import org.tm.archive.mms.AudioSlide; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.mms.Slide; import org.tm.archive.recipients.LiveRecipient; import org.tm.archive.recipients.Recipient; @@ -70,7 +70,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { private final Context context; private final boolean showThread; - private final GlideRequests glideRequests; + private final RequestManager requestManager; private final ItemClickListener itemClickListener; private final Map selected = new HashMap<>(); private final AudioItemListener audioItemListener; @@ -102,7 +102,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { } MediaGalleryAllAdapter(@NonNull Context context, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, GroupedThreadMedia media, ItemClickListener clickListener, @NonNull AudioItemListener audioItemListener, @@ -110,7 +110,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { boolean showThread) { this.context = context; - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.media = media; this.itemClickListener = clickListener; this.audioItemListener = audioItemListener; @@ -345,7 +345,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { imageFileSize.setVisibility(View.GONE); } - thumbnailView.setImageResource(glideRequests, slide, false, false); + thumbnailView.setImageResource(requestManager, slide, false, false); thumbnailView.setOnClickListener(view -> { MediaPreviewCache.INSTANCE.setDrawable(thumbnailView.getImageDrawable()); itemClickListener.onMediaClicked(thumbnailView, mediaRecord); @@ -366,13 +366,13 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { @Override void rebind() { - thumbnailView.setImageResource(glideRequests, slide, false, false); + thumbnailView.setImageResource(requestManager, slide, false, false); super.rebind(); } @Override void unbind() { - thumbnailView.clear(glideRequests); + thumbnailView.clear(requestManager); super.unbind(); } @@ -591,7 +591,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { public void bind(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @NonNull Slide slide) { super.bind(context, mediaRecord, slide); this.slide = slide; - thumbnailView.setImageResource(glideRequests, slide, false, false); + thumbnailView.setImageResource(requestManager, slide, false, false); thumbnailView.setOnClickListener(view -> itemClickListener.onMediaClicked(thumbnailView, mediaRecord)); thumbnailView.setOnLongClickListener(view -> onLongClick()); } @@ -611,13 +611,13 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { @Override void rebind() { - thumbnailView.setImageResource(glideRequests, slide, false, false); + thumbnailView.setImageResource(requestManager, slide, false, false); super.rebind(); } @Override void unbind() { - thumbnailView.clear(glideRequests); + thumbnailView.clear(requestManager); super.unbind(); } } diff --git a/app/src/main/java/org/tm/archive/mediaoverview/MediaOverviewPageFragment.java b/app/src/main/java/org/tm/archive/mediaoverview/MediaOverviewPageFragment.java index e53df3a7..98c2ebf0 100644 --- a/app/src/main/java/org/tm/archive/mediaoverview/MediaOverviewPageFragment.java +++ b/app/src/main/java/org/tm/archive/mediaoverview/MediaOverviewPageFragment.java @@ -26,6 +26,7 @@ import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager; import org.signal.core.util.DimensionUnit; @@ -41,7 +42,6 @@ import org.tm.archive.database.loaders.GroupedThreadMediaLoader; import org.tm.archive.database.loaders.MediaLoader; import org.tm.archive.mediapreview.MediaIntentFactory; import org.tm.archive.mediapreview.MediaPreviewV2Activity; -import org.tm.archive.mms.GlideApp; import org.tm.archive.mms.PartAuthority; import org.tm.archive.util.BottomOffsetDecoration; import org.tm.archive.util.MediaUtil; @@ -125,7 +125,7 @@ public final class MediaOverviewPageFragment extends Fragment this.gridManager = new StickyHeaderGridLayoutManager(spans); this.adapter = new MediaGalleryAllAdapter(context, - GlideApp.with(this), + Glide.with(this), new GroupedThreadMediaLoader.EmptyGroupedThreadMedia(), this, this, diff --git a/app/src/main/java/org/tm/archive/mediapreview/ImageMediaPreviewFragment.java b/app/src/main/java/org/tm/archive/mediapreview/ImageMediaPreviewFragment.java index 153dc209..7af792e2 100644 --- a/app/src/main/java/org/tm/archive/mediapreview/ImageMediaPreviewFragment.java +++ b/app/src/main/java/org/tm/archive/mediapreview/ImageMediaPreviewFragment.java @@ -9,10 +9,11 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; import org.tm.archive.components.ZoomingImageView; -import org.tm.archive.mms.GlideApp; -import org.tm.archive.mms.GlideRequests; import org.signal.core.util.concurrent.LifecycleDisposable; import org.tm.archive.util.MediaUtil; @@ -33,7 +34,7 @@ public final class ImageMediaPreviewFragment extends MediaPreviewFragment { Bundle savedInstanceState) { View view = inflater.inflate(R.layout.media_preview_image_fragment, container, false); - GlideRequests glideRequests = GlideApp.with(requireActivity()); + RequestManager requestManager = Glide.with(requireActivity()); Bundle arguments = requireArguments(); Uri uri = arguments.getParcelable(DATA_URI); String contentType = arguments.getString(DATA_CONTENT_TYPE); @@ -49,7 +50,7 @@ public final class ImageMediaPreviewFragment extends MediaPreviewFragment { } //noinspection ConstantConditions - zoomingImageView.setImageUri(glideRequests, uri, contentType, () -> events.onMediaReady()); + zoomingImageView.setImageUri(requestManager, uri, contentType, () -> events.onMediaReady()); zoomingImageView.setOnClickListener(v -> events.singleTapOnMedia()); diff --git a/app/src/main/java/org/tm/archive/mediapreview/MediaPreviewV2Fragment.kt b/app/src/main/java/org/tm/archive/mediapreview/MediaPreviewV2Fragment.kt index 8f45acf8..32469ebb 100644 --- a/app/src/main/java/org/tm/archive/mediapreview/MediaPreviewV2Fragment.kt +++ b/app/src/main/java/org/tm/archive/mediapreview/MediaPreviewV2Fragment.kt @@ -32,6 +32,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.MarginPageTransformer import androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.bumptech.glide.Glide import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar @@ -58,7 +59,6 @@ import org.tm.archive.mediapreview.mediarail.MediaRailAdapter import org.tm.archive.mediapreview.mediarail.MediaRailAdapter.ImageLoadingListener import org.tm.archive.mediasend.Media import org.tm.archive.mediasend.v2.MediaSelectionActivity -import org.tm.archive.mms.GlideApp import org.tm.archive.mms.PartAuthority import org.tm.archive.permissions.Permissions import org.tm.archive.recipients.Recipient @@ -187,7 +187,7 @@ class MediaPreviewV2Fragment : LoggingFragment(R.layout.fragment_media_preview_v layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) addItemDecoration(CenterDecoration(0)) albumRailAdapter = MediaRailAdapter( - GlideApp.with(this@MediaPreviewV2Fragment), + Glide.with(this@MediaPreviewV2Fragment), { media -> jumpViewPagerToMedia(media) }, object : ImageLoadingListener() { override fun onAllRequestsFinished() { @@ -586,7 +586,7 @@ class MediaPreviewV2Fragment : LoggingFragment(R.layout.fragment_media_preview_v val attachment: DatabaseAttachment = mediaItem.attachment ?: return MaterialAlertDialogBuilder(requireContext()).apply { - setIcon(R.drawable.ic_warning) + setIcon(R.drawable.symbol_error_triangle_fill_24) setTitle(R.string.MediaPreviewActivity_media_delete_confirmation_title) setMessage(R.string.MediaPreviewActivity_media_delete_confirmation_message) setCancelable(true) diff --git a/app/src/main/java/org/tm/archive/mediapreview/VideoMediaPreviewFragment.java b/app/src/main/java/org/tm/archive/mediapreview/VideoMediaPreviewFragment.java index 0d12d78c..e1c18b33 100644 --- a/app/src/main/java/org/tm/archive/mediapreview/VideoMediaPreviewFragment.java +++ b/app/src/main/java/org/tm/archive/mediapreview/VideoMediaPreviewFragment.java @@ -165,7 +165,9 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment { @Override public void setBottomButtonControls(@NonNull MediaPreviewPlayerControlView playerControlView) { - videoView.setControlView(playerControlView); + if (videoView != null) { + videoView.setControlView(playerControlView); + } updateSkipButtonState(); } diff --git a/app/src/main/java/org/tm/archive/mediapreview/mediarail/MediaRailAdapter.kt b/app/src/main/java/org/tm/archive/mediapreview/mediarail/MediaRailAdapter.kt index 2fdad5d1..b2575cfa 100644 --- a/app/src/main/java/org/tm/archive/mediapreview/mediarail/MediaRailAdapter.kt +++ b/app/src/main/java/org/tm/archive/mediapreview/mediarail/MediaRailAdapter.kt @@ -4,13 +4,13 @@ import android.graphics.drawable.Drawable import android.view.View import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.RequestManager import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.target.Target import org.tm.archive.R import org.tm.archive.components.ThumbnailView import org.tm.archive.mediasend.Media -import org.tm.archive.mms.GlideRequests import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.adapter.mapping.MappingModel import org.tm.archive.util.adapter.mapping.MappingViewHolder @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger * This is the RecyclerView.Adapter for the row of thumbnails present in the media viewer screen. */ class MediaRailAdapter( - private val glideRequests: GlideRequests, + private val requestManager: RequestManager, private val onRailItemSelected: (Media) -> Unit, private val imageLoadingListener: ImageLoadingListener ) : MappingAdapter() { @@ -77,7 +77,7 @@ class MediaRailAdapter( } override fun bind(model: MediaRailItem) { - image.setImageResource(glideRequests, model.media.uri, 0, 0, false, imageLoadingListener) + image.setImageResource(requestManager, model.media.uri, 0, 0, false, imageLoadingListener) image.setOnClickListener { onRailItemSelected(model.media) } captionIndicator.visibility = if (model.media.caption.isPresent) View.VISIBLE else View.GONE diff --git a/app/src/main/java/org/tm/archive/mediasend/AvatarSelectionActivity.java b/app/src/main/java/org/tm/archive/mediasend/AvatarSelectionActivity.java index 73ba346e..5c8c2eaf 100644 --- a/app/src/main/java/org/tm/archive/mediasend/AvatarSelectionActivity.java +++ b/app/src/main/java/org/tm/archive/mediasend/AvatarSelectionActivity.java @@ -79,7 +79,7 @@ public class AvatarSelectionActivity extends AppCompatActivity implements Camera @Override public void onCameraError() { - Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.default_error_msg, Toast.LENGTH_SHORT).show(); finish(); } @@ -181,18 +181,20 @@ public class AvatarSelectionActivity extends AppCompatActivity implements Camera @Override public void onMainImageLoaded() { - } @Override public void onMainImageFailedToLoad() { - } @Override public void restoreState() { } + @Override + public void onQrCodeFound(@NonNull String data) { + } + public boolean popToRoot() { final int backStackCount = getSupportFragmentManager().getBackStackEntryCount(); if (backStackCount == 0) { diff --git a/app/src/main/java/org/tm/archive/mediasend/Camera1Fragment.java b/app/src/main/java/org/tm/archive/mediasend/Camera1Fragment.java index 76cb3a58..27e6feba 100644 --- a/app/src/main/java/org/tm/archive/mediasend/Camera1Fragment.java +++ b/app/src/main/java/org/tm/archive/mediasend/Camera1Fragment.java @@ -49,7 +49,6 @@ import org.tm.archive.mediasend.camerax.CameraXModelBlocklist; import org.tm.archive.mediasend.v2.MediaAnimations; import org.tm.archive.mediasend.v2.MediaCountIndicatorButton; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideApp; import org.tm.archive.util.ServiceUtil; import org.tm.archive.util.TextSecurePreferences; import org.tm.archive.util.ViewUtil; @@ -396,7 +395,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment, Transformation transformation = frontFacing ? new MultiTransformation<>(new CenterCrop(), new FlipTransformation()) : new CenterCrop(); - GlideApp.with(this) + Glide.with(this) .asBitmap() .load(jpegData) .transform(transformation) diff --git a/app/src/main/java/org/tm/archive/mediasend/CameraContactAdapter.java b/app/src/main/java/org/tm/archive/mediasend/CameraContactAdapter.java index 263611d0..78475958 100644 --- a/app/src/main/java/org/tm/archive/mediasend/CameraContactAdapter.java +++ b/app/src/main/java/org/tm/archive/mediasend/CameraContactAdapter.java @@ -11,10 +11,11 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; import org.tm.archive.components.AvatarImageView; import org.tm.archive.components.FromTextView; -import org.tm.archive.mms.GlideRequests; import org.tm.archive.recipients.Recipient; import org.tm.archive.util.adapter.SectionedRecyclerViewAdapter; import org.tm.archive.util.adapter.StableIdGenerator; @@ -35,7 +36,7 @@ class CameraContactAdapter extends SectionedRecyclerViewAdapter selected; private final CameraContactListener cameraContactListener; @@ -50,8 +51,8 @@ class CameraContactAdapter extends SectionedRecyclerViewAdapter(); this.cameraContactListener = listener; } @@ -114,7 +115,7 @@ class CameraContactAdapter extends SectionedRecyclerViewAdapter selected, - @NonNull GlideRequests glideRequests, + @NonNull RequestManager requestManager, @NonNull CameraContactListener cameraContactListener) { if (localPosition == 0) { ((HeaderViewHolder) viewHolder).bind(titleResId); } else { Recipient recipient = recipients.get(localPosition - 1); - ((ContactViewHolder) viewHolder).bind(recipient, selected.contains(recipient), glideRequests, cameraContactListener); + ((ContactViewHolder) viewHolder).bind(recipient, selected.contains(recipient), requestManager, cameraContactListener); } } } @@ -221,10 +222,10 @@ class CameraContactAdapter extends SectionedRecyclerViewAdapter listener.onContactClicked(recipient)); checkbox.setChecked(selected); diff --git a/app/src/main/java/org/tm/archive/mediasend/CameraContactSelectionAdapter.java b/app/src/main/java/org/tm/archive/mediasend/CameraContactSelectionAdapter.java index 4f8889c3..f59ecfaa 100644 --- a/app/src/main/java/org/tm/archive/mediasend/CameraContactSelectionAdapter.java +++ b/app/src/main/java/org/tm/archive/mediasend/CameraContactSelectionAdapter.java @@ -60,7 +60,7 @@ class CameraContactSelectionAdapter extends RecyclerView.Adapter> getMostRecentMediaItem(); @NonNull MediaConstraints getMediaConstraints(); int getMaxVideoDuration(); diff --git a/app/src/main/java/org/tm/archive/mediasend/CameraXFragment.java b/app/src/main/java/org/tm/archive/mediasend/CameraXFragment.java index f2d8f332..e52977dc 100644 --- a/app/src/main/java/org/tm/archive/mediasend/CameraXFragment.java +++ b/app/src/main/java/org/tm/archive/mediasend/CameraXFragment.java @@ -15,6 +15,7 @@ import android.util.Size; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.OrientationEventListener; import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -30,34 +31,33 @@ import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageCapture; import androidx.camera.core.ImageCaptureException; import androidx.camera.core.ImageProxy; -import androidx.camera.video.FallbackStrategy; -import androidx.camera.video.Quality; -import androidx.camera.video.QualitySelector; -import androidx.camera.view.CameraController; -import androidx.camera.view.LifecycleCameraController; import androidx.camera.view.PreviewView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.core.content.ContextCompat; import com.bumptech.glide.Glide; -import com.bumptech.glide.util.Executors; import com.google.android.material.card.MaterialCardView; import org.signal.core.util.Stopwatch; import org.signal.core.util.concurrent.SimpleTask; import org.signal.core.util.logging.Log; +import org.signal.qr.QrProcessor; import org.tm.archive.LoggingFragment; import org.tm.archive.R; import org.tm.archive.animation.AnimationCompleteListener; import org.tm.archive.components.TooltipPopup; +import org.tm.archive.mediasend.camerax.CameraXController; import org.tm.archive.mediasend.camerax.CameraXFlashToggleView; import org.tm.archive.mediasend.camerax.CameraXModePolicy; import org.tm.archive.mediasend.camerax.CameraXUtil; +import org.tm.archive.mediasend.camerax.PlatformCameraController; +import org.tm.archive.mediasend.camerax.SignalCameraController; import org.tm.archive.mediasend.v2.MediaAnimations; import org.tm.archive.mediasend.v2.MediaCountIndicatorButton; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; import org.tm.archive.mms.MediaConstraints; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.MemoryFileDescriptor; import org.tm.archive.util.TextSecurePreferences; import org.tm.archive.util.ViewUtil; @@ -65,9 +65,12 @@ import org.tm.archive.video.VideoUtil; import java.io.FileDescriptor; import java.io.IOException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.disposables.Disposable; +import kotlin.Unit; /** * Camera captured implemented using the CameraX SDK, which uses Camera2 under the hood. Should be @@ -75,38 +78,48 @@ import io.reactivex.rxjava3.disposables.Disposable; */ public class CameraXFragment extends LoggingFragment implements CameraFragment { - private static final String TAG = Log.tag(CameraXFragment.class); - private static final String IS_VIDEO_ENABLED = "is_video_enabled"; + private static final String TAG = Log.tag(CameraXFragment.class); + private static final String IS_VIDEO_ENABLED = "is_video_enabled"; + private static final String IS_QR_SCAN_ENABLED = "is_qr_scan_enabled"; private static final Rational ASPECT_RATIO_16_9 = new Rational(16, 9); private static final PreviewView.ScaleType PREVIEW_SCALE_TYPE = PreviewView.ScaleType.FILL_CENTER; private PreviewView previewView; + private MaterialCardView cameraParent; private ViewGroup controlsContainer; private Controller controller; private View selfieFlash; private MemoryFileDescriptor videoFileDescriptor; - private LifecycleCameraController cameraController; + private CameraXController cameraController; + private CameraXOrientationListener orientationListener; private Disposable mostRecentItemDisposable = Disposable.disposed(); private CameraXModePolicy cameraXModePolicy; private CameraScreenBrightnessController cameraScreenBrightnessController; private boolean isMediaSelected; + private final Executor qrAnalysisExecutor = Executors.newSingleThreadExecutor(); + private final QrProcessor qrProcessor = new QrProcessor(); + public static CameraXFragment newInstanceForAvatarCapture() { CameraXFragment fragment = new CameraXFragment(); Bundle args = new Bundle(); args.putBoolean(IS_VIDEO_ENABLED, false); + args.putBoolean(IS_QR_SCAN_ENABLED, false); fragment.setArguments(args); return fragment; } - public static CameraXFragment newInstance() { + public static CameraXFragment newInstance(boolean qrScanEnabled) { CameraXFragment fragment = new CameraXFragment(); - fragment.setArguments(new Bundle()); + Bundle args = new Bundle(); + args.putBoolean(IS_QR_SCAN_ENABLED, qrScanEnabled); + + fragment.setArguments(args); return fragment; } @@ -124,6 +137,8 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { if (controller == null) { throw new IllegalStateException("Parent must implement controller interface."); } + + this.orientationListener = new CameraXOrientationListener(context); } @Override @@ -134,7 +149,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { @SuppressLint("MissingPermission") @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - ViewGroup cameraParent = view.findViewById(R.id.camerax_camera_parent); + this.cameraParent = view.findViewById(R.id.camerax_camera_parent); this.previewView = view.findViewById(R.id.camerax_camera); this.controlsContainer = view.findViewById(R.id.camerax_controls_container); @@ -144,11 +159,18 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { Log.d(TAG, "Starting CameraX with mode policy " + cameraXModePolicy.getClass().getSimpleName()); - cameraController = new LifecycleCameraController(requireContext()); - cameraController.bindToLifecycle(getViewLifecycleOwner()); - cameraController.setCameraSelector(CameraXUtil.toCameraSelector(TextSecurePreferences.getDirectCaptureCameraId(requireContext()))); - cameraController.setTapToFocusEnabled(true); - cameraController.setImageCaptureMode(CameraXUtil.getOptimalCaptureMode()); + + previewView.setScaleType(PREVIEW_SCALE_TYPE); + if (FeatureFlags.customCameraXController()) { + View focusIndicator = view.findViewById(R.id.camerax_focus_indicator); + cameraController = new SignalCameraController(requireContext(), getViewLifecycleOwner(), previewView, focusIndicator); + } else { + PlatformCameraController platformController = new PlatformCameraController(requireContext()); + platformController.initializeAndBind(requireContext(), getViewLifecycleOwner()); + previewView.setController(platformController.getDelegate()); + cameraController = platformController; + } + cameraXModePolicy.initialize(cameraController); cameraScreenBrightnessController = new CameraScreenBrightnessController( @@ -157,42 +179,47 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { ); previewView.setScaleType(PREVIEW_SCALE_TYPE); - previewView.setController(cameraController); onOrientationChanged(); - view.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - // Let's assume portrait for now, so 9:16 - float aspectRatio = CameraFragment.getAspectRatioForOrientation(Configuration.ORIENTATION_PORTRAIT); - float width = right - left; - float height = Math.min((1f / aspectRatio) * width, bottom - top); + if (FeatureFlags.customCameraXController()) { + cameraController.initializeAndBind(requireContext(), getViewLifecycleOwner()); + } - ViewGroup.LayoutParams params = cameraParent.getLayoutParams(); + if (requireArguments().getBoolean(IS_QR_SCAN_ENABLED, false)) { + cameraController.setImageAnalysisAnalyzer(qrAnalysisExecutor, imageProxy -> { + try { + String data = qrProcessor.getScannedData(imageProxy); + if (data != null) { + controller.onQrCodeFound(data); + } + } finally { + imageProxy.close(); + } + }); + } + } - // If there's a mismatch... - if (params.height != (int) height) { - params.width = (int) width; - params.height = (int) height; + @Override + public void onStart() { + super.onStart(); + orientationListener.enable(); + } - cameraParent.setLayoutParams(params); - cameraController.setPreviewTargetSize(new CameraController.OutputSize(new Size((int) width, (int) height))); - } - }); + @Override + public void onStop() { + super.onStop(); + orientationListener.disable(); } @Override public void onResume() { super.onResume(); - cameraController.bindToLifecycle(getViewLifecycleOwner()); + cameraController.bindToLifecycle(getViewLifecycleOwner(), () -> Log.d(TAG, "Camera init complete from onResume")); requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } - @Override - public void onPause() { - super.onPause(); - } - @Override public void onDestroyView() { super.onDestroyView(); @@ -235,12 +262,10 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { private void onOrientationChanged() { int layout = R.layout.camera_controls_portrait; - int resolution = CameraXUtil.getIdealResolution(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels); - Size size = CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, true); - CameraController.OutputSize outputSize = new CameraController.OutputSize(size); + int resolution = CameraXUtil.getIdealResolution(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels); + Size size = CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, true); - cameraController.setImageCaptureTargetSize(outputSize); - cameraController.setVideoCaptureQualitySelector(QualitySelector.from(Quality.HD, FallbackStrategy.lowerQualityThan(Quality.HD))); + cameraController.setImageCaptureTargetSize(size); controlsContainer.removeAllViews(); controlsContainer.addView(LayoutInflater.from(getContext()).inflate(layout, controlsContainer, false)); @@ -331,16 +356,19 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { selfieFlash = requireView().findViewById(R.id.camera_selfie_flash); captureButton.setOnClickListener(v -> { - captureButton.setEnabled(false); - flipButton.setEnabled(false); - flashButton.setEnabled(false); - onCaptureClicked(); + if (cameraController.isInitialized()) { + captureButton.setEnabled(false); + flipButton.setEnabled(false); + flashButton.setEnabled(false); + onCaptureClicked(); + } else { + Log.i(TAG, "Camera capture button clicked but the camera controller is not yet initialized."); + } }); previewView.setScaleType(PREVIEW_SCALE_TYPE); - cameraController.getInitializationFuture() - .addListener(() -> initializeFlipButton(flipButton, flashButton), Executors.mainThreadExecutor()); + cameraController.addInitializationCompletedListener(ContextCompat.getMainExecutor(requireContext()), () -> initializeFlipButton(flipButton, flashButton)); flashButton.setAutoFlashEnabled(cameraController.getImageCaptureFlashMode() >= ImageCapture.FLASH_MODE_AUTO); flashButton.setFlash(cameraController.getImageCaptureFlashMode()); @@ -477,7 +505,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { ); flashHelper.onWillTakePicture(); - cameraController.takePicture(Executors.mainThreadExecutor(), new ImageCapture.OnImageCapturedCallback() { + cameraController.takePicture(ContextCompat.getMainExecutor(requireContext()), new ImageCapture.OnImageCapturedCallback() { @Override public void onCaptureSuccess(@NonNull ImageProxy image) { flashHelper.endFlash(); @@ -506,8 +534,8 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { } @Override - public void onError(ImageCaptureException exception) { - Log.w(TAG, "Failed to capture image", exception); + public void onError(@NonNull ImageCaptureException exception) { + Log.w(TAG, "Failed to capture image due to error " + exception.getImageCaptureError(), exception.getCause()); flashHelper.endFlash(); controller.onCameraError(); } @@ -528,10 +556,10 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { } @SuppressLint({ "MissingPermission" }) - private void initializeFlipButton(@NonNull View flipButton, @NonNull CameraXFlashToggleView flashButton) { + private Unit initializeFlipButton(@NonNull View flipButton, @NonNull CameraXFlashToggleView flashButton) { if (getContext() == null) { Log.w(TAG, "initializeFlipButton called either before or after fragment was attached."); - return; + return Unit.INSTANCE; } getViewLifecycleOwner().getLifecycle().addObserver(cameraScreenBrightnessController); @@ -568,13 +596,14 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { } else { flipButton.setVisibility(View.GONE); } + return Unit.INSTANCE; } private static class CameraStateProvider implements CameraScreenBrightnessController.CameraStateProvider { - private final CameraController cameraController; + private final CameraXController cameraController; - private CameraStateProvider(CameraController cameraController) { + private CameraStateProvider(CameraXController cameraController) { this.cameraController = cameraController; } @@ -588,4 +617,20 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { return cameraController.getImageCaptureFlashMode() == ImageCapture.FLASH_MODE_ON; } } + + private class CameraXOrientationListener extends OrientationEventListener { + + public CameraXOrientationListener(Context context) { + super(context); + } + + @Override + public void onOrientationChanged(int orientation) { + if (cameraController != null) { + if (FeatureFlags.customCameraXController()) { + cameraController.setImageRotation(orientation); + } + } + } + } } diff --git a/app/src/main/java/org/tm/archive/mediasend/CameraXSelfieFlashHelper.java b/app/src/main/java/org/tm/archive/mediasend/CameraXSelfieFlashHelper.java index 2e90be15..8e4e99dd 100644 --- a/app/src/main/java/org/tm/archive/mediasend/CameraXSelfieFlashHelper.java +++ b/app/src/main/java/org/tm/archive/mediasend/CameraXSelfieFlashHelper.java @@ -7,23 +7,25 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageCapture; -import androidx.camera.view.CameraController; + +import org.tm.archive.mediasend.camerax.CameraXController; +import org.tm.archive.mediasend.camerax.SignalCameraController; final class CameraXSelfieFlashHelper { - private static final float MAX_SCREEN_BRIGHTNESS = 1f; - private static final float MAX_SELFIE_FLASH_ALPHA = 0.9f; + private static final float MAX_SCREEN_BRIGHTNESS = 1f; + private static final float MAX_SELFIE_FLASH_ALPHA = 0.9f; - private final Window window; - private final CameraController camera; - private final View selfieFlash; + private final Window window; + private final CameraXController camera; + private final View selfieFlash; private float brightnessBeforeFlash; private boolean inFlash; private int flashMode = -1; CameraXSelfieFlashHelper(@NonNull Window window, - @NonNull CameraController camera, + @NonNull CameraXController camera, @NonNull View selfieFlash) { this.window = window; @@ -68,7 +70,7 @@ final class CameraXSelfieFlashHelper { } private boolean shouldUseViewBasedFlash() { - CameraSelector cameraSelector = camera.getCameraSelector() ; + CameraSelector cameraSelector = camera.getCameraSelector(); return (camera.getImageCaptureFlashMode() == ImageCapture.FLASH_MODE_ON || flashMode == ImageCapture.FLASH_MODE_ON) && cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA; diff --git a/app/src/main/java/org/tm/archive/mediasend/CameraXVideoCaptureHelper.java b/app/src/main/java/org/tm/archive/mediasend/CameraXVideoCaptureHelper.java index 71ea0c4b..c2403cb0 100644 --- a/app/src/main/java/org/tm/archive/mediasend/CameraXVideoCaptureHelper.java +++ b/app/src/main/java/org/tm/archive/mediasend/CameraXVideoCaptureHelper.java @@ -17,20 +17,20 @@ import androidx.camera.core.ZoomState; import androidx.camera.video.FileDescriptorOutputOptions; import androidx.camera.video.Recording; import androidx.camera.video.VideoRecordEvent; -import androidx.camera.view.CameraController; import androidx.camera.view.PreviewView; import androidx.camera.view.video.AudioConfig; +import androidx.core.content.ContextCompat; import androidx.core.util.Consumer; import androidx.fragment.app.Fragment; -import com.bumptech.glide.util.Executors; - import org.signal.core.util.logging.Log; import org.tm.archive.R; +import org.tm.archive.mediasend.camerax.CameraXController; import org.tm.archive.mediasend.camerax.CameraXModePolicy; import org.tm.archive.permissions.Permissions; import org.tm.archive.util.ContextUtil; import org.tm.archive.util.Debouncer; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.MemoryFileDescriptor; import org.tm.archive.video.VideoUtil; @@ -42,18 +42,18 @@ import java.util.concurrent.TimeUnit; @RequiresApi(26) class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener { - private static final String TAG = CameraXVideoCaptureHelper.class.getName(); + private static final String TAG = Log.tag(CameraXVideoCaptureHelper.class); private static final String VIDEO_DEBUG_LABEL = "video-capture"; private static final long VIDEO_SIZE = 10 * 1024 * 1024; - private final @NonNull Fragment fragment; - private final @NonNull PreviewView previewView; - private final @NonNull CameraController cameraController; - private final @NonNull Callback callback; - private final @NonNull MemoryFileDescriptor memoryFileDescriptor; - private final @NonNull ValueAnimator updateProgressAnimator; - private final @NonNull Debouncer debouncer; - private final @NonNull CameraXModePolicy cameraXModePolicy; + private final @NonNull Fragment fragment; + private final @NonNull PreviewView previewView; + private final @NonNull CameraXController cameraController; + private final @NonNull Callback callback; + private final @NonNull MemoryFileDescriptor memoryFileDescriptor; + private final @NonNull ValueAnimator updateProgressAnimator; + private final @NonNull Debouncer debouncer; + private final @NonNull CameraXModePolicy cameraXModePolicy; private ValueAnimator cameraMetricsAnimator; @@ -74,7 +74,7 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener } else { try { debouncer.clear(); - cameraController.setZoomRatio(Objects.requireNonNull(cameraController.getZoomState().getValue()).getMinZoomRatio()); + cameraController.setZoomRatio(getDefaultVideoZoomRatio()); memoryFileDescriptor.seek(0); callback.onVideoSaved(memoryFileDescriptor.getFileDescriptor()); } catch (IOException e) { @@ -87,7 +87,7 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener CameraXVideoCaptureHelper(@NonNull Fragment fragment, @NonNull CameraButtonView captureButton, - @NonNull CameraController cameraController, + @NonNull CameraXController cameraController, @NonNull PreviewView previewView, @NonNull MemoryFileDescriptor memoryFileDescriptor, @NonNull CameraXModePolicy cameraXModePolicy, @@ -142,14 +142,14 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener @SuppressLint("RestrictedApi") private void beginCameraRecording() { cameraXModePolicy.setToVideo(cameraController); - this.cameraController.setZoomRatio(Objects.requireNonNull(this.cameraController.getZoomState().getValue()).getMinZoomRatio()); + this.cameraController.setZoomRatio(getDefaultVideoZoomRatio()); callback.onVideoRecordStarted(); shrinkCaptureArea(); FileDescriptorOutputOptions outputOptions = new FileDescriptorOutputOptions.Builder(memoryFileDescriptor.getParcelFileDescriptor()).build(); AudioConfig audioConfig = AudioConfig.create(true); - activeRecording = cameraController.startRecording(outputOptions, audioConfig, Executors.mainThreadExecutor(), videoSavedListener); + activeRecording = cameraController.startRecording(outputOptions, audioConfig, ContextCompat.getMainExecutor(fragment.requireContext()), videoSavedListener); updateProgressAnimator.start(); debouncer.publish(this::onVideoCaptureComplete); @@ -232,8 +232,8 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener @Override public void onZoomIncremented(float increment) { ZoomState zoomState = Objects.requireNonNull(cameraController.getZoomState().getValue()); - float range = zoomState.getMaxZoomRatio() - zoomState.getMinZoomRatio(); - cameraController.setZoomRatio((range * increment) + zoomState.getMinZoomRatio()); + float range = zoomState.getMaxZoomRatio() - getDefaultVideoZoomRatio(); + cameraController.setZoomRatio((range * increment) + getDefaultVideoZoomRatio()); } @Override @@ -255,6 +255,14 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener ); } + public float getDefaultVideoZoomRatio() { + if (FeatureFlags.startVideoRecordAt1x()) { + return 1f; + } else { + return Objects.requireNonNull(cameraController.getZoomState().getValue()).getMinZoomRatio(); + } + } + interface Callback { void onVideoRecordStarted(); diff --git a/app/src/main/java/org/tm/archive/mediasend/MediaSendGifFragment.java b/app/src/main/java/org/tm/archive/mediasend/MediaSendGifFragment.java index 206a70d6..74cf1719 100644 --- a/app/src/main/java/org/tm/archive/mediasend/MediaSendGifFragment.java +++ b/app/src/main/java/org/tm/archive/mediasend/MediaSendGifFragment.java @@ -11,9 +11,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.bumptech.glide.Glide; + import org.tm.archive.R; import org.tm.archive.mms.DecryptableStreamUriLoader; -import org.tm.archive.mms.GlideApp; public class MediaSendGifFragment extends Fragment implements MediaSendPageFragment { @@ -41,7 +42,7 @@ public class MediaSendGifFragment extends Fragment implements MediaSendPageFragm super.onViewCreated(view, savedInstanceState); uri = getArguments().getParcelable(KEY_URI); - GlideApp.with(this).load(new DecryptableStreamUriLoader.DecryptableUri(uri)).fitCenter().into((ImageView) view); + Glide.with(this).load(new DecryptableStreamUriLoader.DecryptableUri(uri)).fitCenter().into((ImageView) view); } @Override @@ -54,11 +55,6 @@ public class MediaSendGifFragment extends Fragment implements MediaSendPageFragm return uri; } - @Override - public @Nullable View getPlaybackControls() { - return null; - } - @Override public @Nullable Object saveState() { return null; diff --git a/app/src/main/java/org/tm/archive/mediasend/MediaSendPageFragment.java b/app/src/main/java/org/tm/archive/mediasend/MediaSendPageFragment.java index a3791e75..b93b14f0 100644 --- a/app/src/main/java/org/tm/archive/mediasend/MediaSendPageFragment.java +++ b/app/src/main/java/org/tm/archive/mediasend/MediaSendPageFragment.java @@ -15,8 +15,6 @@ public interface MediaSendPageFragment { void setUri(@NonNull Uri uri); - @Nullable View getPlaybackControls(); - @Nullable Object saveState(); void restoreState(@NonNull Object state); diff --git a/app/src/main/java/org/tm/archive/mediasend/MediaUploadRepository.java b/app/src/main/java/org/tm/archive/mediasend/MediaUploadRepository.java index 9f026472..8931d03f 100644 --- a/app/src/main/java/org/tm/archive/mediasend/MediaUploadRepository.java +++ b/app/src/main/java/org/tm/archive/mediasend/MediaUploadRepository.java @@ -108,6 +108,7 @@ public class MediaUploadRepository { } public void cancelUpload(@NonNull Collection mediaItems) { + Log.d(TAG, "Canceling uploads."); executor.execute(() -> { for (Media media : mediaItems) { cancelUploadInternal(media); @@ -116,6 +117,7 @@ public class MediaUploadRepository { } public void cancelAllUploads() { + Log.d(TAG, "Canceling all uploads."); executor.execute(() -> { for (Media media : new HashSet<>(uploadResults.keySet())) { cancelUploadInternal(media); @@ -159,6 +161,7 @@ public class MediaUploadRepository { PreUploadResult result = uploadResults.get(media); if (result != null) { + Log.d(TAG, "Canceling upload jobs for " + result.getJobIds().size() + " media items."); Stream.of(result.getJobIds()).forEach(jobManager::cancel); uploadResults.remove(media); SignalDatabase.attachments().deleteAttachment(result.getAttachmentId()); diff --git a/app/src/main/java/org/tm/archive/mediasend/VideoEditorFragment.java b/app/src/main/java/org/tm/archive/mediasend/VideoEditorFragment.java deleted file mode 100644 index a76c435c..00000000 --- a/app/src/main/java/org/tm/archive/mediasend/VideoEditorFragment.java +++ /dev/null @@ -1,413 +0,0 @@ -package org.tm.archive.mediasend; - -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.fragment.app.Fragment; - -import org.signal.core.util.logging.Log; -import org.tm.archive.R; -import org.tm.archive.mms.MediaConstraints; -import org.tm.archive.mms.VideoSlide; -import org.tm.archive.scribbles.VideoEditorHud; -import org.tm.archive.util.Throttler; -import org.tm.archive.video.VideoBitRateCalculator; -import org.tm.archive.video.VideoPlayer; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -public class VideoEditorFragment extends Fragment implements VideoEditorHud.EventListener, - MediaSendPageFragment { - - private static final String TAG = Log.tag(VideoEditorFragment.class); - - private static final String KEY_URI = "uri"; - private static final String KEY_MAX_OUTPUT = "max_output_size"; - private static final String KEY_MAX_SEND = "max_send_size"; - private static final String KEY_IS_VIDEO_GIF = "is_video_gif"; - private static final String KEY_MAX_DURATION = "max_duration"; - - private final Throttler videoScanThrottle = new Throttler(150); - private final Handler handler = new Handler(Looper.getMainLooper()); - - private Controller controller; - private Data data = new Data(); - private Uri uri; - private boolean isVideoGif; - private VideoPlayer player; - @Nullable private VideoEditorHud hud; - private Runnable updatePosition; - private boolean isInEdit; - private boolean wasPlayingBeforeEdit; - private long maxVideoDurationUs; - - public static VideoEditorFragment newInstance(@NonNull Uri uri, long maxCompressedVideoSize, long maxAttachmentSize, boolean isVideoGif, long maxVideoDuration) { - Bundle args = new Bundle(); - args.putParcelable(KEY_URI, uri); - args.putLong(KEY_MAX_OUTPUT, maxCompressedVideoSize); - args.putLong(KEY_MAX_SEND, maxAttachmentSize); - args.putBoolean(KEY_IS_VIDEO_GIF, isVideoGif); - args.putLong(KEY_MAX_DURATION, maxVideoDuration); - - VideoEditorFragment fragment = new VideoEditorFragment(); - fragment.setArguments(args); - fragment.setUri(uri); - return fragment; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getActivity() instanceof Controller) { - controller = (Controller) getActivity(); - } else if (getParentFragment() instanceof Controller) { - controller = (Controller) getParentFragment(); - } else { - throw new IllegalStateException("Parent must implement Controller interface."); - } - } - - @Override - public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.mediasend_video_fragment, container, false); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - player = view.findViewById(R.id.video_player); - - uri = requireArguments().getParcelable(KEY_URI); - isVideoGif = requireArguments().getBoolean(KEY_IS_VIDEO_GIF); - maxVideoDurationUs = TimeUnit.MILLISECONDS.toMicros(requireArguments().getLong(KEY_MAX_DURATION)); - - long maxOutput = requireArguments().getLong(KEY_MAX_OUTPUT); - long maxSend = requireArguments().getLong(KEY_MAX_SEND); - VideoSlide slide = new VideoSlide(requireContext(), uri, 0, isVideoGif); - boolean autoplay = isVideoGif; - - player.setWindow(requireActivity().getWindow()); - player.setVideoSource(slide, autoplay, TAG); - - if (slide.isVideoGif()) { - player.setPlayerCallback(new VideoPlayer.PlayerCallback() { - @Override - public void onPlaying() { - controller.onPlayerReady(); - } - - @Override - public void onStopped() { - // Do nothing. - } - - @Override - public void onError() { - controller.onPlayerError(); - } - }); - player.hideControls(); - player.loopForever(); - } else if (MediaConstraints.isVideoTranscodeAvailable()) { - hud = view.findViewById(R.id.video_editor_hud); - hud.setEventListener(this); - clampToMaxVideoDuration(data, true); - updateHud(data); - if (data.durationEdited) { - player.clip(data.startTimeUs, data.endTimeUs, autoplay); - } - try { - hud.setVideoSource(slide, new VideoBitRateCalculator(maxOutput), maxSend); - hud.setVisibility(View.VISIBLE); - startPositionUpdates(); - } catch (IOException e) { - Log.w(TAG, e); - } - - player.setOnClickListener(v -> { - player.pause(); - hud.showPlayButton(); - }); - - player.setPlayerCallback(new VideoPlayer.PlayerCallback() { - - @Override - public void onReady() { - controller.onPlayerReady(); - } - - @Override - public void onPlaying() { - hud.fadePlayButton(); - } - - @Override - public void onStopped() { - hud.showPlayButton(); - } - - @Override - public void onError() { - controller.onPlayerError(); - } - }); - } - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - if (player != null) { - player.cleanup(); - } - } - - @Override - public void onPause() { - super.onPause(); - notifyHidden(); - - stopPositionUpdates(); - } - - @Override - public void onResume() { - super.onResume(); - startPositionUpdates(); - - if (player != null && isVideoGif) { - player.play(); - } - } - - private void startPositionUpdates() { - if (hud != null && Build.VERSION.SDK_INT >= 23) { - stopPositionUpdates(); - updatePosition = new Runnable() { - @Override - public void run() { - hud.setPosition(player.getPlaybackPositionUs()); - handler.postDelayed(this, 100); - } - }; - handler.post(updatePosition); - } - } - - private void stopPositionUpdates() { - handler.removeCallbacks(updatePosition); - } - - @Override - public void onHiddenChanged(boolean hidden) { - if (hidden) { - notifyHidden(); - } - } - - @Override - public void setUri(@NonNull Uri uri) { - this.uri = uri; - } - - @Override - public @NonNull Uri getUri() { - return uri; - } - - @Override - public @Nullable View getPlaybackControls() { - if (hud != null && hud.getVisibility() == View.VISIBLE) return null; - else if (isVideoGif) return null; - else if (player != null) return player.getControlView(); - else return null; - } - - @Override - public @Nullable Object saveState() { - return data; - } - - @Override - public void restoreState(@NonNull Object state) { - if (state instanceof Data) { - data = (Data) state; - if (Build.VERSION.SDK_INT >= 23) { - updateHud(data); - } - } else { - Log.w(TAG, "Received a bad saved state. Received class: " + state.getClass().getName()); - } - } - - @RequiresApi(api = 23) - private void updateHud(Data data) { - if (hud != null && data.totalDurationUs > 0 && data.durationEdited) { - hud.setDurationRange(data.totalDurationUs, data.startTimeUs, data.endTimeUs); - } - } - - @Override - public void notifyHidden() { - pausePlayback(); - } - - public void pausePlayback() { - if (player != null) { - player.pause(); - if (hud != null) { - hud.showPlayButton(); - } - } - } - - @Override - public void onEditVideoDuration(long totalDurationUs, long startTimeUs, long endTimeUs, boolean fromEdited, boolean editingComplete) { - controller.onTouchEventsNeeded(!editingComplete); - - if (hud != null) { - hud.hidePlayButton(); - } - - final long clampedStartTime = Math.max(startTimeUs, 0); - - boolean wasEdited = data.durationEdited; - boolean durationEdited = clampedStartTime > 0 || endTimeUs < totalDurationUs; - boolean endMoved = data.endTimeUs != endTimeUs; - - data.durationEdited = durationEdited; - data.totalDurationUs = totalDurationUs; - data.startTimeUs = clampedStartTime; - data.endTimeUs = endTimeUs; - - clampToMaxVideoDuration(data, !endMoved); - - if (editingComplete) { - isInEdit = false; - videoScanThrottle.clear(); - } else if (!isInEdit) { - isInEdit = true; - wasPlayingBeforeEdit = player.isPlaying(); - } - - videoScanThrottle.publish(() -> { - player.pause(); - if (!editingComplete) { - player.removeClip(false); - } - player.setPlaybackPosition(fromEdited || editingComplete ? clampedStartTime / 1000 : endTimeUs / 1000); - if (editingComplete) { - if (durationEdited) { - player.clip(clampedStartTime, endTimeUs, wasPlayingBeforeEdit); - } else { - player.removeClip(wasPlayingBeforeEdit); - } - - if (!wasPlayingBeforeEdit) { - hud.showPlayButton(); - } - } - }); - - if (!wasEdited && durationEdited) { - controller.onVideoBeginEdit(uri); - } - - if (editingComplete) { - controller.onVideoEndEdit(uri); - } - } - - @Override - public void onPlay() { - player.play(); - } - - @Override - public void onSeek(long position, boolean dragComplete) { - if (dragComplete) { - videoScanThrottle.clear(); - } - - videoScanThrottle.publish(() -> { - player.pause(); - player.setPlaybackPosition(position); - }); - } - - private void clampToMaxVideoDuration(@NonNull Data data, boolean clampEnd) { - if (!MediaConstraints.isVideoTranscodeAvailable()) { - return; - } - - if ((data.endTimeUs - data.startTimeUs) <= maxVideoDurationUs) { - return; - } - - data.durationEdited = true; - - if (clampEnd) { - data.endTimeUs = data.startTimeUs + maxVideoDurationUs; - } else { - data.startTimeUs = data.endTimeUs - maxVideoDurationUs; - } - - updateHud(data); - } - - public static class Data { - boolean durationEdited; - long totalDurationUs; - long startTimeUs; - long endTimeUs; - - public boolean isDurationEdited() { - return durationEdited; - } - - public @NonNull Bundle getBundle() { - Bundle bundle = new Bundle(); - bundle.putByte("EDITED", (byte) (durationEdited ? 1 : 0)); - bundle.putLong("TOTAL", totalDurationUs); - bundle.putLong("START", startTimeUs); - bundle.putLong("END", endTimeUs); - - return bundle; - } - - public static @NonNull Data fromBundle(@NonNull Bundle bundle) { - Data data = new Data(); - data.durationEdited = bundle.getByte("EDITED") == (byte) 1; - data.totalDurationUs = bundle.getLong("TOTAL"); - data.startTimeUs = bundle.getLong("START"); - data.endTimeUs = bundle.getLong("END"); - - return data; - } - } - - public interface Controller { - - void onPlayerReady(); - - void onPlayerError(); - - void onTouchEventsNeeded(boolean needed); - - void onVideoBeginEdit(@NonNull Uri uri); - - void onVideoEndEdit(@NonNull Uri uri); - } -} diff --git a/app/src/main/java/org/tm/archive/mediasend/VideoEditorFragment.kt b/app/src/main/java/org/tm/archive/mediasend/VideoEditorFragment.kt new file mode 100644 index 00000000..15039f70 --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/VideoEditorFragment.kt @@ -0,0 +1,330 @@ +package org.tm.archive.mediasend + +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.RequiresApi +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import org.signal.core.util.logging.Log +import org.tm.archive.R +import org.tm.archive.mediasend.v2.MediaSelectionState +import org.tm.archive.mediasend.v2.MediaSelectionViewModel +import org.tm.archive.mediasend.v2.videos.VideoTrimData +import org.tm.archive.mms.MediaConstraints +import org.tm.archive.mms.VideoSlide +import org.tm.archive.scribbles.VideoEditorPlayButtonLayout +import org.tm.archive.util.Throttler +import org.tm.archive.video.VideoPlayer +import org.tm.archive.video.VideoPlayer.PlayerCallback +import org.tm.archive.video.videoconverter.VideoThumbnailsRangeSelectorView +import org.tm.archive.video.videoconverter.VideoThumbnailsRangeSelectorView.PositionDragListener +import java.io.IOException +import kotlin.time.Duration.Companion.microseconds + +class VideoEditorFragment : Fragment(), PositionDragListener, MediaSendPageFragment { + private val sharedViewModel: MediaSelectionViewModel by viewModels(ownerProducer = { requireActivity() }) + private val videoScanThrottle = Throttler(150) + private val handler = Handler(Looper.getMainLooper()) + + private var canEdit = false + private var isVideoGif = false + private var isInEdit = false + private var isFocused = false + private var wasPlayingBeforeEdit = false + private var maxSend: Long = 0 + private lateinit var uri: Uri + private lateinit var controller: Controller + private lateinit var player: VideoPlayer + private lateinit var hud: VideoEditorPlayButtonLayout + private lateinit var videoTimeLine: VideoThumbnailsRangeSelectorView + + private val updatePosition = object : Runnable { + override fun run() { + if (MediaConstraints.isVideoTranscodeAvailable()) { + val playbackPositionUs = player.playbackPositionUs + if (playbackPositionUs >= 0) { + videoTimeLine.setActualPosition(playbackPositionUs) + handler.postDelayed(this, 100) + } + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + controller = if (activity is Controller) { + activity as Controller + } else if (parentFragment is Controller) { + parentFragment as Controller + } else { + throw IllegalStateException("Parent must implement Controller interface.") + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.mediasend_video_fragment, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + videoTimeLine = requireActivity().findViewById(R.id.video_timeline) + + player = view.findViewById(R.id.video_player) + hud = view.findViewById(R.id.video_editor_hud) + + uri = requireArguments().getParcelable(KEY_URI)!! + isVideoGif = requireArguments().getBoolean(KEY_IS_VIDEO_GIF) + maxSend = requireArguments().getLong(KEY_MAX_SEND) + + val slide = VideoSlide(requireContext(), uri, 0, isVideoGif) + player.setWindow(requireActivity().window) + player.setVideoSource(slide, isVideoGif, TAG) + + if (slide.isVideoGif) { + player.setPlayerCallback(object : PlayerCallback { + override fun onPlaying() { + controller.onPlayerReady() + } + + override fun onStopped() = Unit + + override fun onError() { + controller.onPlayerError() + } + }) + player.hideControls() + player.loopForever() + } else { + if (MediaConstraints.isVideoTranscodeAvailable()) { + sharedViewModel.state.value?.let { state -> + bindVideoTimeline(state) + } + } else { + hud.visibility = View.VISIBLE + } + hud.setPlayClickListener { + player.play() + } + player.setOnClickListener { + player.pause() + hud.showPlayButton() + } + + player.setPlayerCallback(object : PlayerCallback { + override fun onReady() { + controller.onPlayerReady() + } + + override fun onPlaying() { + hud.fadePlayButton() + } + + override fun onStopped() { + hud.showPlayButton() + } + + override fun onError() { + controller.onPlayerError() + } + }) + } + + sharedViewModel.state.observe(viewLifecycleOwner) { incomingState -> + val focusedUri = incomingState.focusedMedia?.uri + val currentlyFocused = focusedUri != null && focusedUri == uri + if (MediaConstraints.isVideoTranscodeAvailable() && canEdit) { + if (currentlyFocused) { + if (!isFocused) { + bindVideoTimeline(incomingState) + } else { + val videoTrimData = if (focusedUri != null) { + incomingState.getOrCreateVideoTrimData(focusedUri) + } else { + VideoTrimData() + } + onEditVideoDuration(videoTrimData, incomingState.isTouchEnabled) + } + } else { + stopPositionUpdates() + player.pause() + } + } + isFocused = currentlyFocused + } + } + + @RequiresApi(23) + private fun bindVideoTimeline(state: MediaSelectionState) { + val uri = state.focusedMedia?.uri ?: return + if (uri != this.uri) { + return + } + + val autoplay = isVideoGif + val slide = VideoSlide(requireContext(), uri, 0, autoplay) + + val data = state.getOrCreateVideoTrimData(uri) + if (data.isDurationEdited) { + player.clip(data.startTimeUs, data.endTimeUs, autoplay) + } + + if (slide.hasVideo()) { + canEdit = true + try { + videoTimeLine.registerPlayerDragListener(this) + + hud.visibility = View.VISIBLE + startPositionUpdates() + } catch (e: IOException) { + Log.w(TAG, e) + } + } + } + + override fun onPositionDrag(position: Long) { + onSeek(position, false) + } + + override fun onEndPositionDrag(position: Long) { + onSeek(position, true) + } + + override fun onDestroyView() { + super.onDestroyView() + + player.cleanup() + } + + override fun onPause() { + super.onPause() + notifyHidden() + + stopPositionUpdates() + } + + override fun onResume() { + super.onResume() + startPositionUpdates() + + if (isVideoGif) { + player.play() + } + } + + private fun startPositionUpdates() { + if (Build.VERSION.SDK_INT >= 23) { + stopPositionUpdates() + handler.post(updatePosition) + } + } + + private fun stopPositionUpdates() { + handler.removeCallbacks(updatePosition) + } + + override fun onHiddenChanged(hidden: Boolean) { + if (hidden) { + notifyHidden() + } + } + + override fun setUri(uri: Uri) { + this.uri = uri + } + + override fun getUri(): Uri { + return uri + } + + override fun saveState(): Any = Unit + + override fun restoreState(state: Any) = Unit + + override fun notifyHidden() { + pausePlayback() + } + + private fun pausePlayback() { + player.pause() + hud.showPlayButton() + } + + @RequiresApi(23) + private fun onEditVideoDuration(data: VideoTrimData, editingComplete: Boolean) { + hud.hidePlayButton() + + if (editingComplete) { + isInEdit = false + videoScanThrottle.clear() + } else if (!isInEdit) { + isInEdit = true + wasPlayingBeforeEdit = player.isPlaying + } + + videoScanThrottle.publish { + player.pause() + if (!editingComplete) { + player.removeClip(false) + } + player.playbackPosition = if (editingComplete) data.startTimeUs / 1000 else data.endTimeUs / 1000 + if (editingComplete) { + if (data.isDurationEdited) { + player.clip(data.startTimeUs, data.endTimeUs, wasPlayingBeforeEdit) + } else { + player.removeClip(wasPlayingBeforeEdit) + } + + if (!wasPlayingBeforeEdit) { + hud.showPlayButton() + } + } + } + } + + private fun onSeek(position: Long, dragComplete: Boolean) { + if (dragComplete) { + videoScanThrottle.clear() + } + + videoScanThrottle.publish { + player.pause() + val milliseconds = position.microseconds.inWholeMilliseconds + player.playbackPosition = milliseconds + } + } + + interface Controller { + fun onPlayerReady() + + fun onPlayerError() + + fun onTouchEventsNeeded(needed: Boolean) + } + + companion object { + private val TAG = Log.tag(VideoEditorFragment::class.java) + + private const val KEY_URI = "uri" + private const val KEY_MAX_SEND = "max_send_size" + private const val KEY_IS_VIDEO_GIF = "is_video_gif" + + fun newInstance(uri: Uri, maxAttachmentSize: Long, isVideoGif: Boolean): VideoEditorFragment { + val args = Bundle() + args.putParcelable(KEY_URI, uri) + args.putLong(KEY_MAX_SEND, maxAttachmentSize) + args.putBoolean(KEY_IS_VIDEO_GIF, isVideoGif) + + val fragment = VideoEditorFragment() + fragment.arguments = args + fragment.setUri(uri) + return fragment + } + } +} diff --git a/app/src/main/java/org/tm/archive/mediasend/VideoTrimTransform.java b/app/src/main/java/org/tm/archive/mediasend/VideoTrimTransform.java deleted file mode 100644 index a6276d1f..00000000 --- a/app/src/main/java/org/tm/archive/mediasend/VideoTrimTransform.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.tm.archive.mediasend; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.WorkerThread; - -import org.tm.archive.database.AttachmentTable; -import org.tm.archive.mms.SentMediaQuality; - -import java.util.Optional; - - -public final class VideoTrimTransform implements MediaTransform { - - private final VideoEditorFragment.Data data; - - public VideoTrimTransform(@NonNull VideoEditorFragment.Data data) { - this.data = data; - } - - @WorkerThread - @Override - public @NonNull Media transform(@NonNull Context context, @NonNull Media media) { - return new Media(media.getUri(), - media.getMimeType(), - media.getDate(), - media.getWidth(), - media.getHeight(), - media.getSize(), - media.getDuration(), - media.isBorderless(), - media.isVideoGif(), - media.getBucketId(), - media.getCaption(), - Optional.of(new AttachmentTable.TransformProperties(false, data.durationEdited, data.startTimeUs, data.endTimeUs, SentMediaQuality.STANDARD.getCode(), false))); - } -} diff --git a/app/src/main/java/org/tm/archive/mediasend/VideoTrimTransform.kt b/app/src/main/java/org/tm/archive/mediasend/VideoTrimTransform.kt new file mode 100644 index 00000000..e8dcf891 --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/VideoTrimTransform.kt @@ -0,0 +1,28 @@ +package org.tm.archive.mediasend + +import android.content.Context +import androidx.annotation.WorkerThread +import org.tm.archive.database.AttachmentTable.TransformProperties +import org.tm.archive.mediasend.v2.videos.VideoTrimData +import org.tm.archive.mms.SentMediaQuality +import java.util.Optional + +class VideoTrimTransform(private val data: VideoTrimData) : MediaTransform { + @WorkerThread + override fun transform(context: Context, media: Media): Media { + return Media( + media.uri, + media.mimeType, + media.date, + media.width, + media.height, + media.size, + media.duration, + media.isBorderless, + media.isVideoGif, + media.bucketId, + media.caption, + Optional.of(TransformProperties(false, data.isDurationEdited, data.startTimeUs, data.endTimeUs, SentMediaQuality.STANDARD.code, false)) + ) + } +} diff --git a/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXController.kt b/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXController.kt new file mode 100644 index 00000000..0bb388b7 --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXController.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.mediasend.camerax + +import android.Manifest +import android.content.Context +import android.util.Size +import androidx.annotation.MainThread +import androidx.annotation.RequiresApi +import androidx.annotation.RequiresPermission +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.ZoomState +import androidx.camera.video.FileDescriptorOutputOptions +import androidx.camera.video.Recording +import androidx.camera.video.VideoRecordEvent +import androidx.camera.view.video.AudioConfig +import androidx.core.util.Consumer +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import com.google.common.util.concurrent.ListenableFuture +import java.util.concurrent.Executor + +interface CameraXController { + + fun isInitialized(): Boolean + + fun initializeAndBind(context: Context, lifecycleOwner: LifecycleOwner) + + @RequiresPermission(Manifest.permission.CAMERA) + fun bindToLifecycle(lifecycleOwner: LifecycleOwner, onCameraBoundListener: Runnable) + + @MainThread + fun unbind() + + @MainThread + fun takePicture(executor: Executor, callback: ImageCapture.OnImageCapturedCallback) + + @RequiresApi(26) + @MainThread + fun startRecording(outputOptions: FileDescriptorOutputOptions, audioConfig: AudioConfig, executor: Executor, videoSavedListener: Consumer): Recording + + @MainThread + fun setImageAnalysisAnalyzer(executor: Executor, analyzer: ImageAnalysis.Analyzer) + + @MainThread + fun setEnabledUseCases(useCaseFlags: Int) + + @MainThread + fun getImageCaptureFlashMode(): Int + + @MainThread + fun setPreviewTargetSize(size: Size) + + @MainThread + fun setImageCaptureTargetSize(size: Size) + + @MainThread + fun setImageRotation(rotation: Int) + + @MainThread + fun setImageCaptureFlashMode(flashMode: Int) + + @MainThread + fun setZoomRatio(ratio: Float): ListenableFuture + + @MainThread + fun getZoomState(): LiveData + + @MainThread + fun setCameraSelector(selector: CameraSelector) + + @MainThread + fun getCameraSelector(): CameraSelector + + @MainThread + fun hasCamera(selectedCamera: CameraSelector): Boolean + + @MainThread + fun addInitializationCompletedListener(executor: Executor, onComplete: () -> Unit) +} diff --git a/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXModePolicy.kt b/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXModePolicy.kt index 05212e41..007a4b57 100644 --- a/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXModePolicy.kt +++ b/app/src/main/java/org/tm/archive/mediasend/camerax/CameraXModePolicy.kt @@ -15,11 +15,11 @@ sealed class CameraXModePolicy { abstract val isVideoSupported: Boolean - abstract fun initialize(cameraController: CameraController) + abstract fun initialize(cameraController: CameraXController) - open fun setToImage(cameraController: CameraController) = Unit + open fun setToImage(cameraController: CameraXController) = Unit - open fun setToVideo(cameraController: CameraController) = Unit + open fun setToVideo(cameraController: CameraXController) = Unit /** * The device supports having Image and Video enabled at the same time @@ -28,7 +28,7 @@ sealed class CameraXModePolicy { override val isVideoSupported: Boolean = true - override fun initialize(cameraController: CameraController) { + override fun initialize(cameraController: CameraXController) { cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE or CameraController.VIDEO_CAPTURE) } } @@ -40,15 +40,15 @@ sealed class CameraXModePolicy { override val isVideoSupported: Boolean = true - override fun initialize(cameraController: CameraController) { + override fun initialize(cameraController: CameraXController) { setToImage(cameraController) } - override fun setToImage(cameraController: CameraController) { + override fun setToImage(cameraController: CameraXController) { cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE) } - override fun setToVideo(cameraController: CameraController) { + override fun setToVideo(cameraController: CameraXController) { cameraController.setEnabledUseCases(CameraController.VIDEO_CAPTURE) } } @@ -60,7 +60,7 @@ sealed class CameraXModePolicy { override val isVideoSupported: Boolean = false - override fun initialize(cameraController: CameraController) { + override fun initialize(cameraController: CameraXController) { cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE) } } diff --git a/app/src/main/java/org/tm/archive/mediasend/camerax/PlatformCameraController.kt b/app/src/main/java/org/tm/archive/mediasend/camerax/PlatformCameraController.kt new file mode 100644 index 00000000..11432d4f --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/camerax/PlatformCameraController.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.mediasend.camerax + +import android.content.Context +import android.util.Size +import androidx.annotation.RequiresApi +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.ZoomState +import androidx.camera.video.FallbackStrategy +import androidx.camera.video.FileDescriptorOutputOptions +import androidx.camera.video.Quality +import androidx.camera.video.QualitySelector +import androidx.camera.video.Recording +import androidx.camera.video.VideoRecordEvent +import androidx.camera.view.CameraController +import androidx.camera.view.LifecycleCameraController +import androidx.camera.view.video.AudioConfig +import androidx.core.util.Consumer +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import com.google.common.util.concurrent.ListenableFuture +import org.tm.archive.util.TextSecurePreferences +import java.util.concurrent.Executor + +class PlatformCameraController(context: Context) : CameraXController { + val delegate = LifecycleCameraController(context) + + override fun isInitialized(): Boolean { + return delegate.initializationFuture.isDone + } + + override fun initializeAndBind(context: Context, lifecycleOwner: LifecycleOwner) { + delegate.bindToLifecycle(lifecycleOwner) + delegate.setCameraSelector(CameraXUtil.toCameraSelector(TextSecurePreferences.getDirectCaptureCameraId(context))) + delegate.setTapToFocusEnabled(true) + delegate.setImageCaptureMode(CameraXUtil.getOptimalCaptureMode()) + delegate.setVideoCaptureQualitySelector(QualitySelector.from(Quality.HD, FallbackStrategy.lowerQualityThan(Quality.HD))) + } + + override fun bindToLifecycle(lifecycleOwner: LifecycleOwner, onCameraBoundListener: Runnable) { + delegate.bindToLifecycle(lifecycleOwner) + onCameraBoundListener.run() + } + + override fun unbind() { + delegate.unbind() + } + + override fun takePicture(executor: Executor, callback: ImageCapture.OnImageCapturedCallback) { + delegate.takePicture(executor, callback) + } + + @RequiresApi(26) + override fun startRecording(outputOptions: FileDescriptorOutputOptions, audioConfig: AudioConfig, executor: Executor, videoSavedListener: Consumer): Recording { + return delegate.startRecording(outputOptions, audioConfig, executor, videoSavedListener) + } + + override fun setImageAnalysisAnalyzer(executor: Executor, analyzer: ImageAnalysis.Analyzer) { + delegate.setImageAnalysisAnalyzer(executor, analyzer) + } + + override fun setEnabledUseCases(useCaseFlags: Int) { + delegate.setEnabledUseCases(useCaseFlags) + } + + override fun getImageCaptureFlashMode(): Int { + return delegate.imageCaptureFlashMode + } + + override fun setPreviewTargetSize(size: Size) { + delegate.previewTargetSize = CameraController.OutputSize(size) + } + + override fun setImageCaptureTargetSize(size: Size) { + delegate.imageCaptureTargetSize = CameraController.OutputSize(size) + } + + override fun setImageRotation(rotation: Int) { + throw NotImplementedError("Not supported by the platform camera controller!") + } + + override fun setImageCaptureFlashMode(flashMode: Int) { + delegate.imageCaptureFlashMode = flashMode + } + + override fun setZoomRatio(ratio: Float): ListenableFuture { + return delegate.setZoomRatio(ratio) + } + + override fun getZoomState(): LiveData { + return delegate.zoomState + } + + override fun setCameraSelector(selector: CameraSelector) { + delegate.cameraSelector = selector + } + + override fun getCameraSelector(): CameraSelector { + return delegate.cameraSelector + } + + override fun hasCamera(selectedCamera: CameraSelector): Boolean { + return delegate.hasCamera(selectedCamera) + } + + override fun addInitializationCompletedListener(executor: Executor, onComplete: () -> Unit) { + delegate.initializationFuture.addListener(onComplete, executor) + } +} diff --git a/app/src/main/java/org/tm/archive/mediasend/camerax/SignalCameraController.kt b/app/src/main/java/org/tm/archive/mediasend/camerax/SignalCameraController.kt new file mode 100644 index 00000000..cbb7979b --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/camerax/SignalCameraController.kt @@ -0,0 +1,540 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.mediasend.camerax + +import android.Manifest +import android.content.Context +import android.util.Size +import android.view.MotionEvent +import android.view.ScaleGestureDetector +import android.view.Surface +import android.view.View +import android.view.ViewConfiguration +import androidx.annotation.MainThread +import androidx.annotation.RequiresApi +import androidx.annotation.RequiresPermission +import androidx.camera.core.Camera +import androidx.camera.core.CameraSelector +import androidx.camera.core.DisplayOrientedMeteringPointFactory +import androidx.camera.core.FocusMeteringAction +import androidx.camera.core.FocusMeteringResult +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.core.UseCase +import androidx.camera.core.UseCaseGroup +import androidx.camera.core.ZoomState +import androidx.camera.core.resolutionselector.AspectRatioStrategy +import androidx.camera.core.resolutionselector.ResolutionSelector +import androidx.camera.core.resolutionselector.ResolutionStrategy +import androidx.camera.extensions.ExtensionMode +import androidx.camera.extensions.ExtensionsManager +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.video.FallbackStrategy +import androidx.camera.video.FileDescriptorOutputOptions +import androidx.camera.video.Quality +import androidx.camera.video.QualitySelector +import androidx.camera.video.Recorder +import androidx.camera.video.Recording +import androidx.camera.video.VideoCapture +import androidx.camera.video.VideoRecordEvent +import androidx.camera.view.CameraController +import androidx.camera.view.PreviewView +import androidx.camera.view.video.AudioConfig +import androidx.core.content.ContextCompat +import androidx.core.util.Consumer +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import com.google.common.util.concurrent.FutureCallback +import com.google.common.util.concurrent.Futures +import com.google.common.util.concurrent.ListenableFuture +import org.signal.core.util.ThreadUtil +import org.signal.core.util.logging.Log +import org.tm.archive.mediasend.camerax.SignalCameraController.InitializationListener +import org.tm.archive.util.TextSecurePreferences +import org.tm.archive.util.ViewUtil +import org.tm.archive.util.visible +import java.util.concurrent.Executor +import kotlin.math.max +import kotlin.math.min + +/** + * This is a class to manage the camera resource, and relies on the AndroidX CameraX library. + * + * The API is a subset of the [CameraController] class, but with a few additions such as [setImageRotation]. + */ +class SignalCameraController( + private val context: Context, + private val lifecycleOwner: LifecycleOwner, + private val previewView: PreviewView, + private val focusIndicator: View +) : CameraXController { + companion object { + val TAG = Log.tag(SignalCameraController::class.java) + + private const val AF_SIZE = 1.0f / 6.0f + private const val AE_SIZE = AF_SIZE * 1.5f + + @JvmStatic + private fun isLandscape(surfaceRotation: Int): Boolean { + return surfaceRotation == Surface.ROTATION_90 || surfaceRotation == Surface.ROTATION_270 + } + } + + private val videoQualitySelector: QualitySelector = QualitySelector.from(Quality.HD, FallbackStrategy.lowerQualityThan(Quality.HD)) + private val imageMode = CameraXUtil.getOptimalCaptureMode() + + private val cameraProviderFuture: ListenableFuture = ProcessCameraProvider.getInstance(context) + private val scaleGestureDetector = ScaleGestureDetector(context, PinchToZoomGestureListener()) + private val initializationCompleteListeners: MutableSet = mutableSetOf() + private val customUseCases: MutableList = mutableListOf() + + private var tapToFocusEvents = 0 + private var listenerAdded = false + + private var imageRotation = 0 + private var recording: Recording? = null + private var previewTargetSize: Size? = null + private var imageCaptureTargetSize: Size? = null + private var cameraSelector: CameraSelector = CameraXUtil.toCameraSelector(TextSecurePreferences.getDirectCaptureCameraId(context)) + private var enabledUseCases: Int = CameraController.IMAGE_CAPTURE + + private var previewUseCase: Preview = createPreviewUseCase() + private var imageCaptureUseCase: ImageCapture = createImageCaptureUseCase() + private var videoCaptureUseCase: VideoCapture = createVideoCaptureRecorder() + + private lateinit var cameraProvider: ProcessCameraProvider + private lateinit var extensionsManager: ExtensionsManager + private lateinit var cameraProperty: Camera + + override fun isInitialized(): Boolean { + return this::cameraProvider.isInitialized && this::extensionsManager.isInitialized + } + + override fun initializeAndBind(context: Context, lifecycleOwner: LifecycleOwner) { + bindToLifecycle(lifecycleOwner) { Log.d(TAG, "Camera initialization and binding complete.") } + } + + @RequiresPermission(Manifest.permission.CAMERA) + override fun bindToLifecycle(lifecycleOwner: LifecycleOwner, onCameraBoundListener: Runnable) { + ThreadUtil.assertMainThread() + if (isInitialized()) { + bindToLifecycleInternal() + onCameraBoundListener.run() + } else if (!listenerAdded) { + cameraProviderFuture.addListener({ + cameraProvider = cameraProviderFuture.get() + val extensionsManagerFuture = + ExtensionsManager.getInstanceAsync(context, cameraProvider) + extensionsManagerFuture.addListener({ + extensionsManager = extensionsManagerFuture.get() + initializationCompleteListeners.forEach { it.onInitialized(cameraProvider) } + bindToLifecycleInternal() + onCameraBoundListener.run() + }, ContextCompat.getMainExecutor(context)) + }, ContextCompat.getMainExecutor(context)) + listenerAdded = true + } + } + + @MainThread + override fun unbind() { + ThreadUtil.assertMainThread() + cameraProvider.unbindAll() + } + + @MainThread + fun bindToLifecycleInternal() { + ThreadUtil.assertMainThread() + try { + if (!this::cameraProvider.isInitialized || !this::extensionsManager.isInitialized) { + Log.d(TAG, "Camera provider not yet initialized.") + return + } + + val extCameraSelector = if (extensionsManager.isExtensionAvailable(cameraSelector, ExtensionMode.AUTO)) { + Log.d(TAG, "Using CameraX ExtensionMode.AUTO") + extensionsManager.getExtensionEnabledCameraSelector( + cameraSelector, + ExtensionMode.AUTO + ) + } else { + Log.d(TAG, "Using standard camera selector") + cameraSelector + } + + val camera = cameraProvider.bindToLifecycle( + lifecycleOwner, + extCameraSelector, + buildUseCaseGroup() + ) + + initializeTapToFocusAndPinchToZoom(camera) + this.cameraProperty = camera + } catch (e: Exception) { + Log.e(TAG, "Use case binding failed", e) + } + } + + @MainThread + override fun setImageAnalysisAnalyzer(executor: Executor, analyzer: ImageAnalysis.Analyzer) { + ThreadUtil.assertMainThread() + val imageAnalysis = ImageAnalysis.Builder() + .setResolutionSelector(ResolutionSelector.Builder().setResolutionStrategy(ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY).build()) + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) + .build() + + imageAnalysis.setAnalyzer(executor, analyzer) + + customUseCases += imageAnalysis + + if (isRecording()) { + stopRecording() + } + + tryToBindCamera() + } + + @MainThread + override fun takePicture(executor: Executor, callback: ImageCapture.OnImageCapturedCallback) { + ThreadUtil.assertMainThread() + assertImageEnabled() + imageCaptureUseCase.takePicture(executor, callback) + } + + @RequiresApi(26) + @MainThread + override fun startRecording(outputOptions: FileDescriptorOutputOptions, audioConfig: AudioConfig, executor: Executor, videoSavedListener: Consumer): Recording { + ThreadUtil.assertMainThread() + assertVideoEnabled() + + recording?.stop() + recording = null + val startedRecording = videoCaptureUseCase.output + .prepareRecording(context, outputOptions) + .apply { + if (audioConfig.audioEnabled) { + withAudioEnabled() + } + } + .start(ContextCompat.getMainExecutor(context)) { + videoSavedListener.accept(it) + if (it is VideoRecordEvent.Finalize) { + recording = null + } + } + + recording = startedRecording + return startedRecording + } + + @MainThread + override fun setEnabledUseCases(useCaseFlags: Int) { + ThreadUtil.assertMainThread() + if (enabledUseCases == useCaseFlags) { + return + } + + val oldEnabledUseCases = enabledUseCases + enabledUseCases = useCaseFlags + if (isRecording()) { + stopRecording() + } + tryToBindCamera { enabledUseCases = oldEnabledUseCases } + } + + @MainThread + override fun getImageCaptureFlashMode(): Int { + ThreadUtil.assertMainThread() + return imageCaptureUseCase.flashMode + } + + @MainThread + override fun setPreviewTargetSize(size: Size) { + ThreadUtil.assertMainThread() + if (size == previewTargetSize || previewTargetSize?.equals(size) == true) { + return + } + Log.d(TAG, "Setting Preview dimensions to $size") + previewTargetSize = size + if (this::cameraProvider.isInitialized) { + cameraProvider.unbind(previewUseCase) + } + previewUseCase = createPreviewUseCase() + + tryToBindCamera(null) + } + + @MainThread + override fun setImageCaptureTargetSize(size: Size) { + ThreadUtil.assertMainThread() + if (size == imageCaptureTargetSize || imageCaptureTargetSize?.equals(size) == true) { + return + } + imageCaptureTargetSize = size + if (this::cameraProvider.isInitialized) { + cameraProvider.unbind(imageCaptureUseCase) + } + imageCaptureUseCase = createImageCaptureUseCase() + tryToBindCamera(null) + } + + @MainThread + override fun setImageRotation(rotation: Int) { + ThreadUtil.assertMainThread() + val newRotation = UseCase.snapToSurfaceRotation(rotation.coerceIn(0, 359)) + + if (newRotation == imageRotation) { + return + } + + if (isLandscape(newRotation) != isLandscape(imageRotation)) { + imageCaptureTargetSize = imageCaptureTargetSize?.swap() + } + + videoCaptureUseCase.targetRotation = newRotation + imageCaptureUseCase.targetRotation = newRotation + + imageRotation = newRotation + } + + @MainThread + override fun setImageCaptureFlashMode(flashMode: Int) { + ThreadUtil.assertMainThread() + imageCaptureUseCase.flashMode = flashMode + } + + @MainThread + override fun setZoomRatio(ratio: Float): ListenableFuture { + ThreadUtil.assertMainThread() + return cameraProperty.cameraControl.setZoomRatio(ratio) + } + + @MainThread + override fun getZoomState(): LiveData { + ThreadUtil.assertMainThread() + return cameraProperty.cameraInfo.zoomState + } + + @MainThread + override fun setCameraSelector(selector: CameraSelector) { + ThreadUtil.assertMainThread() + if (selector == cameraSelector) { + return + } + + val oldCameraSelector: CameraSelector = cameraSelector + cameraSelector = selector + if (!this::cameraProvider.isInitialized) { + return + } + cameraProvider.unbindAll() + tryToBindCamera { cameraSelector = oldCameraSelector } + } + + @MainThread + override fun getCameraSelector(): CameraSelector { + ThreadUtil.assertMainThread() + return cameraSelector + } + + @MainThread + override fun hasCamera(selectedCamera: CameraSelector): Boolean { + ThreadUtil.assertMainThread() + return cameraProvider.hasCamera(selectedCamera) + } + + override fun addInitializationCompletedListener(executor: Executor, onComplete: () -> Unit) { + ThreadUtil.assertMainThread() + initializationCompleteListeners.add(InitializationListener { onComplete() }) + } + + @MainThread + private fun tryToBindCamera(restoreStateRunnable: (() -> Unit)? = null) { + ThreadUtil.assertMainThread() + try { + bindToLifecycleInternal() + } catch (e: RuntimeException) { + Log.i(TAG, "Could not re-bind camera!", e) + restoreStateRunnable?.invoke() + } + } + + @MainThread + private fun stopRecording() { + ThreadUtil.assertMainThread() + recording?.close() + } + + private fun createVideoCaptureRecorder() = VideoCapture.Builder( + Recorder.Builder() + .setQualitySelector(videoQualitySelector) + .build() + ) + .setTargetRotation(imageRotation) + .build() + + private fun createPreviewUseCase() = Preview.Builder() + .apply { + setTargetRotation(Surface.ROTATION_0) + val size = previewTargetSize + if (size != null) { + setResolutionSelector( + ResolutionSelector.Builder() + .setResolutionStrategy(ResolutionStrategy(size, ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER)) + .build() + ) + } + }.build() + .also { + it.setSurfaceProvider(previewView.surfaceProvider) + } + + private fun createImageCaptureUseCase(): ImageCapture = ImageCapture.Builder() + .apply { + setCaptureMode(imageMode) + setTargetRotation(imageRotation) + + val size = imageCaptureTargetSize + if (size != null) { + setResolutionSelector( + ResolutionSelector.Builder() + .setAspectRatioStrategy(AspectRatioStrategy.RATIO_16_9_FALLBACK_AUTO_STRATEGY) + .setResolutionStrategy(ResolutionStrategy(size, ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER)) + .build() + ) + } + }.build() + + private fun buildUseCaseGroup() = UseCaseGroup.Builder().apply { + addUseCase(previewUseCase) + if (isUseCaseEnabled(CameraController.IMAGE_CAPTURE)) { + addUseCase(imageCaptureUseCase) + } else { + cameraProvider.unbind(imageCaptureUseCase) + } + if (isUseCaseEnabled(CameraController.VIDEO_CAPTURE)) { + addUseCase(videoCaptureUseCase) + } else { + cameraProvider.unbind(videoCaptureUseCase) + } + + for (useCase in customUseCases) { + addUseCase(useCase) + } + + previewView.getViewPort(Surface.ROTATION_0)?.let { setViewPort(it) } ?: Log.d(TAG, "ViewPort was null, not adding to UseCase builder.") + }.build() + + @MainThread + private fun initializeTapToFocusAndPinchToZoom(camera: Camera) { + ThreadUtil.assertMainThread() + previewView.setOnTouchListener { v: View?, event: MotionEvent -> + val isSingleTouch = event.pointerCount == 1 + val isUpEvent = event.action == MotionEvent.ACTION_UP + val notALongPress = (event.eventTime - event.downTime < ViewConfiguration.getLongPressTimeout()) + if (isSingleTouch && isUpEvent && notALongPress) { + focusAndMeterOnPoint(camera, event.x, event.y) + v?.performClick() + return@setOnTouchListener true + } + return@setOnTouchListener scaleGestureDetector.onTouchEvent(event) + } + } + + @MainThread + private fun focusAndMeterOnPoint(camera: Camera, x: Float, y: Float) { + ThreadUtil.assertMainThread() + val meteringPointFactory = DisplayOrientedMeteringPointFactory(previewView.display, camera.cameraInfo, previewView.width.toFloat(), previewView.height.toFloat()) + val afPoint = meteringPointFactory.createPoint(x, y, AF_SIZE) + val aePoint = meteringPointFactory.createPoint(x, y, AE_SIZE) + val action = FocusMeteringAction.Builder(afPoint, FocusMeteringAction.FLAG_AF) + .addPoint(aePoint, FocusMeteringAction.FLAG_AE) + .build() + + focusIndicator.x = x - (focusIndicator.width / 2) + focusIndicator.y = y - (focusIndicator.height / 2) + focusIndicator.visible = true + + tapToFocusEvents += 1 + + Futures.addCallback( + camera.cameraControl.startFocusAndMetering(action), + object : FutureCallback { + override fun onSuccess(result: FocusMeteringResult?) { + Log.d(TAG, "Tap to focus was successful? ${result?.isFocusSuccessful}") + tapToFocusEvents -= 1 + if (tapToFocusEvents <= 0) { + ViewUtil.fadeOut(focusIndicator, 80) + } + } + + override fun onFailure(t: Throwable) { + Log.d(TAG, "Tap to focus could not be completed due to an exception.", t) + tapToFocusEvents -= 1 + if (tapToFocusEvents <= 0) { + ViewUtil.fadeOut(focusIndicator, 80) + } + } + }, + ContextCompat.getMainExecutor(context) + ) + } + + @MainThread + private fun onPinchToZoom(pinchToZoomScale: Float) { + val zoomState = getZoomState().getValue() ?: return + var clampedRatio: Float = zoomState.zoomRatio * if (pinchToZoomScale > 1f) { + 1.0f + (pinchToZoomScale - 1.0f) * 2 + } else { + 1.0f - (1.0f - pinchToZoomScale) * 2 + } + clampedRatio = min( + max(clampedRatio.toDouble(), zoomState.minZoomRatio.toDouble()), + zoomState.maxZoomRatio.toDouble() + ).toFloat() + setZoomRatio(clampedRatio) + } + + private fun isRecording(): Boolean { + return recording != null + } + + private fun isUseCaseEnabled(mask: Int): Boolean { + return (enabledUseCases and mask) != 0 + } + + private fun assertVideoEnabled() { + if (!isUseCaseEnabled(CameraController.VIDEO_CAPTURE)) { + throw IllegalStateException("VideoCapture disabled.") + } + } + + private fun assertImageEnabled() { + if (!isUseCaseEnabled(CameraController.IMAGE_CAPTURE)) { + throw IllegalStateException("ImageCapture disabled.") + } + } + + private fun Size.swap(): Size { + return Size(this.height, this.width) + } + + inner class PinchToZoomGestureListener : ScaleGestureDetector.OnScaleGestureListener { + override fun onScale(detector: ScaleGestureDetector): Boolean { + onPinchToZoom(detector.scaleFactor) + return true + } + + override fun onScaleBegin(detector: ScaleGestureDetector): Boolean = true + + override fun onScaleEnd(detector: ScaleGestureDetector) = Unit + } + + fun interface InitializationListener { + fun onInitialized(cameraProvider: ProcessCameraProvider) + } +} diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/MediaAnimations.kt b/app/src/main/java/org/tm/archive/mediasend/v2/MediaAnimations.kt index d9466f0c..f52b7dba 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/MediaAnimations.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/MediaAnimations.kt @@ -1,12 +1,12 @@ package org.tm.archive.mediasend.v2 import android.view.animation.Interpolator -import androidx.interpolator.view.animation.FastOutSlowInInterpolator +import org.tm.archive.util.createDefaultCubicBezierInterpolator object MediaAnimations { /** * Fast-In-Extra-Slow-Out Interpolator */ @JvmStatic - val interpolator: Interpolator = FastOutSlowInInterpolator() + val interpolator: Interpolator = createDefaultCubicBezierInterpolator() } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionActivity.kt b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionActivity.kt index b18f82bb..8e0988a0 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionActivity.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionActivity.kt @@ -3,6 +3,7 @@ package org.tm.archive.mediasend.v2 import android.animation.ValueAnimator import android.content.Context import android.content.Intent +import android.content.pm.ActivityInfo import android.graphics.Color import android.os.Bundle import android.view.KeyEvent @@ -42,6 +43,8 @@ import org.tm.archive.mediasend.v2.text.send.TextStoryPostSendRepository import org.tm.archive.recipients.RecipientId import org.tm.archive.safety.SafetyNumberBottomSheet import org.tm.archive.stories.Stories +import org.tm.archive.util.Debouncer +import org.tm.archive.util.FeatureFlags import org.tm.archive.util.FullscreenHelper import org.tm.archive.util.WindowUtil import org.tm.archive.util.navigation.safeNavigate @@ -79,6 +82,8 @@ class MediaSelectionActivity : private val draftText: CharSequence? get() = intent.getCharSequenceExtra(MESSAGE) + private val debouncer = Debouncer(200) + override fun attachBaseContext(newBase: Context) { delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES super.attachBaseContext(newBase) @@ -87,6 +92,10 @@ class MediaSelectionActivity : override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { setContentView(R.layout.media_selection_activity) + if (FeatureFlags.customCameraXController()) { + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + } + FullscreenHelper.showSystemUI(window) WindowUtil.setNavigationBarColor(this, 0x01000000) WindowUtil.setStatusBarColor(window, Color.TRANSPARENT) @@ -122,7 +131,7 @@ class MediaSelectionActivity : } cameraSwitch.setOnClickListener { - viewModel.sendCommand(HudCommand.GoToCapture) + debouncer.publish { viewModel.sendCommand(HudCommand.GoToCapture) } } if (savedInstanceState == null) { diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionRepository.kt b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionRepository.kt index 7989b0c9..1736b9c6 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionRepository.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionRepository.kt @@ -29,8 +29,8 @@ import org.tm.archive.mediasend.MediaSendActivityResult import org.tm.archive.mediasend.MediaTransform import org.tm.archive.mediasend.MediaUploadRepository import org.tm.archive.mediasend.SentMediaQualityTransform -import org.tm.archive.mediasend.VideoEditorFragment import org.tm.archive.mediasend.VideoTrimTransform +import org.tm.archive.mediasend.v2.videos.VideoTrimData import org.tm.archive.mms.GifSlide import org.tm.archive.mms.ImageSlide import org.tm.archive.mms.MediaConstraints @@ -80,7 +80,6 @@ class MediaSelectionRepository(context: Context) { stateMap: Map, quality: SentMediaQuality, message: CharSequence?, - isSms: Boolean, isViewOnce: Boolean, singleContact: ContactSearchKey.RecipientSearchKey?, contacts: List, @@ -89,10 +88,6 @@ class MediaSelectionRepository(context: Context) { sendType: MessageSendType, scheduledTime: Long = -1 ): Maybe { - if (isSms && contacts.isNotEmpty()) { - throw IllegalStateException("Provided recipients to send to, but this is SMS!") - } - if (selectedMedia.isEmpty()) { throw IllegalStateException("No selected media!") } @@ -121,8 +116,8 @@ class MediaSelectionRepository(context: Context) { StoryType.NONE } - if (isSms || MessageSender.isLocalSelfSend(context, singleRecipient, SendType.SIGNAL)) { - Log.i(TAG, "SMS or local self-send. Skipping pre-upload.") + if (MessageSender.isLocalSelfSend(context, singleRecipient, SendType.SIGNAL)) { + Log.i(TAG, "Local self-send. Skipping pre-upload.") emitter.onSuccess( MediaSendActivityResult( recipientId = singleRecipient!!.id, @@ -207,7 +202,7 @@ class MediaSelectionRepository(context: Context) { ) ) } else { - Log.w(TAG, "Got empty upload results! isSms: $isSms, updatedMedia.size(): ${updatedMedia.size}, isViewOnce: $isViewOnce, target: $singleContact") + Log.w(TAG, "Got empty upload results! updatedMedia.size(): ${updatedMedia.size}, isViewOnce: $isViewOnce, target: $singleContact") emitter.onSuccess( MediaSendActivityResult( recipientId = singleRecipient!!.id, @@ -249,8 +244,8 @@ class MediaSelectionRepository(context: Context) { uploadRepository.deleteAbandonedAttachments() } - fun isLocalSelfSend(recipient: Recipient?, isSms: Boolean): Boolean { - return MessageSender.isLocalSelfSend(context, recipient, if (isSms) MessageSender.SendType.SMS else MessageSender.SendType.SIGNAL) + fun isLocalSelfSend(recipient: Recipient?): Boolean { + return MessageSender.isLocalSelfSend(context, recipient, SendType.SIGNAL) } @WorkerThread @@ -270,7 +265,7 @@ class MediaSelectionRepository(context: Context) { } } - if (state is VideoEditorFragment.Data && state.isDurationEdited) { + if (state is VideoTrimData && state.isDurationEdited) { modelsToRender[it] = VideoTrimTransform(state) } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionState.kt b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionState.kt index 92b98dc6..ac39d394 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionState.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionState.kt @@ -4,11 +4,14 @@ import android.net.Uri import org.tm.archive.conversation.MessageSendType import org.tm.archive.keyvalue.SignalStore import org.tm.archive.mediasend.Media -import org.tm.archive.mediasend.MediaSendConstants +import org.tm.archive.mediasend.v2.videos.VideoTrimData +import org.tm.archive.mms.MediaConstraints import org.tm.archive.mms.SentMediaQuality import org.tm.archive.recipients.Recipient import org.tm.archive.stories.Stories import org.tm.archive.util.FeatureFlags +import org.tm.archive.util.MediaUtil +import org.tm.archive.video.TranscodingPreset data class MediaSelectionState( val sendType: MessageSendType, @@ -17,7 +20,7 @@ data class MediaSelectionState( val recipient: Recipient? = null, val quality: SentMediaQuality = SignalStore.settings().sentMediaQuality, val message: CharSequence? = null, - val viewOnceToggleState: ViewOnceToggleState = ViewOnceToggleState.INFINITE, + val viewOnceToggleState: ViewOnceToggleState = ViewOnceToggleState.default, val isTouchEnabled: Boolean = true, val isSent: Boolean = false, val isPreUploadEnabled: Boolean = false, @@ -29,17 +32,20 @@ data class MediaSelectionState( val suppressEmptyError: Boolean = true ) { - val maxSelection = if (sendType.usesSmsTransport) { - MediaSendConstants.MAX_SMS - } else { - FeatureFlags.maxAttachmentCount() - } + val isVideoTrimmingVisible: Boolean = focusedMedia != null && MediaUtil.isVideoType(focusedMedia.mimeType) && MediaConstraints.isVideoTranscodeAvailable() && !focusedMedia.isVideoGif + + val transcodingPreset: TranscodingPreset = MediaConstraints.getPushMediaConstraints(SentMediaQuality.fromCode(quality.code)).videoTranscodingSettings + + val maxSelection = FeatureFlags.maxAttachmentCount() val canSend = !isSent && selectedMedia.isNotEmpty() + fun getOrCreateVideoTrimData(uri: Uri): VideoTrimData { + return editorStateMap[uri] as? VideoTrimData ?: VideoTrimData() + } + enum class ViewOnceToggleState(val code: Int) { - INFINITE(0), - ONCE(1); + INFINITE(0), ONCE(1); fun next(): ViewOnceToggleState { return when (this) { @@ -49,6 +55,8 @@ data class MediaSelectionState( } companion object { + val default = INFINITE + fun fromCode(code: Int): ViewOnceToggleState { return when (code) { 1 -> ONCE diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionViewModel.kt b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionViewModel.kt index 6420b016..f2dada4d 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionViewModel.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/MediaSelectionViewModel.kt @@ -25,23 +25,28 @@ import io.reactivex.rxjava3.subjects.Subject import org.signal.core.util.BreakIteratorCompat import org.signal.core.util.getParcelableArrayListCompat import org.signal.core.util.getParcelableCompat +import org.signal.core.util.logging.Log import org.tm.archive.components.mention.MentionAnnotation import org.tm.archive.contacts.paged.ContactSearchKey import org.tm.archive.conversation.MessageSendType import org.tm.archive.conversation.MessageStyler import org.tm.archive.mediasend.Media import org.tm.archive.mediasend.MediaSendActivityResult -import org.tm.archive.mediasend.VideoEditorFragment import org.tm.archive.mediasend.v2.review.AddMessageCharacterCount +import org.tm.archive.mediasend.v2.videos.VideoTrimData import org.tm.archive.mms.MediaConstraints import org.tm.archive.mms.SentMediaQuality import org.tm.archive.providers.BlobProvider import org.tm.archive.recipients.Recipient import org.tm.archive.scribbles.ImageEditorFragment import org.tm.archive.stories.Stories +import org.tm.archive.util.MediaUtil import org.tm.archive.util.Util import org.tm.archive.util.livedata.Store import java.util.Collections +import kotlin.math.max +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds /** * ViewModel which maintains the list of selected media and other shared values. @@ -58,6 +63,8 @@ class MediaSelectionViewModel( private val identityChangesSince: Long = System.currentTimeMillis() ) : ViewModel() { + private val TAG = Log.tag(MediaSelectionViewModel::class.java) + private val selectedMediaSubject: Subject> = BehaviorSubject.create() private val store: Store = Store( @@ -101,7 +108,7 @@ class MediaSelectionViewModel( store.update { it.copy( isMeteredConnection = metered, - isPreUploadEnabled = shouldPreUpload(metered, it.sendType.usesSmsTransport, it.recipient) + isPreUploadEnabled = shouldPreUpload(metered, it.recipient) ) } } @@ -114,7 +121,7 @@ class MediaSelectionViewModel( store.update(Recipient.live(recipientSearchKey.recipientId).liveData) { r, s -> s.copy( recipient = r, - isPreUploadEnabled = shouldPreUpload(s.isMeteredConnection, s.sendType.usesSmsTransport, r) + isPreUploadEnabled = shouldPreUpload(s.isMeteredConnection, r) ) } } @@ -181,9 +188,16 @@ class MediaSelectionViewModel( .subscribe { filterResult -> if (filterResult.filteredMedia.isNotEmpty()) { store.update { + val initializedVideoEditorStates = filterResult.filteredMedia.filterNot { media -> it.editorStateMap.containsKey(media.uri) } + .filter { media -> MediaUtil.isNonGifVideo(media) } + .associate { video: Media -> + val duration = video.duration.milliseconds.inWholeMicroseconds + video.uri to VideoTrimData(false, duration, 0, duration) + } it.copy( selectedMedia = filterResult.filteredMedia, - focusedMedia = it.focusedMedia ?: filterResult.filteredMedia.first() + focusedMedia = it.focusedMedia ?: filterResult.filteredMedia.first(), + editorStateMap = it.editorStateMap + initializedVideoEditorStates ) } @@ -290,26 +304,23 @@ class MediaSelectionViewModel( } } - fun setFocusedMedia(media: Media) { + fun onPageChanged(media: Media) { store.update { it.copy(focusedMedia = media) } } - fun setFocusedMedia(position: Int) { + fun onPageChanged(position: Int) { store.update { if (position >= it.selectedMedia.size) { it.copy(focusedMedia = null) } else { - it.copy(focusedMedia = it.selectedMedia[position]) + val focusedMedia: Media = it.selectedMedia[position] + it.copy(focusedMedia = focusedMedia) } } } fun getMediaConstraints(): MediaConstraints { - return if (store.state.sendType.usesSmsTransport) { - MediaConstraints.getMmsMediaConstraints(store.state.sendType.simSubscriptionId ?: -1) - } else { - MediaConstraints.getPushMediaConstraints() - } + return MediaConstraints.getPushMediaConstraints() } fun setSentMediaQuality(sentMediaQuality: SentMediaQuality) { @@ -329,6 +340,40 @@ class MediaSelectionViewModel( store.update { it.copy(viewOnceToggleState = it.viewOnceToggleState.next()) } } + fun onEditVideoDuration(context: Context, totalDurationUs: Long, startTimeUs: Long, endTimeUs: Long, touchEnabled: Boolean) { + store.update { + val uri = it.focusedMedia?.uri ?: return@update it + val data = it.getOrCreateVideoTrimData(uri) + val clampedStartTime = max(startTimeUs, 0) + + val unedited = !data.isDurationEdited + val durationEdited = clampedStartTime > 0 || endTimeUs < totalDurationUs + val isEntireDuration = startTimeUs == 0L && endTimeUs == totalDurationUs + val endMoved = !isEntireDuration && data.endTimeUs != endTimeUs + val maxVideoDurationUs: Long = if (it.isStory && !MediaConstraints.isVideoTranscodeAvailable()) { + Stories.MAX_VIDEO_DURATION_MILLIS + } else { + it.transcodingPreset.calculateMaxVideoUploadDurationInSeconds(getMediaConstraints().getVideoMaxSize(context)).seconds.inWholeMicroseconds + } + val preserveStartTime = unedited || !endMoved + val videoTrimData = VideoTrimData(durationEdited, totalDurationUs, clampedStartTime, endTimeUs) + val updatedData = clampToMaxClipDuration(videoTrimData, maxVideoDurationUs, preserveStartTime) + + if (updatedData != videoTrimData) { + Log.d(TAG, "Video trim clamped from ${videoTrimData.startTimeUs}, ${videoTrimData.endTimeUs} to ${updatedData.startTimeUs}, ${updatedData.endTimeUs}") + } + + if (unedited && durationEdited) { + Log.d(TAG, "Canceling upload because the duration has been edited for the first time..") + cancelUpload(MediaBuilder.buildMedia(uri)) + } + it.copy( + isTouchEnabled = touchEnabled, + editorStateMap = it.editorStateMap + (uri to updatedData) + ) + } + } + fun getEditorState(uri: Uri): Any? { return store.state.editorStateMap[uri] } @@ -339,10 +384,6 @@ class MediaSelectionViewModel( } } - fun onVideoBeginEdit(uri: Uri) { - cancelUpload(MediaBuilder.buildMedia(uri)) - } - fun send( selectedContacts: List = emptyList(), scheduledDate: Long? = null @@ -358,7 +399,6 @@ class MediaSelectionViewModel( stateMap = store.state.editorStateMap, quality = store.state.quality, message = store.state.message, - isSms = store.state.sendType.usesSmsTransport, isViewOnce = isViewOnceEnabled(), singleContact = destination.getRecipientSearchKey(), contacts = selectedContacts.ifEmpty { destination.getRecipientSearchKeyList() }, @@ -371,8 +411,7 @@ class MediaSelectionViewModel( } private fun isViewOnceEnabled(): Boolean { - return !store.state.sendType.usesSmsTransport && - store.state.selectedMedia.size == 1 && + return store.state.selectedMedia.size == 1 && store.state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE } @@ -394,8 +433,8 @@ class MediaSelectionViewModel( repository.uploadRepository.cancelUpload(media) } - private fun shouldPreUpload(metered: Boolean, isSms: Boolean, recipient: Recipient?): Boolean { - return !metered && !isSms && !repository.isLocalSelfSend(recipient, isSms) + private fun shouldPreUpload(metered: Boolean, recipient: Recipient?): Boolean { + return !metered && !repository.isLocalSelfSend(recipient) } fun onSaveState(outState: Bundle) { @@ -484,7 +523,7 @@ class MediaSelectionViewModel( val value: Any = if (getBoolean(BUNDLE_IS_IMAGE)) { ImageEditorFragment.Data(this) } else { - VideoEditorFragment.Data.fromBundle(this) + VideoTrimData.fromBundle(this) } return key to value @@ -499,8 +538,8 @@ class MediaSelectionViewModel( } } - is VideoEditorFragment.Data -> { - value.bundle.apply { + is VideoTrimData -> { + value.toBundle().apply { putParcelable(BUNDLE_URI, key) putBoolean(BUNDLE_IS_IMAGE, false) } @@ -527,6 +566,23 @@ class MediaSelectionViewModel( private const val STATE_CAMERA_FIRST_CAPTURE = "$STATE_PREFIX.camera_first_capture" private const val STATE_EDITORS = "$STATE_PREFIX.editors" private const val STATE_EDITOR_COUNT = "$STATE_PREFIX.editor_count" + + @JvmStatic + fun clampToMaxClipDuration(data: VideoTrimData, maxVideoDurationUs: Long, preserveStartTime: Boolean): VideoTrimData { + if (!MediaConstraints.isVideoTranscodeAvailable()) { + return data + } + + if ((data.endTimeUs - data.startTimeUs) <= maxVideoDurationUs) { + return data + } + + return data.copy( + isDurationEdited = true, + startTimeUs = if (!preserveStartTime) data.endTimeUs - maxVideoDurationUs else data.startTimeUs, + endTimeUs = if (preserveStartTime) data.startTimeUs + maxVideoDurationUs else data.endTimeUs + ) + } } class Factory( diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureEvent.kt b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureEvent.kt index 720953f4..fcd78d76 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureEvent.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureEvent.kt @@ -1,8 +1,11 @@ package org.tm.archive.mediasend.v2.capture import org.tm.archive.mediasend.Media +import org.tm.archive.recipients.Recipient sealed class MediaCaptureEvent { data class MediaCaptureRendered(val media: Media) : MediaCaptureEvent() + data class UsernameScannedFromQrCode(val recipient: Recipient, val username: String) : MediaCaptureEvent() + object DeviceLinkScannedFromQrCode : MediaCaptureEvent() object MediaCaptureRenderFailed : MediaCaptureEvent() } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureFragment.kt b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureFragment.kt index a52472b0..8f625b24 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureFragment.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureFragment.kt @@ -8,9 +8,11 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import app.cash.exhaustive.Exhaustive +import com.google.android.material.dialog.MaterialAlertDialogBuilder import io.reactivex.rxjava3.core.Flowable import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.logging.Log +import org.tm.archive.DeviceActivity import org.tm.archive.R import org.tm.archive.mediasend.CameraFragment import org.tm.archive.mediasend.Media @@ -21,6 +23,7 @@ import org.tm.archive.mediasend.v2.MediaSelectionViewModel import org.tm.archive.mms.MediaConstraints import org.tm.archive.permissions.Permissions import org.tm.archive.stories.Stories +import org.tm.archive.util.CommunicationActions import org.tm.archive.util.navigation.safeNavigate import java.io.FileDescriptor import java.util.Optional @@ -47,7 +50,7 @@ class MediaCaptureFragment : Fragment(R.layout.fragment_container), CameraFragme private val lifecycleDisposable = LifecycleDisposable() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - captureChildFragment = CameraFragment.newInstance() as CameraFragment + captureChildFragment = CameraFragment.newInstance(sharedViewModel.isContactSelectionRequired) as CameraFragment navigator = MediaSelectionNavigator( toGallery = R.id.action_mediaCaptureFragment_to_mediaGalleryFragment @@ -74,6 +77,28 @@ class MediaCaptureFragment : Fragment(R.layout.fragment_container), CameraFragme navigator.goToReview(findNavController()) } + is MediaCaptureEvent.UsernameScannedFromQrCode -> { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.MediaCaptureFragment_username_dialog_title, event.username)) + .setMessage(getString(R.string.MediaCaptureFragment_username_dialog_body, event.username)) + .setPositiveButton(R.string.MediaCaptureFragment_username_dialog_go_to_chat_button) { d, _ -> + CommunicationActions.startConversation(requireContext(), event.recipient, "") + requireActivity().finish() + } + .setNegativeButton(android.R.string.cancel, null) + .show() + } + is MediaCaptureEvent.DeviceLinkScannedFromQrCode -> { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.MediaCaptureFragment_device_link_dialog_title) + .setMessage(R.string.MediaCaptureFragment_device_link_dialog_body) + .setPositiveButton(R.string.MediaCaptureFragment_device_link_dialog_continue) { d, _ -> + startActivity(DeviceActivity.getIntentForScanner(requireContext())) + requireActivity().finish() + } + .setNegativeButton(android.R.string.cancel, null) + .show() + } } } @@ -149,6 +174,10 @@ class MediaCaptureFragment : Fragment(R.layout.fragment_container), CameraFragme } } + override fun onQrCodeFound(data: String) { + viewModel.onQrCodeFound(data) + } + override fun getMostRecentMediaItem(): Flowable> { return viewModel.getMostRecentMedia() } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureRepository.kt b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureRepository.kt index f4e6cfc3..97059064 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureRepository.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureRepository.kt @@ -15,7 +15,7 @@ import org.tm.archive.mediasend.MediaRepository import org.tm.archive.providers.BlobProvider import org.tm.archive.util.MediaUtil import org.tm.archive.util.StorageUtil -import org.tm.archive.video.VideoUtil +import org.tm.archive.video.videoconverter.utils.VideoConstants import java.io.FileDescriptor import java.io.FileInputStream import java.io.IOException @@ -66,7 +66,7 @@ class MediaCaptureRepository(context: Context) { dataSupplier = { FileInputStream(fileDescriptor) }, getLength = { it.channel.size() }, createBlobBuilder = BlobProvider::forData, - mimeType = VideoUtil.RECORDED_VIDEO_CONTENT_TYPE, + mimeType = VideoConstants.RECORDED_VIDEO_CONTENT_TYPE, width = 0, height = 0 ) diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureViewModel.kt b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureViewModel.kt index 4e3318c3..7f36409d 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureViewModel.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/capture/MediaCaptureViewModel.kt @@ -5,20 +5,34 @@ import androidx.lifecycle.ViewModelProvider import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Observable +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.kotlin.plusAssign +import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.subjects.PublishSubject import io.reactivex.rxjava3.subjects.Subject +import org.signal.core.util.logging.Log +import org.tm.archive.components.settings.app.usernamelinks.main.QrScanResult import org.tm.archive.mediasend.Media +import org.tm.archive.profiles.manage.UsernameRepository +import org.tm.archive.recipients.Recipient import org.tm.archive.util.rx.RxStore import java.io.FileDescriptor import java.util.Optional +import java.util.concurrent.TimeUnit class MediaCaptureViewModel(private val repository: MediaCaptureRepository) : ViewModel() { + companion object { + private val TAG = Log.tag(MediaCaptureViewModel::class.java) + } + private val store: RxStore = RxStore(MediaCaptureState()) private val internalEvents: Subject = PublishSubject.create() + private val qrData: Subject = PublishSubject.create() val events: Observable = internalEvents.observeOn(AndroidSchedulers.mainThread()) + val disposables = CompositeDisposable() init { repository.getMostRecentItem { media -> @@ -26,10 +40,42 @@ class MediaCaptureViewModel(private val repository: MediaCaptureRepository) : Vi state.copy(mostRecentMedia = media) } } + + disposables += qrData + .throttleFirst(5, TimeUnit.SECONDS) + .filter { UsernameRepository.isValidLink(it) } + .subscribeOn(Schedulers.io()) + .flatMapSingle { url -> + UsernameRepository.fetchUsernameAndAciFromLink(url) + .map { result -> + when (result) { + is UsernameRepository.UsernameLinkConversionResult.Success -> QrScanResult.Success(result.username.toString(), Recipient.externalUsername(result.aci, result.username.toString())) + is UsernameRepository.UsernameLinkConversionResult.Invalid, + is UsernameRepository.UsernameLinkConversionResult.NotFound, + is UsernameRepository.UsernameLinkConversionResult.NetworkError -> QrScanResult.Failure + } + } + } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { data -> + if (data is QrScanResult.Success) { + internalEvents.onNext(MediaCaptureEvent.UsernameScannedFromQrCode(data.recipient, data.username)) + } else { + Log.w(TAG, "Failed to scan QR code.") + } + } + + disposables += qrData + .throttleFirst(5, TimeUnit.SECONDS) + .filter { it.startsWith("sgnl://linkdevice") } + .subscribe { data -> + internalEvents.onNext(MediaCaptureEvent.DeviceLinkScannedFromQrCode) + } } override fun onCleared() { store.dispose() + disposables.dispose() } fun onImageCaptured(data: ByteArray, width: Int, height: Int) { @@ -44,6 +90,10 @@ class MediaCaptureViewModel(private val repository: MediaCaptureRepository) : Vi return store.stateFlowable.map { Optional.ofNullable(it.mostRecentMedia) } } + fun onQrCodeFound(data: String) { + qrData.onNext(data) + } + private fun onMediaRendered(media: Media) { internalEvents.onNext(MediaCaptureEvent.MediaCaptureRendered(media)) } @@ -52,6 +102,11 @@ class MediaCaptureViewModel(private val repository: MediaCaptureRepository) : Vi internalEvents.onNext(MediaCaptureEvent.MediaCaptureRenderFailed) } + private sealed class QrScanResult { + data class Success(val username: String, val recipient: Recipient) : QrScanResult() + object Failure : QrScanResult() + } + class Factory(private val repository: MediaCaptureRepository) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { return requireNotNull(modelClass.cast(MediaCaptureViewModel(repository))) diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaGallerySelectableItem.kt b/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaGallerySelectableItem.kt index 7ddb5202..f9dfc164 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaGallerySelectableItem.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaGallerySelectableItem.kt @@ -6,6 +6,7 @@ import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.core.view.setPadding +import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.RequestListener @@ -17,7 +18,6 @@ import org.tm.archive.R import org.tm.archive.mediasend.Media import org.tm.archive.mediasend.MediaFolder import org.tm.archive.mms.DecryptableStreamUriLoader -import org.tm.archive.mms.GlideApp import org.tm.archive.util.MediaUtil import org.tm.archive.util.adapter.mapping.LayoutFactory import org.tm.archive.util.adapter.mapping.MappingAdapter @@ -65,7 +65,7 @@ object MediaGallerySelectableItem { class FolderViewHolder(itemView: View, private val onMediaFolderClicked: OnMediaFolderClicked) : BaseViewHolder(itemView) { override fun bind(model: FolderModel) { - GlideApp.with(imageView) + Glide.with(imageView) .load(DecryptableStreamUriLoader.DecryptableUri(model.mediaFolder.thumbnailUri)) .into(imageView) @@ -120,7 +120,7 @@ object MediaGallerySelectableItem { updateImageView(if (model.isSelected) 1f else 0f) } - GlideApp.with(imageView) + Glide.with(imageView) .load(DecryptableStreamUriLoader.DecryptableUri(model.media.uri)) .addListener(ErrorLoggingRequestListener(FILE_VIEW_HOLDER_TAG)) .into(imageView) diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaSelectionGalleryFragment.kt b/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaSelectionGalleryFragment.kt index 28ee9972..dd919336 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaSelectionGalleryFragment.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/gallery/MediaSelectionGalleryFragment.kt @@ -125,7 +125,7 @@ class MediaSelectionGalleryFragment : Fragment(R.layout.fragment_container), Med } override fun onSelectedMediaClicked(media: Media) { - sharedViewModel.setFocusedMedia(media) + sharedViewModel.onPageChanged(media) navigator.goToReview(findNavController()) } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/review/AddMessageDialogFragment.kt b/app/src/main/java/org/tm/archive/mediasend/v2/review/AddMessageDialogFragment.kt index 7796886f..36c48341 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/review/AddMessageDialogFragment.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/review/AddMessageDialogFragment.kt @@ -16,6 +16,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import org.signal.core.util.EditTextUtil import org.tm.archive.R +import org.tm.archive.components.KeyboardAwareLinearLayout import org.tm.archive.components.KeyboardEntryDialogFragment import org.tm.archive.components.ViewBinderDelegate import org.tm.archive.components.emoji.MediaKeyboard @@ -32,6 +33,7 @@ import org.tm.archive.keyboard.KeyboardPage import org.tm.archive.keyboard.KeyboardPagerViewModel import org.tm.archive.keyvalue.SignalStore import org.tm.archive.mediasend.v2.HudCommand +import org.tm.archive.mediasend.v2.MediaSelectionState import org.tm.archive.mediasend.v2.MediaSelectionViewModel import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId @@ -94,10 +96,17 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a binding.content.emojiToggle.visible = false } else { binding.content.emojiToggle.setOnClickListener { onEmojiToggleClicked() } + if (requireArguments().getBoolean(ARG_INITIAL_EMOJI_TOGGLE) && view is KeyboardAwareLinearLayout) { + view.addOnKeyboardShownListener(EmojiLaunchListener(view)) + } } binding.hud.setOnClickListener { dismissAllowingStateLoss() } + binding.content.viewOnceToggle.setOnClickListener { + viewModel.incrementViewOnceState() + } + val confirm: View = view.findViewById(R.id.confirm_button) confirm.setOnClickListener { dismissAllowingStateLoss() } @@ -118,6 +127,15 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a } ) + viewModel.state.observe(viewLifecycleOwner) { state -> + binding.content.viewOnceToggle.displayedChild = if (state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE) 1 else 0 + if (state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE) { + binding.content.addAMessageInput.text = null + dismiss() + } + binding.content.viewOnceToggle.visible = state.selectedMedia.size == 1 && !state.isStory + } + initializeMentions() } @@ -271,16 +289,25 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a binding.content.addAMessageInput.dispatchKeyEvent(keyEvent) } + private inner class EmojiLaunchListener(private val layout: KeyboardAwareLinearLayout) : KeyboardAwareLinearLayout.OnKeyboardShownListener { + override fun onKeyboardShown() { + layout.removeOnKeyboardShownListener(this) + onEmojiToggleClicked() + } + } + companion object { const val TAG = "ADD_MESSAGE_DIALOG_FRAGMENT" private const val ARG_INITIAL_TEXT = "arg.initial.text" + private const val ARG_INITIAL_EMOJI_TOGGLE = "arg.initial.emojiToggle" - fun show(fragmentManager: FragmentManager, initialText: CharSequence?) { + fun show(fragmentManager: FragmentManager, initialText: CharSequence?, startWithEmojiKeyboard: Boolean) { AddMessageDialogFragment().apply { arguments = Bundle().apply { putCharSequence(ARG_INITIAL_TEXT, initialText) + putBoolean(ARG_INITIAL_EMOJI_TOGGLE, startWithEmojiKeyboard) } }.show(fragmentManager, TAG) } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewAnimatorController.kt b/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewAnimatorController.kt index f131ea33..60222572 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewAnimatorController.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewAnimatorController.kt @@ -4,35 +4,44 @@ import android.animation.Animator import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.view.View +import android.view.animation.Interpolator import androidx.core.animation.doOnEnd -import org.tm.archive.util.ContextUtil +import org.tm.archive.mediasend.v2.MediaAnimations import org.tm.archive.util.visible object MediaReviewAnimatorController { - fun getSlideInAnimator(view: View): Animator { - return if (ContextUtil.getAnimationScale(view.context) == 0f) { - view.translationY = 0f - ValueAnimator.ofFloat(0f, 1f) - } else { - ObjectAnimator.ofFloat(view, "translationY", view.translationY, 0f) - } - } - fun getFadeInAnimator(view: View, isEnabled: Boolean = true): Animator { view.visible = true view.isEnabled = isEnabled - return ObjectAnimator.ofFloat(view, "alpha", view.alpha, 1f) + return ObjectAnimator.ofFloat(view, "alpha", view.alpha, 1f).apply { + interpolator = MediaAnimations.interpolator + } } fun getFadeOutAnimator(view: View, isEnabled: Boolean = false): Animator { view.isEnabled = isEnabled - val animator = ObjectAnimator.ofFloat(view, "alpha", view.alpha, 0f) + val animator = ObjectAnimator.ofFloat(view, "alpha", view.alpha, 0f).apply { + interpolator = MediaAnimations.interpolator + } animator.doOnEnd { view.visible = false } return animator } + + fun getHeightAnimator(view: View, start: Int, end: Int, interpolator: Interpolator = MediaAnimations.interpolator): Animator { + return ValueAnimator.ofInt(start, end).apply { + setInterpolator(interpolator) + addUpdateListener { + val animatedValue = it.animatedValue as Int + val layoutParams = view.layoutParams + layoutParams.height = animatedValue + view.layoutParams = layoutParams + } + duration = 120 + } + } } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewFragment.kt b/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewFragment.kt index 1dd1f16b..828268a0 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewFragment.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewFragment.kt @@ -2,9 +2,14 @@ package org.tm.archive.mediasend.v2.review import android.animation.Animator import android.animation.AnimatorSet +import android.content.Context import android.content.res.ColorStateList import android.graphics.Color +import android.graphics.Rect +import android.net.Uri import android.os.Bundle +import android.provider.OpenableColumns +import android.view.Gravity import android.view.View import android.view.ViewGroup import android.widget.ImageView @@ -17,6 +22,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.ViewCompat +import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController @@ -25,9 +31,12 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import app.cash.exhaustive.Exhaustive import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.imageview.ShapeableImageView import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.concurrent.SimpleTask +import org.signal.core.util.isNotNullOrBlank +import org.signal.core.util.logging.Log import org.tm.archive.R import org.tm.archive.contacts.paged.ContactSearchKey import org.tm.archive.conversation.MessageSendType @@ -35,6 +44,8 @@ import org.tm.archive.conversation.ScheduleMessageContextMenu import org.tm.archive.conversation.ScheduleMessageTimePickerBottomSheet import org.tm.archive.conversation.mutiselect.forward.MultiselectForwardActivity import org.tm.archive.conversation.mutiselect.forward.MultiselectForwardFragmentArgs +import org.tm.archive.keyvalue.SignalStore +import org.tm.archive.mediasend.Media import org.tm.archive.mediasend.MediaSendActivityResult import org.tm.archive.mediasend.v2.HudCommand import org.tm.archive.mediasend.v2.MediaAnimations @@ -44,21 +55,30 @@ import org.tm.archive.mediasend.v2.MediaSelectionState import org.tm.archive.mediasend.v2.MediaSelectionViewModel import org.tm.archive.mediasend.v2.MediaValidator import org.tm.archive.mediasend.v2.stories.StoriesMultiselectForwardActivity +import org.tm.archive.mms.MediaConstraints import org.tm.archive.mms.SentMediaQuality import org.tm.archive.permissions.Permissions import org.tm.archive.recipients.Recipient import org.tm.archive.scribbles.ImageEditorFragment +import org.tm.archive.util.BottomSheetUtil import org.tm.archive.util.MediaUtil +import org.tm.archive.util.MemoryUnitFormat import org.tm.archive.util.SystemWindowInsetsSetter import org.tm.archive.util.adapter.mapping.MappingAdapter import org.tm.archive.util.fragments.requireListener import org.tm.archive.util.views.TouchInterceptingFrameLayout import org.tm.archive.util.visible +import org.tm.archive.video.TranscodingQuality +import org.tm.archive.video.videoconverter.VideoThumbnailsRangeSelectorView +import java.io.IOException +import java.util.Locale +import java.util.concurrent.TimeUnit +import kotlin.math.roundToInt /** * Allows the user to view and edit selected media. */ -class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), ScheduleMessageTimePickerBottomSheet.ScheduleCallback { +class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), ScheduleMessageTimePickerBottomSheet.ScheduleCallback, VideoThumbnailsRangeSelectorView.RangeDragListener { private val sharedViewModel: MediaSelectionViewModel by viewModels( ownerProducer = { requireActivity() } @@ -73,23 +93,28 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul private lateinit var sendButton: ImageView private lateinit var addMediaButton: View private lateinit var viewOnceButton: ViewSwitcher - private lateinit var viewOnceMessage: TextView + private lateinit var emojiButton: ShapeableImageView private lateinit var addMessageButton: TextView - private lateinit var addMessageEntry: TextView private lateinit var recipientDisplay: TextView private lateinit var pager: ViewPager2 private lateinit var controls: ConstraintLayout private lateinit var selectionRecycler: RecyclerView private lateinit var controlsShade: View + private lateinit var videoTimeLine: VideoThumbnailsRangeSelectorView + private lateinit var videoSizeHint: TextView + private lateinit var videoTimelinePlaceholder: View private lateinit var progress: ProgressBar private lateinit var progressWrapper: TouchInterceptingFrameLayout + private val exclusionZone = listOf(Rect()) private val navigator = MediaSelectionNavigator( toGallery = R.id.action_mediaReviewFragment_to_mediaGalleryFragment ) private var animatorSet: AnimatorSet? = null private var disposables: LifecycleDisposable = LifecycleDisposable() + private var sentMediaQuality: SentMediaQuality = SignalStore.settings().sentMediaQuality + private var viewOnceToggleState: MediaSelectionState.ViewOnceToggleState = MediaSelectionState.ViewOnceToggleState.default private var scheduledSendTime: Long? = null @@ -109,16 +134,18 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul sendButton = view.findViewById(R.id.send) addMediaButton = view.findViewById(R.id.add_media) viewOnceButton = view.findViewById(R.id.view_once_toggle) + emojiButton = view.findViewById(R.id.emoji_button) addMessageButton = view.findViewById(R.id.add_a_message) - addMessageEntry = view.findViewById(R.id.add_a_message_entry) recipientDisplay = view.findViewById(R.id.recipient) pager = view.findViewById(R.id.media_pager) controls = view.findViewById(R.id.controls) selectionRecycler = view.findViewById(R.id.selection_recycler) controlsShade = view.findViewById(R.id.controls_shade) - viewOnceMessage = view.findViewById(R.id.view_once_message) progress = view.findViewById(R.id.progress) progressWrapper = view.findViewById(R.id.progress_wrapper) + videoTimeLine = view.findViewById(R.id.video_timeline) + videoSizeHint = view.findViewById(R.id.video_size_hint) + videoTimelinePlaceholder = view.findViewById(R.id.timeline_placeholder) DrawableCompat.setTint(progress.indeterminateDrawable, Color.WHITE) progressWrapper.setOnInterceptTouchEventListener { true } @@ -134,6 +161,14 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul pager.adapter = pagerAdapter + controls.addOnLayoutChangeListener { v, left, _, right, _, _, _, _, _ -> + val outRect: Rect = exclusionZone[0] + videoTimeLine.getHitRect(outRect) + outRect.left = left + outRect.right = right + ViewCompat.setSystemGestureExclusionRects(v, exclusionZone) + } + drawToolButton.setOnClickListener { sharedViewModel.sendCommand(HudCommand.StartDraw) } @@ -143,7 +178,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } qualityButton.setOnClickListener { - QualitySelectorBottomSheetDialog.show(parentFragmentManager) + QualitySelectorBottomSheet().show(parentFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) } saveButton.setOnClickListener { @@ -170,7 +205,6 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul if (sharedViewModel.isContactSelectionRequired) { val args = MultiselectForwardFragmentArgs( - false, title = R.string.MediaReviewFragment__send_to, storySendRequirements = sharedViewModel.getStorySendRequirements(), isSearchEnabled = !sharedViewModel.isStory(), @@ -241,12 +275,14 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul sharedViewModel.incrementViewOnceState() } - addMessageButton.setOnClickListener { - AddMessageDialogFragment.show(parentFragmentManager, sharedViewModel.state.value?.message) + if (!SignalStore.settings().isPreferSystemEmoji) { + emojiButton.setOnClickListener { + AddMessageDialogFragment.show(parentFragmentManager, sharedViewModel.state.value?.message, true) + } } - addMessageEntry.setOnClickListener { - AddMessageDialogFragment.show(parentFragmentManager, sharedViewModel.state.value?.message) + addMessageButton.setOnClickListener { + AddMessageDialogFragment.show(parentFragmentManager, sharedViewModel.state.value?.message, false) } if (sharedViewModel.isReply) { @@ -255,10 +291,16 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { - sharedViewModel.setFocusedMedia(position) + qualityButton.alpha = 0f + saveButton.alpha = 0f + sharedViewModel.onPageChanged(position) } }) + if (MediaConstraints.isVideoTranscodeAvailable()) { + videoTimeLine.registerEditorOnRangeChangeListener(this) + } + val selectionAdapter = MappingAdapter(false) MediaReviewAddItem.register(selectionAdapter) { launchGallery() @@ -267,7 +309,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul if (isSelected) { sharedViewModel.removeMedia(media) } else { - sharedViewModel.setFocusedMedia(media) + sharedViewModel.onPageChanged(media) } } selectionRecycler.adapter = selectionAdapter @@ -282,10 +324,24 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul presentSendButton(state.sendType, state.recipient) presentPager(state) - presentAddMessageEntry(state.message) - presentImageQualityToggle(state.quality) + presentAddMessageEntry(state.viewOnceToggleState, state.message) + presentImageQualityToggle(state) + if (state.quality != sentMediaQuality) { + presentQualityToggleToast(state) + } + sentMediaQuality = state.quality viewOnceButton.displayedChild = if (state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE) 1 else 0 + if (state.viewOnceToggleState != viewOnceToggleState && + state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE && + state.selectedMedia.size == 1 + ) { + presentViewOnceToggleToast(MediaUtil.isNonGifVideo(state.selectedMedia[0])) + } + viewOnceToggleState = state.viewOnceToggleState + + presentVideoTimeline(state) + presentVideoSizeHint(state) computeViewStateAndAnimate(state) } @@ -305,6 +361,56 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul ) } + private fun presentViewOnceToggleToast(isVideo: Boolean) { + val description = if (isVideo) { + getString(R.string.MediaReviewFragment__video_set_to_view_once) + } else { + getString(R.string.MediaReviewFragment__photo_set_to_view_once) + } + + MediaReviewToastPopupWindow.show(controls, R.drawable.symbol_view_once_24, description) + } + + private fun presentQualityToggleToast(state: MediaSelectionState) { + val mediaList = state.selectedMedia + if (mediaList.isEmpty()) { + return + } + + val description = if (mediaList.size == 1) { + val media: Media = mediaList[0] + if (MediaUtil.isNonGifVideo(media)) { + if (state.quality == SentMediaQuality.HIGH) { + getString(R.string.MediaReviewFragment__video_set_to_high_quality) + } else { + getString(R.string.MediaReviewFragment__video_set_to_standard_quality) + } + } else if (MediaUtil.isImageType(media.mimeType)) { + if (state.quality == SentMediaQuality.HIGH) { + getString(R.string.MediaReviewFragment__photo_set_to_high_quality) + } else { + getString(R.string.MediaReviewFragment__photo_set_to_standard_quality) + } + } else { + Log.i(TAG, "Could not display quality toggle toast for attachment of type: ${media.mimeType}") + return + } + } else { + if (state.quality == SentMediaQuality.HIGH) { + resources.getQuantityString(R.plurals.MediaReviewFragment__items_set_to_high_quality, mediaList.size, mediaList.size) + } else { + resources.getQuantityString(R.plurals.MediaReviewFragment__items_set_to_standard_quality, mediaList.size, mediaList.size) + } + } + + val icon = when (state.quality) { + SentMediaQuality.HIGH -> R.drawable.symbol_quality_high_24 + else -> R.drawable.symbol_quality_high_slash_24 + } + + MediaReviewToastPopupWindow.show(controls, icon, description) + } + override fun onResume() { super.onResume() sharedViewModel.kick() @@ -357,15 +463,38 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul ) } - private fun presentAddMessageEntry(message: CharSequence?) { - addMessageEntry.setText(message, TextView.BufferType.SPANNABLE) + private fun presentAddMessageEntry(viewOnceState: MediaSelectionState.ViewOnceToggleState, message: CharSequence?) { + when (viewOnceState) { + MediaSelectionState.ViewOnceToggleState.INFINITE -> { + addMessageButton.gravity = Gravity.CENTER_VERTICAL + addMessageButton.setText( + message.takeIf { it.isNotNullOrBlank() } ?: getString(R.string.MediaReviewFragment__add_a_message), + TextView.BufferType.SPANNABLE + ) + addMessageButton.isClickable = true + } + MediaSelectionState.ViewOnceToggleState.ONCE -> { + addMessageButton.gravity = Gravity.CENTER + addMessageButton.setText(R.string.MediaReviewFragment__view_once_message) + addMessageButton.isClickable = false + } + } } - private fun presentImageQualityToggle(quality: SentMediaQuality) { + private fun presentImageQualityToggle(state: MediaSelectionState) { + qualityButton.updateLayoutParams { + if (MediaUtil.isImageAndNotGif(state.focusedMedia?.mimeType ?: "")) { + startToStart = ConstraintLayout.LayoutParams.UNSET + startToEnd = cropAndRotateButton.id + } else { + startToStart = ConstraintLayout.LayoutParams.PARENT_ID + startToEnd = ConstraintLayout.LayoutParams.UNSET + } + } qualityButton.setImageResource( - when (quality) { - SentMediaQuality.STANDARD -> R.drawable.ic_sq_24 - SentMediaQuality.HIGH -> R.drawable.ic_hq_24 + when (state.quality) { + SentMediaQuality.STANDARD -> R.drawable.symbol_quality_high_slash_24 + SentMediaQuality.HIGH -> R.drawable.symbol_quality_high_24 } ) } @@ -378,8 +507,8 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } val sendButtonForegroundDrawable = when { - recipient != null -> ContextCompat.getDrawable(requireContext(), R.drawable.ic_send_24) - else -> ContextCompat.getDrawable(requireContext(), R.drawable.ic_arrow_end_24) + recipient != null -> ContextCompat.getDrawable(requireContext(), R.drawable.symbol_send_fill_24) + else -> ContextCompat.getDrawable(requireContext(), R.drawable.symbol_arrow_end_24) } val sendButtonForegroundTint = when { @@ -408,12 +537,51 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } } + private fun presentVideoTimeline(state: MediaSelectionState) { + val mediaItem = state.focusedMedia ?: return + if (!MediaUtil.isVideoType(mediaItem.mimeType) || !MediaConstraints.isVideoTranscodeAvailable()) { + return + } + val uri = mediaItem.uri + val updatedInputInTimeline = videoTimeLine.setInput(uri) + if (updatedInputInTimeline) { + videoTimeLine.unregisterDragListener() + } + val size: Long = tryGetUriSize(requireContext(), uri, Long.MAX_VALUE) + val maxSend = sharedViewModel.getMediaConstraints().getVideoMaxSize(requireContext()) + if (size > maxSend) { + videoTimeLine.setTimeLimit(state.transcodingPreset.calculateMaxVideoUploadDurationInSeconds(maxSend), TimeUnit.SECONDS) + } + + if (state.isTouchEnabled) { + val data = state.getOrCreateVideoTrimData(uri) + + if (data.totalInputDurationUs > 0) { + videoTimeLine.setRange(data.startTimeUs, data.endTimeUs) + } + } + } + + private fun presentVideoSizeHint(state: MediaSelectionState) { + val focusedMedia = state.focusedMedia ?: return + val trimData = state.getOrCreateVideoTrimData(focusedMedia.uri) + + videoSizeHint.text = if (state.isVideoTrimmingVisible) { + val seconds = trimData.getDuration().inWholeSeconds + val bytes = TranscodingQuality.createFromPreset(state.transcodingPreset, trimData.getDuration().inWholeMilliseconds).byteCountEstimate + String.format(Locale.getDefault(), "%d:%02d • %s", seconds / 60, seconds % 60, MemoryUnitFormat.formatBytes(bytes, MemoryUnitFormat.MEGA_BYTES, true)) + } else { + null + } + } + private fun computeViewStateAndAnimate(state: MediaSelectionState) { this.animatorSet?.cancel() val animators = mutableListOf() animators.addAll(computeAddMessageAnimators(state)) + animators.addAll(computeEmojiButtonAnimators(state)) animators.addAll(computeViewOnceButtonAnimators(state)) animators.addAll(computeAddMediaButtonsAnimators(state)) animators.addAll(computeSendButtonAnimators(state)) @@ -423,53 +591,69 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul animators.addAll(computeDrawToolButtonAnimators(state)) animators.addAll(computeRecipientDisplayAnimators(state)) animators.addAll(computeControlsShadeAnimators(state)) + animators.addAll(computeVideoTimelineAnimator(state)) val animatorSet = AnimatorSet() animatorSet.playTogether(animators) - animatorSet.interpolator = MediaAnimations.interpolator animatorSet.start() this.animatorSet = animatorSet } private fun computeControlsShadeAnimators(state: MediaSelectionState): List { - return if (state.isTouchEnabled) { - listOf(MediaReviewAnimatorController.getFadeInAnimator(controlsShade)) + val animators = mutableListOf() + animators += if (state.isTouchEnabled) { + MediaReviewAnimatorController.getFadeInAnimator(controlsShade) } else { - listOf(MediaReviewAnimatorController.getFadeOutAnimator(controlsShade)) + MediaReviewAnimatorController.getFadeOutAnimator(controlsShade) } + + animators += if (state.isVideoTrimmingVisible) { + MediaReviewAnimatorController.getHeightAnimator(videoTimelinePlaceholder, videoTimelinePlaceholder.height, resources.getDimension(R.dimen.video_timeline_height_expanded).roundToInt()) + } else { + MediaReviewAnimatorController.getHeightAnimator(videoTimelinePlaceholder, videoTimelinePlaceholder.height, resources.getDimension(R.dimen.video_timeline_height_collapsed).roundToInt()) + } + + return animators + } + + private fun computeVideoTimelineAnimator(state: MediaSelectionState): List { + val animators = mutableListOf() + + if (state.isVideoTrimmingVisible) { + animators += MediaReviewAnimatorController.getFadeInAnimator(videoTimeLine).apply { + startDelay = 100 + duration = 500 + } + } else { + animators += MediaReviewAnimatorController.getFadeOutAnimator(videoTimeLine).apply { + duration = 400 + } + } + + animators += if (state.isVideoTrimmingVisible && state.isTouchEnabled) { + MediaReviewAnimatorController.getFadeInAnimator(videoSizeHint).apply { + startDelay = 100 + duration = 500 + } + } else { + MediaReviewAnimatorController.getFadeOutAnimator(videoSizeHint).apply { + duration = 400 + } + } + + return animators } private fun computeAddMessageAnimators(state: MediaSelectionState): List { - return when { - !state.isTouchEnabled -> { - listOf( - MediaReviewAnimatorController.getFadeOutAnimator(viewOnceMessage), - MediaReviewAnimatorController.getFadeOutAnimator(addMessageButton), - MediaReviewAnimatorController.getFadeOutAnimator(addMessageEntry) - ) - } - state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE -> { - listOf( - MediaReviewAnimatorController.getFadeInAnimator(viewOnceMessage), - MediaReviewAnimatorController.getFadeOutAnimator(addMessageButton), - MediaReviewAnimatorController.getFadeOutAnimator(addMessageEntry) - ) - } - state.message.isNullOrEmpty() -> { - listOf( - MediaReviewAnimatorController.getFadeOutAnimator(viewOnceMessage), - MediaReviewAnimatorController.getFadeInAnimator(addMessageButton), - MediaReviewAnimatorController.getFadeOutAnimator(addMessageEntry) - ) - } - else -> { - listOf( - MediaReviewAnimatorController.getFadeOutAnimator(viewOnceMessage), - MediaReviewAnimatorController.getFadeInAnimator(addMessageEntry), - MediaReviewAnimatorController.getFadeOutAnimator(addMessageButton) - ) - } + return if (!state.isTouchEnabled) { + listOf( + MediaReviewAnimatorController.getFadeOutAnimator(addMessageButton) + ) + } else { + listOf( + MediaReviewAnimatorController.getFadeInAnimator(addMessageButton) + ) } } @@ -481,6 +665,14 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } } + private fun computeEmojiButtonAnimators(state: MediaSelectionState): List { + return if (state.isTouchEnabled && !SignalStore.settings().isPreferSystemEmoji && state.viewOnceToggleState != MediaSelectionState.ViewOnceToggleState.ONCE) { + listOf(MediaReviewAnimatorController.getFadeInAnimator(emojiButton)) + } else { + listOf(MediaReviewAnimatorController.getFadeOutAnimator(emojiButton)) + } + } + private fun computeAddMediaButtonsAnimators(state: MediaSelectionState): List { return when { !state.isTouchEnabled || state.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE -> { @@ -505,27 +697,19 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } private fun computeSendButtonAnimators(state: MediaSelectionState): List { - val slideIn = listOf( - MediaReviewAnimatorController.getSlideInAnimator(sendButton) - ) - - return slideIn + if (state.isTouchEnabled) { + return if (state.isTouchEnabled) { listOf( - MediaReviewAnimatorController.getFadeInAnimator(sendButton, state.canSend) + MediaReviewAnimatorController.getFadeInAnimator(sendButton, isEnabled = state.canSend) ) } else { listOf( - MediaReviewAnimatorController.getFadeOutAnimator(sendButton, state.canSend) + MediaReviewAnimatorController.getFadeOutAnimator(sendButton, isEnabled = state.canSend) ) } } private fun computeSaveButtonAnimators(state: MediaSelectionState): List { - val slideIn = listOf( - MediaReviewAnimatorController.getSlideInAnimator(saveButton) - ) - - return slideIn + if (state.isTouchEnabled && !MediaUtil.isVideo(state.focusedMedia?.mimeType)) { + return if (state.isTouchEnabled && !MediaUtil.isVideo(state.focusedMedia?.mimeType)) { listOf( MediaReviewAnimatorController.getFadeInAnimator(saveButton) ) @@ -537,9 +721,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } private fun computeQualityButtonAnimators(state: MediaSelectionState): List { - val slide = listOf(MediaReviewAnimatorController.getSlideInAnimator(qualityButton)) - - return slide + if (state.isTouchEnabled && !state.isStory && state.selectedMedia.any { MediaUtil.isImageType(it.mimeType) }) { + return if (state.isTouchEnabled && !state.isStory) { listOf(MediaReviewAnimatorController.getFadeInAnimator(qualityButton)) } else { listOf(MediaReviewAnimatorController.getFadeOutAnimator(qualityButton)) @@ -547,9 +729,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } private fun computeCropAndRotateButtonAnimators(state: MediaSelectionState): List { - val slide = listOf(MediaReviewAnimatorController.getSlideInAnimator(cropAndRotateButton)) - - return slide + if (state.isTouchEnabled && MediaUtil.isImageAndNotGif(state.focusedMedia?.mimeType ?: "")) { + return if (state.isTouchEnabled && MediaUtil.isImageAndNotGif(state.focusedMedia?.mimeType ?: "")) { listOf(MediaReviewAnimatorController.getFadeInAnimator(cropAndRotateButton)) } else { listOf(MediaReviewAnimatorController.getFadeOutAnimator(cropAndRotateButton)) @@ -557,9 +737,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } private fun computeDrawToolButtonAnimators(state: MediaSelectionState): List { - val slide = listOf(MediaReviewAnimatorController.getSlideInAnimator(drawToolButton)) - - return slide + if (state.isTouchEnabled && MediaUtil.isImageAndNotGif(state.focusedMedia?.mimeType ?: "")) { + return if (state.isTouchEnabled && MediaUtil.isImageAndNotGif(state.focusedMedia?.mimeType ?: "")) { listOf(MediaReviewAnimatorController.getFadeInAnimator(drawToolButton)) } else { listOf(MediaReviewAnimatorController.getFadeOutAnimator(drawToolButton)) @@ -575,6 +753,29 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } } + companion object { + private val TAG = Log.tag(MediaReviewFragment::class.java) + + @JvmStatic + private fun tryGetUriSize(context: Context, uri: Uri, defaultValue: Long): Long { + return try { + var size: Long = 0 + context.contentResolver.query(uri, null, null, null, null).use { cursor -> + if (cursor != null && cursor.moveToFirst() && cursor.getColumnIndex(OpenableColumns.SIZE) >= 0) { + size = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)) + } + } + if (size <= 0) { + size = MediaUtil.getMediaSize(context, uri) + } + size + } catch (e: IOException) { + Log.w(TAG, e) + defaultValue + } + } + } + interface Callback { fun onSentWithResult(mediaSendActivityResult: MediaSendActivityResult) fun onSentWithoutResult() @@ -587,4 +788,8 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul scheduledSendTime = scheduledTime sendButton.performClick() } + + override fun onRangeDrag(minValue: Long, maxValue: Long, duration: Long, end: Boolean) { + sharedViewModel.onEditVideoDuration(context = requireContext(), totalDurationUs = duration, startTimeUs = minValue, endTimeUs = maxValue, touchEnabled = end) + } } diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewToastPopupWindow.kt b/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewToastPopupWindow.kt new file mode 100644 index 00000000..2091caa4 --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/v2/review/MediaReviewToastPopupWindow.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.mediasend.v2.review + +import android.view.Gravity +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.PopupWindow +import android.widget.TextView +import org.tm.archive.R +import kotlin.time.Duration.Companion.seconds + +/** + * Toast-style notification used in the media review flow. This exists so we can specify the location and animation of how it appears. + */ +class MediaReviewToastPopupWindow private constructor(parent: ViewGroup, iconResource: Int, descriptionText: String) : PopupWindow( + LayoutInflater.from(parent.context).inflate(R.layout.v2_media_review_quality_popup_window, parent, false), + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT +) { + + private val icon: ImageView = contentView.findViewById(R.id.media_review_toast_popup_icon) + private val description: TextView = contentView.findViewById(R.id.media_review_toast_popup_description) + + init { + animationStyle = R.style.StickerPopupAnimation + icon.setImageResource(iconResource) + description.text = descriptionText + } + + private fun show(parent: ViewGroup) { + showAtLocation(parent, Gravity.CENTER, 0, 0) + contentView.postDelayed({ dismiss() }, DURATION) + } + + companion object { + private val DURATION = 3.seconds.inWholeMilliseconds + + @JvmStatic + fun show(parent: ViewGroup, icon: Int, description: String): MediaReviewToastPopupWindow { + val qualityToast = MediaReviewToastPopupWindow(parent, icon, description) + qualityToast.show(parent) + return qualityToast + } + } +} diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/review/QualitySelectorBottomSheet.kt b/app/src/main/java/org/tm/archive/mediasend/v2/review/QualitySelectorBottomSheet.kt new file mode 100644 index 00000000..6c859279 --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/v2/review/QualitySelectorBottomSheet.kt @@ -0,0 +1,124 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.mediasend.v2.review + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.fragment.app.viewModels +import org.signal.core.ui.BottomSheets +import org.signal.core.ui.theme.SignalTheme +import org.tm.archive.R +import org.tm.archive.compose.ComposeBottomSheetDialogFragment +import org.tm.archive.mediasend.v2.MediaSelectionViewModel +import org.tm.archive.mms.SentMediaQuality + +/** + * Bottom sheet dialog to select the media quality (Standard vs. High) when sending media. + */ +class QualitySelectorBottomSheet : ComposeBottomSheetDialogFragment() { + private val sharedViewModel: MediaSelectionViewModel by viewModels(ownerProducer = { requireActivity() }) + + override val forceDarkTheme = true + + @Composable + override fun SheetContent() { + val state by sharedViewModel.state.observeAsState() + val quality = state?.quality + if (quality != null) { + Content(quality = quality, onQualitySelected = { + sharedViewModel.setSentMediaQuality(it) + dismiss() + }) + } + } +} + +@Composable +private fun Content(quality: SentMediaQuality, onQualitySelected: (SentMediaQuality) -> Unit) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth()) { + BottomSheets.Handle(modifier = Modifier.padding(top = 6.dp)) + } + + Text( + text = stringResource(id = R.string.QualitySelectorBottomSheetDialog__media_quality), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.padding(top = 20.dp, bottom = 14.dp) + ) + Row( + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 20.dp) + ) { + val standardQuality = quality == SentMediaQuality.STANDARD + Button( + modifier = Modifier.defaultMinSize(minWidth = 174.dp, minHeight = 60.dp), + onClick = { onQualitySelected(SentMediaQuality.STANDARD) }, + shape = RoundedCornerShape(percent = 25), + colors = if (standardQuality) ButtonDefaults.filledTonalButtonColors() else ButtonDefaults.textButtonColors(), + elevation = if (standardQuality) ButtonDefaults.filledTonalButtonElevation() else null, + contentPadding = if (standardQuality) ButtonDefaults.ContentPadding else ButtonDefaults.TextButtonContentPadding + ) { + ButtonLabel(title = stringResource(id = R.string.QualitySelectorBottomSheetDialog__standard), description = stringResource(id = R.string.QualitySelectorBottomSheetDialog__faster_less_data)) + } + Button( + modifier = Modifier.defaultMinSize(minWidth = 174.dp, minHeight = 60.dp), + onClick = { onQualitySelected(SentMediaQuality.HIGH) }, + shape = RoundedCornerShape(percent = 25), + colors = if (!standardQuality) ButtonDefaults.filledTonalButtonColors() else ButtonDefaults.textButtonColors(), + elevation = if (!standardQuality) ButtonDefaults.filledTonalButtonElevation() else null, + contentPadding = if (!standardQuality) ButtonDefaults.ContentPadding else ButtonDefaults.TextButtonContentPadding + ) { + ButtonLabel(title = stringResource(id = R.string.QualitySelectorBottomSheetDialog__high), description = stringResource(id = R.string.QualitySelectorBottomSheetDialog__slower_more_data)) + } + } + } +} + +@Composable +private fun ButtonLabel(title: String, description: String) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text(text = title, color = MaterialTheme.colorScheme.onSurface) + Text(text = description, color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.bodySmall) + } +} + +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewQualitySelectorBottomSheetStandard() { + SignalTheme(isDarkMode = true) { + Content(SentMediaQuality.STANDARD) {} + } +} + +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewQualitySelectorBottomSheetHigh() { + SignalTheme(isDarkMode = true) { + Content(SentMediaQuality.HIGH) {} + } +} diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/review/QualitySelectorBottomSheetDialog.java b/app/src/main/java/org/tm/archive/mediasend/v2/review/QualitySelectorBottomSheetDialog.java deleted file mode 100644 index 430f2747..00000000 --- a/app/src/main/java/org/tm/archive/mediasend/v2/review/QualitySelectorBottomSheetDialog.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.tm.archive.mediasend.v2.review; - -import android.os.Bundle; -import android.view.ContextThemeWrapper; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.FragmentManager; -import androidx.lifecycle.ViewModelProvider; - -import com.google.android.material.bottomsheet.BottomSheetDialogFragment; - -import org.tm.archive.R; -import org.tm.archive.mediasend.v2.MediaSelectionState; -import org.tm.archive.mediasend.v2.MediaSelectionViewModel; -import org.tm.archive.mms.SentMediaQuality; -import org.tm.archive.util.BottomSheetUtil; -import org.tm.archive.util.WindowUtil; -import org.tm.archive.util.views.CheckedLinearLayout; - -/** - * Dialog for selecting media quality, tightly coupled with {@link MediaSelectionViewModel}. - */ -public final class QualitySelectorBottomSheetDialog extends BottomSheetDialogFragment { - - private MediaSelectionViewModel viewModel; - private CheckedLinearLayout standard; - private CheckedLinearLayout high; - - public static void show(@NonNull FragmentManager manager) { - QualitySelectorBottomSheetDialog fragment = new QualitySelectorBottomSheetDialog(); - - fragment.show(manager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG); - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_Signal_RoundedBottomSheet); - super.onCreate(savedInstanceState); - } - - @Override - public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(inflater.getContext(), R.style.TextSecure_DarkTheme); - LayoutInflater themedInflater = LayoutInflater.from(contextThemeWrapper); - - return themedInflater.inflate(R.layout.quality_selector_dialog, container, false); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { - standard = view.findViewById(R.id.quality_selector_dialog_standard); - high = view.findViewById(R.id.quality_selector_dialog_high); - - View.OnClickListener listener = v -> { - select(v); - view.postDelayed(this::dismissAllowingStateLoss, 250); - }; - - standard.setOnClickListener(listener); - high.setOnClickListener(listener); - - viewModel = new ViewModelProvider(requireActivity()).get(MediaSelectionViewModel.class); - viewModel.getState().observe(getViewLifecycleOwner(), this::updateQuality); - } - - @Override - public void onResume() { - super.onResume(); - WindowUtil.initializeScreenshotSecurity(requireContext(), requireDialog().getWindow()); - } - - private void updateQuality(@NonNull MediaSelectionState selectionState) { - select(selectionState.getQuality() == SentMediaQuality.STANDARD ? standard : high); - } - - private void select(@NonNull View view) { - standard.setChecked(view == standard); - high.setChecked(view == high); - viewModel.setSentMediaQuality(standard == view ? SentMediaQuality.STANDARD : SentMediaQuality.HIGH); - } - - @Override - public void show(@NonNull FragmentManager manager, @Nullable String tag) { - BottomSheetUtil.show(manager, tag, this); - } -} diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/text/TextStoryPostCreationFragment.kt b/app/src/main/java/org/tm/archive/mediasend/v2/text/TextStoryPostCreationFragment.kt index f5a80b39..0c810acc 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/text/TextStoryPostCreationFragment.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/text/TextStoryPostCreationFragment.kt @@ -146,7 +146,6 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati StoriesMultiselectForwardActivity.Args( MultiselectForwardFragmentArgs( title = R.string.MediaReviewFragment__send_to, - canSendToNonPush = false, storySendRequirements = Stories.MediaTransform.SendRequirements.VALID_DURATION, isSearchEnabled = false ), diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/videos/MediaReviewVideoPageFragment.kt b/app/src/main/java/org/tm/archive/mediasend/v2/videos/MediaReviewVideoPageFragment.kt index fd0fee18..ecd75a70 100644 --- a/app/src/main/java/org/tm/archive/mediasend/v2/videos/MediaReviewVideoPageFragment.kt +++ b/app/src/main/java/org/tm/archive/mediasend/v2/videos/MediaReviewVideoPageFragment.kt @@ -10,8 +10,6 @@ import org.tm.archive.R import org.tm.archive.mediasend.VideoEditorFragment import org.tm.archive.mediasend.v2.HudCommand import org.tm.archive.mediasend.v2.MediaSelectionViewModel -import org.tm.archive.mms.MediaConstraints -import org.tm.archive.stories.Stories private const val VIDEO_EDITOR_TAG = "video.editor.fragment" @@ -34,18 +32,6 @@ class MediaReviewVideoPageFragment : Fragment(R.layout.fragment_container), Vide restoreVideoEditorState() } - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - saveEditorState() - } - - private fun saveEditorState() { - val saveState = videoEditorFragment.saveState() - if (saveState != null) { - sharedViewModel.setEditorState(requireUri(), saveState) - } - } - override fun onPlayerReady() { sharedViewModel.sendCommand(HudCommand.ResumeEntryTransition) } @@ -57,17 +43,8 @@ class MediaReviewVideoPageFragment : Fragment(R.layout.fragment_container), Vide override fun onTouchEventsNeeded(needed: Boolean) { sharedViewModel.setTouchEnabled(!needed) } - - override fun onVideoBeginEdit(uri: Uri) { - sharedViewModel.onVideoBeginEdit(uri) - } - - override fun onVideoEndEdit(uri: Uri) { - saveEditorState() - } - private fun restoreVideoEditorState() { - val data = sharedViewModel.getEditorState(requireUri()) as? VideoEditorFragment.Data + val data = sharedViewModel.getEditorState(requireUri()) as? VideoTrimData if (data != null) { videoEditorFragment.restoreState(data) @@ -82,10 +59,8 @@ class MediaReviewVideoPageFragment : Fragment(R.layout.fragment_container), Vide } else { val videoEditorFragment = VideoEditorFragment.newInstance( requireUri(), - requireMaxCompressedVideoSize(), requireMaxAttachmentSize(), - requireIsVideoGif(), - requireMaxVideoDuration() + requireIsVideoGif() ) childFragmentManager.beginTransaction() @@ -101,10 +76,8 @@ class MediaReviewVideoPageFragment : Fragment(R.layout.fragment_container), Vide } private fun requireUri(): Uri = requireNotNull(requireArguments().getParcelableCompat(ARG_URI, Uri::class.java)) - private fun requireMaxCompressedVideoSize(): Long = sharedViewModel.getMediaConstraints().getCompressedVideoMaxSize(requireContext()).toLong() - private fun requireMaxAttachmentSize(): Long = sharedViewModel.getMediaConstraints().getVideoMaxSize(requireContext()).toLong() + private fun requireMaxAttachmentSize(): Long = sharedViewModel.getMediaConstraints().getVideoMaxSize(requireContext()) private fun requireIsVideoGif(): Boolean = requireNotNull(requireArguments().getBoolean(ARG_IS_VIDEO_GIF)) - private fun requireMaxVideoDuration(): Long = if (sharedViewModel.isStory() && !MediaConstraints.isVideoTranscodeAvailable()) Stories.MAX_VIDEO_DURATION_MILLIS else Long.MAX_VALUE companion object { private const val ARG_URI = "arg.uri" diff --git a/app/src/main/java/org/tm/archive/mediasend/v2/videos/VideoTrimData.kt b/app/src/main/java/org/tm/archive/mediasend/v2/videos/VideoTrimData.kt new file mode 100644 index 00000000..3a546013 --- /dev/null +++ b/app/src/main/java/org/tm/archive/mediasend/v2/videos/VideoTrimData.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.mediasend.v2.videos + +import android.os.Bundle +import kotlin.time.Duration +import kotlin.time.Duration.Companion.microseconds + +/** + * This represents the editor state for the video trimmer. + */ +data class VideoTrimData( + val isDurationEdited: Boolean = false, + val totalInputDurationUs: Long = 0, + val startTimeUs: Long = 0, + val endTimeUs: Long = 0 +) { + + fun getDuration(): Duration = (endTimeUs - startTimeUs).microseconds + + fun toBundle(): Bundle { + return Bundle().apply { + putByte(KEY_EDITED, (if (isDurationEdited) 1 else 0).toByte()) + putLong(KEY_TOTAL, totalInputDurationUs) + putLong(KEY_START, startTimeUs) + putLong(KEY_END, endTimeUs) + } + } + + companion object { + private const val KEY_EDITED = "EDITED" + private const val KEY_TOTAL = "TOTAL" + private const val KEY_START = "START" + private const val KEY_END = "END" + + fun fromBundle(bundle: Bundle): VideoTrimData { + return VideoTrimData( + isDurationEdited = bundle.getByte(KEY_EDITED) == 1.toByte(), + totalInputDurationUs = bundle.getLong(KEY_TOTAL), + startTimeUs = bundle.getLong(KEY_START), + endTimeUs = bundle.getLong(KEY_END) + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/megaphone/BasicMegaphoneView.java b/app/src/main/java/org/tm/archive/megaphone/BasicMegaphoneView.java index 8d066289..0c0c501e 100644 --- a/app/src/main/java/org/tm/archive/megaphone/BasicMegaphoneView.java +++ b/app/src/main/java/org/tm/archive/megaphone/BasicMegaphoneView.java @@ -60,9 +60,9 @@ public class BasicMegaphoneView extends FrameLayout { if (megaphone.getImageRes() != 0) { image.setVisibility(VISIBLE); image.setImageResource(megaphone.getImageRes()); - } else if (megaphone.getImageRequest() != null) { + } else if (megaphone.getImageRequestBuilder() != null) { image.setVisibility(VISIBLE); - megaphone.getImageRequest().into(image); + megaphone.getImageRequestBuilder().into(image); } else if (megaphone.getLottieRes() != 0) { image.setVisibility(VISIBLE); image.setAnimation(megaphone.getLottieRes()); diff --git a/app/src/main/java/org/tm/archive/megaphone/ClientDeprecatedActivity.java b/app/src/main/java/org/tm/archive/megaphone/ClientDeprecatedActivity.java index 64e8c80c..fc9b52d1 100644 --- a/app/src/main/java/org/tm/archive/megaphone/ClientDeprecatedActivity.java +++ b/app/src/main/java/org/tm/archive/megaphone/ClientDeprecatedActivity.java @@ -1,5 +1,6 @@ package org.tm.archive.megaphone; +import android.annotation.SuppressLint; import android.os.Bundle; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -38,6 +39,7 @@ public class ClientDeprecatedActivity extends PassphraseRequiredActivity { theme.onResume(this); } + @SuppressLint("MissingSuperCall") @Override public void onBackPressed() { // Disabled diff --git a/app/src/main/java/org/tm/archive/megaphone/Megaphone.java b/app/src/main/java/org/tm/archive/megaphone/Megaphone.java index 45432480..0b422f8e 100644 --- a/app/src/main/java/org/tm/archive/megaphone/Megaphone.java +++ b/app/src/main/java/org/tm/archive/megaphone/Megaphone.java @@ -9,8 +9,9 @@ import androidx.annotation.Nullable; import androidx.annotation.RawRes; import androidx.annotation.StringRes; +import com.bumptech.glide.RequestBuilder; + import org.tm.archive.megaphone.Megaphones.Event; -import org.tm.archive.mms.GlideRequest; /** * For guidance on creating megaphones, see {@link Megaphones}. @@ -27,7 +28,7 @@ public class Megaphone { private final MegaphoneText bodyText; private final int imageRes; private final int lottieRes; - private final GlideRequest imageRequest; + private final RequestBuilder requestBuilder; private final MegaphoneText buttonText; private final EventListener buttonListener; private final EventListener snoozeListener; @@ -43,7 +44,7 @@ public class Megaphone { this.bodyText = builder.bodyText; this.imageRes = builder.imageRes; this.lottieRes = builder.lottieRes; - this.imageRequest = builder.imageRequest; + this.requestBuilder = builder.requestBuilder; this.buttonText = builder.buttonText; this.buttonListener = builder.buttonListener; this.snoozeListener = builder.snoozeListener; @@ -80,8 +81,8 @@ public class Megaphone { return imageRes; } - public @Nullable GlideRequest getImageRequest() { - return imageRequest; + public @Nullable RequestBuilder getImageRequestBuilder() { + return requestBuilder; } public @Nullable MegaphoneText getButtonText() { @@ -126,7 +127,7 @@ public class Megaphone { private MegaphoneText bodyText; private int imageRes; private int lottieRes; - private GlideRequest imageRequest; + private RequestBuilder requestBuilder; private MegaphoneText buttonText; private EventListener buttonListener; private EventListener snoozeListener; @@ -181,8 +182,8 @@ public class Megaphone { return this; } - public @NonNull Builder setImageRequest(@Nullable GlideRequest imageRequest) { - this.imageRequest = imageRequest; + public @NonNull Builder setImageRequestBuilder(@Nullable RequestBuilder requestBuilder) { + this.requestBuilder = requestBuilder; return this; } diff --git a/app/src/main/java/org/tm/archive/megaphone/MegaphoneRepository.java b/app/src/main/java/org/tm/archive/megaphone/MegaphoneRepository.java index d0e1abfc..673fa1b3 100644 --- a/app/src/main/java/org/tm/archive/megaphone/MegaphoneRepository.java +++ b/app/src/main/java/org/tm/archive/megaphone/MegaphoneRepository.java @@ -52,6 +52,7 @@ public class MegaphoneRepository { public void onFirstEverAppLaunch() { executor.execute(() -> { database.markFinished(Event.ADD_A_PROFILE_PHOTO); + database.markFinished(Event.PNP_LAUNCH); resetDatabaseCache(); }); } diff --git a/app/src/main/java/org/tm/archive/megaphone/Megaphones.java b/app/src/main/java/org/tm/archive/megaphone/Megaphones.java index aa2c581f..7bdc14d4 100644 --- a/app/src/main/java/org/tm/archive/megaphone/Megaphones.java +++ b/app/src/main/java/org/tm/archive/megaphone/Megaphones.java @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -11,6 +12,7 @@ import androidx.annotation.WorkerThread; import androidx.core.app.NotificationManagerCompat; import com.annimon.stream.Stream; +import com.bumptech.glide.Glide; import org.signal.core.util.MapUtil; import org.signal.core.util.SetUtil; @@ -18,23 +20,25 @@ import org.signal.core.util.TranslationDetection; import org.signal.core.util.logging.Log; import org.tm.archive.R; import org.tm.archive.components.settings.app.AppSettingsActivity; +import org.tm.archive.database.SignalDatabase; import org.tm.archive.database.model.MegaphoneRecord; import org.tm.archive.database.model.RemoteMegaphoneRecord; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobmanager.impl.NetworkConstraint; -import org.tm.archive.keyvalue.PhoneNumberPrivacyValues; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode; import org.tm.archive.keyvalue.SignalStore; -import org.tm.archive.keyvalue.SmsExportPhase; +import org.tm.archive.keyvalue.protos.LeastActiveLinkedDevice; import org.tm.archive.lock.SignalPinReminderDialog; import org.tm.archive.lock.SignalPinReminders; import org.tm.archive.lock.v2.CreateSvrPinActivity; import org.tm.archive.lock.v2.SvrMigrationActivity; -import org.tm.archive.mms.GlideApp; import org.tm.archive.notifications.NotificationChannels; import org.tm.archive.notifications.TurnOnNotificationsBottomSheet; import org.tm.archive.profiles.AvatarHelper; import org.tm.archive.profiles.manage.EditProfileActivity; +import org.tm.archive.profiles.username.NewWaysToConnectDialogFragment; import org.tm.archive.recipients.Recipient; +import org.tm.archive.storage.StorageSyncHelper; import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.ServiceUtil; import org.tm.archive.util.dynamiclanguage.DynamicLanguageContextWrapper; @@ -102,24 +106,37 @@ public final class Megaphones { * This is also when you would hide certain megaphones based on things like {@link FeatureFlags}. */ private static Map buildDisplayOrder(@NonNull Context context, @NonNull Map records) { - return new LinkedHashMap() {{ + return new LinkedHashMap<>() {{ put(Event.PINS_FOR_ALL, new PinsForAllSchedule()); put(Event.CLIENT_DEPRECATED, SignalStore.misc().isClientDeprecated() ? ALWAYS : NEVER); put(Event.NOTIFICATIONS, shouldShowNotificationsMegaphone(context) ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(30)) : NEVER); put(Event.GRANT_FULL_SCREEN_INTENT, shouldShowGrantFullScreenIntentPermission(context) ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(3)) : NEVER); - put(Event.SMS_EXPORT, new SmsExportReminderSchedule(context)); put(Event.BACKUP_SCHEDULE_PERMISSION, shouldShowBackupSchedulePermissionMegaphone(context) ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(3)) : NEVER); put(Event.ONBOARDING, shouldShowOnboardingMegaphone(context) ? ALWAYS : NEVER); put(Event.TURN_OFF_CENSORSHIP_CIRCUMVENTION, shouldShowTurnOffCircumventionMegaphone() ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(7)) : NEVER); put(Event.REMOTE_MEGAPHONE, shouldShowRemoteMegaphone(records) ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(1)) : NEVER); + put(Event.LINKED_DEVICE_INACTIVE, shouldShowLinkedDeviceInactiveMegaphone() ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(3)): NEVER); put(Event.PIN_REMINDER, new SignalPinReminderSchedule()); put(Event.SET_UP_YOUR_USERNAME, shouldShowSetUpYourUsernameMegaphone(records) ? ALWAYS : NEVER); // Feature-introduction megaphones should *probably* be added below this divider put(Event.ADD_A_PROFILE_PHOTO, shouldShowAddAProfilePhotoMegaphone(context) ? ALWAYS : NEVER); + put(Event.PNP_LAUNCH, shouldShowPnpLaunchMegaphone() ? ALWAYS : NEVER); }}; } + private static boolean shouldShowLinkedDeviceInactiveMegaphone() { + LeastActiveLinkedDevice device = SignalStore.misc().getLeastActiveLinkedDevice(); + if (device == null) { + return false; + } + + long expiringAt = device.lastActiveTimestamp + FeatureFlags.linkedDeviceLifespan(); + long expiringIn = Math.max(expiringAt - System.currentTimeMillis(), 0); + + return expiringIn < TimeUnit.DAYS.toMillis(7) && expiringIn > 0; + } + private static @NonNull Megaphone forRecord(@NonNull Context context, @NonNull MegaphoneRecord record) { switch (record.getEvent()) { case PINS_FOR_ALL: @@ -136,22 +153,46 @@ public final class Megaphones { return buildAddAProfilePhotoMegaphone(context); case TURN_OFF_CENSORSHIP_CIRCUMVENTION: return buildTurnOffCircumventionMegaphone(context); + case LINKED_DEVICE_INACTIVE: + return buildLinkedDeviceInactiveMegaphone(context); case REMOTE_MEGAPHONE: return buildRemoteMegaphone(context); case BACKUP_SCHEDULE_PERMISSION: return buildBackupPermissionMegaphone(context); - case SMS_EXPORT: - return buildSmsExportMegaphone(context); case SET_UP_YOUR_USERNAME: return buildSetUpYourUsernameMegaphone(context); case GRANT_FULL_SCREEN_INTENT: return buildGrantFullScreenIntentPermission(context); - + case PNP_LAUNCH: + return buildPnpLaunchMegaphone(); default: throw new IllegalArgumentException("Event not handled!"); } } + private static Megaphone buildLinkedDeviceInactiveMegaphone(Context context) { + LeastActiveLinkedDevice device = SignalStore.misc().getLeastActiveLinkedDevice(); + if (device == null) { + throw new IllegalStateException("No linked device to show"); + } + + long expiringAt = device.lastActiveTimestamp + FeatureFlags.linkedDeviceLifespan(); + long expiringIn = Math.max(expiringAt - System.currentTimeMillis(), 0); + int expiringDays = (int) TimeUnit.MILLISECONDS.toDays(expiringIn); + + return new Megaphone.Builder(Event.LINKED_DEVICE_INACTIVE, Megaphone.Style.BASIC) + .setTitle(R.string.LinkedDeviceInactiveMegaphone_title) + .setBody(context.getResources().getQuantityString(R.plurals.LinkedDeviceInactiveMegaphone_body, expiringDays, device.name, expiringDays)) + .setImage(R.drawable.ic_inactive_linked_device) + .setActionButton(R.string.LinkedDeviceInactiveMegaphone_got_it_button_label, (megaphone, listener) -> { + listener.onMegaphoneSnooze(Event.LINKED_DEVICE_INACTIVE); + }) + .setSecondaryButton(R.string.LinkedDeviceInactiveMegaphone_dont_remind_button_label, (megaphone, listener) -> { + listener.onMegaphoneCompleted(Event.LINKED_DEVICE_INACTIVE); + }) + .build(); + } + private static @NonNull Megaphone buildPinsForAllMegaphone(@NonNull MegaphoneRecord record) { if (PinsForAllSchedule.shouldDisplayFullScreen(record.getFirstVisible(), System.currentTimeMillis())) { return new Megaphone.Builder(Event.PINS_FOR_ALL, Megaphone.Style.FULLSCREEN) @@ -276,7 +317,7 @@ public final class Megaphones { .setBody(record.getBody()); if (record.getImageUri() != null) { - builder.setImageRequest(GlideApp.with(context).asDrawable().load(record.getImageUri())); + builder.setImageRequestBuilder(Glide.with(context).asDrawable().load(record.getImageUri())); } if (record.hasPrimaryAction()) { @@ -320,38 +361,43 @@ public final class Megaphones { .build(); } - private static @NonNull Megaphone buildSmsExportMegaphone(@NonNull Context context) { - SmsExportPhase phase = SignalStore.misc().getSmsExportPhase(); - - Megaphone.Builder builder = new Megaphone.Builder(Event.SMS_EXPORT, Megaphone.Style.FULLSCREEN) - .setOnVisibleListener((megaphone, controller) -> { - if (phase.isBlockingUi()) { - SmsExportReminderSchedule.setShowPhase3Megaphone(false); - } - controller.onMegaphoneNavigationRequested(new Intent(context, SmsExportMegaphoneActivity.class), SmsExportMegaphoneActivity.REQUEST_CODE); - }); - - if (phase.isBlockingUi()) { - builder.disableSnooze(); - } - - return builder.build(); - } - public static @NonNull Megaphone buildSetUpYourUsernameMegaphone(@NonNull Context context) { return new Megaphone.Builder(Event.SET_UP_YOUR_USERNAME, Megaphone.Style.BASIC) - .setTitle(R.string.SetUpYourUsername__set_up_your_signal_username) - .setBody(R.string.SetUpYourUsername__usernames_let_others) - .setImage(R.drawable.usernames_64) - .setActionButton(R.string.SetUpYourUsername__continue, (megaphone, controller) -> { - controller.onMegaphoneNavigationRequested(EditProfileActivity.getIntentForUsernameEdit(context)); + .setTitle(R.string.NewWaysToConnectDialogFragment__new_ways_to_connect) + .setBody(R.string.SetUpYourUsername__introducing_phone_number_privacy) + .setImage(R.drawable.usernames_megaphone) + .setActionButton(R.string.SetUpYourUsername__learn_more, (megaphone, controller) -> { + controller.onMegaphoneDialogFragmentRequested(new NewWaysToConnectDialogFragment()); }) - .setSecondaryButton(R.string.SetUpYourUsername__not_now, (megaphone, controller) -> { + .setSecondaryButton(R.string.SetUpYourUsername__dismiss, (megaphone, controller) -> { controller.onMegaphoneCompleted(Event.SET_UP_YOUR_USERNAME); }) .build(); } + public static @NonNull Megaphone buildPnpLaunchMegaphone() { + return new Megaphone.Builder(Event.PNP_LAUNCH, Megaphone.Style.BASIC) + .setTitle(R.string.PnpLaunchMegaphone_title) + .setBody(R.string.PnpLaunchMegaphone_body) + .setImage(R.drawable.usernames_megaphone) + .setActionButton(R.string.PnpLaunchMegaphone_learn_more, (megaphone, controller) -> { + controller.onMegaphoneDialogFragmentRequested(new NewWaysToConnectDialogFragment()); + controller.onMegaphoneCompleted(Event.PNP_LAUNCH); + + SignalStore.uiHints().setHasCompletedUsernameOnboarding(true); + SignalDatabase.recipients().markNeedsSync(Recipient.self().getId()); + StorageSyncHelper.scheduleSyncForDataChange(); + }) + .setSecondaryButton(R.string.PnpLaunchMegaphone_dismiss, (megaphone, controller) -> { + controller.onMegaphoneCompleted(Event.PNP_LAUNCH); + + SignalStore.uiHints().setHasCompletedUsernameOnboarding(true); + SignalDatabase.recipients().markNeedsSync(Recipient.self().getId()); + StorageSyncHelper.scheduleSyncForDataChange(); + }) + .build(); + } + public static @NonNull Megaphone buildGrantFullScreenIntentPermission(@NonNull Context context) { return new Megaphone.Builder(Event.GRANT_FULL_SCREEN_INTENT, Megaphone.Style.BASIC) .setTitle(R.string.GrantFullScreenIntentPermission_megaphone_title) @@ -360,7 +406,7 @@ public final class Megaphones { .setActionButton(R.string.GrantFullScreenIntentPermission_megaphone_turn_on, (megaphone, controller) -> { controller.onMegaphoneDialogFragmentRequested(TurnOnNotificationsBottomSheet.turnOnFullScreenIntentFragment(context)); }) - .setSecondaryButton(R.string.SetUpYourUsername__not_now, (megaphone, controller) -> { + .setSecondaryButton(R.string.GrantFullScreenIntentPermission_megaphone_not_now, (megaphone, controller) -> { controller.onMegaphoneCompleted(Event.GRANT_FULL_SCREEN_INTENT); }) .build(); @@ -396,13 +442,13 @@ public final class Megaphones { } private static boolean shouldShowAddAProfilePhotoMegaphone(@NonNull Context context) { - if (SignalStore.misc().hasEverHadAnAvatar()) { + if (SignalStore.misc().getHasEverHadAnAvatar()) { return false; } boolean hasAnAvatar = AvatarHelper.hasAvatar(context, Recipient.self().getId()); if (hasAnAvatar) { - SignalStore.misc().markHasEverHadAnAvatar(); + SignalStore.misc().setHasEverHadAnAvatar(true); return false; } @@ -413,19 +459,22 @@ public final class Megaphones { * Prompt megaphone 3 days after turning off phone number discovery when no username is set. */ private static boolean shouldShowSetUpYourUsernameMegaphone(@NonNull Map records) { - boolean hasUsername = SignalStore.account().isRegistered() && SignalStore.account().getUsername() != null; - boolean hasCompleted = MapUtil.mapOrDefault(records, Event.SET_UP_YOUR_USERNAME, MegaphoneRecord::isFinished, false); - long phoneNumberDiscoveryDisabledAt = SignalStore.phoneNumberPrivacy().getPhoneNumberListingModeTimestamp(); - PhoneNumberPrivacyValues.PhoneNumberListingMode listingMode = SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode(); + boolean hasUsername = SignalStore.account().isRegistered() && SignalStore.account().getUsername() != null; + boolean hasCompleted = MapUtil.mapOrDefault(records, Event.SET_UP_YOUR_USERNAME, MegaphoneRecord::isFinished, false); + long phoneNumberDiscoveryDisabledAt = SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityModeTimestamp(); + PhoneNumberDiscoverabilityMode listingMode = SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode(); - return FeatureFlags.usernames() && - !hasUsername && - listingMode.isUnlisted() && + return !hasUsername && + listingMode == PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE && !hasCompleted && phoneNumberDiscoveryDisabledAt > 0 && (System.currentTimeMillis() - phoneNumberDiscoveryDisabledAt) >= TimeUnit.DAYS.toMillis(3); } + private static boolean shouldShowPnpLaunchMegaphone() { + return TextUtils.isEmpty(SignalStore.account().getUsername()) && !SignalStore.uiHints().hasCompletedUsernameOnboarding(); + } + private static boolean shouldShowGrantFullScreenIntentPermission(@NonNull Context context) { return Build.VERSION.SDK_INT >= 34 && !NotificationManagerCompat.from(context).canUseFullScreenIntent(); } @@ -469,9 +518,10 @@ public final class Megaphones { DONATE_Q2_2022("donate_q2_2022"), TURN_OFF_CENSORSHIP_CIRCUMVENTION("turn_off_censorship_circumvention"), REMOTE_MEGAPHONE("remote_megaphone"), + LINKED_DEVICE_INACTIVE("linked_device_inactive"), BACKUP_SCHEDULE_PERMISSION("backup_schedule_permission"), - SMS_EXPORT("sms_export"), SET_UP_YOUR_USERNAME("set_up_your_username"), + PNP_LAUNCH("pnp_launch"), GRANT_FULL_SCREEN_INTENT("grant_full_screen_intent"); private final String key; diff --git a/app/src/main/java/org/tm/archive/megaphone/OnboardingMegaphoneView.java b/app/src/main/java/org/tm/archive/megaphone/OnboardingMegaphoneView.java index 36fa23c9..68c26891 100644 --- a/app/src/main/java/org/tm/archive/megaphone/OnboardingMegaphoneView.java +++ b/app/src/main/java/org/tm/archive/megaphone/OnboardingMegaphoneView.java @@ -135,7 +135,7 @@ public class OnboardingMegaphoneView extends FrameLayout { data.add(TYPE_INVITE); } - if (SignalStore.onboarding().shouldShowAddPhoto() && !SignalStore.misc().hasEverHadAnAvatar()) { + if (SignalStore.onboarding().shouldShowAddPhoto() && !SignalStore.misc().getHasEverHadAnAvatar()) { data.add(TYPE_ADD_PHOTO); } diff --git a/app/src/main/java/org/tm/archive/megaphone/PopupMegaphoneView.java b/app/src/main/java/org/tm/archive/megaphone/PopupMegaphoneView.java index 08345376..59f834a0 100644 --- a/app/src/main/java/org/tm/archive/megaphone/PopupMegaphoneView.java +++ b/app/src/main/java/org/tm/archive/megaphone/PopupMegaphoneView.java @@ -55,9 +55,9 @@ public class PopupMegaphoneView extends FrameLayout { this.megaphone = megaphone; this.megaphoneListener = megaphoneListener; - if (megaphone.getImageRequest() != null) { + if (megaphone.getImageRequestBuilder() != null) { image.setVisibility(VISIBLE); - megaphone.getImageRequest().into(image); + megaphone.getImageRequestBuilder().into(image); } else if (megaphone.getLottieRes() != 0) { image.setVisibility(VISIBLE); image.setAnimation(megaphone.getLottieRes()); diff --git a/app/src/main/java/org/tm/archive/megaphone/SmsExportMegaphoneActivity.kt b/app/src/main/java/org/tm/archive/megaphone/SmsExportMegaphoneActivity.kt deleted file mode 100644 index e74f138b..00000000 --- a/app/src/main/java/org/tm/archive/megaphone/SmsExportMegaphoneActivity.kt +++ /dev/null @@ -1,79 +0,0 @@ -package org.tm.archive.megaphone - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import org.tm.archive.PassphraseRequiredActivity -import org.tm.archive.R -import org.tm.archive.databinding.SmsRemovalInformationFragmentBinding -import org.tm.archive.dependencies.ApplicationDependencies -import org.tm.archive.exporter.flow.SmsExportActivity -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.util.CommunicationActions -import org.tm.archive.util.DynamicNoActionBarTheme -import org.tm.archive.util.DynamicTheme -import org.tm.archive.util.visible - -class SmsExportMegaphoneActivity : PassphraseRequiredActivity() { - - companion object { - const val REQUEST_CODE: Short = 5343 - } - - private val theme: DynamicTheme = DynamicNoActionBarTheme() - private lateinit var binding: SmsRemovalInformationFragmentBinding - private lateinit var smsExportLauncher: ActivityResultLauncher - - override fun onPreCreate() { - theme.onCreate(this) - } - - override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { - binding = SmsRemovalInformationFragmentBinding.inflate(layoutInflater) - setContentView(binding.root) - - smsExportLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - ApplicationDependencies.getMegaphoneRepository().markSeen(Megaphones.Event.SMS_EXPORT) - setResult(Activity.RESULT_OK) - finish() - } - } - - binding.toolbar.setNavigationOnClickListener { onBackPressed() } - - binding.learnMoreButton.setOnClickListener { - CommunicationActions.openBrowserLink(this, getString(R.string.sms_export_url)) - } - - if (SignalStore.misc().smsExportPhase.isBlockingUi()) { - binding.headline.setText(R.string.SmsExportMegaphoneActivity__signal_no_longer_supports_sms) - binding.laterButton.visible = false - binding.bullet1Text.setText(R.string.SmsRemoval_info_bullet_1_phase_3) - } else { - binding.bullet1Text.text = getString(R.string.SmsRemoval_info_bullet_1) - - binding.headline.setText(R.string.SmsExportMegaphoneActivity__signal_will_no_longer_support_sms) - binding.laterButton.setOnClickListener { - onBackPressed() - } - } - - binding.exportSmsButton.setOnClickListener { - smsExportLauncher.launch(SmsExportActivity.createIntent(this)) - } - } - - override fun onBackPressed() { - ApplicationDependencies.getMegaphoneRepository().markSeen(Megaphones.Event.SMS_EXPORT) - setResult(Activity.RESULT_CANCELED) - super.onBackPressed() - } - - override fun onResume() { - super.onResume() - theme.onResume(this) - } -} diff --git a/app/src/main/java/org/tm/archive/megaphone/SmsExportReminderSchedule.kt b/app/src/main/java/org/tm/archive/megaphone/SmsExportReminderSchedule.kt deleted file mode 100644 index 9010494e..00000000 --- a/app/src/main/java/org/tm/archive/megaphone/SmsExportReminderSchedule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.tm.archive.megaphone - -import android.content.Context -import androidx.annotation.WorkerThread -import org.tm.archive.util.Util - -class SmsExportReminderSchedule(private val context: Context) : MegaphoneSchedule { - - companion object { - @JvmStatic - var showPhase3Megaphone = true - } - - @WorkerThread - override fun shouldDisplay(seenCount: Int, lastSeen: Long, firstVisible: Long, currentTime: Long): Boolean { - return if (Util.isDefaultSmsProvider(context)) { - showPhase3Megaphone - } else { - false - } - } -} diff --git a/app/src/main/java/org/tm/archive/messagedetails/InternalMessageDetailsFragment.kt b/app/src/main/java/org/tm/archive/messagedetails/InternalMessageDetailsFragment.kt new file mode 100644 index 00000000..cf897027 --- /dev/null +++ b/app/src/main/java/org/tm/archive/messagedetails/InternalMessageDetailsFragment.kt @@ -0,0 +1,230 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.messagedetails + +import android.content.Context +import android.widget.Toast +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.os.bundleOf +import androidx.fragment.app.FragmentActivity +import org.tm.archive.compose.ComposeFullScreenDialogFragment +import org.tm.archive.database.model.MessageRecord +import org.tm.archive.messagedetails.InternalMessageDetailsViewModel.AttachmentInfo +import org.tm.archive.messagedetails.InternalMessageDetailsViewModel.ViewState +import org.tm.archive.recipients.RecipientId +import org.tm.archive.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment +import org.tm.archive.util.Util +import org.tm.archive.util.viewModel + +class InternalMessageDetailsFragment : ComposeFullScreenDialogFragment() { + companion object { + const val ARG_MESSAGE_ID = "message_id" + + @JvmStatic + fun create(messageRecord: MessageRecord): InternalMessageDetailsFragment { + return InternalMessageDetailsFragment().apply { + arguments = bundleOf( + ARG_MESSAGE_ID to messageRecord.id + ) + } + } + } + + val viewModel: InternalMessageDetailsViewModel by viewModel { InternalMessageDetailsViewModel(requireArguments().getLong(ARG_MESSAGE_ID, 0)) } + + @Composable + override fun DialogContent() { + val state by viewModel.state + + state?.let { + Content(it) + } + } +} + +@Composable +private fun Content(state: ViewState) { + val context = LocalContext.current + + Surface( + modifier = Modifier + .fillMaxSize() + ) { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()) + ) { + Text( + text = "Message Details", + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier + .padding(8.dp) + .fillMaxWidth() + ) + ClickToCopyRow( + name = "MessageId", + value = state.id.toString() + ) + ClickToCopyRow( + name = "Sent Timestamp", + value = state.sentTimestamp.toString() + ) + ClickToCopyRow( + name = "Received Timestamp", + value = state.receivedTimestamp.toString() + ) + + val serverTimestampString = if (state.serverSentTimestamp <= 0L) { + "N/A" + } else { + state.serverSentTimestamp.toString() + } + + ClickToCopyRow( + name = "Server Sent Timestamp", + value = serverTimestampString + ) + DetailRow( + name = "To", + value = state.to.toString(), + onClick = { + val fragmentManager = (context as FragmentActivity).supportFragmentManager + RecipientBottomSheetDialogFragment.show(fragmentManager, state.to, null) + } + ) + DetailRow( + name = "From", + value = state.from.toString(), + onClick = { + val fragmentManager = (context as FragmentActivity).supportFragmentManager + RecipientBottomSheetDialogFragment.show(fragmentManager, state.from, null) + } + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Attachments", + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier + .padding(8.dp) + .fillMaxWidth() + ) + + if (state.attachments.isEmpty()) { + Text( + text = "None", + modifier = Modifier + .padding(8.dp) + .fillMaxWidth() + ) + } else { + state.attachments.forEach { attachment -> + AttachmentBlock(attachment) + } + } + } + } +} + +@Composable +private fun DetailRow(name: String, value: String, onClick: () -> Unit) { + val formattedString = buildAnnotatedString { + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { + append("$name: ") + } + withStyle(SpanStyle(fontFamily = FontFamily.Monospace)) { + append(value) + } + } + + Text( + text = formattedString, + modifier = Modifier + .clickable { onClick() } + .padding(8.dp) + .fillMaxWidth() + ) +} + +@Composable +private fun ClickToCopyRow(name: String, value: String, valueToCopy: String = value) { + val context: Context = LocalContext.current + + DetailRow( + name = name, + value = value, + onClick = { + Util.copyToClipboard(context, valueToCopy) + Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show() + } + ) +} + +@Composable +private fun AttachmentBlock(attachment: AttachmentInfo) { + ClickToCopyRow( + name = "ID", + value = attachment.id.toString() + ) + ClickToCopyRow( + name = "Filename", + value = attachment.fileName.toString() + ) + ClickToCopyRow( + name = "Content Type", + value = attachment.contentType + ) + ClickToCopyRow( + name = "Start Hash", + value = attachment.hashStart ?: "null" + ) + ClickToCopyRow( + name = "End Hash", + value = attachment.hashEnd ?: "null" + ) + ClickToCopyRow( + name = "Transform Properties", + value = attachment.transformProperties ?: "null" + ) +} + +@Preview +@Composable +private fun ContentPreview() { + Content( + ViewState( + id = 1, + sentTimestamp = 2, + receivedTimestamp = 3, + serverSentTimestamp = 4, + to = RecipientId.from(1), + from = RecipientId.from(2), + attachments = emptyList() + ) + ) +} diff --git a/app/src/main/java/org/tm/archive/messagedetails/InternalMessageDetailsViewModel.kt b/app/src/main/java/org/tm/archive/messagedetails/InternalMessageDetailsViewModel.kt new file mode 100644 index 00000000..6c439536 --- /dev/null +++ b/app/src/main/java/org/tm/archive/messagedetails/InternalMessageDetailsViewModel.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.messagedetails + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.tm.archive.database.SignalDatabase +import org.tm.archive.recipients.RecipientId +import org.whispersystems.signalservice.internal.util.JsonUtil + +class InternalMessageDetailsViewModel(val messageId: Long) : ViewModel() { + + private val _state: MutableState = mutableStateOf(null) + val state: State = _state + + init { + viewModelScope.launch(Dispatchers.IO) { + val messageRecord = SignalDatabase.messages.getMessageRecord(messageId) + val attachments = SignalDatabase.attachments.getAttachmentsForMessage(messageId) + + _state.value = ViewState( + id = messageRecord.id, + sentTimestamp = messageRecord.dateSent, + receivedTimestamp = messageRecord.dateReceived, + serverSentTimestamp = messageRecord.serverTimestamp, + from = messageRecord.fromRecipient.id, + to = messageRecord.toRecipient.id, + attachments = attachments.map { attachment -> + val info = SignalDatabase.attachments.getDataFileInfo(attachment.attachmentId) + + AttachmentInfo( + id = attachment.attachmentId.id, + contentType = attachment.contentType, + size = attachment.size, + fileName = attachment.fileName, + hashStart = info?.hashStart, + hashEnd = info?.hashEnd, + transformProperties = info?.transformProperties?.let { JsonUtil.toJson(it) } ?: "null" + ) + } + ) + } + } + + data class ViewState( + val id: Long, + val sentTimestamp: Long, + val receivedTimestamp: Long, + val serverSentTimestamp: Long, + val from: RecipientId, + val to: RecipientId, + val attachments: List + ) + + data class AttachmentInfo( + val id: Long, + val contentType: String, + val size: Long, + val fileName: String?, + val hashStart: String?, + val hashEnd: String?, + val transformProperties: String? + ) +} diff --git a/app/src/main/java/org/tm/archive/messagedetails/MessageDetailsAdapter.java b/app/src/main/java/org/tm/archive/messagedetails/MessageDetailsAdapter.java index 04255782..cbcd31e3 100644 --- a/app/src/main/java/org/tm/archive/messagedetails/MessageDetailsAdapter.java +++ b/app/src/main/java/org/tm/archive/messagedetails/MessageDetailsAdapter.java @@ -10,24 +10,25 @@ import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.ListAdapter; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; + import org.tm.archive.R; import org.tm.archive.conversation.ConversationMessage; import org.tm.archive.conversation.colors.Colorizer; import org.tm.archive.database.model.MessageRecord; import org.tm.archive.databinding.MessageDetailsViewEditHistoryBinding; -import org.tm.archive.mms.GlideRequests; final class MessageDetailsAdapter extends ListAdapter, RecyclerView.ViewHolder> { private final LifecycleOwner lifecycleOwner; - private final GlideRequests glideRequests; + private final RequestManager requestManager; private final Colorizer colorizer; private final Callbacks callbacks; - MessageDetailsAdapter(@NonNull LifecycleOwner lifecycleOwner, @NonNull GlideRequests glideRequests, @NonNull Colorizer colorizer, @NonNull Callbacks callbacks) { + MessageDetailsAdapter(@NonNull LifecycleOwner lifecycleOwner, @NonNull RequestManager requestManager, @NonNull Colorizer colorizer, @NonNull Callbacks callbacks) { super(new MessageDetailsDiffer()); this.lifecycleOwner = lifecycleOwner; - this.glideRequests = glideRequests; + this.requestManager = requestManager; this.colorizer = colorizer; this.callbacks = callbacks; } @@ -36,7 +37,7 @@ final class MessageDetailsAdapter extends ListAdapter callbacks.onInternalDetailsClicked(messageRecord)); } private void bindMessageView(@NonNull LifecycleOwner lifecycleOwner, @NonNull ConversationMessage conversationMessage) { @@ -101,7 +119,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder implements G conversationMessage, Optional.empty(), Optional.empty(), - glideRequests, + requestManager, Locale.getDefault(), new HashSet<>(), conversationMessage.getMessageRecord().getToRecipient(), diff --git a/app/src/main/java/org/tm/archive/messagerequests/CalleeMustAcceptMessageRequestActivity.java b/app/src/main/java/org/tm/archive/messagerequests/CalleeMustAcceptMessageRequestActivity.java index 798020f9..175dda1e 100644 --- a/app/src/main/java/org/tm/archive/messagerequests/CalleeMustAcceptMessageRequestActivity.java +++ b/app/src/main/java/org/tm/archive/messagerequests/CalleeMustAcceptMessageRequestActivity.java @@ -14,12 +14,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; +import com.bumptech.glide.Glide; + import org.tm.archive.BaseActivity; import org.tm.archive.R; import org.tm.archive.components.AvatarImageView; import org.tm.archive.contacts.avatars.FallbackContactPhoto; import org.tm.archive.contacts.avatars.ResourceContactPhoto; -import org.tm.archive.mms.GlideApp; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; @@ -70,7 +71,7 @@ public class CalleeMustAcceptMessageRequestActivity extends BaseActivity { viewModel.getRecipient().observe(this, recipient -> { description.setText(getString(R.string.CalleeMustAcceptMessageRequestDialogFragment__s_will_get_a_message_request_from_you, recipient.getDisplayName(this))); - avatar.setAvatar(GlideApp.with(this), recipient, false); + avatar.setAvatar(Glide.with(this), recipient, false); }); } diff --git a/app/src/main/java/org/tm/archive/messagerequests/GroupInfo.java b/app/src/main/java/org/tm/archive/messagerequests/GroupInfo.java deleted file mode 100644 index ab5f7f77..00000000 --- a/app/src/main/java/org/tm/archive/messagerequests/GroupInfo.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.tm.archive.messagerequests; - -import androidx.annotation.NonNull; - -public final class GroupInfo { - public static final GroupInfo ZERO = new GroupInfo(0, 0, ""); - - private final int fullMemberCount; - private final int pendingMemberCount; - private final String description; - - public GroupInfo(int fullMemberCount, int pendingMemberCount, @NonNull String description) { - this.fullMemberCount = fullMemberCount; - this.pendingMemberCount = pendingMemberCount; - this.description = description; - } - - public int getFullMemberCount() { - return fullMemberCount; - } - - public int getPendingMemberCount() { - return pendingMemberCount; - } - - public @NonNull String getDescription() { - return description; - } -} diff --git a/app/src/main/java/org/tm/archive/messagerequests/GroupInfo.kt b/app/src/main/java/org/tm/archive/messagerequests/GroupInfo.kt new file mode 100644 index 00000000..22d46e34 --- /dev/null +++ b/app/src/main/java/org/tm/archive/messagerequests/GroupInfo.kt @@ -0,0 +1,16 @@ +package org.tm.archive.messagerequests + +/** + * Group info needed to show message request state UX. + */ +class GroupInfo( + val fullMemberCount: Int = 0, + val pendingMemberCount: Int = 0, + val description: String = "", + val hasExistingContacts: Boolean = false +) { + companion object { + @JvmField + val ZERO = GroupInfo() + } +} diff --git a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestRepository.java b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestRepository.java index 88c754db..8c141c68 100644 --- a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestRepository.java +++ b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestRepository.java @@ -4,7 +4,6 @@ import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; -import androidx.core.util.Consumer; import org.signal.core.util.Result; import org.signal.core.util.concurrent.SignalExecutors; @@ -24,12 +23,13 @@ import org.tm.archive.groups.ui.GroupChangeFailureReason; import org.tm.archive.jobs.MultiDeviceMessageRequestResponseJob; import org.tm.archive.jobs.ReportSpamJob; import org.tm.archive.jobs.SendViewedReceiptJob; +import org.tm.archive.mms.MmsException; +import org.tm.archive.mms.OutgoingMessage; import org.tm.archive.notifications.MarkReadReceiver; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.recipients.RecipientUtil; import org.tm.archive.sms.MessageSender; -import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.TextSecurePreferences; import org.whispersystems.signalservice.internal.push.exceptions.GroupPatchNotAcceptedException; @@ -37,7 +37,9 @@ import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import io.reactivex.rxjava3.core.Completable; import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.schedulers.Schedulers; import kotlin.Unit; @@ -54,28 +56,6 @@ public final class MessageRequestRepository { this.executor = SignalExecutors.BOUNDED; } - public void getGroups(@NonNull RecipientId recipientId, @NonNull Consumer> onGroupsLoaded) { - executor.execute(() -> { - GroupTable groupDatabase = SignalDatabase.groups(); - onGroupsLoaded.accept(groupDatabase.getPushGroupNamesContainingMember(recipientId)); - }); - } - - public void getGroupInfo(@NonNull RecipientId recipientId, @NonNull Consumer onGroupInfoLoaded) { - executor.execute(() -> { - GroupTable groupDatabase = SignalDatabase.groups(); - Optional groupRecord = groupDatabase.getGroup(recipientId); - onGroupInfoLoaded.accept(groupRecord.map(record -> { - if (record.isV2Group()) { - DecryptedGroup decryptedGroup = record.requireV2GroupProperties().getDecryptedGroup(); - return new GroupInfo(decryptedGroup.members.size(), decryptedGroup.pendingMembers.size(), decryptedGroup.description); - } else { - return new GroupInfo(record.getMembers().size(), 0, ""); - } - }).orElse(GroupInfo.ZERO)); - }); - } - @WorkerThread public @NonNull MessageRequestRecipientInfo getRecipientInfo(@NonNull RecipientId recipientId, long threadId) { List sharedGroups = SignalDatabase.groups().getPushGroupNamesContainingMember(recipientId); @@ -83,11 +63,20 @@ public final class MessageRequestRepository { GroupInfo groupInfo = GroupInfo.ZERO; if (groupRecord.isPresent()) { + boolean groupHasExistingContacts = false; if (groupRecord.get().isV2Group()) { + List recipients = Recipient.resolvedList(groupRecord.get().getMembers()); + for (Recipient recipient : recipients) { + if ((recipient.isProfileSharing() || recipient.hasGroupsInCommon()) && !recipient.isSelf()) { + groupHasExistingContacts = true; + break; + } + } + DecryptedGroup decryptedGroup = groupRecord.get().requireV2GroupProperties().getDecryptedGroup(); - groupInfo = new GroupInfo(decryptedGroup.members.size(), decryptedGroup.pendingMembers.size(), decryptedGroup.description); + groupInfo = new GroupInfo(decryptedGroup.members.size(), decryptedGroup.pendingMembers.size(), decryptedGroup.description, groupHasExistingContacts); } else { - groupInfo = new GroupInfo(groupRecord.get().getMembers().size(), 0, ""); + groupInfo = new GroupInfo(groupRecord.get().getMembers().size(), 0, "", false); } } @@ -104,10 +93,11 @@ public final class MessageRequestRepository { @WorkerThread public @NonNull MessageRequestState getMessageRequestState(@NonNull Recipient recipient, long threadId) { if (recipient.isBlocked()) { + boolean reportedAsSpam = reportedAsSpam(threadId); if (recipient.isGroup()) { - return MessageRequestState.BLOCKED_GROUP; + return new MessageRequestState(MessageRequestState.State.BLOCKED_GROUP, reportedAsSpam); } else { - return MessageRequestState.BLOCKED_INDIVIDUAL; + return new MessageRequestState(MessageRequestState.State.INDIVIDUAL_BLOCKED, reportedAsSpam); } } else if (threadId <= 0) { return MessageRequestState.NONE; @@ -115,45 +105,60 @@ public final class MessageRequestRepository { switch (getGroupMemberLevel(recipient.getId())) { case NOT_A_MEMBER: return MessageRequestState.NONE; - case PENDING_MEMBER: - return MessageRequestState.GROUP_V2_INVITE; - default: + case PENDING_MEMBER: { + boolean reportedAsSpam = reportedAsSpam(threadId); + return new MessageRequestState(MessageRequestState.State.GROUP_V2_INVITE, reportedAsSpam); + } + default: { if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { return MessageRequestState.NONE; } else { - return MessageRequestState.GROUP_V2_ADD; + boolean reportedAsSpam = reportedAsSpam(threadId); + return new MessageRequestState(MessageRequestState.State.GROUP_V2_ADD, reportedAsSpam); } + } } } else if (!RecipientUtil.isLegacyProfileSharingAccepted(recipient) && isLegacyThread(recipient)) { if (recipient.isGroup()) { - return MessageRequestState.DEPRECATED_GROUP_V1; + return MessageRequestState.DEPRECATED_V1; } else { - return MessageRequestState.LEGACY_INDIVIDUAL; + return new MessageRequestState(MessageRequestState.State.LEGACY_INDIVIDUAL); } } else if (recipient.isPushV1Group()) { if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { - return MessageRequestState.DEPRECATED_GROUP_V1; + return MessageRequestState.DEPRECATED_V1; } else if (!recipient.isActiveGroup()) { return MessageRequestState.NONE; } else { - return MessageRequestState.DEPRECATED_GROUP_V1; + return MessageRequestState.DEPRECATED_V1; } } else { if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { return MessageRequestState.NONE; } else { - Recipient.HiddenState hiddenState = RecipientUtil.getRecipientHiddenState(threadId); + Recipient.HiddenState hiddenState = RecipientUtil.getRecipientHiddenState(threadId); + boolean reportedAsSpam = reportedAsSpam(threadId); + if (hiddenState == Recipient.HiddenState.NOT_HIDDEN) { - return MessageRequestState.INDIVIDUAL; + return new MessageRequestState(MessageRequestState.State.INDIVIDUAL, reportedAsSpam); } else if (hiddenState == Recipient.HiddenState.HIDDEN) { - return MessageRequestState.NONE_HIDDEN; + return new MessageRequestState(MessageRequestState.State.NONE_HIDDEN, reportedAsSpam); } else { - return MessageRequestState.INDIVIDUAL_HIDDEN; + return new MessageRequestState(MessageRequestState.State.INDIVIDUAL_HIDDEN, reportedAsSpam); } } } } + public boolean threadContainsSms(long threadId) { + return SignalDatabase.messages().threadContainsSms(threadId); + } + + private boolean reportedAsSpam(long threadId) { + return SignalDatabase.messages().hasReportSpamMessage(threadId) || + SignalDatabase.messages().getOutgoingSecureMessageCount(threadId) > 0; + } + @SuppressWarnings("unchecked") public @NonNull Single> acceptMessageRequest(@NonNull RecipientId recipientId, long threadId) { //noinspection CodeBlock2Expr @@ -172,7 +177,7 @@ public final class MessageRequestRepository { @NonNull Runnable onMessageRequestAccepted, @NonNull GroupChangeErrorCallback error) { - executor.execute(()-> { + executor.execute(() -> { Recipient recipient = Recipient.resolved(recipientId); if (recipient.isPushV2Group()) { try { @@ -182,6 +187,7 @@ public final class MessageRequestRepository { RecipientTable recipientTable = SignalDatabase.recipients(); recipientTable.setProfileSharing(recipientId, true); + insertMessageRequestAccept(recipient, threadId); onMessageRequestAccepted.run(); } catch (GroupChangeException | IOException e) { Log.w(TAG, e); @@ -205,11 +211,25 @@ public final class MessageRequestRepository { ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forAccept(recipientId)); } + insertMessageRequestAccept(recipient, threadId); onMessageRequestAccepted.run(); } }); } + private void insertMessageRequestAccept(Recipient recipient, long threadId) { + try { + SignalDatabase.messages().insertMessageOutbox( + OutgoingMessage.messageRequestAcceptMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())), + threadId, + false, + null + ); + } catch (MmsException e) { + Log.w(TAG, "Unable to insert message request accept message", e); + } + } + @SuppressWarnings("unchecked") public @NonNull Single> deleteMessageRequest(@NonNull RecipientId recipientId, long threadId) { //noinspection CodeBlock2Expr @@ -295,6 +315,18 @@ public final class MessageRequestRepository { }); } + @SuppressWarnings("unchecked") + public @NonNull Completable reportSpamMessageRequest(@NonNull RecipientId recipientId, long threadId) { + //noinspection CodeBlock2Expr + return Completable.create(emitter -> { + reportSpamMessageRequest( + recipientId, + threadId, + emitter::onComplete + ); + }).subscribeOn(Schedulers.io()); + } + @SuppressWarnings("unchecked") public @NonNull Single> blockAndReportSpamMessageRequest(@NonNull RecipientId recipientId, long threadId) { //noinspection CodeBlock2Expr @@ -315,13 +347,22 @@ public final class MessageRequestRepository { { executor.execute(() -> { Recipient recipient = Recipient.resolved(recipientId); - try{ + try { RecipientUtil.block(context, recipient); + SignalDatabase.messages().insertMessageOutbox( + OutgoingMessage.reportSpamMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())), + threadId, + false, + null + ); } catch (GroupChangeException | IOException e) { Log.w(TAG, e); error.onError(GroupChangeFailureReason.fromException(e)); return; + } catch (MmsException e) { + Log.w(TAG, "Unable to insert report spam message", e); } + Recipient.live(recipientId).refresh(); ApplicationDependencies.getJobManager().add(new ReportSpamJob(threadId, System.currentTimeMillis())); @@ -334,6 +375,33 @@ public final class MessageRequestRepository { }); } + private void reportSpamMessageRequest(@NonNull RecipientId recipientId, + long threadId, + @NonNull Runnable onReported) + { + executor.execute(() -> { + try { + Recipient recipient = Recipient.resolved(recipientId); + SignalDatabase.messages().insertMessageOutbox( + OutgoingMessage.reportSpamMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())), + threadId, + false, + null + ); + } catch (MmsException e) { + Log.w(TAG, "Unable to insert report spam message", e); + } + + ApplicationDependencies.getJobManager().add(new ReportSpamJob(threadId, System.currentTimeMillis())); + + if (TextSecurePreferences.isMultiDevice(context)) { + ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forReportSpam(recipientId)); + } + + onReported.run(); + }); + } + @SuppressWarnings("unchecked") public @NonNull Single> unblockAndAccept(@NonNull RecipientId recipientId) { //noinspection CodeBlock2Expr @@ -361,9 +429,9 @@ public final class MessageRequestRepository { private GroupTable.MemberLevel getGroupMemberLevel(@NonNull RecipientId recipientId) { return SignalDatabase.groups() - .getGroup(recipientId) - .map(g -> g.memberLevel(Recipient.self())) - .orElse(GroupTable.MemberLevel.NOT_A_MEMBER); + .getGroup(recipientId) + .map(g -> g.memberLevel(Recipient.self())) + .orElse(GroupTable.MemberLevel.NOT_A_MEMBER); } diff --git a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestState.java b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestState.java deleted file mode 100644 index ab9b8ed1..00000000 --- a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestState.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.tm.archive.messagerequests; - -/** - * An enum representing the possible message request states a user can be in. - */ -public enum MessageRequestState { - /** No message request necessary */ - NONE, - - /** No message request necessary as the user was hidden after accepting*/ - NONE_HIDDEN, - - /** A user is blocked */ - BLOCKED_INDIVIDUAL, - - /** A group is blocked */ - BLOCKED_GROUP, - - /** An individual conversation that existed pre-message-requests but doesn't have profile sharing enabled */ - LEGACY_INDIVIDUAL, - - /** A V1 group conversation that is no longer allowed, because we've forced GV2 on. */ - DEPRECATED_GROUP_V1, - - /** An invite response is needed for a V2 group */ - GROUP_V2_INVITE, - - /** A message request is needed for a V2 group */ - GROUP_V2_ADD, - - /** A message request is needed for an individual */ - INDIVIDUAL, - - /** A message request is needed for an individual since they have been hidden */ - INDIVIDUAL_HIDDEN -} diff --git a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestState.kt b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestState.kt new file mode 100644 index 00000000..cb0be857 --- /dev/null +++ b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestState.kt @@ -0,0 +1,56 @@ +package org.tm.archive.messagerequests + +/** + * Data necessary to render message request view. + */ +data class MessageRequestState @JvmOverloads constructor(val state: State = State.NONE, val reportedAsSpam: Boolean = false) { + + companion object { + @JvmField + val NONE = MessageRequestState() + + @JvmField + val DEPRECATED_V1 = MessageRequestState() + } + + val isAccepted: Boolean + get() = state == State.NONE || state == State.NONE_HIDDEN + + val isBlocked: Boolean + get() = state == State.INDIVIDUAL_BLOCKED || state == State.BLOCKED_GROUP + + /** + * An enum representing the possible message request states a user can be in. + */ + enum class State { + /** No message request necessary */ + NONE, + + /** No message request necessary as the user was hidden after accepting */ + NONE_HIDDEN, + + /** A group is blocked */ + BLOCKED_GROUP, + + /** An individual conversation that existed pre-message-requests but doesn't have profile sharing enabled */ + LEGACY_INDIVIDUAL, + + /** A V1 group conversation that is no longer allowed, because we've forced GV2 on. */ + DEPRECATED_GROUP_V1, + + /** An invite response is needed for a V2 group */ + GROUP_V2_INVITE, + + /** A message request is needed for a V2 group */ + GROUP_V2_ADD, + + /** A message request is needed for an individual */ + INDIVIDUAL, + + /** A user is blocked */ + INDIVIDUAL_BLOCKED, + + /** A message request is needed for an individual since they have been hidden */ + INDIVIDUAL_HIDDEN + } +} diff --git a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestViewModel.java b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestViewModel.java deleted file mode 100644 index 9028ff73..00000000 --- a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestViewModel.java +++ /dev/null @@ -1,275 +0,0 @@ -package org.tm.archive.messagerequests; - -import android.content.Context; - -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.WorkerThread; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; -import androidx.lifecycle.ViewModelProvider; - -import org.signal.core.util.concurrent.SignalExecutors; -import org.tm.archive.groups.ui.GroupChangeFailureReason; -import org.tm.archive.profiles.spoofing.ReviewUtil; -import org.tm.archive.recipients.LiveRecipient; -import org.tm.archive.recipients.Recipient; -import org.tm.archive.recipients.RecipientForeverObserver; -import org.tm.archive.recipients.RecipientId; -import org.tm.archive.util.SingleLiveEvent; -import org.tm.archive.util.livedata.LiveDataUtil; -import org.tm.archive.util.livedata.Store; - -import java.util.Collections; -import java.util.List; - -public class MessageRequestViewModel extends ViewModel { - - private final SingleLiveEvent status = new SingleLiveEvent<>(); - private final SingleLiveEvent failures = new SingleLiveEvent<>(); - private final MutableLiveData recipient = new MutableLiveData<>(); - private final MutableLiveData> groups = new MutableLiveData<>(Collections.emptyList()); - private final MutableLiveData groupInfo = new MutableLiveData<>(GroupInfo.ZERO); - private final Store recipientInfoStore = new Store<>(new RecipientInfo(null, null, null, null)); - - private final LiveData messageData; - private final LiveData requestReviewDisplayState; - private final MessageRequestRepository repository; - - private LiveRecipient liveRecipient; - private long threadId; - - private final RecipientForeverObserver recipientObserver = recipient -> { - loadGroupInfo(); - this.recipient.setValue(recipient); - }; - - private MessageRequestViewModel(MessageRequestRepository repository) { - this.repository = repository; - this.messageData = LiveDataUtil.mapAsync(recipient, this::createMessageDataForRecipient); - this.requestReviewDisplayState = LiveDataUtil.mapAsync(messageData, MessageRequestViewModel::transformHolderToReviewDisplayState); - - recipientInfoStore.update(this.recipient, (recipient, state) -> new RecipientInfo(recipient, state.groupInfo, state.sharedGroups, state.messageRequestState)); - recipientInfoStore.update(this.groupInfo, (groupInfo, state) -> new RecipientInfo(state.recipient, groupInfo, state.sharedGroups, state.messageRequestState)); - recipientInfoStore.update(this.groups, (sharedGroups, state) -> new RecipientInfo(state.recipient, state.groupInfo, sharedGroups, state.messageRequestState)); - recipientInfoStore.update(this.messageData, (messageData, state) -> new RecipientInfo(state.recipient, state.groupInfo, state.sharedGroups, messageData.messageState)); - } - - public void setConversationInfo(@NonNull RecipientId recipientId, long threadId) { - if (liveRecipient != null) { - liveRecipient.removeForeverObserver(recipientObserver); - } - - liveRecipient = Recipient.live(recipientId); - this.threadId = threadId; - - loadRecipient(); - loadGroups(); - loadGroupInfo(); - } - - @Override - protected void onCleared() { - if (liveRecipient != null) { - liveRecipient.removeForeverObserver(recipientObserver); - } - } - - public LiveData getRequestReviewDisplayState() { - return requestReviewDisplayState; - } - - public LiveData getRecipient() { - return recipient; - } - - public LiveData getMessageData() { - return messageData; - } - - public LiveData getRecipientInfo() { - return recipientInfoStore.getStateLiveData(); - } - - public LiveData getMessageRequestStatus() { - return status; - } - - public LiveData getFailures() { - return failures; - } - - public boolean shouldShowMessageRequest() { - MessageData data = messageData.getValue(); - return data != null && data.getMessageState() != MessageRequestState.NONE; - } - - @MainThread - public void onAccept() { - status.setValue(Status.ACCEPTING); - repository.acceptMessageRequest(liveRecipient.getId(), - threadId, - () -> status.postValue(Status.ACCEPTED), - this::onGroupChangeError); - } - - @MainThread - public void onDelete() { - status.setValue(Status.DELETING); - repository.deleteMessageRequest(liveRecipient.getId(), - threadId, - () -> status.postValue(Status.DELETED), - this::onGroupChangeError); - } - - @MainThread - public void onBlock() { - status.setValue(Status.BLOCKING); - repository.blockMessageRequest(liveRecipient.getId(), - () -> status.postValue(Status.BLOCKED), - this::onGroupChangeError); - } - - @MainThread - public void onUnblock() { - repository.unblockAndAccept(liveRecipient.getId(), - () -> status.postValue(Status.ACCEPTED)); - } - - @MainThread - public void onBlockAndReportSpam() { - repository.blockAndReportSpamMessageRequest(liveRecipient.getId(), - threadId, - () -> status.postValue(Status.BLOCKED_AND_REPORTED), - this::onGroupChangeError); - } - - private void onGroupChangeError(@NonNull GroupChangeFailureReason error) { - status.postValue(Status.IDLE); - failures.postValue(error); - } - - private void loadRecipient() { - liveRecipient.observeForever(recipientObserver); - SignalExecutors.BOUNDED.execute(() -> { - recipient.postValue(liveRecipient.get()); - }); - } - - private void loadGroups() { - repository.getGroups(liveRecipient.getId(), this.groups::postValue); - } - - private void loadGroupInfo() { - repository.getGroupInfo(liveRecipient.getId(), groupInfo::postValue); - } - - private static RequestReviewDisplayState transformHolderToReviewDisplayState(@NonNull MessageData holder) { - if (holder.getMessageState() == MessageRequestState.INDIVIDUAL) { - return ReviewUtil.isRecipientReviewSuggested(holder.getRecipient().getId()) ? RequestReviewDisplayState.SHOWN - : RequestReviewDisplayState.HIDDEN; - } else { - return RequestReviewDisplayState.NONE; - } - } - - @WorkerThread - private @NonNull MessageData createMessageDataForRecipient(@NonNull Recipient recipient) { - MessageRequestState state = repository.getMessageRequestState(recipient, threadId); - return new MessageData(recipient, state); - } - - public static class RecipientInfo { - @Nullable private final Recipient recipient; - @NonNull private final GroupInfo groupInfo; - @NonNull private final List sharedGroups; - @Nullable private final MessageRequestState messageRequestState; - - public RecipientInfo(@Nullable Recipient recipient, @Nullable GroupInfo groupInfo, @Nullable List sharedGroups, @Nullable MessageRequestState messageRequestState) { - this.recipient = recipient; - this.groupInfo = groupInfo == null ? GroupInfo.ZERO : groupInfo; - this.sharedGroups = sharedGroups == null ? Collections.emptyList() : sharedGroups; - this.messageRequestState = messageRequestState; - } - - @Nullable - public Recipient getRecipient() { - return recipient; - } - - public int getGroupMemberCount() { - return groupInfo.getFullMemberCount(); - } - - public int getGroupPendingMemberCount() { - return groupInfo.getPendingMemberCount(); - } - - public @NonNull String getGroupDescription() { - return groupInfo.getDescription(); - } - - @NonNull - public List getSharedGroups() { - return sharedGroups; - } - - @Nullable - public MessageRequestState getMessageRequestState() { - return messageRequestState; - } - } - - public enum Status { - IDLE, - BLOCKING, - BLOCKED, - BLOCKED_AND_REPORTED, - DELETING, - DELETED, - ACCEPTING, - ACCEPTED - } - - public enum RequestReviewDisplayState { - HIDDEN, - SHOWN, - NONE - } - - public static final class MessageData { - private final Recipient recipient; - private final MessageRequestState messageState; - - public MessageData(@NonNull Recipient recipient, @NonNull MessageRequestState messageState) { - this.recipient = recipient; - this.messageState = messageState; - } - - public @NonNull Recipient getRecipient() { - return recipient; - } - - public @NonNull MessageRequestState getMessageState() { - return messageState; - } - } - - public static class Factory implements ViewModelProvider.Factory { - - private final Context context; - - public Factory(Context context) { - this.context = context; - } - - @Override - public @NonNull T create(@NonNull Class modelClass) { - //noinspection unchecked - return (T) new MessageRequestViewModel(new MessageRequestRepository(context.getApplicationContext())); - } - } - -} diff --git a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestsBottomView.java b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestsBottomView.java deleted file mode 100644 index 24b24a08..00000000 --- a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestsBottomView.java +++ /dev/null @@ -1,192 +0,0 @@ -package org.tm.archive.messagerequests; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.util.AttributeSet; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.constraintlayout.widget.Group; -import androidx.core.text.HtmlCompat; - -import com.google.android.material.button.MaterialButton; - -import org.tm.archive.R; -import org.tm.archive.recipients.Recipient; -import org.tm.archive.util.CommunicationActions; -import org.tm.archive.util.Debouncer; -import org.tm.archive.util.HtmlUtil; -import org.tm.archive.util.views.LearnMoreTextView; - -import java.util.stream.Stream; - -public class MessageRequestsBottomView extends ConstraintLayout { - - private final Debouncer showProgressDebouncer = new Debouncer(250); - - private LearnMoreTextView question; - private MaterialButton accept; - private MaterialButton block; - private MaterialButton delete; - private MaterialButton bigDelete; - private MaterialButton bigUnblock; - private View busyIndicator; - - private Group normalButtons; - private Group blockedButtons; - private @Nullable Group activeGroup; - - public MessageRequestsBottomView(Context context) { - super(context); - onFinishInflate(); - } - - public MessageRequestsBottomView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public MessageRequestsBottomView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - inflate(getContext(), R.layout.message_request_bottom_bar, this); - - question = findViewById(R.id.message_request_question); - accept = findViewById(R.id.message_request_accept); - block = findViewById(R.id.message_request_block); - delete = findViewById(R.id.message_request_delete); - bigDelete = findViewById(R.id.message_request_big_delete); - bigUnblock = findViewById(R.id.message_request_big_unblock); - normalButtons = findViewById(R.id.message_request_normal_buttons); - blockedButtons = findViewById(R.id.message_request_blocked_buttons); - busyIndicator = findViewById(R.id.message_request_busy_indicator); - - setWallpaperEnabled(false); - } - - public void setMessageData(@NonNull MessageRequestViewModel.MessageData messageData) { - Recipient recipient = messageData.getRecipient(); - - question.setLearnMoreVisible(false); - question.setOnLinkClickListener(null); - - switch (messageData.getMessageState()) { - case BLOCKED_INDIVIDUAL: - int message = recipient.isReleaseNotes() ? R.string.MessageRequestBottomView_get_updates_and_news_from_s_you_wont_receive_any_updates_until_you_unblock_them - : recipient.isRegistered() ? R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_wont_receive_any_messages_until_you_unblock_them - : R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_wont_receive_any_messages_until_you_unblock_them_SMS; - - question.setText(HtmlCompat.fromHtml(getContext().getString(message, - HtmlUtil.bold(recipient.getShortDisplayName(getContext()))), 0)); - setActiveInactiveGroups(blockedButtons, normalButtons); - break; - case BLOCKED_GROUP: - question.setText(R.string.MessageRequestBottomView_unblock_this_group_and_share_your_name_and_photo_with_its_members); - setActiveInactiveGroups(blockedButtons, normalButtons); - break; - case LEGACY_INDIVIDUAL: - question.setText(getContext().getString(R.string.MessageRequestBottomView_continue_your_conversation_with_s_and_share_your_name_and_photo, recipient.getShortDisplayName(getContext()))); - question.setLearnMoreVisible(true); - question.setOnLinkClickListener(v -> CommunicationActions.openBrowserLink(getContext(), getContext().getString(R.string.MessageRequestBottomView_legacy_learn_more_url))); - setActiveInactiveGroups(normalButtons, blockedButtons); - accept.setText(R.string.MessageRequestBottomView_continue); - break; - case DEPRECATED_GROUP_V1: - question.setText(R.string.MessageRequestBottomView_upgrade_this_group_to_activate_new_features); - setActiveInactiveGroups(null, normalButtons, blockedButtons); - break; - case GROUP_V2_INVITE: - question.setText(R.string.MessageRequestBottomView_do_you_want_to_join_this_group_you_wont_see_their_messages); - setActiveInactiveGroups(normalButtons, blockedButtons); - accept.setText(R.string.MessageRequestBottomView_accept); - break; - case GROUP_V2_ADD: - question.setText(R.string.MessageRequestBottomView_join_this_group_they_wont_know_youve_seen_their_messages_until_you_accept); - setActiveInactiveGroups(normalButtons, blockedButtons); - accept.setText(R.string.MessageRequestBottomView_accept); - break; - case INDIVIDUAL: - question.setText(HtmlCompat.fromHtml(getContext().getString(R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_they_wont_know_youve_seen_their_messages_until_you_accept, - HtmlUtil.bold(recipient.getShortDisplayName(getContext()))), 0)); - setActiveInactiveGroups(normalButtons, blockedButtons); - accept.setText(R.string.MessageRequestBottomView_accept); - break; - case INDIVIDUAL_HIDDEN: - question.setText(HtmlCompat.fromHtml(getContext().getString(R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_you_removed_them_before, - HtmlUtil.bold(recipient.getShortDisplayName(getContext()))), 0)); - setActiveInactiveGroups(normalButtons, blockedButtons); - accept.setText(R.string.MessageRequestBottomView_accept); - break; - } - } - - private void setActiveInactiveGroups(@Nullable Group activeGroup, @NonNull Group... inActiveGroups) { - int initialVisibility = this.activeGroup != null ? this.activeGroup.getVisibility() : VISIBLE; - - this.activeGroup = activeGroup; - - for (Group inactive : inActiveGroups) { - inactive.setVisibility(GONE); - } - - if (activeGroup != null) { - activeGroup.setVisibility(initialVisibility); - } - } - - public void showBusy() { - showProgressDebouncer.publish(() -> busyIndicator.setVisibility(VISIBLE)); - if (activeGroup != null) { - activeGroup.setVisibility(INVISIBLE); - } - } - - public void hideBusy() { - showProgressDebouncer.clear(); - busyIndicator.setVisibility(GONE); - if (activeGroup != null) { - activeGroup.setVisibility(VISIBLE); - } - } - - public void setWallpaperEnabled(boolean isEnabled) { - MessageRequestBarColorTheme theme = MessageRequestBarColorTheme.resolveTheme(isEnabled); - - Stream.of(delete, bigDelete, block, bigUnblock, accept).forEach(button -> { - button.setBackgroundTintList(ColorStateList.valueOf(theme.getButtonBackgroundColor(getContext()))); - }); - - Stream.of(delete, bigDelete, block).forEach(button -> { - button.setTextColor(theme.getButtonForegroundDenyColor(getContext())); - }); - - Stream.of(accept, bigUnblock).forEach(button -> { - button.setTextColor(theme.getButtonForegroundAcceptColor(getContext())); - }); - - setBackgroundColor(theme.getContainerButtonBackgroundColor(getContext())); - } - - public void setAcceptOnClickListener(OnClickListener acceptOnClickListener) { - accept.setOnClickListener(acceptOnClickListener); - } - - public void setDeleteOnClickListener(OnClickListener deleteOnClickListener) { - delete.setOnClickListener(deleteOnClickListener); - bigDelete.setOnClickListener(deleteOnClickListener); - } - - public void setBlockOnClickListener(OnClickListener blockOnClickListener) { - block.setOnClickListener(blockOnClickListener); - } - - public void setUnblockOnClickListener(OnClickListener unblockOnClickListener) { - bigUnblock.setOnClickListener(unblockOnClickListener); - } -} diff --git a/app/src/main/java/org/tm/archive/messagerequests/MessageRequestsBottomView.kt b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestsBottomView.kt new file mode 100644 index 00000000..57e39f7b --- /dev/null +++ b/app/src/main/java/org/tm/archive/messagerequests/MessageRequestsBottomView.kt @@ -0,0 +1,161 @@ +package org.tm.archive.messagerequests + +import android.content.Context +import android.content.res.ColorStateList +import android.util.AttributeSet +import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.text.HtmlCompat +import com.google.android.material.button.MaterialButton +import org.tm.archive.R +import org.tm.archive.messagerequests.MessageRequestBarColorTheme.Companion.resolveTheme +import org.tm.archive.recipients.Recipient +import org.tm.archive.util.CommunicationActions +import org.tm.archive.util.Debouncer +import org.tm.archive.util.HtmlUtil +import org.tm.archive.util.views.LearnMoreTextView +import org.tm.archive.util.visible + +/** + * View shown in a conversation during a message request state or related state (e.g., blocked). + */ +class MessageRequestsBottomView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) { + private val showProgressDebouncer = Debouncer(250) + + private val question: LearnMoreTextView + private val accept: MaterialButton + private val block: MaterialButton + private val unblock: MaterialButton + private val delete: MaterialButton + private val report: MaterialButton + private val busyIndicator: View + private val buttonBar: View + + init { + inflate(context, R.layout.message_request_bottom_bar, this) + + question = findViewById(R.id.message_request_question) + accept = findViewById(R.id.message_request_accept) + block = findViewById(R.id.message_request_block) + unblock = findViewById(R.id.message_request_unblock) + delete = findViewById(R.id.message_request_delete) + report = findViewById(R.id.message_request_report) + busyIndicator = findViewById(R.id.message_request_busy_indicator) + buttonBar = findViewById(R.id.message_request_button_layout) + + setWallpaperEnabled(false) + } + + fun setMessageRequestData(recipient: Recipient, messageRequestState: MessageRequestState) { + question.setLearnMoreVisible(false) + question.setOnLinkClickListener(null) + + updateButtonVisibility(messageRequestState) + + when (messageRequestState.state) { + MessageRequestState.State.INDIVIDUAL_BLOCKED -> { + val message = if (recipient.isReleaseNotes) R.string.MessageRequestBottomView_get_updates_and_news_from_s_you_wont_receive_any_updates_until_you_unblock_them else if (recipient.isRegistered) R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_wont_receive_any_messages_until_you_unblock_them else R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_wont_receive_any_messages_until_you_unblock_them_SMS + question.text = HtmlCompat.fromHtml( + context.getString( + message, + HtmlUtil.bold(recipient.getShortDisplayName(context)) + ), + 0 + ) + } + + MessageRequestState.State.BLOCKED_GROUP -> question.setText(R.string.MessageRequestBottomView_unblock_this_group_and_share_your_name_and_photo_with_its_members) + + MessageRequestState.State.LEGACY_INDIVIDUAL -> { + question.text = context.getString(R.string.MessageRequestBottomView_continue_your_conversation_with_s_and_share_your_name_and_photo, recipient.getShortDisplayName(context)) + question.setLearnMoreVisible(true) + question.setOnLinkClickListener { CommunicationActions.openBrowserLink(context, context.getString(R.string.MessageRequestBottomView_legacy_learn_more_url)) } + accept.setText(R.string.MessageRequestBottomView_continue) + } + + MessageRequestState.State.DEPRECATED_GROUP_V1 -> question.setText(R.string.MessageRequestBottomView_upgrade_this_group_to_activate_new_features) + MessageRequestState.State.GROUP_V2_INVITE -> { + question.setText(R.string.MessageRequestBottomView_do_you_want_to_join_this_group_you_wont_see_their_messages) + accept.setText(R.string.MessageRequestBottomView_accept) + } + + MessageRequestState.State.GROUP_V2_ADD -> { + question.setText(R.string.MessageRequestBottomView_join_this_group_they_wont_know_youve_seen_their_messages_until_you_accept) + accept.setText(R.string.MessageRequestBottomView_accept) + } + + MessageRequestState.State.INDIVIDUAL -> { + question.text = HtmlCompat.fromHtml( + context.getString( + R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_they_wont_know_youve_seen_their_messages_until_you_accept, + HtmlUtil.bold(recipient.getShortDisplayName(context)) + ), + 0 + ) + accept.setText(R.string.MessageRequestBottomView_accept) + } + + MessageRequestState.State.INDIVIDUAL_HIDDEN -> { + question.text = HtmlCompat.fromHtml( + context.getString( + R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_you_removed_them_before, + HtmlUtil.bold(recipient.getShortDisplayName(context)) + ), + 0 + ) + accept.setText(R.string.MessageRequestBottomView_accept) + } + + MessageRequestState.State.NONE -> Unit + MessageRequestState.State.NONE_HIDDEN -> Unit + } + } + + private fun updateButtonVisibility(messageState: MessageRequestState) { + accept.visible = !messageState.isBlocked + block.visible = !messageState.isBlocked + unblock.visible = messageState.isBlocked + delete.visible = messageState.reportedAsSpam || messageState.isBlocked + report.visible = !messageState.reportedAsSpam + } + + fun showBusy() { + showProgressDebouncer.publish { busyIndicator.visibility = VISIBLE } + buttonBar.visibility = INVISIBLE + } + + fun hideBusy() { + showProgressDebouncer.clear() + busyIndicator.visibility = GONE + buttonBar.visibility = VISIBLE + } + + fun setWallpaperEnabled(isEnabled: Boolean) { + val theme = resolveTheme(isEnabled) + listOf(delete, block, accept, unblock, report).forEach { it.backgroundTintList = ColorStateList.valueOf(theme.getButtonBackgroundColor(context)) } + listOf(delete, block, report).forEach { it.setTextColor(theme.getButtonForegroundDenyColor(context)) } + listOf(accept, unblock).forEach { it.setTextColor(theme.getButtonForegroundAcceptColor(context)) } + + setBackgroundColor(theme.getContainerButtonBackgroundColor(context)) + } + + fun setAcceptOnClickListener(acceptOnClickListener: OnClickListener?) { + accept.setOnClickListener(acceptOnClickListener) + } + + fun setDeleteOnClickListener(deleteOnClickListener: OnClickListener?) { + delete.setOnClickListener(deleteOnClickListener) + } + + fun setBlockOnClickListener(blockOnClickListener: OnClickListener?) { + block.setOnClickListener(blockOnClickListener) + } + + fun setUnblockOnClickListener(unblockOnClickListener: OnClickListener?) { + unblock.setOnClickListener(unblockOnClickListener) + } + + fun setReportOnClickListener(reportOnClickListener: OnClickListener?) { + report.setOnClickListener(reportOnClickListener) + } +} diff --git a/app/src/main/java/org/tm/archive/messages/DataMessageProcessor.kt b/app/src/main/java/org/tm/archive/messages/DataMessageProcessor.kt index 466e14fd..549fb912 100644 --- a/app/src/main/java/org/tm/archive/messages/DataMessageProcessor.kt +++ b/app/src/main/java/org/tm/archive/messages/DataMessageProcessor.kt @@ -46,6 +46,7 @@ import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.groups.BadGroupIdException import org.tm.archive.groups.GroupId import org.tm.archive.jobs.AttachmentDownloadJob +import org.tm.archive.jobs.DirectoryRefreshJob import org.tm.archive.jobs.GroupCallPeekJob import org.tm.archive.jobs.GroupV2UpdateSelfProfileKeyJob import org.tm.archive.jobs.PaymentLedgerUpdateJob @@ -57,6 +58,7 @@ import org.tm.archive.jobs.RefreshAttributesJob import org.tm.archive.jobs.RetrieveProfileJob import org.tm.archive.jobs.SendDeliveryReceiptJob import org.tm.archive.jobs.TrimThreadJob +import org.tm.archive.keyvalue.SignalStore import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.linkpreview.LinkPreviewUtil import org.tm.archive.messages.MessageContentProcessor.Companion.debug @@ -87,6 +89,7 @@ import org.tm.archive.recipients.RecipientUtil import org.tm.archive.stickers.StickerLocator import org.tm.archive.storage.StorageSyncHelper import org.tm.archive.util.EarlyMessageCacheEntry +import org.tm.archive.util.FeatureFlags import org.tm.archive.util.LinkUtil import org.tm.archive.util.MediaUtil import org.tm.archive.util.MessageConstraintsUtil @@ -131,31 +134,45 @@ object DataMessageProcessor { var groupProcessResult: MessageContentProcessor.Gv2PreProcessResult? = null if (groupId != null) { - groupProcessResult = MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient, groupSecretParams) + groupProcessResult = MessageContentProcessor.handleGv2PreProcessing( + context = context, + timestamp = envelope.timestamp!!, + content = content, + metadata = metadata, + groupId = groupId, + groupV2 = message.groupV2!!, + senderRecipient = senderRecipient, + groupSecretParams = groupSecretParams, + serverGuid = envelope.serverGuid + ) + if (groupProcessResult == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { return } localMetrics?.onGv2Processed() } + var insertResult: InsertResult? = null var messageId: MessageId? = null when { message.isInvalid -> handleInvalidMessage(context, senderRecipient.id, groupId, envelope.timestamp!!) - message.isEndSession -> messageId = handleEndSessionMessage(context, senderRecipient.id, envelope, metadata) - message.isExpirationUpdate -> messageId = handleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient.id, groupId, message.expireTimerDuration, receivedTime, false) - message.isStoryReaction -> messageId = handleStoryReaction(context, envelope, metadata, message, senderRecipient.id, groupId) + message.isEndSession -> insertResult = handleEndSessionMessage(context, senderRecipient.id, envelope, metadata) + message.isExpirationUpdate -> insertResult = handleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient.id, groupId, message.expireTimerDuration, receivedTime, false) + message.isStoryReaction -> insertResult = handleStoryReaction(context, envelope, metadata, message, senderRecipient.id, groupId) message.reaction != null -> messageId = handleReaction(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry) message.hasRemoteDelete -> messageId = handleRemoteDelete(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry) - message.isPaymentActivationRequest -> messageId = handlePaymentActivation(envelope, metadata, message, senderRecipient.id, receivedTime, isActivatePaymentsRequest = true, isPaymentsActivated = false) - message.isPaymentActivated -> messageId = handlePaymentActivation(envelope, metadata, message, senderRecipient.id, receivedTime, isActivatePaymentsRequest = false, isPaymentsActivated = true) - message.payment != null -> messageId = handlePayment(context, envelope, metadata, message, senderRecipient.id, receivedTime) - message.storyContext != null -> messageId = handleStoryReply(context, envelope, metadata, message, senderRecipient, groupId, receivedTime) - message.giftBadge != null -> messageId = handleGiftMessage(context, envelope, metadata, message, senderRecipient, threadRecipient.id, receivedTime) - message.isMediaMessage -> messageId = handleMediaMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) - message.body != null -> messageId = handleTextMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) + message.isPaymentActivationRequest -> insertResult = handlePaymentActivation(envelope, metadata, message, senderRecipient.id, receivedTime, isActivatePaymentsRequest = true, isPaymentsActivated = false) + message.isPaymentActivated -> insertResult = handlePaymentActivation(envelope, metadata, message, senderRecipient.id, receivedTime, isActivatePaymentsRequest = false, isPaymentsActivated = true) + message.payment != null -> insertResult = handlePayment(context, envelope, metadata, message, senderRecipient.id, receivedTime) + message.storyContext != null -> insertResult = handleStoryReply(context, envelope, metadata, message, senderRecipient, groupId, receivedTime) + message.giftBadge != null -> insertResult = handleGiftMessage(context, envelope, metadata, message, senderRecipient, threadRecipient.id, receivedTime) + message.isMediaMessage -> insertResult = handleMediaMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) + message.body != null -> insertResult = handleTextMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) message.groupCallUpdate != null -> handleGroupCallUpdateMessage(envelope, message, senderRecipient.id, groupId) } + messageId = messageId ?: insertResult?.messageId?.let { MessageId(it) } + if (groupId != null) { val unknownGroup = when (groupProcessResult) { MessageContentProcessor.Gv2PreProcessResult.GROUP_UP_TO_DATE -> threadRecipient.isUnknownGroup @@ -200,6 +217,18 @@ object DataMessageProcessor { } } } + + if (insertResult != null && insertResult.threadWasNewlyCreated && !threadRecipient.isGroup && !threadRecipient.isSelf && !senderRecipient.isSystemContact) { + val timeSinceLastSync = System.currentTimeMillis() - SignalStore.misc().lastCdsForegroundSyncTime + if (timeSinceLastSync > FeatureFlags.cdsForegroundSyncInterval() || timeSinceLastSync < 0) { + log(envelope.timestamp!!, "New 1:1 chat. Scheduling a CDS sync to see if they match someone in our contacts.") + ApplicationDependencies.getJobManager().add(DirectoryRefreshJob(false)) + SignalStore.misc().lastCdsForegroundSyncTime = System.currentTimeMillis() + } else { + warn(envelope.timestamp!!, "New 1:1 chat, but performed a CDS sync $timeSinceLastSync ms ago, which is less than our threshold. Skipping CDS sync.") + } + } + localMetrics?.onPostProcessComplete() localMetrics?.complete(groupId != null) } @@ -258,7 +287,7 @@ object DataMessageProcessor { senderRecipientId: RecipientId, envelope: Envelope, metadata: EnvelopeMetadata - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "End session message.") val incomingMessage = IncomingMessage( @@ -277,7 +306,7 @@ object DataMessageProcessor { ApplicationDependencies.getProtocolStore().aci().deleteAllSessions(metadata.sourceServiceId.toString()) SecurityEvent.broadcastSecurityUpdateEvent(context) ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.threadId)) - MessageId(insertResult.messageId) + insertResult } else { null } @@ -297,7 +326,7 @@ object DataMessageProcessor { expiresIn: Duration, receivedTime: Long, sideEffect: Boolean - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Expiration update. Side effect: $sideEffect") if (groupId != null) { @@ -326,7 +355,7 @@ object DataMessageProcessor { SignalDatabase.recipients.setExpireMessages(threadRecipientId, expiresIn.inWholeSeconds.toInt()) if (insertResult != null) { - return MessageId(insertResult.messageId) + return insertResult } } catch (e: MmsException) { throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId) @@ -362,7 +391,7 @@ object DataMessageProcessor { message: DataMessage, senderRecipientId: RecipientId, groupId: GroupId.V2? - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Story reaction.") val storyContext = message.storyContext!! @@ -411,7 +440,7 @@ object DataMessageProcessor { } val mediaMessage = IncomingMessage( - type = MessageType.NORMAL, + type = MessageType.STORY_REACTION, from = senderRecipientId, sentTimeMillis = envelope.timestamp!!, serverTimeMillis = envelope.serverTimestamp!!, @@ -438,7 +467,7 @@ object DataMessageProcessor { } if (parentStoryId.isDirectReply()) { - MessageId(insertResult.messageId) + insertResult } else { null } @@ -573,7 +602,7 @@ object DataMessageProcessor { receivedTime: Long, isActivatePaymentsRequest: Boolean, isPaymentsActivated: Boolean - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated") Preconditions.checkArgument(isActivatePaymentsRequest || isPaymentsActivated) @@ -589,11 +618,7 @@ object DataMessageProcessor { type = if (isActivatePaymentsRequest) MessageType.ACTIVATE_PAYMENTS_REQUEST else MessageType.PAYMENTS_ACTIVATED ) - val insertResult: InsertResult? = SignalDatabase.messages.insertMessageInbox(mediaMessage, -1).orNull() - - if (insertResult != null) { - return MessageId(insertResult.messageId) - } + return SignalDatabase.messages.insertMessageInbox(mediaMessage, -1).orNull() } catch (e: MmsException) { throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId) } @@ -608,7 +633,7 @@ object DataMessageProcessor { message: DataMessage, senderRecipientId: RecipientId, receivedTime: Long - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Payment message.") if (message.payment?.notification?.mobileCoin?.receipt == null) { @@ -646,9 +671,8 @@ object DataMessageProcessor { val insertResult: InsertResult? = SignalDatabase.messages.insertMessageInbox(mediaMessage, -1).orNull() if (insertResult != null) { - val messageId = MessageId(insertResult.messageId) ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.threadId)) - return messageId + return insertResult } } catch (e: PublicKeyConflictException) { warn(envelope.timestamp!!, "Ignoring payment with public key already in database") @@ -677,7 +701,7 @@ object DataMessageProcessor { senderRecipient: Recipient, groupId: GroupId.V2?, receivedTime: Long - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Story reply.") val storyContext: DataMessage.StoryContext = message.storyContext!! @@ -773,7 +797,7 @@ object DataMessageProcessor { } if (parentStoryId.isDirectReply()) { - MessageId.fromNullable(insertResult.messageId) + insertResult } else { null } @@ -797,7 +821,7 @@ object DataMessageProcessor { senderRecipient: Recipient, threadRecipientId: RecipientId, receivedTime: Long - ): MessageId? { + ): InsertResult? { log(message.timestamp!!, "Gift message.") val giftBadge: DataMessage.GiftBadge = message.giftBadge!! @@ -833,7 +857,7 @@ object DataMessageProcessor { return if (insertResult != null) { ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.threadId)) TrimThreadJob.enqueueAsync(insertResult.threadId) - MessageId(insertResult.messageId) + insertResult } else { null } @@ -850,7 +874,7 @@ object DataMessageProcessor { groupId: GroupId.V2?, receivedTime: Long, localMetrics: SignalLocalMetrics.MessageReceive? - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Media message.") notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId) @@ -925,7 +949,7 @@ object DataMessageProcessor { } } - MessageId(insertResult.messageId) + insertResult } else { null } @@ -942,7 +966,7 @@ object DataMessageProcessor { groupId: GroupId.V2?, receivedTime: Long, localMetrics: SignalLocalMetrics.MessageReceive? - ): MessageId? { + ): InsertResult? { log(envelope.timestamp!!, "Text message.") val body = message.body ?: "" @@ -969,7 +993,7 @@ object DataMessageProcessor { return if (insertResult != null) { ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.threadId)) - MessageId(insertResult.messageId) + insertResult } else { null } @@ -1054,8 +1078,6 @@ object DataMessageProcessor { if (quotedMessage != null && !quotedMessage.isRemoteDelete) { log(timestamp, "Found matching message record...") - - val attachments: MutableList = mutableListOf() val mentions: MutableList = mutableListOf() diff --git a/app/src/main/java/org/tm/archive/messages/GroupSendUtil.java b/app/src/main/java/org/tm/archive/messages/GroupSendUtil.java index 072f0bcd..18bafb25 100644 --- a/app/src/main/java/org/tm/archive/messages/GroupSendUtil.java +++ b/app/src/main/java/org/tm/archive/messages/GroupSendUtil.java @@ -812,6 +812,9 @@ public final class GroupSendUtil { this.messageId = messageId; } + @Override + public void onMessageEncrypted() {} + @Override public void onMessageSent() { SignalLocalMetrics.GroupMessageSend.onLegacyMessageSent(messageId); diff --git a/app/src/main/java/org/tm/archive/messages/IncomingMessageObserver.kt b/app/src/main/java/org/tm/archive/messages/IncomingMessageObserver.kt index c962f2d0..97731593 100644 --- a/app/src/main/java/org/tm/archive/messages/IncomingMessageObserver.kt +++ b/app/src/main/java/org/tm/archive/messages/IncomingMessageObserver.kt @@ -30,8 +30,8 @@ import org.tm.archive.notifications.NotificationChannels import org.tm.archive.recipients.RecipientId import org.tm.archive.util.AppForegroundObserver import org.tm.archive.util.SignalLocalMetrics +import org.tm.archive.util.asChain import org.whispersystems.signalservice.api.push.ServiceId -import org.whispersystems.signalservice.api.util.UuidUtil import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException import org.whispersystems.signalservice.internal.push.Envelope @@ -295,7 +295,7 @@ class IncomingMessageObserver(private val context: Application) { is MessageDecryptor.Result.Success -> { val job = PushProcessMessageJob.processOrDefer(messageContentProcessor, result, localReceiveMetric) if (job != null) { - return result.followUpOperations + FollowUpOperation { job } + return result.followUpOperations + FollowUpOperation { job.asChain() } } } is MessageDecryptor.Result.Error -> { @@ -304,7 +304,7 @@ class IncomingMessageObserver(private val context: Application) { result.toMessageState(), result.errorMetadata.toExceptionMetadata(), result.envelope.timestamp!! - ) + ).asChain() } } is MessageDecryptor.Result.Ignore -> { @@ -319,12 +319,13 @@ class IncomingMessageObserver(private val context: Application) { } private fun processReceipt(envelope: Envelope) { - if (!UuidUtil.isUuid(envelope.sourceServiceId)) { - Log.w(TAG, "Invalid envelope source UUID!") + val serviceId = ServiceId.parseOrNull(envelope.sourceServiceId) + if (serviceId == null) { + Log.w(TAG, "Invalid envelope sourceServiceId!") return } - val senderId = RecipientId.from(ServiceId.parseOrThrow(envelope.sourceServiceId!!)) + val senderId = RecipientId.from(serviceId) Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDevice}, Timestamp: ${envelope.timestamp}") SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.timestamp!!, senderId, System.currentTimeMillis()) @@ -404,7 +405,7 @@ class IncomingMessageObserver(private val context: Application) { if (followUpOperations != null) { Log.d(TAG, "Running ${followUpOperations.size} follow-up operations...") val jobs = followUpOperations.mapNotNull { it.run() } - ApplicationDependencies.getJobManager().addAll(jobs) + ApplicationDependencies.getJobManager().addAllChains(jobs) } signalWebSocket.sendAck(response) diff --git a/app/src/main/java/org/tm/archive/messages/MessageContentProcessor.kt b/app/src/main/java/org/tm/archive/messages/MessageContentProcessor.kt index 1d2a2497..75216753 100644 --- a/app/src/main/java/org/tm/archive/messages/MessageContentProcessor.kt +++ b/app/src/main/java/org/tm/archive/messages/MessageContentProcessor.kt @@ -1,8 +1,6 @@ package org.tm.archive.messages import android.content.Context -import org.archiver.ArchiveConstants -import org.archiver.ArchiveSender import org.signal.core.util.logging.Log import org.signal.core.util.orNull import org.signal.core.util.toOptional @@ -53,7 +51,6 @@ import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.internal.push.CallMessage import org.whispersystems.signalservice.internal.push.Content -import org.whispersystems.signalservice.internal.push.DataMessage import org.whispersystems.signalservice.internal.push.Envelope import org.whispersystems.signalservice.internal.push.GroupContextV2 import org.whispersystems.signalservice.internal.push.TypingMessage @@ -231,10 +228,11 @@ open class MessageContentProcessor(private val context: Context) { groupId: GroupId.V2, groupV2: GroupContextV2, senderRecipient: Recipient, - groupSecretParams: GroupSecretParams? = null + groupSecretParams: GroupSecretParams? = null, + serverGuid: String? = null ): Gv2PreProcessResult { val preUpdateGroupRecord = SignalDatabase.groups.getGroup(groupId) - val groupUpdateResult = updateGv2GroupFromServerOrP2PChange(context, timestamp, groupV2, preUpdateGroupRecord, groupSecretParams) + val groupUpdateResult = updateGv2GroupFromServerOrP2PChange(context, timestamp, groupV2, preUpdateGroupRecord, groupSecretParams, serverGuid) if (groupUpdateResult == null) { log(timestamp, "Ignoring GV2 message for group we are not currently in $groupId") return Gv2PreProcessResult.IGNORE @@ -275,13 +273,14 @@ open class MessageContentProcessor(private val context: Context) { timestamp: Long, groupV2: GroupContextV2, localRecord: Optional, - groupSecretParams: GroupSecretParams? = null + groupSecretParams: GroupSecretParams? = null, + serverGuid: String? = null ): GroupsV2StateProcessor.GroupUpdateResult? { return try { val signedGroupChange: ByteArray? = if (groupV2.hasSignedGroupChange) groupV2.signedGroupChange else null val updatedTimestamp = if (signedGroupChange != null) timestamp else timestamp - 1 if (groupV2.revision != null) { - GroupManager.updateGroupFromServer(context, groupV2.groupMasterKey, localRecord, groupSecretParams, groupV2.revision!!, updatedTimestamp, signedGroupChange) + GroupManager.updateGroupFromServer(context, groupV2.groupMasterKey, localRecord, groupSecretParams, groupV2.revision!!, updatedTimestamp, signedGroupChange, serverGuid) } else { warn(timestamp, "Ignore group update message without a revision") null @@ -354,15 +353,21 @@ open class MessageContentProcessor(private val context: Context) { warn(timestamp, "Handling encryption error.") val threadRecipient = if (exceptionMetadata.groupId != null) Recipient.externalPossiblyMigratedGroup(exceptionMetadata.groupId) else sender - SignalDatabase - .messages - .insertBadDecryptMessage( - recipientId = sender.id, - senderDevice = exceptionMetadata.senderDevice, - sentTimestamp = timestamp, - receivedTimestamp = System.currentTimeMillis(), - threadId = SignalDatabase.threads.getOrCreateThreadIdFor(threadRecipient) - ) + val threadId: Long? = SignalDatabase.threads.getThreadIdFor(threadRecipient.id) + + if (threadId != null) { + SignalDatabase + .messages + .insertBadDecryptMessage( + recipientId = sender.id, + senderDevice = exceptionMetadata.senderDevice, + sentTimestamp = timestamp, + receivedTimestamp = System.currentTimeMillis(), + threadId = threadId + ) + } else { + warn(timestamp, "Could not find a thread for the target recipient. Skipping.") + } } MessageState.INVALID_VERSION -> { @@ -647,13 +652,21 @@ open class MessageContentProcessor(private val context: Context) { private fun handleIndividualRetryReceipt(requester: Recipient, messageLogEntry: MessageLogEntry?, envelope: Envelope, metadata: EnvelopeMetadata, decryptionErrorMessage: DecryptionErrorMessage) { var archivedSession = false - // TODO [pnp] Ignore retry receipts that have a PNI destinationUuid - if (decryptionErrorMessage.ratchetKey.isPresent && - ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get()) - ) { - warn(envelope.timestamp!!, "[RetryReceipt-I] Ratchet key matches. Archiving the session.") - ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId) - archivedSession = true + if (ServiceId.parseOrNull(envelope.destinationServiceId) is ServiceId.PNI) { + warn(envelope.timestamp!!, "[RetryReceipt-I] Destination is our PNI. Ignoring.") + return + } + + if (decryptionErrorMessage.ratchetKey.isPresent) { + if (ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get())) { + warn(envelope.timestamp!!, "[RetryReceipt-I] Ratchet key matches. Archiving the session.") + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId) + archivedSession = true + } else { + log(envelope.timestamp!!, "[RetryReceipt-I] Ratchet key does not match. Leaving the session as-is.") + } + } else { + warn(envelope.timestamp!!, "[RetryReceipt-I] Missing ratchet key! Can't archive session.") } if (messageLogEntry != null) { diff --git a/app/src/main/java/org/tm/archive/messages/MessageDecryptor.kt b/app/src/main/java/org/tm/archive/messages/MessageDecryptor.kt index c11caff4..8459b7d8 100644 --- a/app/src/main/java/org/tm/archive/messages/MessageDecryptor.kt +++ b/app/src/main/java/org/tm/archive/messages/MessageDecryptor.kt @@ -8,6 +8,7 @@ import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.squareup.wire.internal.toUnmodifiableList import org.signal.core.util.PendingIntentFlags +import org.signal.core.util.isAbsent import org.signal.core.util.logging.Log import org.signal.core.util.roundedString import org.signal.libsignal.metadata.InvalidMetadataMessageException @@ -36,7 +37,7 @@ import org.tm.archive.database.SignalDatabase import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.groups.BadGroupIdException import org.tm.archive.groups.GroupId -import org.tm.archive.jobmanager.Job +import org.tm.archive.jobmanager.JobManager import org.tm.archive.jobs.AutomaticSessionResetJob import org.tm.archive.jobs.PreKeysSyncJob import org.tm.archive.jobs.SendRetryReceiptJob @@ -49,6 +50,8 @@ import org.tm.archive.notifications.NotificationIds import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId import org.tm.archive.util.FeatureFlags +import org.tm.archive.util.LRUCache +import org.tm.archive.util.asChain import org.whispersystems.signalservice.api.InvalidMessageStructureException import org.whispersystems.signalservice.api.crypto.ContentHint import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata @@ -76,6 +79,8 @@ object MessageDecryptor { private val TAG = Log.tag(MessageDecryptor::class.java) + private val decryptionErrorCounts: MutableMap = LRUCache(100) + /** * Decrypts an envelope and provides a [Result]. This method has side effects, but all of them are limited to [SignalDatabase]. * That means that this operation should be atomic when performed within a transaction. @@ -124,8 +129,9 @@ object MessageDecryptor { val followUpOperations: MutableList = mutableListOf() if (envelope.type == Envelope.Type.PREKEY_BUNDLE) { + Log.i(TAG, "${logPrefix(envelope)} Prekey message. Scheduling a prekey sync job.") followUpOperations += FollowUpOperation { - PreKeysSyncJob.create() + PreKeysSyncJob.create().asChain() } } @@ -218,7 +224,7 @@ object MessageDecryptor { followUpOperations += FollowUpOperation { val sender: Recipient = Recipient.external(context, e.sender) - AutomaticSessionResetJob(sender.id, e.senderDevice, envelope.timestamp!!) + AutomaticSessionResetJob(sender.id, e.senderDevice, envelope.timestamp!!).asChain() } Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList()) @@ -276,37 +282,82 @@ object MessageDecryptor { val senderDevice: Int = protocolException.senderDevice val receivedTimestamp: Long = System.currentTimeMillis() val sender: Recipient = Recipient.external(context, protocolException.sender) + val senderServiceId: ServiceId? = ServiceId.parseOrNull(protocolException.sender) if (sender.isSelf) { - Log.w(TAG, "${logPrefix(envelope)} Decryption error for a sync message! Enqueuing a session reset job.") + Log.w(TAG, "${logPrefix(envelope)} Decryption error for a sync message! Enqueuing a session reset job.", true) followUpOperations += FollowUpOperation { - AutomaticSessionResetJob(sender.id, senderDevice, envelope.timestamp!!) + AutomaticSessionResetJob(sender.id, senderDevice, envelope.timestamp!!).asChain() } return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations) } + val errorCount: DecryptionErrorCount = decryptionErrorCounts.getOrPut(sender.id) { DecryptionErrorCount(count = 0, lastReceivedTime = 0) } + val timeSinceLastError = receivedTimestamp - errorCount.lastReceivedTime + if (timeSinceLastError > FeatureFlags.retryReceiptMaxCountResetAge() && errorCount.count > 0) { + Log.i(TAG, "${logPrefix(envelope, senderServiceId)} Resetting decryption error count for ${sender.id} because it has been $timeSinceLastError ms since the last error.", true) + errorCount.count = 0 + } + + errorCount.count++ + errorCount.lastReceivedTime = receivedTimestamp + + if (errorCount.count > FeatureFlags.retryReceiptMaxCount()) { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} This is error number ${errorCount.count} from ${sender.id}, which is greater than the maximum of ${FeatureFlags.retryReceiptMaxCount()}. Ignoring.", true) + + if (contentHint == ContentHint.IMPLICIT) { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} The content hint is $contentHint, so no error message is needed.", true) + Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations) + } else { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} The content hint is $contentHint, so we need to insert an error right away.", true) + return Result.DecryptionError(envelope, serverDeliveredTimestamp, protocolException.toErrorMetadata(), followUpOperations.toUnmodifiableList()) + } + } else { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} This is error number ${errorCount.count} from ${sender.id}.${if (errorCount.count > 1) " It has been $timeSinceLastError ms since the last error." else "" }", true) + } + followUpOperations += FollowUpOperation { - buildSendRetryReceiptJob(envelope, protocolException, sender) + val retryJob = buildSendRetryReceiptJob(envelope, protocolException, sender) + + // Note: if the message is sealed sender, it's envelope type will be UNIDENTIFIED_SENDER. The only way we can currently check if the error is + // prekey-related in that situation is using a string match. + if (envelope.type == Envelope.Type.PREKEY_BUNDLE || protocolException.message?.lowercase()?.contains("prekey") == true) { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} Got a decryption error on a prekey message. Forcing a prekey rotation before requesting the retry.", true) + PreKeysSyncJob.create(forceRotationRequested = true).asChain().then(retryJob) + } else { + retryJob.asChain() + } } return when (contentHint) { ContentHint.DEFAULT -> { - Log.w(TAG, "${logPrefix(envelope)} The content hint is $contentHint, so we need to insert an error right away.", true) + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} The content hint is $contentHint, so we need to insert an error right away.", true) Result.DecryptionError(envelope, serverDeliveredTimestamp, protocolException.toErrorMetadata(), followUpOperations.toUnmodifiableList()) } ContentHint.RESENDABLE -> { - Log.w(TAG, "${logPrefix(envelope)} The content hint is $contentHint, so we can try to resend the message.", true) + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} The content hint is $contentHint, so we can try to resend the message.", true) followUpOperations += FollowUpOperation { val groupId: GroupId? = protocolException.parseGroupId(envelope) - val threadId: Long = if (groupId != null) { + + val threadId: Long? = if (groupId != null) { + if (SignalDatabase.groups.getGroup(groupId).isAbsent()) { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} No group found for $groupId! Not inserting a retry receipt.") + return@FollowUpOperation null + } + val groupRecipient: Recipient = Recipient.externalPossiblyMigratedGroup(groupId) - SignalDatabase.threads.getOrCreateThreadIdFor(groupRecipient) + SignalDatabase.threads.getThreadIdFor(groupRecipient.id) } else { - SignalDatabase.threads.getOrCreateThreadIdFor(sender) + SignalDatabase.threads.getThreadIdFor(sender.id) + } + + if (threadId == null) { + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} Thread does not already exist for sender ${sender.id}! We will not create one just to show a retry receipt.") + return@FollowUpOperation null } ApplicationDependencies.getPendingRetryReceiptCache().insert(sender.id, senderDevice, envelope.timestamp!!, receivedTimestamp, threadId) @@ -318,7 +369,7 @@ object MessageDecryptor { } ContentHint.IMPLICIT -> { - Log.w(TAG, "${logPrefix(envelope)} The content hint is $contentHint, so no error message is needed.", true) + Log.w(TAG, "${logPrefix(envelope, senderServiceId)} The content hint is $contentHint, so no error message is needed.", true) Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations) } } @@ -344,7 +395,7 @@ object MessageDecryptor { val aciAddress = SignalProtocolAddress(aci.toString(), deviceId) val pniAddress = SignalProtocolAddress(pni.toString(), deviceId) val aciIdentity = protocolStore.getAciStore().getIdentity(aciAddress) - val pniIdentity = protocolStore.getAciStore().getIdentity(pniAddress) + var pniIdentity = protocolStore.getAciStore().getIdentity(pniAddress) if (aciIdentity == null) { Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for ACI address $aciAddress") @@ -353,7 +404,18 @@ object MessageDecryptor { if (pniIdentity == null) { Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for PNI address $pniAddress") - return + if (deviceId != SignalServiceAddress.DEFAULT_DEVICE_ID) { + pniIdentity = protocolStore.getAciStore().getIdentity(SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID)) + + if (pniIdentity != null) { + Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] Found PNI identity when looking up device 1. Using that.") + } else { + Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No PNI identity when looking up device 1 either.") + return + } + } else { + return + } } if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature!!.toByteArray())) { @@ -387,20 +449,24 @@ object MessageDecryptor { } private fun logPrefix(envelope: Envelope): String { - return logPrefix(envelope.timestamp!!, envelope.sourceServiceId ?: "", envelope.sourceDevice) + return logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(envelope.sourceServiceId)?.logString() ?: "", envelope.sourceDevice) } - private fun logPrefix(envelope: Envelope, sender: ServiceId): String { - return logPrefix(envelope.timestamp!!, sender.toString(), envelope.sourceDevice) + private fun logPrefix(envelope: Envelope, sender: ServiceId?): String { + return logPrefix(envelope.timestamp!!, sender?.logString() ?: "?", envelope.sourceDevice) + } + + private fun logPrefix(envelope: Envelope, sender: String): String { + return logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(sender)?.logString() ?: "?", envelope.sourceDevice) } private fun logPrefix(envelope: Envelope, cipherResult: SignalServiceCipherResult): String { - return logPrefix(envelope.timestamp!!, cipherResult.metadata.sourceServiceId.toString(), cipherResult.metadata.sourceDeviceId) + return logPrefix(envelope.timestamp!!, cipherResult.metadata.sourceServiceId.logString(), cipherResult.metadata.sourceDeviceId) } private fun logPrefix(envelope: Envelope, exception: ProtocolException): String { return if (exception.sender != null) { - logPrefix(envelope.timestamp!!, exception.sender, exception.senderDevice) + logPrefix(envelope.timestamp!!, ServiceId.parseOrNull(exception.sender)?.logString() ?: "?", exception.senderDevice) } else { logPrefix(envelope.timestamp!!, envelope.sourceServiceId, envelope.sourceDevice) } @@ -534,7 +600,12 @@ object MessageDecryptor { val groupId: GroupId? ) + data class DecryptionErrorCount( + var count: Int, + var lastReceivedTime: Long + ) + fun interface FollowUpOperation { - fun run(): Job? + fun run(): JobManager.Chain? } } diff --git a/app/src/main/java/org/tm/archive/messages/SyncMessageProcessor.kt b/app/src/main/java/org/tm/archive/messages/SyncMessageProcessor.kt index 7f788811..8a7621be 100644 --- a/app/src/main/java/org/tm/archive/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/tm/archive/messages/SyncMessageProcessor.kt @@ -6,8 +6,12 @@ import com.mobilecoin.lib.exceptions.SerializationException import okio.ByteString import org.signal.core.util.Hex import org.signal.core.util.orNull +import org.signal.libsignal.protocol.IdentityKey +import org.signal.libsignal.protocol.InvalidKeyException +import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.util.Pair import org.signal.ringrtc.CallException +import org.signal.ringrtc.CallId import org.signal.ringrtc.CallLinkRootKey import org.tm.archive.attachments.Attachment import org.tm.archive.attachments.DatabaseAttachment @@ -19,6 +23,7 @@ import org.tm.archive.database.CallLinkTable import org.tm.archive.database.CallTable import org.tm.archive.database.GroupReceiptTable import org.tm.archive.database.GroupTable +import org.tm.archive.database.MessageTable import org.tm.archive.database.MessageTable.MarkedMessageInfo import org.tm.archive.database.NoSuchMessageException import org.tm.archive.database.PaymentMetaDataUtil @@ -73,9 +78,6 @@ import org.tm.archive.messages.SignalServiceProtoUtil.toSignalServiceAttachmentP import org.tm.archive.messages.SignalServiceProtoUtil.type import org.tm.archive.mms.MmsException import org.tm.archive.mms.OutgoingMessage -import org.tm.archive.mms.OutgoingMessage.Companion.endSessionMessage -import org.tm.archive.mms.OutgoingMessage.Companion.expirationUpdateMessage -import org.tm.archive.mms.OutgoingMessage.Companion.text import org.tm.archive.mms.QuoteModel import org.tm.archive.notifications.MarkReadReceiver import org.tm.archive.payments.MobileCoinPublicAddress @@ -99,6 +101,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.storage.StorageKey import org.whispersystems.signalservice.internal.push.Content @@ -122,6 +125,7 @@ import org.whispersystems.signalservice.internal.push.Verified import java.io.IOException import java.util.Optional import java.util.UUID +import java.util.concurrent.TimeUnit import kotlin.time.Duration object SyncMessageProcessor { @@ -171,6 +175,8 @@ object SyncMessageProcessor { log(envelope.timestamp!!, "Processing sent transcript for message with ID ${sent.timestamp!!}") try { + handlePniIdentityKeys(envelope, sent) + if (sent.storyMessage != null || sent.storyMessageRecipients.isNotEmpty()) { handleSynchronizeSentStoryMessage(envelope, sent) return @@ -248,6 +254,34 @@ object SyncMessageProcessor { } } + private fun handlePniIdentityKeys(envelope: Envelope, sent: Sent) { + for (status in sent.unidentifiedStatus) { + if (status.destinationIdentityKey == null) { + continue + } + + val pni = PNI.parsePrefixedOrNull(status.destinationServiceId) + if (pni == null) { + continue + } + + val address = SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID) + + if (ApplicationDependencies.getProtocolStore().aci().identities().getIdentity(address) != null) { + log(envelope.timestamp!!, "Ignoring identity on sent transcript for $pni because we already have one.") + continue + } + + try { + log(envelope.timestamp!!, "Saving identity from sent transcript for $pni") + val identityKey = IdentityKey(status.destinationIdentityKey!!.toByteArray()) + ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(address, identityKey) + } catch (e: InvalidKeyException) { + warn(envelope.timestamp!!, "Failed to deserialize identity key for $pni") + } + } + } + private fun getSyncMessageDestination(message: Sent): Recipient { return if (message.message.hasGroupContext) { Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.message!!.groupV2!!.groupMasterKey)) @@ -336,7 +370,7 @@ object SyncMessageProcessor { messageId = SignalDatabase.messages.insertMessageOutbox(outgoingTextMessage, threadId, false, null) SignalDatabase.messages.markUnidentified(messageId, sent.isUnidentified(toRecipient.serviceId.orNull())) } - SignalDatabase.threads.update(threadId, true) + SignalDatabase.messages.markAsSent(messageId, true) if (targetMessage.expireStarted > 0) { SignalDatabase.messages.markExpireStarted(messageId, targetMessage.expireStarted) @@ -576,7 +610,7 @@ object SyncMessageProcessor { log(envelopeTimestamp, "Synchronize end session message.") val recipient: Recipient = getSyncMessageDestination(sent) - val outgoingEndSessionMessage: OutgoingMessage = endSessionMessage(recipient, sent.timestamp!!) + val outgoingEndSessionMessage: OutgoingMessage = OutgoingMessage.endSessionMessage(recipient, sent.timestamp!!) val threadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) if (!recipient.isGroup) { @@ -590,7 +624,6 @@ object SyncMessageProcessor { ) SignalDatabase.messages.markAsSent(messageId, true) - SignalDatabase.threads.update(threadId, true) } return threadId @@ -625,7 +658,7 @@ object SyncMessageProcessor { } val recipient: Recipient = getSyncMessageDestination(sent) - val expirationUpdateMessage: OutgoingMessage = expirationUpdateMessage(recipient, if (sideEffect) sent.timestamp!! - 1 else sent.timestamp!!, sent.message!!.expireTimerDuration.inWholeMilliseconds) + val expirationUpdateMessage: OutgoingMessage = OutgoingMessage.expirationUpdateMessage(recipient, if (sideEffect) sent.timestamp!! - 1 else sent.timestamp!!, sent.message!!.expireTimerDuration.inWholeMilliseconds) val threadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) val messageId: Long = SignalDatabase.messages.insertMessageOutbox(expirationUpdateMessage, threadId, false, null) @@ -831,11 +864,10 @@ object SyncMessageProcessor { messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null) updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId()) } else { - val outgoingTextMessage = text(threadRecipient = recipient, body = body, expiresIn = expiresInMillis, sentTimeMillis = sent.timestamp!!, bodyRanges = bodyRanges) + val outgoingTextMessage = OutgoingMessage.text(threadRecipient = recipient, body = body, expiresIn = expiresInMillis, sentTimeMillis = sent.timestamp!!, bodyRanges = bodyRanges) messageId = SignalDatabase.messages.insertMessageOutbox(outgoingTextMessage, threadId, false, null) SignalDatabase.messages.markUnidentified(messageId, sent.isUnidentified(recipient.serviceId.orNull())) } - SignalDatabase.threads.update(threadId, true) SignalDatabase.messages.markAsSent(messageId, true) if (expiresInMillis > 0) { SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) @@ -846,6 +878,7 @@ object SyncMessageProcessor { SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) } + return threadId } @@ -884,9 +917,9 @@ object SyncMessageProcessor { ) { log(envelopeTimestamp, "Synchronize read message. Count: ${readMessages.size}, Timestamps: ${readMessages.map { it.timestamp }}") - val threadToLatestRead: Map = HashMap() - val unhandled = SignalDatabase.messages.setTimestampReadFromSyncMessageProto(readMessages, envelopeTimestamp, threadToLatestRead.toMutableMap()) - val markedMessages: List = SignalDatabase.threads.setReadSince(threadToLatestRead, false) + val threadToLatestRead: MutableMap = HashMap() + val unhandled: Collection = SignalDatabase.messages.setTimestampReadFromSyncMessage(readMessages, envelopeTimestamp, threadToLatestRead) + val markedMessages: List = SignalDatabase.threads.setReadSince(threadToLatestRead, false) if (Util.hasItems(markedMessages)) { log("Updating past SignalDatabase.messages: " + markedMessages.size) @@ -1059,6 +1092,12 @@ object SyncMessageProcessor { MessageRequestResponse.Type.ACCEPT -> { SignalDatabase.recipients.setProfileSharing(recipient.id, true) SignalDatabase.recipients.setBlocked(recipient.id, false) + SignalDatabase.messages.insertMessageOutbox( + OutgoingMessage.messageRequestAcceptMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong())), + threadId, + false, + null + ) } MessageRequestResponse.Type.DELETE -> { SignalDatabase.recipients.setProfileSharing(recipient.id, false) @@ -1077,6 +1116,24 @@ object SyncMessageProcessor { SignalDatabase.threads.deleteConversation(threadId) } } + MessageRequestResponse.Type.SPAM -> { + SignalDatabase.messages.insertMessageOutbox( + OutgoingMessage.reportSpamMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong())), + threadId, + false, + null + ) + } + MessageRequestResponse.Type.BLOCK_AND_SPAM -> { + SignalDatabase.recipients.setBlocked(recipient.id, true) + SignalDatabase.recipients.setProfileSharing(recipient.id, false) + SignalDatabase.messages.insertMessageOutbox( + OutgoingMessage.reportSpamMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong())), + threadId, + false, + null + ) + } else -> warn("Got an unknown response type! Skipping") } } @@ -1176,16 +1233,45 @@ object SyncMessageProcessor { } private fun handleSynchronizeCallLogEvent(callLogEvent: CallLogEvent, envelopeTimestamp: Long) { - if (callLogEvent.type != CallLogEvent.Type.CLEAR) { - log(envelopeTimestamp, "Synchronize call log event has an invalid type ${callLogEvent.type}, ignoring.") - return - } else if (callLogEvent.timestamp == null) { - log(envelopeTimestamp, "Synchronize call log event has null timestamp") - return + val timestamp = callLogEvent.timestamp + val callId = callLogEvent.callId?.let { CallId(it) } + val peer: RecipientId? = callLogEvent.conversationId?.let { byteString -> + ACI.parseOrNull(byteString)?.let { RecipientId.from(it) } + ?: GroupId.pushOrNull(byteString.toByteArray())?.let { SignalDatabase.recipients.getByGroupId(it).orNull() } + ?: CallLinkRoomId.fromBytes(byteString.toByteArray()).let { SignalDatabase.recipients.getByCallLinkRoomId(it).orNull() } } - SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(callLogEvent.timestamp!!) - SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(callLogEvent.timestamp!!) + if (callId != null && peer != null) { + val call = SignalDatabase.calls.getCallById(callId.longValue(), peer) + + if (call != null) { + log(envelopeTimestamp, "Synchronizing call log event with exact call data.") + synchronizeCallLogEventViaTimestamp(envelopeTimestamp, callLogEvent.type, call.timestamp) + return + } + } + + if (timestamp != null) { + warn(envelopeTimestamp, "Synchronize call log event using timestamp instead of exact values") + synchronizeCallLogEventViaTimestamp(envelopeTimestamp, callLogEvent.type, timestamp) + } else { + log(envelopeTimestamp, "Failed to synchronize call log event, not enough information.") + } + } + + private fun synchronizeCallLogEventViaTimestamp(envelopeTimestamp: Long, eventType: CallLogEvent.Type?, timestamp: Long) { + when (eventType) { + CallLogEvent.Type.CLEAR -> { + SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(timestamp) + SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(timestamp) + } + + CallLogEvent.Type.MARKED_AS_READ -> { + SignalDatabase.calls.markAllCallEventsRead(timestamp) + } + + else -> log(envelopeTimestamp, "Synchronize call log event has an invalid type $eventType, ignoring.") + } } private fun handleSynchronizeCallLink(callLinkUpdate: CallLinkUpdate, envelopeTimestamp: Long) { @@ -1202,6 +1288,13 @@ object SyncMessageProcessor { } val roomId = CallLinkRoomId.fromCallLinkRootKey(callLinkRootKey) + if (callLinkUpdate.type == CallLinkUpdate.Type.DELETE) { + log(envelopeTimestamp, "Synchronize call link deletion.") + SignalDatabase.callLinks.deleteCallLink(roomId) + + return + } + if (SignalDatabase.callLinks.callLinkExists(roomId)) { log(envelopeTimestamp, "Synchronize call link for a link we already know about. Updating credentials.") SignalDatabase.callLinks.updateCallLinkCredentials( diff --git a/app/src/main/java/org/tm/archive/messages/protocol/BufferedKyberPreKeyStore.kt b/app/src/main/java/org/tm/archive/messages/protocol/BufferedKyberPreKeyStore.kt index 6a4e0d7a..577e26c2 100644 --- a/app/src/main/java/org/tm/archive/messages/protocol/BufferedKyberPreKeyStore.kt +++ b/app/src/main/java/org/tm/archive/messages/protocol/BufferedKyberPreKeyStore.kt @@ -25,7 +25,7 @@ class BufferedKyberPreKeyStore(private val selfServiceId: ServiceId) : SignalSer private var hasLoadedAll: Boolean = false /** The kyber prekeys that have been marked as removed (if they're not last resort). */ - private val removedIfNotLastResort: MutableList = mutableListOf() + private val removedIfNotLastResort: MutableSet = mutableSetOf() @kotlin.jvm.Throws(InvalidKeyIdException::class) override fun loadKyberPreKey(kyberPreKeyId: Int): KyberPreKeyRecord { diff --git a/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignalServiceAccountDataStore.kt b/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignalServiceAccountDataStore.kt index 0e0ecdee..fc0b4ca2 100644 --- a/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignalServiceAccountDataStore.kt +++ b/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignalServiceAccountDataStore.kt @@ -200,6 +200,7 @@ class BufferedSignalServiceAccountDataStore(selfServiceId: ServiceId) : SignalSe fun flushToDisk(persistentStore: SignalServiceAccountDataStore) { identityStore.flushToDisk(persistentStore) oneTimePreKeyStore.flushToDisk(persistentStore) + kyberPreKeyStore.flushToDisk(persistentStore) signedPreKeyStore.flushToDisk(persistentStore) sessionStore.flushToDisk(persistentStore) senderKeyStore.flushToDisk(persistentStore) diff --git a/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignedPreKeyStore.kt b/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignedPreKeyStore.kt index 71a717c7..4fb7b2c8 100644 --- a/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignedPreKeyStore.kt +++ b/app/src/main/java/org/tm/archive/messages/protocol/BufferedSignedPreKeyStore.kt @@ -24,7 +24,7 @@ class BufferedSignedPreKeyStore(private val selfServiceId: ServiceId) : SignedPr @kotlin.jvm.Throws(InvalidKeyIdException::class) override fun loadSignedPreKey(id: Int): SignedPreKeyRecord { return store.computeIfAbsent(id) { - SignalDatabase.signedPreKeys.get(selfServiceId, id) ?: throw InvalidKeyIdException("Missing one-time prekey with ID: $id") + SignalDatabase.signedPreKeys.get(selfServiceId, id) ?: throw InvalidKeyIdException("Missing signed prekey with ID: $id") } } diff --git a/app/src/main/java/org/tm/archive/migrations/ApplicationMigrations.java b/app/src/main/java/org/tm/archive/migrations/ApplicationMigrations.java index 8f720018..d1cc6888 100644 --- a/app/src/main/java/org/tm/archive/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/tm/archive/migrations/ApplicationMigrations.java @@ -143,11 +143,14 @@ public class ApplicationMigrations { static final int SELF_REGISTERTED_STATE = 99; static final int SVR2_ENCLAVE_UPDATE = 100; static final int STORAGE_LOCAL_UNKNOWNS_FIX = 101; + static final int PNP_LAUNCH = 102; + static final int EMOJI_VERSION_10 = 103; + static final int ATTACHMENT_HASH_BACKFILL = 104; } - public static final int CURRENT_VERSION = 101; + public static final int CURRENT_VERSION = 104; - /** + /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call * to {@link JobManager#beginJobLoop()}. Otherwise, other non-migration jobs may have started * executing before we add the migration jobs. @@ -164,7 +167,7 @@ public class ApplicationMigrations { return; } else { Log.d(TAG, "About to update. Clearing deprecation flag."); - SignalStore.misc().clearClientDeprecated(); + SignalStore.misc().setClientDeprecated(false); } final int lastSeenVersion = TextSecurePreferences.getAppMigrationVersion(context); @@ -652,6 +655,18 @@ public class ApplicationMigrations { jobs.put(Version.STORAGE_LOCAL_UNKNOWNS_FIX, new StorageFixLocalUnknownMigrationJob()); } + if (lastSeenVersion < Version.PNP_LAUNCH) { + jobs.put(Version.PNP_LAUNCH, new PnpLaunchMigrationJob()); + } + + if (lastSeenVersion < Version.EMOJI_VERSION_10) { + jobs.put(Version.EMOJI_VERSION_10, new EmojiDownloadMigrationJob()); + } + + if (lastSeenVersion < Version.ATTACHMENT_HASH_BACKFILL) { + jobs.put(Version.ATTACHMENT_HASH_BACKFILL, new AttachmentHashBackfillMigrationJob()); + } + return jobs; } diff --git a/app/src/main/java/org/tm/archive/migrations/AttachmentHashBackfillMigrationJob.kt b/app/src/main/java/org/tm/archive/migrations/AttachmentHashBackfillMigrationJob.kt new file mode 100644 index 00000000..45510afd --- /dev/null +++ b/app/src/main/java/org/tm/archive/migrations/AttachmentHashBackfillMigrationJob.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.migrations + +import org.signal.core.util.logging.Log +import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.jobmanager.Job +import org.tm.archive.jobs.AttachmentHashBackfillJob +import java.lang.Exception + +/** + * Kicks off the attachment hash backfill process by enqueueing a [AttachmentHashBackfillJob]. + */ +internal class AttachmentHashBackfillMigrationJob(parameters: Parameters = Parameters.Builder().build()) : MigrationJob(parameters) { + + companion object { + val TAG = Log.tag(AttachmentHashBackfillMigrationJob::class.java) + const val KEY = "AttachmentHashBackfillMigrationJob" + } + + override fun getFactoryKey(): String = KEY + + override fun isUiBlocking(): Boolean = false + + override fun performMigration() { + ApplicationDependencies.getJobManager().add(AttachmentHashBackfillJob()) + } + + override fun shouldRetry(e: Exception): Boolean = false + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): AttachmentHashBackfillMigrationJob { + return AttachmentHashBackfillMigrationJob(parameters) + } + } +} diff --git a/app/src/main/java/org/tm/archive/migrations/CachedAttachmentsMigrationJob.java b/app/src/main/java/org/tm/archive/migrations/CachedAttachmentsMigrationJob.java index bc668f74..6e987bba 100644 --- a/app/src/main/java/org/tm/archive/migrations/CachedAttachmentsMigrationJob.java +++ b/app/src/main/java/org/tm/archive/migrations/CachedAttachmentsMigrationJob.java @@ -3,9 +3,10 @@ package org.tm.archive.migrations; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.bumptech.glide.Glide; + import org.signal.core.util.logging.Log; import org.tm.archive.jobmanager.Job; -import org.tm.archive.mms.GlideApp; import org.tm.archive.util.FileUtils; import java.io.File; @@ -39,7 +40,7 @@ public class CachedAttachmentsMigrationJob extends MigrationJob { } FileUtils.deleteDirectoryContents(context.getExternalCacheDir()); - GlideApp.get(context).clearDiskCache(); + Glide.get(context).clearDiskCache(); } @Override diff --git a/app/src/main/java/org/tm/archive/migrations/LegacyMigrationJob.java b/app/src/main/java/org/tm/archive/migrations/LegacyMigrationJob.java index 6712358e..117181fc 100644 --- a/app/src/main/java/org/tm/archive/migrations/LegacyMigrationJob.java +++ b/app/src/main/java/org/tm/archive/migrations/LegacyMigrationJob.java @@ -6,6 +6,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.PreferenceManager; +import com.bumptech.glide.Glide; + import org.signal.core.util.logging.Log; import org.tm.archive.attachments.DatabaseAttachment; import org.tm.archive.crypto.MasterSecret; @@ -21,7 +23,6 @@ import org.tm.archive.jobs.DirectoryRefreshJob; import org.tm.archive.jobs.PreKeysSyncJob; import org.tm.archive.jobs.RefreshAttributesJob; import org.tm.archive.keyvalue.SignalStore; -import org.tm.archive.mms.GlideApp; import org.tm.archive.service.KeyCachingService; import org.tm.archive.transport.RetryLaterException; import org.tm.archive.util.FileUtils; @@ -200,7 +201,7 @@ public class LegacyMigrationJob extends MigrationJob { if (lastSeenVersion < IMAGE_CACHE_CLEANUP) { FileUtils.deleteDirectoryContents(context.getExternalCacheDir()); - GlideApp.get(context).clearDiskCache(); + Glide.get(context).clearDiskCache(); } // This migration became unnecessary after switching away from WorkManager diff --git a/app/src/main/java/org/tm/archive/migrations/PnpLaunchMigrationJob.kt b/app/src/main/java/org/tm/archive/migrations/PnpLaunchMigrationJob.kt new file mode 100644 index 00000000..6d9bd1f8 --- /dev/null +++ b/app/src/main/java/org/tm/archive/migrations/PnpLaunchMigrationJob.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.migrations + +import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.jobmanager.Job +import org.tm.archive.jobs.ProfileUploadJob +import org.tm.archive.jobs.RefreshAttributesJob +import java.lang.Exception + +/** + * Kicks off a chain of jobs to update the server with our latest PNP settings. + */ +internal class PnpLaunchMigrationJob(parameters: Parameters = Parameters.Builder().build()) : MigrationJob(parameters) { + companion object { + const val KEY = "PnpLaunchMigrationJob" + } + + override fun getFactoryKey(): String = KEY + + override fun isUiBlocking(): Boolean = false + + override fun performMigration() { + ApplicationDependencies.getJobManager() + .startChain(RefreshAttributesJob()) + .then(ProfileUploadJob()) + .enqueue() + } + + override fun shouldRetry(e: Exception): Boolean = false + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): PnpLaunchMigrationJob { + return PnpLaunchMigrationJob(parameters) + } + } +} diff --git a/app/src/main/java/org/tm/archive/mms/ApnUnavailableException.java b/app/src/main/java/org/tm/archive/mms/ApnUnavailableException.java deleted file mode 100644 index bc0501b9..00000000 --- a/app/src/main/java/org/tm/archive/mms/ApnUnavailableException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.tm.archive.mms; - -public class ApnUnavailableException extends Exception { - - public ApnUnavailableException() { - } - - public ApnUnavailableException(String detailMessage) { - super(detailMessage); - } - - public ApnUnavailableException(Throwable throwable) { - super(throwable); - } - - public ApnUnavailableException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } -} diff --git a/app/src/main/java/org/tm/archive/mms/AttachmentManager.java b/app/src/main/java/org/tm/archive/mms/AttachmentManager.java index ea5e271e..b6429a33 100644 --- a/app/src/main/java/org/tm/archive/mms/AttachmentManager.java +++ b/app/src/main/java/org/tm/archive/mms/AttachmentManager.java @@ -39,9 +39,14 @@ import androidx.annotation.WorkerThread; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.signal.core.util.ThreadUtil; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.ListenableFuture.Listener; +import org.signal.core.util.concurrent.SettableFuture; import org.signal.core.util.concurrent.SimpleTask; import org.signal.core.util.logging.Log; import org.tm.archive.R; @@ -81,9 +86,6 @@ import org.tm.archive.util.MediaUtil; import org.tm.archive.util.ProfileUtil; import org.tm.archive.util.ViewUtil; import org.tm.archive.util.concurrent.AssertedSuccessListener; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.tm.archive.util.concurrent.ListenableFuture.Listener; -import org.tm.archive.util.concurrent.SettableFuture; import org.tm.archive.util.views.Stub; import org.whispersystems.signalservice.api.util.ExpiringProfileCredentialUtil; @@ -137,14 +139,14 @@ public class AttachmentManager { } - public void clear(@NonNull GlideRequests glideRequests, boolean animate) { + public void clear(@NonNull RequestManager requestManager, boolean animate) { if (attachmentViewStub.resolved()) { if (animate) { ViewUtil.fadeOut(attachmentViewStub.get(), 200).addListener(new Listener() { @Override public void onSuccess(Boolean result) { - thumbnail.clear(glideRequests); + thumbnail.clear(requestManager); attachmentViewStub.get().setVisibility(View.GONE); attachmentListener.onAttachmentChanged(); } @@ -154,7 +156,7 @@ public class AttachmentManager { } }); } else { - thumbnail.clear(glideRequests); + thumbnail.clear(requestManager); attachmentViewStub.get().setVisibility(View.GONE); attachmentListener.onAttachmentChanged(); } @@ -255,7 +257,7 @@ public class AttachmentManager { } @SuppressLint("StaticFieldLeak") - public ListenableFuture setMedia(@NonNull final GlideRequests glideRequests, + public ListenableFuture setMedia(@NonNull final RequestManager requestManager, @NonNull final Uri uri, @NonNull final SlideFactory.MediaType mediaType, @NonNull final MediaConstraints constraints, @@ -271,7 +273,7 @@ public class AttachmentManager { @Override protected void onPreExecute() { - thumbnail.clear(glideRequests); + thumbnail.clear(requestManager); thumbnail.showProgressSpinner(); attachmentViewStub.get().setVisibility(View.VISIBLE); } @@ -323,7 +325,7 @@ public class AttachmentManager { result.set(true); } else { Attachment attachment = slide.asAttachment(); - result.deferTo(thumbnail.setImageResource(glideRequests, slide, false, true, attachment.width, attachment.height)); + result.deferTo(thumbnail.setImageResource(requestManager, slide, false, true, attachment.width, attachment.height)); removableMediaView.display(thumbnail, mediaType == SlideFactory.MediaType.IMAGE); } @@ -580,7 +582,7 @@ public class AttachmentManager { }); cleanup(); - clear(GlideApp.with(context.getApplicationContext()), true); + clear(Glide.with(context.getApplicationContext()), true); } } diff --git a/app/src/main/java/org/tm/archive/mms/AudioSlide.java b/app/src/main/java/org/tm/archive/mms/AudioSlide.java index 4cbe4b9a..c4616bd5 100644 --- a/app/src/main/java/org/tm/archive/mms/AudioSlide.java +++ b/app/src/main/java/org/tm/archive/mms/AudioSlide.java @@ -91,6 +91,6 @@ public class AudioSlide extends Slide { @Override public @DrawableRes int getPlaceholderRes(Theme theme) { - return R.drawable.ic_audio; + return R.drawable.symbol_speaker_fill_24; } } diff --git a/app/src/main/java/org/tm/archive/mms/CompatMmsConnection.java b/app/src/main/java/org/tm/archive/mms/CompatMmsConnection.java deleted file mode 100644 index 22e3a200..00000000 --- a/app/src/main/java/org/tm/archive/mms/CompatMmsConnection.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.tm.archive.mms; - -import android.content.Context; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.android.mms.pdu_alt.PduHeaders; -import com.google.android.mms.pdu_alt.RetrieveConf; -import com.google.android.mms.pdu_alt.SendConf; - -import org.signal.core.util.logging.Log; -import org.tm.archive.transport.UndeliverableMessageException; - -import java.io.IOException; - -public class CompatMmsConnection implements OutgoingMmsConnection, IncomingMmsConnection { - private static final String TAG = Log.tag(CompatMmsConnection.class); - - private Context context; - - public CompatMmsConnection(Context context) { - this.context = context; - } - - @Nullable - @Override - public SendConf send(@NonNull byte[] pduBytes, int subscriptionId) - throws UndeliverableMessageException - { - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) { - try { - Log.i(TAG, "Sending via Lollipop API"); - return new OutgoingLollipopMmsConnection(context).send(pduBytes, subscriptionId); - } catch (UndeliverableMessageException e) { - Log.w(TAG, e); - } - - Log.i(TAG, "Falling back to legacy connection..."); - } - - if (subscriptionId == -1) { - Log.i(TAG, "Sending via legacy connection"); - try { - SendConf result = new OutgoingLegacyMmsConnection(context).send(pduBytes, subscriptionId); - - if (result != null && result.getResponseStatus() == PduHeaders.RESPONSE_STATUS_OK) { - return result; - } else { - Log.w(TAG, "Got bad legacy response: " + (result != null ? result.getResponseStatus() : null)); - } - } catch (UndeliverableMessageException | ApnUnavailableException e) { - Log.w(TAG, e); - } - } - - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && VERSION.SDK_INT < VERSION_CODES.LOLLIPOP_MR1) { - Log.i(TAG, "Falling back to sending via Lollipop API"); - return new OutgoingLollipopMmsConnection(context).send(pduBytes, subscriptionId); - } - - throw new UndeliverableMessageException("Both lollipop and legacy connections failed..."); - } - - @Nullable - @Override - public RetrieveConf retrieve(@NonNull String contentLocation, - byte[] transactionId, - int subscriptionId) - throws MmsException, MmsRadioException, ApnUnavailableException, IOException - { - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) { - Log.i(TAG, "Receiving via Lollipop API"); - try { - return new IncomingLollipopMmsConnection(context).retrieve(contentLocation, transactionId, subscriptionId); - } catch (MmsException e) { - Log.w(TAG, e); - } - - Log.i(TAG, "Falling back to receiving via legacy connection"); - } - - if (VERSION.SDK_INT < 22 || subscriptionId == -1) { - Log.i(TAG, "Receiving via legacy API"); - try { - return new IncomingLegacyMmsConnection(context).retrieve(contentLocation, transactionId, subscriptionId); - } catch (MmsRadioException | ApnUnavailableException | IOException e) { - Log.w(TAG, e); - } - } - - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && VERSION.SDK_INT < VERSION_CODES.LOLLIPOP_MR1) { - Log.i(TAG, "Falling back to receiving via Lollipop API"); - return new IncomingLollipopMmsConnection(context).retrieve(contentLocation, transactionId, subscriptionId); - } - - throw new IOException("Both lollipop and fallback APIs failed..."); - } -} diff --git a/app/src/main/java/org/tm/archive/mms/IncomingLegacyMmsConnection.java b/app/src/main/java/org/tm/archive/mms/IncomingLegacyMmsConnection.java deleted file mode 100644 index 6f2815b5..00000000 --- a/app/src/main/java/org/tm/archive/mms/IncomingLegacyMmsConnection.java +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (C) 2015 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -import android.content.Context; -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.android.mms.InvalidHeaderValueException; -import com.google.android.mms.pdu_alt.NotifyRespInd; -import com.google.android.mms.pdu_alt.PduComposer; -import com.google.android.mms.pdu_alt.PduHeaders; -import com.google.android.mms.pdu_alt.PduParser; -import com.google.android.mms.pdu_alt.RetrieveConf; - -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpGetHC4; -import org.apache.http.client.methods.HttpUriRequest; -import org.signal.core.util.logging.Log; - -import java.io.IOException; -import java.util.Arrays; - - -@SuppressWarnings("deprecation") -public class IncomingLegacyMmsConnection extends LegacyMmsConnection implements IncomingMmsConnection { - private static final String TAG = Log.tag(IncomingLegacyMmsConnection.class); - - public IncomingLegacyMmsConnection(Context context) throws ApnUnavailableException { - super(context); - } - - private HttpUriRequest constructRequest(Apn contentApn, boolean useProxy) throws IOException { - HttpGetHC4 request; - - try { - request = new HttpGetHC4(contentApn.getMmsc()); - } catch (IllegalArgumentException e) { - // #7339 - throw new IOException(e); - } - - for (Header header : getBaseHeaders()) { - request.addHeader(header); - } - - if (useProxy) { - HttpHost proxy = new HttpHost(contentApn.getProxy(), contentApn.getPort()); - request.setConfig(RequestConfig.custom().setProxy(proxy).build()); - } - - return request; - } - - @Override - public @Nullable RetrieveConf retrieve(@NonNull String contentLocation, - byte[] transactionId, int subscriptionId) - throws MmsRadioException, ApnUnavailableException, IOException - { - MmsRadio radio = MmsRadio.getInstance(context); - Apn contentApn = new Apn(contentLocation, apn.getProxy(), Integer.toString(apn.getPort()), apn.getUsername(), apn.getPassword()); - - if (isDirectConnect()) { - Log.i(TAG, "Connecting directly..."); - try { - return retrieve(contentApn, transactionId, false, false); - } catch (IOException | ApnUnavailableException e) { - Log.w(TAG, e); - } - } - - Log.i(TAG, "Changing radio to MMS mode.."); - radio.connect(); - - try { - Log.i(TAG, "Downloading in MMS mode with proxy..."); - - try { - return retrieve(contentApn, transactionId, true, true); - } catch (IOException | ApnUnavailableException e) { - Log.w(TAG, e); - } - - Log.i(TAG, "Downloading in MMS mode without proxy..."); - - return retrieve(contentApn, transactionId, true, false); - - } finally { - radio.disconnect(); - } - } - - public RetrieveConf retrieve(Apn contentApn, byte[] transactionId, boolean usingMmsRadio, boolean useProxyIfAvailable) - throws IOException, ApnUnavailableException - { - byte[] pdu = null; - - final boolean useProxy = useProxyIfAvailable && contentApn.hasProxy(); - final String targetHost = useProxy - ? contentApn.getProxy() - : Uri.parse(contentApn.getMmsc()).getHost(); - if (checkRouteToHost(context, targetHost, usingMmsRadio)) { - Log.i(TAG, "got successful route to host " + targetHost); - pdu = execute(constructRequest(contentApn, useProxy)); - } - - if (pdu == null) { - throw new IOException("Connection manager could not obtain route to host."); - } - - RetrieveConf retrieved = (RetrieveConf)new PduParser(pdu).parse(); - - if (retrieved == null) { - Log.w(TAG, "Couldn't parse PDU, byte response: " + Arrays.toString(pdu)); - Log.w(TAG, "Couldn't parse PDU, ASCII: " + new String(pdu)); - throw new IOException("Bad retrieved PDU"); - } - - sendRetrievedAcknowledgement(transactionId, usingMmsRadio, useProxy); - return retrieved; - } - - private void sendRetrievedAcknowledgement(byte[] transactionId, - boolean usingRadio, - boolean useProxy) - throws ApnUnavailableException - { - try { - NotifyRespInd notifyResponse = new NotifyRespInd(PduHeaders.CURRENT_MMS_VERSION, - transactionId, - PduHeaders.STATUS_RETRIEVED); - - OutgoingLegacyMmsConnection connection = new OutgoingLegacyMmsConnection(context); - connection.sendNotificationReceived(new PduComposer(context, notifyResponse).make(), usingRadio, useProxy); - } catch (InvalidHeaderValueException | IOException e) { - Log.w(TAG, e); - } - } -} diff --git a/app/src/main/java/org/tm/archive/mms/IncomingLollipopMmsConnection.java b/app/src/main/java/org/tm/archive/mms/IncomingLollipopMmsConnection.java deleted file mode 100644 index 7c527a7b..00000000 --- a/app/src/main/java/org/tm/archive/mms/IncomingLollipopMmsConnection.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (C) 2015 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -import android.content.Context; -import android.content.Intent; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.telephony.SmsManager; -import android.text.TextUtils; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.android.mms.InvalidHeaderValueException; -import com.google.android.mms.pdu_alt.NotifyRespInd; -import com.google.android.mms.pdu_alt.PduComposer; -import com.google.android.mms.pdu_alt.PduHeaders; -import com.google.android.mms.pdu_alt.PduParser; -import com.google.android.mms.pdu_alt.RetrieveConf; - -import org.signal.core.util.StreamUtil; -import org.signal.core.util.logging.Log; -import org.tm.archive.providers.MmsBodyProvider; -import org.tm.archive.transport.UndeliverableMessageException; -import org.tm.archive.util.Util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Locale; -import java.util.concurrent.TimeoutException; - -public class IncomingLollipopMmsConnection extends LollipopMmsConnection implements IncomingMmsConnection { - - public static final String ACTION = IncomingLollipopMmsConnection.class.getCanonicalName() + "MMS_DOWNLOADED_ACTION"; - private static final String TAG = Log.tag(IncomingLollipopMmsConnection.class); - - public IncomingLollipopMmsConnection(Context context) { - super(context, ACTION); - } - - @Override - public synchronized void onResult(Context context, Intent intent) { - if (VERSION.SDK_INT >= 22) { - Log.i(TAG, "HTTP status: " + intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, -1)); - } - Log.i(TAG, "code: " + getResultCode() + ", result string: " + getResultData()); - } - - @Override - public synchronized @Nullable RetrieveConf retrieve(@NonNull String contentLocation, - byte[] transactionId, - int subscriptionId) throws MmsException - { - beginTransaction(); - - try { - MmsBodyProvider.Pointer pointer = MmsBodyProvider.makeTemporaryPointer(getContext()); - - final String transactionIdString = Util.toIsoString(transactionId); - Log.i(TAG, String.format(Locale.ENGLISH, "Downloading subscriptionId=%s multimedia from '%s' [transactionId='%s'] to '%s'", - subscriptionId, - contentLocation, - transactionIdString, - pointer.getUri())); - - SmsManager smsManager; - - if (VERSION.SDK_INT >= 22 && subscriptionId != -1) { - smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId); - } else { - smsManager = SmsManager.getDefault(); - } - - final Bundle configOverrides = smsManager.getCarrierConfigValues(); - - if (configOverrides.getBoolean(SmsManager.MMS_CONFIG_APPEND_TRANSACTION_ID)) { - if (!contentLocation.contains(transactionIdString)) { - Log.i(TAG, "Appending transactionId to contentLocation at the direction of CarrierConfigValues. New location: " + contentLocation); - contentLocation += transactionIdString; - } else { - Log.i(TAG, "Skipping 'append transaction id' as contentLocation already contains it"); - } - } - - if (TextUtils.isEmpty(configOverrides.getString(SmsManager.MMS_CONFIG_USER_AGENT))) { - configOverrides.remove(SmsManager.MMS_CONFIG_USER_AGENT); - } - - if (TextUtils.isEmpty(configOverrides.getString(SmsManager.MMS_CONFIG_UA_PROF_URL))) { - configOverrides.remove(SmsManager.MMS_CONFIG_UA_PROF_URL); - } - - smsManager.downloadMultimediaMessage(getContext(), - contentLocation, - pointer.getUri(), - configOverrides, - getPendingIntent()); - - waitForResult(); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StreamUtil.copy(pointer.getInputStream(), baos); - pointer.close(); - - Log.i(TAG, baos.size() + "-byte response: ");// + Hex.dump(baos.toByteArray())); - - Bundle configValues = smsManager.getCarrierConfigValues(); - boolean parseContentDisposition = configValues.getBoolean(SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION); - - RetrieveConf retrieved; - - try { - retrieved = (RetrieveConf) new PduParser(baos.toByteArray(), parseContentDisposition).parse(); - } catch (AssertionError | NullPointerException e) { - Log.w(TAG, "Badly formatted MMS message caused the parser to fail.", e); - throw new MmsException(e); - } - - if (retrieved == null) return null; - - sendRetrievedAcknowledgement(transactionId, retrieved.getMmsVersion(), subscriptionId); - return retrieved; - } catch (IOException | TimeoutException e) { - Log.w(TAG, e); - throw new MmsException(e); - } finally { - endTransaction(); - } - } - - private void sendRetrievedAcknowledgement(byte[] transactionId, int mmsVersion, int subscriptionId) { - try { - NotifyRespInd retrieveResponse = new NotifyRespInd(mmsVersion, transactionId, PduHeaders.STATUS_RETRIEVED); - new OutgoingLollipopMmsConnection(getContext()).send(new PduComposer(getContext(), retrieveResponse).make(), subscriptionId); - } catch (UndeliverableMessageException e) { - Log.w(TAG, e); - } catch (InvalidHeaderValueException e) { - Log.w(TAG, e); - } - } -} diff --git a/app/src/main/java/org/tm/archive/mms/IncomingMessage.kt b/app/src/main/java/org/tm/archive/mms/IncomingMessage.kt index 79ee9196..3003ca30 100644 --- a/app/src/main/java/org/tm/archive/mms/IncomingMessage.kt +++ b/app/src/main/java/org/tm/archive/mms/IncomingMessage.kt @@ -8,7 +8,9 @@ import org.tm.archive.database.model.ParentStoryId import org.tm.archive.database.model.StoryType import org.tm.archive.database.model.databaseprotos.BodyRangeList import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription import org.tm.archive.database.model.databaseprotos.GiftBadge +import org.tm.archive.database.model.databaseprotos.MessageExtras import org.tm.archive.groups.GroupId import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.recipients.RecipientId @@ -36,7 +38,8 @@ class IncomingMessage( sharedContacts: List = emptyList(), linkPreviews: List = emptyList(), mentions: List = emptyList(), - val giftBadge: GiftBadge? = null + val giftBadge: GiftBadge? = null, + val messageExtras: MessageExtras? = null ) { val attachments: List = ArrayList(attachments) @@ -94,7 +97,7 @@ class IncomingMessage( } @JvmStatic - fun groupUpdate(from: RecipientId, timestamp: Long, groupId: GroupId, groupContext: DecryptedGroupV2Context): IncomingMessage { + fun groupUpdate(from: RecipientId, timestamp: Long, groupId: GroupId, groupContext: DecryptedGroupV2Context, serverGuid: String?): IncomingMessage { val messageGroupContext = MessageGroupContext(groupContext) return IncomingMessage( @@ -104,8 +107,8 @@ class IncomingMessage( serverTimeMillis = timestamp, groupId = groupId, groupContext = messageGroupContext, - body = messageGroupContext.encodedGroupContext, - type = MessageType.GROUP_UPDATE + type = MessageType.GROUP_UPDATE, + messageExtras = MessageExtras(gv2UpdateDescription = GV2UpdateDescription(gv2ChangeDescription = groupContext, groupChangeUpdate = null)) ) } } diff --git a/app/src/main/java/org/tm/archive/mms/IncomingMmsConnection.java b/app/src/main/java/org/tm/archive/mms/IncomingMmsConnection.java deleted file mode 100644 index 27d2f285..00000000 --- a/app/src/main/java/org/tm/archive/mms/IncomingMmsConnection.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.tm.archive.mms; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.android.mms.pdu_alt.RetrieveConf; - -import java.io.IOException; - -public interface IncomingMmsConnection { - @Nullable - RetrieveConf retrieve(@NonNull String contentLocation, byte[] transactionId, int subscriptionId) throws MmsException, MmsRadioException, ApnUnavailableException, IOException; -} diff --git a/app/src/main/java/org/tm/archive/mms/LegacyMmsConnection.java b/app/src/main/java/org/tm/archive/mms/LegacyMmsConnection.java deleted file mode 100644 index 5351ecca..00000000 --- a/app/src/main/java/org/tm/archive/mms/LegacyMmsConnection.java +++ /dev/null @@ -1,313 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; - -import org.apache.http.Header; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.NoConnectionReuseStrategyHC4; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.client.LaxRedirectStrategy; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.message.BasicHeader; -import org.signal.core.util.StreamUtil; -import org.signal.core.util.logging.Log; -import org.tm.archive.database.ApnDatabase; -import org.tm.archive.util.ServiceUtil; -import org.tm.archive.util.TelephonyUtil; -import org.tm.archive.util.TextSecurePreferences; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.URL; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -@SuppressWarnings("deprecation") -public abstract class LegacyMmsConnection { - - public static final String USER_AGENT = "Android-Mms/2.0"; - - private static final String TAG = Log.tag(LegacyMmsConnection.class); - - protected final Context context; - protected final Apn apn; - - protected LegacyMmsConnection(Context context) throws ApnUnavailableException { - this.context = context; - this.apn = getApn(context); - } - - public static Apn getApn(Context context) throws ApnUnavailableException { - - try { - Optional params = ApnDatabase.getInstance(context) - .getMmsConnectionParameters(TelephonyUtil.getMccMnc(context), - TelephonyUtil.getApn(context)); - - if (!params.isPresent()) { - throw new ApnUnavailableException("No parameters available from ApnDefaults."); - } - - return params.get(); - } catch (IOException ioe) { - throw new ApnUnavailableException("ApnDatabase threw an IOException", ioe); - } - } - - protected boolean isDirectConnect() { - // We think Sprint supports direct connection over wifi/data, but not Verizon - Set sprintMccMncs = new HashSet() {{ - add("312530"); - add("311880"); - add("311870"); - add("311490"); - add("310120"); - add("316010"); - add("312190"); - }}; - - return ServiceUtil.getTelephonyManager(context).getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA && - sprintMccMncs.contains(TelephonyUtil.getMccMnc(context)); - } - - @SuppressWarnings("TryWithIdenticalCatches") - protected static boolean checkRouteToHost(Context context, String host, boolean usingMmsRadio) - throws IOException - { - InetAddress inetAddress = InetAddress.getByName(host); - if (!usingMmsRadio) { - if (inetAddress.isSiteLocalAddress()) { - throw new IOException("RFC1918 address in non-MMS radio situation!"); - } - Log.w(TAG, "returning vacuous success since MMS radio is not in use"); - return true; - } - - if (inetAddress == null) { - throw new IOException("Unable to lookup host: InetAddress.getByName() returned null."); - } - - byte[] ipAddressBytes = inetAddress.getAddress(); - if (ipAddressBytes == null) { - Log.w(TAG, "resolved IP address bytes are null, returning true to attempt a connection anyway."); - return true; - } - - Log.i(TAG, "Checking route to address: " + host + ", " + inetAddress.getHostAddress()); - ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); - - try { - final Method requestRouteMethod = manager.getClass().getMethod("requestRouteToHostAddress", Integer.TYPE, InetAddress.class); - final boolean routeToHostObtained = (Boolean) requestRouteMethod.invoke(manager, MmsRadio.TYPE_MOBILE_MMS, inetAddress); - Log.i(TAG, "requestRouteToHostAddress(" + inetAddress + ") -> " + routeToHostObtained); - return routeToHostObtained; - } catch (NoSuchMethodException nsme) { - Log.w(TAG, nsme); - } catch (IllegalAccessException iae) { - Log.w(TAG, iae); - } catch (InvocationTargetException ite) { - Log.w(TAG, ite); - } - - return false; - } - - protected static byte[] parseResponse(InputStream is) throws IOException { - InputStream in = new BufferedInputStream(is); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StreamUtil.copy(in, baos); - - Log.i(TAG, "Received full server response, " + baos.size() + " bytes"); - - return baos.toByteArray(); - } - - protected CloseableHttpClient constructHttpClient() throws IOException { - RequestConfig config = RequestConfig.custom() - .setConnectTimeout(20 * 1000) - .setConnectionRequestTimeout(20 * 1000) - .setSocketTimeout(20 * 1000) - .setMaxRedirects(20) - .build(); - - URL mmsc = new URL(apn.getMmsc()); - CredentialsProvider credsProvider = new BasicCredentialsProvider(); - - if (apn.hasAuthentication()) { - credsProvider.setCredentials(new AuthScope(mmsc.getHost(), mmsc.getPort() > -1 ? mmsc.getPort() : mmsc.getDefaultPort()), - new UsernamePasswordCredentials(apn.getUsername(), apn.getPassword())); - } - - return HttpClients.custom() - .setConnectionReuseStrategy(new NoConnectionReuseStrategyHC4()) - .setRedirectStrategy(new LaxRedirectStrategy()) - .setUserAgent(TextSecurePreferences.getMmsUserAgent(context, USER_AGENT)) - .setConnectionManager(new BasicHttpClientConnectionManager()) - .setDefaultRequestConfig(config) - .setDefaultCredentialsProvider(credsProvider) - .build(); - } - - protected byte[] execute(HttpUriRequest request) throws IOException { - Log.i(TAG, "connecting to " + apn.getMmsc()); - - CloseableHttpClient client = null; - CloseableHttpResponse response = null; - try { - client = constructHttpClient(); - response = client.execute(request); - - Log.i(TAG, "* response code: " + response.getStatusLine()); - - if (response.getStatusLine().getStatusCode() == 200) { - return parseResponse(response.getEntity().getContent()); - } - } catch (NullPointerException npe) { - // TODO determine root cause - // see: https://github.com/signalapp/Signal-Android/issues/4379 - throw new IOException(npe); - } finally { - if (response != null) response.close(); - if (client != null) client.close(); - } - - throw new IOException("unhandled response code"); - } - - protected List
getBaseHeaders() { - final String number = getLine1Number(context); - - return new LinkedList
() {{ - add(new BasicHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic")); - add(new BasicHeader("x-wap-profile", "http://www.google.com/oha/rdf/ua-profile-kila.xml")); - add(new BasicHeader("Content-Type", "application/vnd.wap.mms-message")); - add(new BasicHeader("x-carrier-magic", "http://magic.google.com")); - if (!TextUtils.isEmpty(number)) { - add(new BasicHeader("x-up-calling-line-id", number)); - add(new BasicHeader("X-MDN", number)); - } - }}; - } - - @SuppressLint("HardwareIds") - private static String getLine1Number(@NonNull Context context) { - if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED || - ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED || - ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { - return TelephonyUtil.getManager(context).getLine1Number(); - } else { - return ""; - } - } - - public static class Apn { - - public static Apn EMPTY = new Apn("", "", "", "", ""); - - private final String mmsc; - private final String proxy; - private final String port; - private final String username; - private final String password; - - public Apn(String mmsc, String proxy, String port, String username, String password) { - this.mmsc = mmsc; - this.proxy = proxy; - this.port = port; - this.username = username; - this.password = password; - } - - public Apn(Apn customApn, Apn defaultApn, - boolean useCustomMmsc, - boolean useCustomProxy, - boolean useCustomProxyPort, - boolean useCustomUsername, - boolean useCustomPassword) - { - this.mmsc = useCustomMmsc ? customApn.mmsc : defaultApn.mmsc; - this.proxy = useCustomProxy ? customApn.proxy : defaultApn.proxy; - this.port = useCustomProxyPort ? customApn.port : defaultApn.port; - this.username = useCustomUsername ? customApn.username : defaultApn.username; - this.password = useCustomPassword ? customApn.password : defaultApn.password; - } - - public boolean hasProxy() { - return !TextUtils.isEmpty(proxy); - } - - public String getMmsc() { - return mmsc; - } - - public String getProxy() { - return hasProxy() ? proxy : null; - } - - public int getPort() { - return TextUtils.isEmpty(port) ? 80 : Integer.parseInt(port); - } - - public boolean hasAuthentication() { - return !TextUtils.isEmpty(username); - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - @Override - public @NonNull String toString() { - return Log.tag(Apn.class) + - "{ mmsc: \"" + mmsc + "\"" + - ", proxy: " + (proxy == null ? "none" : '"' + proxy + '"') + - ", port: " + (port == null ? "(none)" : port) + - ", user: " + (username == null ? "none" : '"' + username + '"') + - ", pass: " + (password == null ? "none" : '"' + password + '"') + " }"; - } - } -} diff --git a/app/src/main/java/org/tm/archive/mms/LollipopMmsConnection.java b/app/src/main/java/org/tm/archive/mms/LollipopMmsConnection.java deleted file mode 100644 index f2bf9aa5..00000000 --- a/app/src/main/java/org/tm/archive/mms/LollipopMmsConnection.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (C) 2015 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; - -import org.signal.core.util.PendingIntentFlags; -import org.signal.core.util.logging.Log; -import org.tm.archive.util.Util; - -import java.util.concurrent.TimeoutException; - -public abstract class LollipopMmsConnection extends BroadcastReceiver { - private static final String TAG = Log.tag(LollipopMmsConnection.class); - - private final Context context; - private final String action; - - private boolean resultAvailable; - - public abstract void onResult(Context context, Intent intent); - - protected LollipopMmsConnection(Context context, String action) { - super(); - this.context = context; - this.action = action; - } - - @Override - public synchronized void onReceive(Context context, Intent intent) { - Log.i(TAG, "onReceive()"); - if (!action.equals(intent.getAction())) { - Log.w(TAG, "received broadcast with unexpected action " + intent.getAction()); - return; - } - - onResult(context, intent); - - resultAvailable = true; - notifyAll(); - } - - protected void beginTransaction() { - getContext().getApplicationContext().registerReceiver(this, new IntentFilter(action)); - } - - protected void endTransaction() { - getContext().getApplicationContext().unregisterReceiver(this); - resultAvailable = false; - } - - protected void waitForResult() throws TimeoutException { - long timeoutExpiration = System.currentTimeMillis() + 60000; - while (!resultAvailable) { - Util.wait(this, Math.max(1, timeoutExpiration - System.currentTimeMillis())); - if (System.currentTimeMillis() >= timeoutExpiration) { - throw new TimeoutException("timeout when waiting for MMS"); - } - } - } - - protected PendingIntent getPendingIntent() { - return PendingIntent.getBroadcast(getContext(), 1, new Intent(action), PendingIntentFlags.oneShot()); - } - - protected Context getContext() { - return context; - } -} diff --git a/app/src/main/java/org/tm/archive/mms/MediaConstraints.java b/app/src/main/java/org/tm/archive/mms/MediaConstraints.java index c590f6cd..8b18dd31 100644 --- a/app/src/main/java/org/tm/archive/mms/MediaConstraints.java +++ b/app/src/main/java/org/tm/archive/mms/MediaConstraints.java @@ -17,6 +17,7 @@ import org.tm.archive.util.BitmapUtil; import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.MediaUtil; import org.tm.archive.util.MemoryFileDescriptor; +import org.tm.archive.video.TranscodingPreset; import java.io.IOException; import java.io.InputStream; @@ -32,14 +33,14 @@ public abstract class MediaConstraints { return new PushMediaConstraints(sentMediaQuality); } - public static MediaConstraints getMmsMediaConstraints(int subscriptionId) { - return new MmsMediaConstraints(subscriptionId); - } - public abstract int getImageMaxWidth(Context context); public abstract int getImageMaxHeight(Context context); public abstract int getImageMaxSize(Context context); + public TranscodingPreset getVideoTranscodingSettings() { + return TranscodingPreset.LEVEL_1; + } + public boolean isHighQuality() { return false; } diff --git a/app/src/main/java/org/tm/archive/mms/MediaNotFoundException.java b/app/src/main/java/org/tm/archive/mms/MediaNotFoundException.java deleted file mode 100644 index 057078b2..00000000 --- a/app/src/main/java/org/tm/archive/mms/MediaNotFoundException.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -public class MediaNotFoundException extends Exception { - - public MediaNotFoundException() { - } - - public MediaNotFoundException(String detailMessage) { - super(detailMessage); - } - - public MediaNotFoundException(Throwable throwable) { - super(throwable); - } - - public MediaNotFoundException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } - -} diff --git a/app/src/main/java/org/tm/archive/mms/MediaTooLargeException.java b/app/src/main/java/org/tm/archive/mms/MediaTooLargeException.java deleted file mode 100644 index 6c699433..00000000 --- a/app/src/main/java/org/tm/archive/mms/MediaTooLargeException.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -public class MediaTooLargeException extends Exception { - - public MediaTooLargeException() { - // TODO Auto-generated constructor stub - } - - public MediaTooLargeException(String detailMessage) { - super(detailMessage); - // TODO Auto-generated constructor stub - } - - public MediaTooLargeException(Throwable throwable) { - super(throwable); - // TODO Auto-generated constructor stub - } - - public MediaTooLargeException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - // TODO Auto-generated constructor stub - } - -} diff --git a/app/src/main/java/org/tm/archive/mms/MessageGroupContext.java b/app/src/main/java/org/tm/archive/mms/MessageGroupContext.java index 64faac43..3e610840 100644 --- a/app/src/main/java/org/tm/archive/mms/MessageGroupContext.java +++ b/app/src/main/java/org/tm/archive/mms/MessageGroupContext.java @@ -11,6 +11,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedMember; import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context; +import org.tm.archive.database.model.databaseprotos.MessageExtras; import org.tm.archive.messages.SignalServiceProtoUtil; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; @@ -30,7 +31,6 @@ import java.util.List; */ public final class MessageGroupContext { - @NonNull private final String encodedGroupContext; @NonNull private final GroupProperties group; @Nullable private final GroupV1Properties groupV1; @Nullable private final GroupV2Properties groupV2; @@ -38,7 +38,6 @@ public final class MessageGroupContext { public MessageGroupContext(@NonNull String encodedGroupContext, boolean v2) throws IOException { - this.encodedGroupContext = encodedGroupContext; if (v2) { this.groupV1 = null; this.groupV2 = new GroupV2Properties(DecryptedGroupV2Context.ADAPTER.decode(Base64.decode(encodedGroupContext))); @@ -50,15 +49,25 @@ public final class MessageGroupContext { } } + public MessageGroupContext(@NonNull MessageExtras messageExtras, boolean v2) { + if (v2) { + this.groupV1 = null; + this.groupV2 = new GroupV2Properties(messageExtras.gv2UpdateDescription.gv2ChangeDescription); + this.group = groupV2; + } else { + this.groupV1 = new GroupV1Properties(messageExtras.gv1Context); + this.groupV2 = null; + this.group = groupV1; + } + } + public MessageGroupContext(@NonNull GroupContext group) { - this.encodedGroupContext = Base64.encodeWithPadding(group.encode()); this.groupV1 = new GroupV1Properties(group); this.groupV2 = null; this.group = groupV1; } public MessageGroupContext(@NonNull DecryptedGroupV2Context group) { - this.encodedGroupContext = Base64.encodeWithPadding(group.encode()); this.groupV1 = null; this.groupV2 = new GroupV2Properties(group); this.group = groupV2; @@ -82,10 +91,6 @@ public final class MessageGroupContext { return groupV2 != null; } - public @NonNull String getEncodedGroupContext() { - return encodedGroupContext; - } - public String getName() { return group.getName(); } diff --git a/app/src/main/java/org/tm/archive/mms/MmsConfigManager.java b/app/src/main/java/org/tm/archive/mms/MmsConfigManager.java deleted file mode 100644 index 935c902e..00000000 --- a/app/src/main/java/org/tm/archive/mms/MmsConfigManager.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.tm.archive.mms; - - -import android.content.Context; -import android.content.res.Configuration; - -import androidx.annotation.NonNull; -import androidx.annotation.WorkerThread; - -import com.android.mms.service_alt.MmsConfig; - -import org.tm.archive.util.dualsim.SubscriptionInfoCompat; -import org.tm.archive.util.dualsim.SubscriptionManagerCompat; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -final class MmsConfigManager { - - private static final Map mmsConfigMap = new HashMap<>(); - - @WorkerThread - synchronized static @NonNull MmsConfig getMmsConfig(Context context, int subscriptionId) { - MmsConfig mmsConfig = mmsConfigMap.get(subscriptionId); - if (mmsConfig != null) { - return mmsConfig; - } - - MmsConfig loadedConfig = loadMmsConfig(context, subscriptionId); - - mmsConfigMap.put(subscriptionId, loadedConfig); - - return loadedConfig; - } - - private static @NonNull MmsConfig loadMmsConfig(Context context, int subscriptionId) { - Optional subscriptionInfo = new SubscriptionManagerCompat(context).getActiveSubscriptionInfo(subscriptionId); - - if (subscriptionInfo.isPresent()) { - SubscriptionInfoCompat subscriptionInfoCompat = subscriptionInfo.get(); - Configuration configuration = context.getResources().getConfiguration(); - configuration.mcc = subscriptionInfoCompat.getMcc(); - configuration.mnc = subscriptionInfoCompat.getMnc(); - - Context subContext = context.createConfigurationContext(configuration); - return new MmsConfig(subContext, subscriptionId); - } - - return new MmsConfig(context, subscriptionId); - } - -} diff --git a/app/src/main/java/org/tm/archive/mms/MmsMediaConstraints.java b/app/src/main/java/org/tm/archive/mms/MmsMediaConstraints.java deleted file mode 100644 index 13730277..00000000 --- a/app/src/main/java/org/tm/archive/mms/MmsMediaConstraints.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.tm.archive.mms; - -import android.content.Context; - -import com.android.mms.service_alt.MmsConfig; - -final class MmsMediaConstraints extends MediaConstraints { - - private final int subscriptionId; - - private static final int MIN_IMAGE_DIMEN = 1024; - - MmsMediaConstraints(int subscriptionId) { - this.subscriptionId = subscriptionId; - } - - @Override - public int getImageMaxWidth(Context context) { - return Math.max(MIN_IMAGE_DIMEN, getOverriddenMmsConfig(context).getMaxImageWidth()); - } - - @Override - public int getImageMaxHeight(Context context) { - return Math.max(MIN_IMAGE_DIMEN, getOverriddenMmsConfig(context).getMaxImageHeight()); - } - - @Override - public int[] getImageDimensionTargets(Context context) { - int[] targets = new int[4]; - - targets[0] = getImageMaxHeight(context); - - for (int i = 1; i < targets.length; i++) { - targets[i] = targets[i - 1] / 2; - } - - return targets; - } - - @Override - public int getImageMaxSize(Context context) { - return getMaxMessageSize(context); - } - - @Override - public long getGifMaxSize(Context context) { - return getMaxMessageSize(context); - } - - @Override - public long getVideoMaxSize(Context context) { - return getMaxMessageSize(context); - } - - @Override - public long getUncompressedVideoMaxSize(Context context) { - return Math.max(getVideoMaxSize(context), 15 * 1024 * 1024); - } - - @Override - public long getAudioMaxSize(Context context) { - return getMaxMessageSize(context); - } - - @Override - public long getDocumentMaxSize(Context context) { - return getMaxMessageSize(context); - } - - private int getMaxMessageSize(Context context) { - return getOverriddenMmsConfig(context).getMaxMessageSize(); - } - - private MmsConfig.Overridden getOverriddenMmsConfig(Context context) { - MmsConfig mmsConfig = MmsConfigManager.getMmsConfig(context, subscriptionId); - - return new MmsConfig.Overridden(mmsConfig, null); - } -} diff --git a/app/src/main/java/org/tm/archive/mms/MmsRadio.java b/app/src/main/java/org/tm/archive/mms/MmsRadio.java deleted file mode 100644 index 0285cd0a..00000000 --- a/app/src/main/java/org/tm/archive/mms/MmsRadio.java +++ /dev/null @@ -1,165 +0,0 @@ -package org.tm.archive.mms; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.PowerManager; - -import org.signal.core.util.logging.Log; -import org.tm.archive.util.Util; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class MmsRadio { - - private static final String TAG = Log.tag(MmsRadio.class); - - private static MmsRadio instance; - - public static synchronized MmsRadio getInstance(Context context) { - if (instance == null) - instance = new MmsRadio(context.getApplicationContext()); - - return instance; - } - - /// - - private static final String FEATURE_ENABLE_MMS = "enableMMS"; - private static final int APN_ALREADY_ACTIVE = 0; - public static final int TYPE_MOBILE_MMS = 2; - - private final Context context; - - private ConnectivityManager connectivityManager; - private ConnectivityListener connectivityListener; - private PowerManager.WakeLock wakeLock; - private int connectedCounter = 0; - - private MmsRadio(Context context) { - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - this.context = context; - this.connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "signal:mms"); - this.wakeLock.setReferenceCounted(true); - } - - public synchronized void disconnect() { - Log.i(TAG, "MMS Radio Disconnect Called..."); - wakeLock.release(); - connectedCounter--; - - Log.i(TAG, "Reference count: " + connectedCounter); - - if (connectedCounter == 0) { - Log.i(TAG, "Turning off MMS radio..."); - try { - final Method stopUsingNetworkFeatureMethod = connectivityManager.getClass().getMethod("stopUsingNetworkFeature", Integer.TYPE, String.class); - stopUsingNetworkFeatureMethod.invoke(connectivityManager, ConnectivityManager.TYPE_MOBILE, FEATURE_ENABLE_MMS); - } catch (NoSuchMethodException nsme) { - Log.w(TAG, nsme); - } catch (IllegalAccessException iae) { - Log.w(TAG, iae); - } catch (InvocationTargetException ite) { - Log.w(TAG, ite); - } - - if (connectivityListener != null) { - Log.i(TAG, "Unregistering receiver..."); - context.unregisterReceiver(connectivityListener); - connectivityListener = null; - } - } - } - - public synchronized void connect() throws MmsRadioException { - int status; - - try { - final Method startUsingNetworkFeatureMethod = connectivityManager.getClass().getMethod("startUsingNetworkFeature", Integer.TYPE, String.class); - status = (int)startUsingNetworkFeatureMethod.invoke(connectivityManager, ConnectivityManager.TYPE_MOBILE, FEATURE_ENABLE_MMS); - } catch (NoSuchMethodException nsme) { - throw new MmsRadioException(nsme); - } catch (IllegalAccessException iae) { - throw new MmsRadioException(iae); - } catch (InvocationTargetException ite) { - throw new MmsRadioException(ite); - } - - Log.i(TAG, "startUsingNetworkFeature status: " + status); - - if (status == APN_ALREADY_ACTIVE) { - wakeLock.acquire(); - connectedCounter++; - return; - } else { - wakeLock.acquire(); - connectedCounter++; - - if (connectivityListener == null) { - IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - connectivityListener = new ConnectivityListener(); - context.registerReceiver(connectivityListener, filter); - } - - Util.wait(this, 30000); - - if (!isConnected()) { - Log.w(TAG, "Got back from connectivity wait, and not connected..."); - disconnect(); - throw new MmsRadioException("Unable to successfully enable MMS radio."); - } - } - } - - private boolean isConnected() { - NetworkInfo info = connectivityManager.getNetworkInfo(TYPE_MOBILE_MMS); - - Log.i(TAG, "Connected: " + info); - - if ((info == null) || (info.getType() != TYPE_MOBILE_MMS) || !info.isConnected()) - return false; - - return true; - } - - private boolean isConnectivityPossible() { - NetworkInfo networkInfo = connectivityManager.getNetworkInfo(TYPE_MOBILE_MMS); - - return networkInfo != null && networkInfo.isAvailable(); - } - - private boolean isConnectivityFailure() { - NetworkInfo networkInfo = connectivityManager.getNetworkInfo(TYPE_MOBILE_MMS); - - return networkInfo == null || networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED; - } - - private synchronized void issueConnectivityChange() { - if (isConnected()) { - Log.i(TAG, "Notifying connected..."); - notifyAll(); - return; - } - - if (!isConnected() && (isConnectivityFailure() || !isConnectivityPossible())) { - Log.i(TAG, "Notifying not connected..."); - notifyAll(); - return; - } - } - - private class ConnectivityListener extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Got connectivity change..."); - issueConnectivityChange(); - } - } - - -} diff --git a/app/src/main/java/org/tm/archive/mms/MmsRadioException.java b/app/src/main/java/org/tm/archive/mms/MmsRadioException.java deleted file mode 100644 index dfef6cf0..00000000 --- a/app/src/main/java/org/tm/archive/mms/MmsRadioException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.tm.archive.mms; - -public class MmsRadioException extends Throwable { - public MmsRadioException(String s) { - super(s); - } - - public MmsRadioException(Exception e) { - super(e); - } -} diff --git a/app/src/main/java/org/tm/archive/mms/MmsSendResult.java b/app/src/main/java/org/tm/archive/mms/MmsSendResult.java deleted file mode 100644 index fc42e928..00000000 --- a/app/src/main/java/org/tm/archive/mms/MmsSendResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.tm.archive.mms; - -public class MmsSendResult { - - private final byte[] messageId; - private final int responseStatus; - - public MmsSendResult(byte[] messageId, int responseStatus) { - this.messageId = messageId; - this.responseStatus = responseStatus; - } - - public int getResponseStatus() { - return responseStatus; - } - - public byte[] getMessageId() { - return messageId; - } -} diff --git a/app/src/main/java/org/tm/archive/mms/OutgoingLegacyMmsConnection.java b/app/src/main/java/org/tm/archive/mms/OutgoingLegacyMmsConnection.java deleted file mode 100644 index d6ab8d68..00000000 --- a/app/src/main/java/org/tm/archive/mms/OutgoingLegacyMmsConnection.java +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Copyright (C) 2015 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.android.mms.pdu_alt.PduParser; -import com.google.android.mms.pdu_alt.SendConf; - -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpPostHC4; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.ByteArrayEntityHC4; -import org.signal.core.util.logging.Log; -import org.tm.archive.transport.UndeliverableMessageException; - -import java.io.IOException; - - -@SuppressWarnings("deprecation") -public class OutgoingLegacyMmsConnection extends LegacyMmsConnection implements OutgoingMmsConnection { - private final static String TAG = Log.tag(OutgoingLegacyMmsConnection.class); - - public OutgoingLegacyMmsConnection(Context context) throws ApnUnavailableException { - super(context); - } - - private HttpUriRequest constructRequest(byte[] pduBytes, boolean useProxy) - throws IOException - { - try { - HttpPostHC4 request = new HttpPostHC4(apn.getMmsc()); - for (Header header : getBaseHeaders()) { - request.addHeader(header); - } - - request.setEntity(new ByteArrayEntityHC4(pduBytes)); - if (useProxy) { - HttpHost proxy = new HttpHost(apn.getProxy(), apn.getPort()); - request.setConfig(RequestConfig.custom().setProxy(proxy).build()); - } - return request; - } catch (IllegalArgumentException iae) { - throw new IOException(iae); - } - } - - public void sendNotificationReceived(byte[] pduBytes, boolean usingMmsRadio, boolean useProxyIfAvailable) - throws IOException - { - sendBytes(pduBytes, usingMmsRadio, useProxyIfAvailable); - } - - @Override - public @Nullable SendConf send(@NonNull byte[] pduBytes, int subscriptionId) throws UndeliverableMessageException { - try { - MmsRadio radio = MmsRadio.getInstance(context); - - if (isDirectConnect()) { - Log.i(TAG, "Sending MMS directly without radio change..."); - try { - return send(pduBytes, false, false); - } catch (IOException e) { - Log.w(TAG, e); - } - } - - Log.i(TAG, "Sending MMS with radio change and proxy..."); - radio.connect(); - - try { - try { - return send(pduBytes, true, true); - } catch (IOException e) { - Log.w(TAG, e); - } - - Log.i(TAG, "Sending MMS with radio change and without proxy..."); - - try { - return send(pduBytes, true, false); - } catch (IOException ioe) { - Log.w(TAG, ioe); - throw new UndeliverableMessageException(ioe); - } - } finally { - radio.disconnect(); - } - - } catch (MmsRadioException e) { - Log.w(TAG, e); - throw new UndeliverableMessageException(e); - } - - } - - private SendConf send(byte[] pduBytes, boolean useMmsRadio, boolean useProxyIfAvailable) throws IOException { - byte[] response = sendBytes(pduBytes, useMmsRadio, useProxyIfAvailable); - return (SendConf) new PduParser(response).parse(); - } - - private byte[] sendBytes(byte[] pduBytes, boolean useMmsRadio, boolean useProxyIfAvailable) throws IOException { - final boolean useProxy = useProxyIfAvailable && apn.hasProxy(); - final String targetHost = useProxy - ? apn.getProxy() - : Uri.parse(apn.getMmsc()).getHost(); - - Log.i(TAG, "Sending MMS of length: " + pduBytes.length - + (useMmsRadio ? ", using mms radio" : "") - + (useProxy ? ", using proxy" : "")); - - try { - if (checkRouteToHost(context, targetHost, useMmsRadio)) { - Log.i(TAG, "got successful route to host " + targetHost); - byte[] response = execute(constructRequest(pduBytes, useProxy)); - if (response != null) return response; - } - } catch (IOException ioe) { - Log.w(TAG, ioe); - } - throw new IOException("Connection manager could not obtain route to host."); - } - - - public static boolean isConnectionPossible(Context context) { - try { - ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = connectivityManager.getNetworkInfo(MmsRadio.TYPE_MOBILE_MMS); - if (networkInfo == null) { - Log.w(TAG, "MMS network info was null, unsupported by this device"); - return false; - } - - getApn(context); - return true; - } catch (ApnUnavailableException e) { - Log.w(TAG, e); - return false; - } - } -} diff --git a/app/src/main/java/org/tm/archive/mms/OutgoingLollipopMmsConnection.java b/app/src/main/java/org/tm/archive/mms/OutgoingLollipopMmsConnection.java deleted file mode 100644 index 123b6170..00000000 --- a/app/src/main/java/org/tm/archive/mms/OutgoingLollipopMmsConnection.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (C) 2015 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.mms; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.telephony.SmsManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.mms.service_alt.MmsConfig; -import com.google.android.mms.pdu_alt.PduParser; -import com.google.android.mms.pdu_alt.SendConf; - -import org.signal.core.util.StreamUtil; -import org.signal.core.util.logging.Log; -import org.tm.archive.providers.MmsBodyProvider; -import org.tm.archive.transport.UndeliverableMessageException; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.concurrent.TimeoutException; - -public class OutgoingLollipopMmsConnection extends LollipopMmsConnection implements OutgoingMmsConnection { - private static final String TAG = Log.tag(OutgoingLollipopMmsConnection.class); - private static final String ACTION = OutgoingLollipopMmsConnection.class.getCanonicalName() + "MMS_SENT_ACTION"; - - private byte[] response; - - public OutgoingLollipopMmsConnection(Context context) { - super(context, ACTION); - } - - @TargetApi(22) - @Override - public synchronized void onResult(Context context, Intent intent) { - if (VERSION.SDK_INT >= 22) { - Log.i(TAG, "HTTP status: " + intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, -1)); - } - - response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA); - } - - @Override - public @Nullable synchronized SendConf send(@NonNull byte[] pduBytes, int subscriptionId) - throws UndeliverableMessageException - { - beginTransaction(); - try { - MmsBodyProvider.Pointer pointer = MmsBodyProvider.makeTemporaryPointer(getContext()); - StreamUtil.copy(new ByteArrayInputStream(pduBytes), pointer.getOutputStream()); - - SmsManager smsManager; - - if (VERSION.SDK_INT >= 22 && subscriptionId != -1) { - smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId); - } else { - smsManager = SmsManager.getDefault(); - } - - Bundle configOverrides = new Bundle(); - configOverrides.putBoolean(SmsManager.MMS_CONFIG_GROUP_MMS_ENABLED, true); - - MmsConfig mmsConfig = MmsConfigManager.getMmsConfig(getContext(), subscriptionId); - - if (mmsConfig != null) { - MmsConfig.Overridden overridden = new MmsConfig.Overridden(mmsConfig, new Bundle()); - configOverrides.putString(SmsManager.MMS_CONFIG_HTTP_PARAMS, overridden.getHttpParams()); - configOverrides.putInt(SmsManager.MMS_CONFIG_MAX_MESSAGE_SIZE, overridden.getMaxMessageSize()); - } - - smsManager.sendMultimediaMessage(getContext(), - pointer.getUri(), - null, - configOverrides, - getPendingIntent()); - - waitForResult(); - - Log.i(TAG, "MMS broadcast received and processed."); - pointer.close(); - - if (response == null) { - throw new UndeliverableMessageException("Null response."); - } - - return (SendConf) new PduParser(response).parse(); - } catch (IOException | TimeoutException e) { - throw new UndeliverableMessageException(e); - } finally { - endTransaction(); - } - } -} - diff --git a/app/src/main/java/org/tm/archive/mms/OutgoingMessage.kt b/app/src/main/java/org/tm/archive/mms/OutgoingMessage.kt index 954c9ccd..c9d51d8f 100644 --- a/app/src/main/java/org/tm/archive/mms/OutgoingMessage.kt +++ b/app/src/main/java/org/tm/archive/mms/OutgoingMessage.kt @@ -9,8 +9,9 @@ import org.tm.archive.database.model.Mention import org.tm.archive.database.model.ParentStoryId import org.tm.archive.database.model.StoryType import org.tm.archive.database.model.databaseprotos.BodyRangeList -import org.tm.archive.database.model.databaseprotos.DecryptedGroupV2Context +import org.tm.archive.database.model.databaseprotos.GV2UpdateDescription import org.tm.archive.database.model.databaseprotos.GiftBadge +import org.tm.archive.database.model.databaseprotos.MessageExtras import org.tm.archive.linkpreview.LinkPreview import org.tm.archive.recipients.Recipient import org.tm.archive.sms.GroupV2UpdateMessageUtil @@ -50,7 +51,10 @@ data class OutgoingMessage( val isIdentityVerified: Boolean = false, val isIdentityDefault: Boolean = false, val scheduledDate: Long = -1, - val messageToEdit: Long = 0 + val messageToEdit: Long = 0, + val isReportSpam: Boolean = false, + val isMessageRequestAccept: Boolean = false, + val messageExtras: MessageExtras? = null ) { val isV2Group: Boolean = messageGroupContext != null && GroupV2UpdateMessageUtil.isGroupV2(messageGroupContext) @@ -226,17 +230,18 @@ data class OutgoingMessage( * Helper for creating a group update message when a state change occurs and needs to be sent to others. */ @JvmStatic - fun groupUpdateMessage(threadRecipient: Recipient, group: DecryptedGroupV2Context, sentTimeMillis: Long): OutgoingMessage { - val groupContext = MessageGroupContext(group) + fun groupUpdateMessage(threadRecipient: Recipient, update: GV2UpdateDescription, sentTimeMillis: Long): OutgoingMessage { + val messageExtras = MessageExtras(gv2UpdateDescription = update) + val groupContext = MessageGroupContext(update.gv2ChangeDescription!!) return OutgoingMessage( threadRecipient = threadRecipient, - body = groupContext.encodedGroupContext, sentTimeMillis = sentTimeMillis, messageGroupContext = groupContext, isGroup = true, isGroupUpdate = true, - isSecure = true + isSecure = true, + messageExtras = messageExtras ) } @@ -258,7 +263,6 @@ data class OutgoingMessage( ): OutgoingMessage { return OutgoingMessage( threadRecipient = threadRecipient, - body = groupContext.encodedGroupContext, isGroup = true, isGroupUpdate = true, messageGroupContext = groupContext, @@ -401,6 +405,30 @@ data class OutgoingMessage( ) } + @JvmStatic + fun reportSpamMessage(threadRecipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { + return OutgoingMessage( + threadRecipient = threadRecipient, + sentTimeMillis = sentTimeMillis, + expiresIn = expiresIn, + isReportSpam = true, + isUrgent = false, + isSecure = true + ) + } + + @JvmStatic + fun messageRequestAcceptMessage(threadRecipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { + return OutgoingMessage( + threadRecipient = threadRecipient, + sentTimeMillis = sentTimeMillis, + expiresIn = expiresIn, + isMessageRequestAccept = true, + isUrgent = false, + isSecure = true + ) + } + @JvmStatic fun buildMessage(slideDeck: SlideDeck, message: String): String { return if (message.isNotEmpty() && slideDeck.body.isNotEmpty()) { diff --git a/app/src/main/java/org/tm/archive/mms/OutgoingMmsConnection.java b/app/src/main/java/org/tm/archive/mms/OutgoingMmsConnection.java deleted file mode 100644 index ac8231cb..00000000 --- a/app/src/main/java/org/tm/archive/mms/OutgoingMmsConnection.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.tm.archive.mms; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.android.mms.pdu_alt.SendConf; - -import org.tm.archive.transport.UndeliverableMessageException; - - -public interface OutgoingMmsConnection { - @Nullable - SendConf send(@NonNull byte[] pduBytes, int subscriptionId) throws UndeliverableMessageException; -} diff --git a/app/src/main/java/org/tm/archive/mms/PartParser.java b/app/src/main/java/org/tm/archive/mms/PartParser.java deleted file mode 100644 index cd440e29..00000000 --- a/app/src/main/java/org/tm/archive/mms/PartParser.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.tm.archive.mms; - -import com.google.android.mms.ContentType; -import com.google.android.mms.pdu_alt.CharacterSets; -import com.google.android.mms.pdu_alt.PduBody; -import com.google.android.mms.pdu_alt.PduPart; - -import org.signal.core.util.logging.Log; -import org.tm.archive.util.Util; - -import java.io.UnsupportedEncodingException; -import java.util.Arrays; -import java.util.List; - - -public class PartParser { - - private static final String TAG = Log.tag(PartParser.class); - private static final List DOCUMENT_TYPES = Arrays.asList("text/vcard", "text/x-vcard"); - - public static String getMessageText(PduBody body) { - String bodyText = null; - - for (int i=0;i(secret, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()))); diff --git a/app/src/main/java/org/tm/archive/mms/SlideFactory.java b/app/src/main/java/org/tm/archive/mms/SlideFactory.java index cf54a0c4..98b621a8 100644 --- a/app/src/main/java/org/tm/archive/mms/SlideFactory.java +++ b/app/src/main/java/org/tm/archive/mms/SlideFactory.java @@ -16,6 +16,7 @@ import org.tm.archive.database.AttachmentTable; import org.tm.archive.util.MediaUtil; import java.io.IOException; +import java.util.Optional; /** * SlideFactory encapsulates logic related to constructing slides from a set of paramaeters as defined @@ -171,7 +172,7 @@ public final class SlideFactory { case IMAGE: return new ImageSlide(context, uri, mimeType, dataSize, width, height, false, null, blurHash, transformProperties); case GIF: return new GifSlide(context, uri, dataSize, width, height); case AUDIO: return new AudioSlide(context, uri, dataSize, false); - case VIDEO: return new VideoSlide(context, uri, dataSize, gif); + case VIDEO: return new VideoSlide(context, uri, dataSize, gif, null, AttachmentTable.TransformProperties.forSentMediaQuality(transformProperties != null ? transformProperties.sentMediaQuality : SentMediaQuality.STANDARD.getCode())); case VCARD: case DOCUMENT: return new DocumentSlide(context, uri, mimeType, dataSize, fileName); default: throw new AssertionError("unrecognized enum"); diff --git a/app/src/main/java/org/tm/archive/net/RemoteDeprecationDetectorInterceptor.java b/app/src/main/java/org/tm/archive/net/RemoteDeprecationDetectorInterceptor.java index be5484b9..a7bd41f9 100644 --- a/app/src/main/java/org/tm/archive/net/RemoteDeprecationDetectorInterceptor.java +++ b/app/src/main/java/org/tm/archive/net/RemoteDeprecationDetectorInterceptor.java @@ -23,7 +23,7 @@ public final class RemoteDeprecationDetectorInterceptor implements Interceptor { if (response.code() == 499 && !SignalStore.misc().isClientDeprecated()) { Log.w(TAG, "Received 499. Client version is deprecated."); - SignalStore.misc().markClientDeprecated(); + SignalStore.misc().setClientDeprecated(true); } return response; diff --git a/app/src/main/java/org/tm/archive/nicknames/NicknameActivity.kt b/app/src/main/java/org/tm/archive/nicknames/NicknameActivity.kt new file mode 100644 index 00000000..6f2c06aa --- /dev/null +++ b/app/src/main/java/org/tm/archive/nicknames/NicknameActivity.kt @@ -0,0 +1,490 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.nicknames + +import android.content.Context +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContract +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.os.bundleOf +import org.signal.core.ui.Buttons +import org.signal.core.ui.Dialogs +import org.signal.core.ui.Previews +import org.signal.core.ui.Scaffolds +import org.signal.core.ui.TextFields +import org.signal.core.ui.theme.SignalTheme +import org.signal.core.util.getParcelableCompat +import org.tm.archive.PassphraseRequiredActivity +import org.tm.archive.R +import org.tm.archive.avatar.AvatarImage +import org.tm.archive.recipients.RecipientId +import org.tm.archive.util.DynamicNoActionBarTheme +import org.tm.archive.util.viewModel + +/** + * Fragment allowing a user to set a custom nickname for the given recipient. + */ +class NicknameActivity : PassphraseRequiredActivity(), NicknameContentCallback { + + private val theme = DynamicNoActionBarTheme() + + private val args: Args by lazy { + Args.fromBundle(intent.extras!!) + } + + private val viewModel: NicknameViewModel by viewModel { + NicknameViewModel(args.recipientId) + } + + override fun onPreCreate() { + theme.onCreate(this) + } + + override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { + setContent { + val state by viewModel.state + + LaunchedEffect(state.formState) { + if (state.formState == NicknameState.FormState.SAVED) { + supportFinishAfterTransition() + } + } + + SignalTheme { + NicknameContent( + callback = remember { this }, + state = state, + focusNoteFirst = args.focusNoteFirst + ) + } + } + } + + override fun onResume() { + super.onResume() + theme.onResume(this) + } + + override fun onNavigationClick() { + supportFinishAfterTransition() + } + + override fun onSaveClick() { + viewModel.save() + } + + override fun onDeleteClick() { + viewModel.delete() + } + + override fun onFirstNameChanged(value: String) { + viewModel.onFirstNameChanged(value) + } + + override fun onLastNameChanged(value: String) { + viewModel.onLastNameChanged(value) + } + + override fun onNoteChanged(value: String) { + viewModel.onNoteChanged(value) + } + + /** + * @param recipientId The recipient to edit the nickname and note for + * @param focusNoteFirst Whether default focus should be on the edit note field + */ + data class Args( + val recipientId: RecipientId, + val focusNoteFirst: Boolean + ) { + fun toBundle(): Bundle { + return bundleOf( + RECIPIENT_ID to recipientId, + FOCUS_NOTE_FIRST to focusNoteFirst + ) + } + + companion object { + private const val RECIPIENT_ID = "recipient_id" + private const val FOCUS_NOTE_FIRST = "focus_note_first" + + fun fromBundle(bundle: Bundle): Args { + return Args( + recipientId = bundle.getParcelableCompat(RECIPIENT_ID, RecipientId::class.java)!!, + focusNoteFirst = bundle.getBoolean(FOCUS_NOTE_FIRST) + ) + } + } + } + + /** + * Launches the nickname activity with the proper arguments. + * Doesn't return a response, but is a helpful signal to know when to refresh UI. + */ + class Contract : ActivityResultContract() { + override fun createIntent(context: Context, input: Args): Intent { + return Intent(context, NicknameActivity::class.java).putExtras(input.toBundle()) + } + + override fun parseResult(resultCode: Int, intent: Intent?) = Unit + } +} + +private interface NicknameContentCallback { + fun onNavigationClick() + fun onSaveClick() + fun onDeleteClick() + fun onFirstNameChanged(value: String) + fun onLastNameChanged(value: String) + fun onNoteChanged(value: String) +} + +@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun NicknameContentPreview() { + Previews.Preview { + val callback = remember { + object : NicknameContentCallback { + override fun onNavigationClick() = Unit + override fun onSaveClick() = Unit + override fun onDeleteClick() = Unit + override fun onFirstNameChanged(value: String) = Unit + override fun onLastNameChanged(value: String) = Unit + override fun onNoteChanged(value: String) = Unit + } + } + + NicknameContent( + callback = callback, + state = NicknameState( + isEditing = true, + note = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temor incididunt ut labore et dolore magna aliqua. Ut enim ad minimu" + ), + focusNoteFirst = false + ) + } +} + +@Composable +private fun NicknameContent( + callback: NicknameContentCallback, + state: NicknameState, + focusNoteFirst: Boolean +) { + var displayDeletionDialog by remember { mutableStateOf(false) } + + Scaffolds.Settings( + title = stringResource(id = R.string.NicknameActivity__nickname), + onNavigationClick = callback::onNavigationClick, + navigationIconPainter = painterResource(id = R.drawable.symbol_arrow_left_24) + ) { paddingValues -> + + val firstNameFocusRequester = remember { FocusRequester() } + val noteFocusRequester = remember { FocusRequester() } + + Column( + modifier = Modifier + .padding(paddingValues) + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + LazyColumn(modifier = Modifier.weight(1f)) { + item { + Text( + text = stringResource(id = R.string.NicknameActivity__nicknames_amp_notes), + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyMedium + ) + } + + item { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 24.dp) + ) { + if (state.recipient != null) { + AvatarImage(recipient = state.recipient, modifier = Modifier.size(80.dp)) + } else { + Spacer(modifier = Modifier.size(80.dp)) + } + } + } + + item { + ClearableTextField( + value = state.firstName, + hint = stringResource(id = R.string.NicknameActivity__first_name), + clearContentDescription = stringResource(id = R.string.NicknameActivity__clear_first_name), + enabled = true, + singleLine = true, + onValueChange = callback::onFirstNameChanged, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + modifier = Modifier + .focusRequester(firstNameFocusRequester) + .fillMaxWidth() + .padding(bottom = 20.dp) + ) + } + + item { + ClearableTextField( + value = state.lastName, + hint = stringResource(id = R.string.NicknameActivity__last_name), + clearContentDescription = stringResource(id = R.string.NicknameActivity__clear_last_name), + enabled = true, + singleLine = true, + onValueChange = callback::onLastNameChanged, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 20.dp) + ) + } + + item { + ClearableTextField( + value = state.note, + hint = stringResource(id = R.string.NicknameActivity__note), + clearContentDescription = "", + clearable = false, + enabled = true, + onValueChange = callback::onNoteChanged, + keyboardActions = KeyboardActions.Default, + keyboardOptions = KeyboardOptions.Default, + charactersRemaining = state.noteCharactersRemaining, + modifier = Modifier + .focusRequester(noteFocusRequester) + .fillMaxWidth() + .padding(bottom = 20.dp) + ) + } + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 20.dp) + ) { + if (state.isEditing) { + TextButton( + onClick = { + displayDeletionDialog = true + }, + modifier = Modifier + .align(Alignment.BottomStart) + ) { + Text( + text = stringResource(id = R.string.delete), + color = MaterialTheme.colorScheme.primary + ) + } + } + Buttons.LargeTonal( + onClick = callback::onSaveClick, + enabled = state.canSave, + modifier = Modifier + .align(Alignment.BottomEnd) + ) { + Text( + text = stringResource(id = R.string.NicknameActivity__save) + ) + } + } + } + + if (displayDeletionDialog) { + Dialogs.SimpleAlertDialog( + title = stringResource(id = R.string.NicknameActivity__delete_nickname), + body = stringResource(id = R.string.NicknameActivity__this_will_permanently_delete_this_nickname_and_note), + confirm = stringResource(id = R.string.delete), + dismiss = stringResource(id = android.R.string.cancel), + onConfirm = { + callback.onDeleteClick() + }, + onDismiss = { displayDeletionDialog = false } + ) + } + + LaunchedEffect(state.hasBecomeReady) { + if (state.hasBecomeReady) { + if (focusNoteFirst) { + noteFocusRequester.requestFocus() + } else { + firstNameFocusRequester.requestFocus() + } + } + } + } +} + +@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ClearableTextFieldPreview() { + Previews.Preview { + val focusRequester = remember { FocusRequester() } + + Column(modifier = Modifier.padding(16.dp)) { + ClearableTextField( + value = "", + hint = "Without content", + enabled = true, + onValueChange = {}, + clearContentDescription = "" + ) + Spacer(modifier = Modifier.size(16.dp)) + ClearableTextField( + value = "Test", + hint = "With Content", + enabled = true, + onValueChange = {}, + clearContentDescription = "" + ) + Spacer(modifier = Modifier.size(16.dp)) + ClearableTextField( + value = "", + hint = "Disabled", + enabled = false, + onValueChange = {}, + clearContentDescription = "" + ) + Spacer(modifier = Modifier.size(16.dp)) + ClearableTextField( + value = "", + hint = "Focused", + enabled = true, + onValueChange = {}, + modifier = Modifier.focusRequester(focusRequester), + clearContentDescription = "" + ) + } + + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun ClearableTextField( + value: String, + hint: String, + clearContentDescription: String, + enabled: Boolean, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + singleLine: Boolean = false, + clearable: Boolean = true, + charactersRemaining: Int = Int.MAX_VALUE, + keyboardActions: KeyboardActions = KeyboardActions.Default, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default +) { + var focused by remember { mutableStateOf(false) } + + val displayCountdown = charactersRemaining <= 100 + + val clearButton: @Composable () -> Unit = { + ClearButton( + visible = focused, + onClick = { onValueChange("") }, + contentDescription = clearContentDescription + ) + } + + Box(modifier = modifier) { + TextFields.TextField( + value = value, + onValueChange = onValueChange, + label = { + Text(text = hint) + }, + enabled = enabled, + singleLine = singleLine, + keyboardActions = keyboardActions, + keyboardOptions = keyboardOptions, + modifier = Modifier + .fillMaxWidth() + .onFocusChanged { focused = it.hasFocus && clearable }, + colors = TextFieldDefaults.colors( + unfocusedLabelColor = MaterialTheme.colorScheme.outline, + unfocusedIndicatorColor = MaterialTheme.colorScheme.outline + ), + trailingIcon = if (clearable) clearButton else null, + contentPadding = TextFieldDefaults.contentPaddingWithLabel(end = if (displayCountdown) 48.dp else 16.dp) + ) + + AnimatedVisibility( + visible = displayCountdown, + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(bottom = 10.dp, end = 12.dp) + ) { + Text( + text = "$charactersRemaining", + style = MaterialTheme.typography.bodySmall, + color = if (charactersRemaining <= 5) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.outline + ) + } + } +} + +@Composable +private fun ClearButton( + visible: Boolean, + onClick: () -> Unit, + contentDescription: String +) { + AnimatedVisibility(visible = visible) { + IconButton( + onClick = onClick + ) { + Icon( + painter = painterResource(id = R.drawable.symbol_x_circle_fill_24), + contentDescription = contentDescription, + tint = MaterialTheme.colorScheme.outline + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/nicknames/NicknameState.kt b/app/src/main/java/org/tm/archive/nicknames/NicknameState.kt new file mode 100644 index 00000000..d8badbd6 --- /dev/null +++ b/app/src/main/java/org/tm/archive/nicknames/NicknameState.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.nicknames + +import org.tm.archive.recipients.Recipient + +data class NicknameState( + val recipient: Recipient? = null, + val firstName: String = "", + val lastName: String = "", + val note: String = "", + val noteCharactersRemaining: Int = 0, + val formState: FormState = FormState.LOADING, + val hasBecomeReady: Boolean = false, + val isEditing: Boolean = false +) { + + private val isFormBlank: Boolean = firstName.isBlank() && lastName.isBlank() && note.isBlank() + private val hasNameOrNote: Boolean = firstName.isNotBlank() || lastName.isNotBlank() || note.isNotBlank() + private val isFormReady: Boolean = formState == FormState.READY + private val isBlankFormDuringEdit: Boolean = isFormBlank && isEditing + + val canSave: Boolean = isFormReady && (hasNameOrNote || isBlankFormDuringEdit) + enum class FormState { + LOADING, + READY, + SAVING, + SAVED + } +} diff --git a/app/src/main/java/org/tm/archive/nicknames/NicknameViewModel.kt b/app/src/main/java/org/tm/archive/nicknames/NicknameViewModel.kt new file mode 100644 index 00000000..1fea8218 --- /dev/null +++ b/app/src/main/java/org/tm/archive/nicknames/NicknameViewModel.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.nicknames + +import androidx.annotation.MainThread +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.signal.core.util.BreakIteratorCompat +import org.signal.core.util.isNotNullOrBlank +import org.tm.archive.database.SignalDatabase +import org.tm.archive.profiles.ProfileName +import org.tm.archive.recipients.Recipient +import org.tm.archive.recipients.RecipientId + +class NicknameViewModel( + private val recipientId: RecipientId +) : ViewModel() { + companion object { + private const val NAME_MAX_LENGTH = 26 + private const val NOTE_MAX_LENGTH = 240 + } + + private val internalState = mutableStateOf(NicknameState()) + private val iteratorCompat = BreakIteratorCompat.getInstance() + + val state: MutableState = internalState + + private val recipientDisposable = Recipient.observable(recipientId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { recipient -> + internalState.value = if (state.value.formState == NicknameState.FormState.LOADING) { + val noteLength = iteratorCompat.run { + setText(recipient.note ?: "") + countBreaks() + } + + NicknameState( + recipient = recipient, + firstName = recipient.nickname.givenName, + lastName = recipient.nickname.familyName, + note = recipient.note ?: "", + noteCharactersRemaining = NOTE_MAX_LENGTH - noteLength, + formState = NicknameState.FormState.READY, + hasBecomeReady = true, + isEditing = !recipient.nickname.isEmpty || recipient.note?.isNotNullOrBlank() == true + ) + } else { + state.value.copy(recipient = recipient) + } + } + + override fun onCleared() { + recipientDisposable.dispose() + } + + @MainThread + fun onFirstNameChanged(value: String) { + iteratorCompat.setText(value) + internalState.value = state.value.copy(firstName = iteratorCompat.take(NAME_MAX_LENGTH).toString()) + } + + @MainThread + fun onLastNameChanged(value: String) { + iteratorCompat.setText(value) + internalState.value = state.value.copy(lastName = iteratorCompat.take(NAME_MAX_LENGTH).toString()) + } + + @MainThread + fun onNoteChanged(value: String) { + if (internalState.value.noteCharactersRemaining == 0 && value.graphemeCount > NOTE_MAX_LENGTH) { + return + } + + iteratorCompat.setText(value) + val trimmed = iteratorCompat.take(NOTE_MAX_LENGTH) + val count = trimmed.graphemeCount + + internalState.value = state.value.copy( + note = trimmed.toString(), + noteCharactersRemaining = NOTE_MAX_LENGTH - count + ) + } + + @MainThread + fun delete() { + viewModelScope.launch { + internalState.value = state.value.copy(formState = NicknameState.FormState.SAVING) + + withContext(Dispatchers.IO) { + SignalDatabase.recipients.setNicknameAndNote( + recipientId, + ProfileName.EMPTY, + "" + ) + } + + internalState.value = state.value.copy(formState = NicknameState.FormState.SAVED) + } + } + + @MainThread + fun save() { + viewModelScope.launch { + val stateSnapshot = state.value.copy(formState = NicknameState.FormState.SAVING) + internalState.value = stateSnapshot + + withContext(Dispatchers.IO) { + SignalDatabase.recipients.setNicknameAndNote( + recipientId, + ProfileName.fromParts(stateSnapshot.firstName, stateSnapshot.lastName), + stateSnapshot.note + ) + } + + internalState.value = state.value.copy(formState = NicknameState.FormState.SAVED) + } + } + + private val CharSequence.graphemeCount: Int + get() { + iteratorCompat.setText(this) + return iteratorCompat.countBreaks() + } +} diff --git a/app/src/main/java/org/tm/archive/nicknames/ViewNoteSheet.kt b/app/src/main/java/org/tm/archive/nicknames/ViewNoteSheet.kt new file mode 100644 index 00000000..e868dd48 --- /dev/null +++ b/app/src/main/java/org/tm/archive/nicknames/ViewNoteSheet.kt @@ -0,0 +1,169 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.nicknames + +import android.os.Bundle +import android.text.util.Linkify +import androidx.activity.result.ActivityResultLauncher +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.os.bundleOf +import androidx.core.text.method.LinkMovementMethodCompat +import androidx.core.text.util.LinkifyCompat +import org.signal.core.ui.BottomSheets +import org.signal.core.ui.Previews +import org.signal.core.util.getParcelableCompat +import org.tm.archive.R +import org.tm.archive.components.emoji.EmojiTextView +import org.tm.archive.compose.ComposeBottomSheetDialogFragment +import org.tm.archive.recipients.RecipientId +import org.tm.archive.util.viewModel + +/** + * Allows user to view the full note for a given recipient. + */ +class ViewNoteSheet : ComposeBottomSheetDialogFragment() { + + companion object { + + private const val RECIPIENT_ID = "recipient_id" + + @JvmStatic + fun create(recipientId: RecipientId): ViewNoteSheet { + return ViewNoteSheet().apply { + arguments = bundleOf( + RECIPIENT_ID to recipientId + ) + } + } + } + + private val recipientId: RecipientId by lazy { + requireArguments().getParcelableCompat(RECIPIENT_ID, RecipientId::class.java)!! + } + + private val viewModel: ViewNoteSheetViewModel by viewModel { + ViewNoteSheetViewModel(recipientId) + } + + private lateinit var editNoteLauncher: ActivityResultLauncher + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + editNoteLauncher = registerForActivityResult(NicknameActivity.Contract()) {} + } + + @Composable + override fun SheetContent() { + val note by remember { viewModel.note } + + ViewNoteBottomSheetContent( + onEditNoteClick = this::onEditNoteClick, + note = note + ) + } + + private fun onEditNoteClick() { + editNoteLauncher.launch( + NicknameActivity.Args( + recipientId = recipientId, + focusNoteFirst = true + ) + ) + + dismissAllowingStateLoss() + } +} + +@Preview +@Composable +private fun ViewNoteBottomSheetContentPreview() { + Previews.Preview { + ViewNoteBottomSheetContent( + onEditNoteClick = {}, + note = "Lorem ipsum dolor sit amet\n\nWebsite: https://example.com" + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ViewNoteBottomSheetContent( + onEditNoteClick: () -> Unit, + note: String +) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + ) { + BottomSheets.Handle() + + CenterAlignedTopAppBar( + title = { + Text( + text = stringResource(id = R.string.ViewNoteSheet__note) + ) + }, + actions = { + IconButton(onClick = onEditNoteClick) { + Icon( + painter = painterResource(id = R.drawable.symbol_edit_24), + contentDescription = stringResource(id = R.string.ViewNoteSheet__edit_note) + ) + } + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = Color.Transparent + ) + ) + + val mask = if (LocalInspectionMode.current) { + Linkify.WEB_URLS + } else { + Linkify.WEB_URLS or Linkify.EMAIL_ADDRESSES or Linkify.PHONE_NUMBERS + } + + AndroidView( + factory = { context -> + val view = EmojiTextView(context) + + @Suppress("DEPRECATION") + view.setTextAppearance(context, R.style.Signal_Text_BodyLarge) + view.movementMethod = LinkMovementMethodCompat.getInstance() + + view + }, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 48.dp) + ) { + it.text = note + + LinkifyCompat.addLinks(it, mask) + } + } +} diff --git a/app/src/main/java/org/tm/archive/nicknames/ViewNoteSheetViewModel.kt b/app/src/main/java/org/tm/archive/nicknames/ViewNoteSheetViewModel.kt new file mode 100644 index 00000000..f20ea169 --- /dev/null +++ b/app/src/main/java/org/tm/archive/nicknames/ViewNoteSheetViewModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.nicknames + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.kotlin.subscribeBy +import io.reactivex.rxjava3.schedulers.Schedulers +import org.tm.archive.recipients.Recipient +import org.tm.archive.recipients.RecipientId + +class ViewNoteSheetViewModel( + recipientId: RecipientId +) : ViewModel() { + private val internalNote = mutableStateOf("") + val note: State = internalNote + + private val recipientDisposable = Recipient.observable(recipientId) + .map { it.note ?: "" } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy { internalNote.value = it } + + override fun onCleared() { + recipientDisposable.dispose() + } +} diff --git a/app/src/main/java/org/tm/archive/notifications/SlowNotificationHeuristics.kt b/app/src/main/java/org/tm/archive/notifications/SlowNotificationHeuristics.kt index 1da98d17..55fc5772 100644 --- a/app/src/main/java/org/tm/archive/notifications/SlowNotificationHeuristics.kt +++ b/app/src/main/java/org/tm/archive/notifications/SlowNotificationHeuristics.kt @@ -21,6 +21,7 @@ import org.tm.archive.util.SignalLocalMetrics import java.util.concurrent.TimeUnit import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.hours +import kotlin.time.Duration.Companion.minutes /** * Heuristic for estimating if a user has been experiencing issues with delayed notifications. @@ -52,10 +53,12 @@ object SlowNotificationHeuristics { minimumEventAgeMs = 3.days.inWholeMilliseconds, minimumServiceEventCount = 10, serviceStartFailurePercentage = 0.5f, - messageLatencyPercentage = 75, - messageLatencyThreshold = 6.hours.inWholeMilliseconds, minimumMessageLatencyEvents = 50, - weeklyFailedQueueDrains = 5 + weeklyFailedQueueDrains = 5, + messageLatencyPercentiles = mapOf( + 90 to 2.hours.inWholeMilliseconds, + 50 to 30.minutes.inWholeMilliseconds + ) ) } @@ -102,7 +105,7 @@ object SlowNotificationHeuristics { val failedServiceStarts = hasRepeatedFailedServiceStarts(metrics, configuration.minimumEventAgeMs, configuration.minimumServiceEventCount, configuration.serviceStartFailurePercentage) val failedQueueDrains = isFailingToDrainQueue(metrics, configuration.minimumEventAgeMs, configuration.weeklyFailedQueueDrains) - val longMessageLatency = hasLongMessageLatency(metrics, configuration.minimumEventAgeMs, configuration.messageLatencyPercentage, configuration.minimumMessageLatencyEvents, configuration.messageLatencyThreshold) + val longMessageLatency = hasLongMessageLatency(metrics, configuration.minimumEventAgeMs, configuration.minimumMessageLatencyEvents, configuration.messageLatencyPercentiles) if (failedServiceStarts || failedQueueDrains || longMessageLatency) { Log.w(TAG, "User seems to be having delayed notifications: failed-service-starts=$failedServiceStarts failedQueueDrains=$failedQueueDrains longMessageLatency=$longMessageLatency") @@ -171,24 +174,26 @@ object SlowNotificationHeuristics { return true } - private fun hasLongMessageLatency(metrics: List, minimumEventAgeMs: Long, percentage: Int, messageThreshold: Int, durationThreshold: Long): Boolean { + private fun hasLongMessageLatency(metrics: List, minimumEventAgeMs: Long, messageThreshold: Int, percentiles: Map): Boolean { if (!haveEnoughData(SignalLocalMetrics.MessageLatency.NAME_HIGH, minimumEventAgeMs)) { Log.d(TAG, "insufficient data for message latency") return false } - val eventCount = metrics.count { it.name == SignalLocalMetrics.MessageLatency.NAME_HIGH } + val eventCount = metrics.find { it.name == SignalLocalMetrics.MessageLatency.NAME_HIGH }?.count ?: 0 if (eventCount < messageThreshold) { Log.d(TAG, "not enough messages for message latency") return false } val db = LocalMetricsDatabase.getInstance(ApplicationDependencies.getApplication()) - val averageLatency = db.eventPercent(SignalLocalMetrics.MessageLatency.NAME_HIGH, percentage.coerceAtMost(100).coerceAtLeast(0)) + for ((percentage, threshold) in percentiles.entries) { + val averageLatency = db.eventPercent(SignalLocalMetrics.MessageLatency.NAME_HIGH, percentage.coerceAtMost(100).coerceAtLeast(0)) - val longMessageLatency = averageLatency > durationThreshold - if (longMessageLatency) { - Log.w(TAG, "User has high average message latency of $averageLatency ms over $eventCount events") + if (averageLatency > threshold) { + Log.w(TAG, "User has high average message latency of $averageLatency ms over $eventCount events over threshold of $threshold ms") + return true + } } - return longMessageLatency + return false } private fun haveEnoughData(eventName: String, minimumEventAgeMs: Long): Boolean { @@ -206,6 +211,5 @@ data class Configuration( val serviceStartFailurePercentage: Float, val weeklyFailedQueueDrains: Int, val minimumMessageLatencyEvents: Int, - val messageLatencyThreshold: Long, - val messageLatencyPercentage: Int + val messageLatencyPercentiles: Map ) diff --git a/app/src/main/java/org/tm/archive/notifications/v2/DefaultMessageNotifier.kt b/app/src/main/java/org/tm/archive/notifications/v2/DefaultMessageNotifier.kt index cbce6f92..9710f46c 100644 --- a/app/src/main/java/org/tm/archive/notifications/v2/DefaultMessageNotifier.kt +++ b/app/src/main/java/org/tm/archive/notifications/v2/DefaultMessageNotifier.kt @@ -10,10 +10,7 @@ import android.os.Build import android.service.notification.StatusBarNotification import androidx.appcompat.view.ContextThemeWrapper import androidx.core.content.ContextCompat -import com.tm.androidcopysdk.CommonUtils -import com.tm.androidcopysdk.utils.PrefManager import me.leolin.shortcutbadger.ShortcutBadger -import org.selfAuthentication.SelfAuthenticatorManager import org.signal.core.util.PendingIntentFlags import org.signal.core.util.logging.Log import org.tm.archive.R @@ -113,14 +110,6 @@ class DefaultMessageNotifier(context: Application) : MessageNotifier { Log.i(TAG, "Scheduling delayed notification...") executor.enqueue(context, conversationId) } else { - //**TM_SA**//Start - /*val isAlreadyDoneSelfAuthentication = PrefManager.getBooleanPref(context, "isAlreadyDoneSelfAuthentication", false) - .Log.d("SelfAuthenticatorProcess", "onCreate = isAlreadyDoneSelfAuthentication = $isAlreadyDoneSelfAuthentication")*/ - - if(!CommonUtils.isActivatedUser(context)){ - return - } - //**TM_SA**//End updateNotification(context, conversationId, BubbleState.HIDDEN) } } diff --git a/app/src/main/java/org/tm/archive/notifications/v2/NotificationBuilder.kt b/app/src/main/java/org/tm/archive/notifications/v2/NotificationBuilder.kt index 5b28e9d7..8e33e50a 100644 --- a/app/src/main/java/org/tm/archive/notifications/v2/NotificationBuilder.kt +++ b/app/src/main/java/org/tm/archive/notifications/v2/NotificationBuilder.kt @@ -15,9 +15,7 @@ import androidx.core.app.NotificationCompat import androidx.core.app.RemoteInput import androidx.core.content.LocusIdCompat import androidx.core.graphics.drawable.IconCompat -import com.tm.androidcopysdk.CommonUtils import org.signal.core.util.PendingIntentFlags.mutable -import org.signal.core.util.logging.Log import org.tm.archive.R import org.tm.archive.conversation.ConversationIntents import org.tm.archive.database.RecipientTable @@ -179,11 +177,7 @@ sealed class NotificationBuilder(protected val context: Context) { } companion object { - fun create(context: Context): NotificationBuilder? { - if (!CommonUtils.isActivatedUser(context)) {//**TM_TA**//Start - Log.d("NotificationsController", "stop notifications for messages when suspend") - return null - }//**TM_TA**//End + fun create(context: Context): NotificationBuilder { return NotificationBuilderCompat(context) } } @@ -200,7 +194,7 @@ sealed class NotificationBuilder(protected val context: Context) { val markAsRead: PendingIntent? = conversation.getMarkAsReadIntent(context) if (markAsRead != null) { val markAsReadAction: NotificationCompat.Action = - NotificationCompat.Action.Builder(R.drawable.check, context.getString(R.string.MessageNotifier_mark_read), markAsRead) + NotificationCompat.Action.Builder(R.drawable.symbol_check_24, context.getString(R.string.MessageNotifier_mark_read), markAsRead) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ) .setShowsUserInterface(false) .build() @@ -245,7 +239,7 @@ sealed class NotificationBuilder(protected val context: Context) { val markAsRead: PendingIntent? = state.getMarkAsReadIntent(context) if (markAsRead != null) { - val markAllAsReadAction = NotificationCompat.Action(R.drawable.check, context.getString(R.string.MessageNotifier_mark_all_as_read), markAsRead) + val markAllAsReadAction = NotificationCompat.Action(R.drawable.symbol_check_24, context.getString(R.string.MessageNotifier_mark_all_as_read), markAsRead) builder.addAction(markAllAsReadAction) builder.extend(NotificationCompat.WearableExtender().addAction(markAllAsReadAction)) } @@ -254,7 +248,7 @@ sealed class NotificationBuilder(protected val context: Context) { override fun addTurnOffJoinedNotificationsAction(pendingIntent: PendingIntent?) { if (pendingIntent != null) { val turnOffTheseNotifications = NotificationCompat.Action( - R.drawable.check, + R.drawable.symbol_check_24, context.getString(R.string.MessageNotifier_turn_off_these_notifications), pendingIntent ) diff --git a/app/src/main/java/org/tm/archive/notifications/v2/NotificationExtensions.kt b/app/src/main/java/org/tm/archive/notifications/v2/NotificationExtensions.kt index 4e461783..af66af95 100644 --- a/app/src/main/java/org/tm/archive/notifications/v2/NotificationExtensions.kt +++ b/app/src/main/java/org/tm/archive/notifications/v2/NotificationExtensions.kt @@ -7,6 +7,7 @@ import android.graphics.Bitmap import android.graphics.drawable.Drawable import android.net.Uri import android.os.Build +import com.bumptech.glide.Glide import com.bumptech.glide.load.MultiTransformation import com.bumptech.glide.load.Transformation import com.bumptech.glide.load.engine.DiskCacheStrategy @@ -18,7 +19,6 @@ import org.tm.archive.contacts.avatars.GeneratedContactPhoto import org.tm.archive.contacts.avatars.ProfileContactPhoto import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri -import org.tm.archive.mms.GlideApp import org.tm.archive.notifications.NotificationIds import org.tm.archive.recipients.Recipient import org.tm.archive.util.BitmapUtil @@ -46,7 +46,7 @@ fun Recipient.getContactDrawable(context: Context): Drawable? { } transforms += CircleCrop() - GlideApp.with(context.applicationContext) + Glide.with(context.applicationContext) .load(contactPhoto) .diskCacheStrategy(DiskCacheStrategy.ALL) .transform(MultiTransformation(transforms)) @@ -67,7 +67,7 @@ fun Recipient.getContactDrawable(context: Context): Drawable? { fun Uri.toBitmap(context: Context, dimension: Int): Bitmap { return try { - GlideApp.with(context.applicationContext) + Glide.with(context.applicationContext) .asBitmap() .load(DecryptableUri(this)) .diskCacheStrategy(DiskCacheStrategy.NONE) diff --git a/app/src/main/java/org/tm/archive/notifications/v2/NotificationFactory.kt b/app/src/main/java/org/tm/archive/notifications/v2/NotificationFactory.kt index f3371cee..b2085358 100644 --- a/app/src/main/java/org/tm/archive/notifications/v2/NotificationFactory.kt +++ b/app/src/main/java/org/tm/archive/notifications/v2/NotificationFactory.kt @@ -220,9 +220,10 @@ object NotificationFactory { return } - val builder: NotificationBuilder = NotificationBuilder.create(context) ?: return //*TM_TA*/return + val builder: NotificationBuilder = NotificationBuilder.create(context) + builder.apply { - setSmallIcon(R.drawable.ic_notification)//**TM_SA**// change icon + setSmallIcon(R.drawable.ic_notification) setColor(ContextCompat.getColor(context, R.color.core_ultramarine)) setCategory(NotificationCompat.CATEGORY_MESSAGE) setGroup(DefaultMessageNotifier.NOTIFICATION_GROUP) @@ -268,7 +269,7 @@ object NotificationFactory { return } - val builder: NotificationBuilder = NotificationBuilder.create(context) ?: return //*TM_TA*/return + val builder: NotificationBuilder = NotificationBuilder.create(context) builder.apply { setSmallIcon(R.drawable.ic_notification) @@ -352,11 +353,11 @@ object NotificationFactory { .build() }.makeUniqueToPreventMerging() - val builder: NotificationBuilder = NotificationBuilder.create(context) ?: return //*TM_TA*/return + val builder: NotificationBuilder = NotificationBuilder.create(context) builder.apply { setSmallIcon(R.drawable.ic_notification) - setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.ic_action_warning_red)) + setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.symbol_error_triangle_fill_32)) setContentTitle(context.getString(R.string.MessageNotifier_message_delivery_failed)) setContentText(context.getString(R.string.MessageNotifier_failed_to_deliver_message)) setTicker(context.getString(R.string.MessageNotifier_error_delivering_message)) @@ -392,7 +393,7 @@ object NotificationFactory { GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, AvatarColor.UNKNOWN) }.toLargeBitmap(context) - val builder: NotificationBuilder = NotificationBuilder.create(context) ?: return //*TM_TA*/return + val builder: NotificationBuilder = NotificationBuilder.create(context) builder.apply { setSmallIcon(R.drawable.ic_notification) @@ -422,7 +423,7 @@ object NotificationFactory { .build() }.makeUniqueToPreventMerging() - val builder: NotificationBuilder = NotificationBuilder.create(context) ?: return //*TM_TA*/return + val builder: NotificationBuilder = NotificationBuilder.create(context) builder.apply { setSmallIcon(R.drawable.ic_notification) @@ -441,7 +442,7 @@ object NotificationFactory { @JvmStatic fun notifyToBubbleConversation(context: Context, recipient: Recipient, threadId: Long) { - val builder: NotificationBuilder = NotificationBuilder.create(context) ?: return //*TM_TA*/return + val builder: NotificationBuilder = NotificationBuilder.create(context) val conversation = NotificationConversation( recipient = recipient, diff --git a/app/src/main/java/org/tm/archive/notifications/v2/NotificationItem.kt b/app/src/main/java/org/tm/archive/notifications/v2/NotificationItem.kt index e44ee64c..dfd55ccf 100644 --- a/app/src/main/java/org/tm/archive/notifications/v2/NotificationItem.kt +++ b/app/src/main/java/org/tm/archive/notifications/v2/NotificationItem.kt @@ -93,7 +93,7 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco context.getString(R.string.SingleRecipientNotificationBuilder_new_message) } else { SpannableStringBuilder().apply { - append(Util.getBoldedString(authorRecipient.getShortDisplayNameIncludingUsername(context))) + append(Util.getBoldedString(authorRecipient.getShortDisplayName(context))) if (threadRecipient != authorRecipient) { append(Util.getBoldedString("@${threadRecipient.getDisplayName(context)}")) } @@ -225,15 +225,15 @@ class MessageNotification(threadRecipient: Recipient, record: MessageRecord) : N } else if (record.isRemoteDelete) { SpanUtil.italic(context.getString(R.string.MessageNotifier_this_message_was_deleted)) } else if (record.isMms && !record.isMmsNotification && (record as MmsMessageRecord).slideDeck.slides.isNotEmpty()) { - ThreadBodyUtil.getFormattedBodyFor(context, record).body + ThreadBodyUtil.getFormattedBodyForNotification(context, record, getBodyWithMentionsAndStyles(context, record)) } else if (record.isGroupCall) { MessageRecord.getGroupCallUpdateDescription(context, record.body, false).spannable } else if (record.hasGiftBadge()) { - ThreadBodyUtil.getFormattedBodyFor(context, record).body + ThreadBodyUtil.getFormattedBodyForNotification(context, record, null) } else if (record.isStoryReaction()) { - ThreadBodyUtil.getFormattedBodyFor(context, record).body + ThreadBodyUtil.getFormattedBodyForNotification(context, record, null) } else if (record.isPaymentNotification) { - ThreadBodyUtil.getFormattedBodyFor(context, record).body + ThreadBodyUtil.getFormattedBodyForNotification(context, record, null) } else { getBodyWithMentionsAndStyles(context, record) } diff --git a/app/src/main/java/org/tm/archive/permissions/RationaleDialog.java b/app/src/main/java/org/tm/archive/permissions/RationaleDialog.java index cc11f8d5..ce124044 100644 --- a/app/src/main/java/org/tm/archive/permissions/RationaleDialog.java +++ b/app/src/main/java/org/tm/archive/permissions/RationaleDialog.java @@ -20,23 +20,29 @@ import androidx.core.graphics.drawable.DrawableCompat; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import org.signal.core.util.DimensionUnit; import org.tm.archive.R; import org.tm.archive.util.ThemeUtil; import org.tm.archive.util.ViewUtil; +import java.util.Objects; + public class RationaleDialog { public static MaterialAlertDialogBuilder createFor(@NonNull Context context, @NonNull String message, @DrawableRes int... drawables) { - View view = LayoutInflater.from(context).inflate(R.layout.permissions_rationale_dialog, null); - ViewGroup header = view.findViewById(R.id.header_container); - TextView text = view.findViewById(R.id.message); + View view = LayoutInflater.from(context).inflate(R.layout.permissions_rationale_dialog, null); + ViewGroup header = view.findViewById(R.id.header_container); + TextView text = view.findViewById(R.id.message); + int iconSize = (int) DimensionUnit.DP.toPixels(32); for (int i=0;i Unit + ): Controller { + return permissionHandler( + permission = android.Manifest.permission.CAMERA, + icon = painterResource(id = R.drawable.symbol_camera_24), + rationale = rationale, + onPermissionGranted = onPermissionGranted + ) + } + + /** + * Generic permissions rationale dialog and state management for single permissions. + */ + @OptIn(ExperimentalPermissionsApi::class) + @Composable + fun permissionHandler( + permission: String, + icon: Painter, + rationale: String, + onPermissionGranted: () -> Unit + ): Controller { + var requestState by remember { + mutableStateOf(RequestState.NONE) + } + + val permissionState = rememberPermissionState(permission = permission) { + if (it && requestState == RequestState.SYSTEM) { + onPermissionGranted() + } + } + + if (requestState == RequestState.RATIONALE) { + Dialogs.PermissionRationaleDialog( + icon = icon, + rationale = rationale, + confirm = stringResource(id = R.string.Permissions_continue), + dismiss = stringResource(id = R.string.Permissions_not_now), + onConfirm = { + requestState = RequestState.SYSTEM + permissionState.launchPermissionRequest() + }, + onDismiss = { + requestState = RequestState.NONE + } + ) + } + + return object : Controller { + override fun request() { + if (permissionState.status.isGranted) { + requestState = RequestState.NONE + onPermissionGranted() + } else { + requestState = RequestState.RATIONALE + } + } + } + } +} diff --git a/app/src/main/java/org/tm/archive/phonenumbers/PhoneNumberVisualTransformation.kt b/app/src/main/java/org/tm/archive/phonenumbers/PhoneNumberVisualTransformation.kt new file mode 100644 index 00000000..094be8ce --- /dev/null +++ b/app/src/main/java/org/tm/archive/phonenumbers/PhoneNumberVisualTransformation.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.phonenumbers + +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation +import com.google.i18n.phonenumbers.AsYouTypeFormatter +import com.google.i18n.phonenumbers.PhoneNumberUtil + +/** + * Formats the input number according to the regionCode. Assumes the input is all digits. + */ +class PhoneNumberVisualTransformation( + regionCode: String +) : VisualTransformation { + + private val asYouTypeFormatter: AsYouTypeFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(regionCode) + + override fun filter(text: AnnotatedString): TransformedText { + asYouTypeFormatter.clear() + val output = text.map { asYouTypeFormatter.inputDigit(it) }.lastOrNull() ?: text.text + + return TransformedText( + AnnotatedString(output), + PhoneNumberOffsetMapping(output) + ) + } + + /** + * Each character in our phone number is either a digit or a transformed offset. + */ + private class PhoneNumberOffsetMapping( + private val transformed: String + ) : OffsetMapping { + override fun originalToTransformed(offset: Int): Int { + // We need a different algorithm here. We need to take UNTIL we've hit offset digits, and then return the resulting length. + var remaining = (offset + 1) + return transformed.takeWhile { + if (it.isDigit()) { + remaining-- + } + + remaining != 0 + }.length + } + + override fun transformedToOriginal(offset: Int): Int { + val substring = transformed.substring(0, offset) + val characterCount = substring.count { !it.isDigit() } + return offset - characterCount + } + } +} diff --git a/app/src/main/java/org/tm/archive/pin/PinRestoreEntryFragment.java b/app/src/main/java/org/tm/archive/pin/PinRestoreEntryFragment.java index b32c5d39..e909c6b2 100644 --- a/app/src/main/java/org/tm/archive/pin/PinRestoreEntryFragment.java +++ b/app/src/main/java/org/tm/archive/pin/PinRestoreEntryFragment.java @@ -23,9 +23,11 @@ import com.google.android.material.button.MaterialButton; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.signal.core.util.logging.Log; +import org.tm.archive.BuildConfig; import org.tm.archive.LoggingFragment; import org.tm.archive.MainActivity; import org.tm.archive.R; +import org.tm.archive.backup.v2.ui.MessageBackupsTestRestoreActivity; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobs.ProfileUploadJob; import org.tm.archive.keyvalue.SignalStore; @@ -236,7 +238,9 @@ public class PinRestoreEntryFragment extends LoggingFragment { Activity activity = requireActivity(); - if (Recipient.self().getProfileName().isEmpty() || !AvatarHelper.hasAvatar(activity, Recipient.self().getId())) { + if (BuildConfig.MESSAGE_BACKUP_RESTORE_ENABLED) { + startActivity(MessageBackupsTestRestoreActivity.Companion.getIntent(activity)); + } else if (Recipient.self().getProfileName().isEmpty() || !AvatarHelper.hasAvatar(activity, Recipient.self().getId())) { final Intent main = MainActivity.clearTop(activity); final Intent profile = CreateProfileActivity.getIntentForUserProfile(activity); diff --git a/app/src/main/java/org/tm/archive/pin/SvrRepository.kt b/app/src/main/java/org/tm/archive/pin/SvrRepository.kt index 8dfd220b..72b0c8f2 100644 --- a/app/src/main/java/org/tm/archive/pin/SvrRepository.kt +++ b/app/src/main/java/org/tm/archive/pin/SvrRepository.kt @@ -39,11 +39,10 @@ object SvrRepository { val TAG = Log.tag(SvrRepository::class.java) - private val svr2Deprecated: SecureValueRecovery = ApplicationDependencies.getSignalServiceAccountManager().getSecureValueRecoveryV2(BuildConfig.SVR2_MRENCLAVE_DEPRECATED) private val svr2: SecureValueRecovery = ApplicationDependencies.getSignalServiceAccountManager().getSecureValueRecoveryV2(BuildConfig.SVR2_MRENCLAVE) /** An ordered list of SVR implementations to read from. They should be in priority order, with the most important one listed first. */ - private val readImplementations: List = listOf(svr2, svr2Deprecated) + private val readImplementations: List = listOf(svr2) /** An ordered list of SVR implementations to write to. They should be in priority order, with the most important one listed first. */ private val writeImplementations: List = listOf(svr2) @@ -74,8 +73,7 @@ object SvrRepository { Log.i(TAG, "restoreMasterKeyPreRegistration()", true) val operations: List RestoreResponse>> = listOf( - svr2 to { restoreMasterKeyPreRegistration(svr2, credentials.svr2, userPin) }, - svr2Deprecated to { restoreMasterKeyPreRegistration(svr2Deprecated, credentials.svr2, userPin) } + svr2 to { restoreMasterKeyPreRegistration(svr2, credentials.svr2, userPin) } ) for ((implementation, operation) in operations) { diff --git a/app/src/main/java/org/tm/archive/preferences/MmsPreferencesActivity.java b/app/src/main/java/org/tm/archive/preferences/MmsPreferencesActivity.java deleted file mode 100644 index f5388d32..00000000 --- a/app/src/main/java/org/tm/archive/preferences/MmsPreferencesActivity.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.preferences; - -import android.os.Bundle; -import android.view.MenuItem; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; - -import org.tm.archive.PassphraseRequiredActivity; -import org.tm.archive.util.DynamicLanguage; -import org.tm.archive.util.DynamicTheme; - -public class MmsPreferencesActivity extends PassphraseRequiredActivity { - - private final DynamicTheme dynamicTheme = new DynamicTheme(); - private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); - - @Override - protected void onPreCreate() { - dynamicTheme.onCreate(this); - dynamicLanguage.onCreate(this); - } - - @Override - protected void onCreate(Bundle icicle, boolean ready) { - assert getSupportActionBar() != null; - this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - Fragment fragment = new MmsPreferencesFragment(); - FragmentManager fragmentManager = getSupportFragmentManager(); - FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); - fragmentTransaction.replace(android.R.id.content, fragment); - fragmentTransaction.commit(); - - } - - @Override - public void onResume() { - super.onResume(); - dynamicTheme.onResume(this); - dynamicLanguage.onResume(this); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - } - - return false; - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - } - -} diff --git a/app/src/main/java/org/tm/archive/preferences/MmsPreferencesFragment.java b/app/src/main/java/org/tm/archive/preferences/MmsPreferencesFragment.java deleted file mode 100644 index 6a830c22..00000000 --- a/app/src/main/java/org/tm/archive/preferences/MmsPreferencesFragment.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.preferences; - -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; - -import androidx.annotation.Nullable; - -import org.signal.core.util.logging.Log; -import org.tm.archive.R; -import org.tm.archive.components.CustomDefaultPreference; -import org.tm.archive.database.ApnDatabase; -import org.tm.archive.mms.LegacyMmsConnection; -import org.tm.archive.util.TelephonyUtil; -import org.tm.archive.util.TextSecurePreferences; - -import java.io.IOException; - - -public class MmsPreferencesFragment extends CorrectedPreferenceFragment { - - private static final String TAG = Log.tag(MmsPreferencesFragment.class); - - @Override - public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { - addPreferencesFromResource(R.xml.preferences_manual_mms); - } - - @Override - public void onResume() { - super.onResume(); - new LoadApnDefaultsTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - private class LoadApnDefaultsTask extends AsyncTask { - - @Override - protected LegacyMmsConnection.Apn doInBackground(Void... params) { - try { - Context context = getActivity(); - - if (context != null) { - return ApnDatabase.getInstance(context) - .getDefaultApnParameters(TelephonyUtil.getMccMnc(context), - TelephonyUtil.getApn(context)); - } - } catch (IOException e) { - Log.w(TAG, e); - } - - return null; - } - - @Override - protected void onPostExecute(LegacyMmsConnection.Apn apnDefaults) { - ((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_HOST_PREF)) - .setValidator(new CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.UriValidator()) - .setDefaultValue(apnDefaults.getMmsc()); - - ((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_PROXY_HOST_PREF)) - .setValidator(new CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.HostnameValidator()) - .setDefaultValue(apnDefaults.getProxy()); - - ((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_PROXY_PORT_PREF)) - .setValidator(new CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.PortValidator()) - .setDefaultValue(apnDefaults.getPort()); - - ((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_USERNAME_PREF)) - .setDefaultValue(apnDefaults.getPort()); - - ((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_PASSWORD_PREF)) - .setDefaultValue(apnDefaults.getPassword()); - - ((CustomDefaultPreference)findPreference(TextSecurePreferences.MMS_USER_AGENT)) - .setDefaultValue(LegacyMmsConnection.USER_AGENT); - } - } - -} diff --git a/app/src/main/java/org/tm/archive/profiles/SystemProfileUtil.java b/app/src/main/java/org/tm/archive/profiles/SystemProfileUtil.java index b97f1bf8..91436732 100644 --- a/app/src/main/java/org/tm/archive/profiles/SystemProfileUtil.java +++ b/app/src/main/java/org/tm/archive/profiles/SystemProfileUtil.java @@ -14,12 +14,12 @@ import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.SettableFuture; import org.signal.core.util.logging.Log; import org.tm.archive.mms.MediaConstraints; import org.tm.archive.util.BitmapDecodingException; import org.tm.archive.util.BitmapUtil; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.tm.archive.util.concurrent.SettableFuture; public class SystemProfileUtil { diff --git a/app/src/main/java/org/tm/archive/profiles/edit/CreateProfileFragment.java b/app/src/main/java/org/tm/archive/profiles/edit/CreateProfileFragment.java index b7e394c3..4c03f2f6 100644 --- a/app/src/main/java/org/tm/archive/profiles/edit/CreateProfileFragment.java +++ b/app/src/main/java/org/tm/archive/profiles/edit/CreateProfileFragment.java @@ -20,10 +20,9 @@ import androidx.lifecycle.ViewModelProvider; import androidx.navigation.Navigation; import com.airbnb.lottie.SimpleColorFilter; +import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.tm.androidcopysdk.utils.PrefManager; -import org.archiver.ArchivePreferenceConstants; import org.signal.core.util.EditTextUtil; import org.signal.core.util.StreamUtil; import org.signal.core.util.concurrent.SimpleTask; @@ -38,7 +37,6 @@ import org.tm.archive.groups.ParcelableGroupId; import org.tm.archive.keyvalue.PhoneNumberPrivacyValues; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.mediasend.Media; -import org.tm.archive.mms.GlideApp; import org.tm.archive.profiles.edit.pnp.WhoCanFindMeByPhoneNumberFragment; import org.tm.archive.profiles.manage.EditProfileNameFragment; import org.tm.archive.providers.BlobProvider; @@ -132,7 +130,7 @@ public class CreateProfileFragment extends LoggingFragment { if (avatarBytes != null) { viewModel.setAvatarMedia(media); viewModel.setAvatar(avatarBytes); - GlideApp.with(CreateProfileFragment.this) + Glide.with(CreateProfileFragment.this) .load(avatarBytes) .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) @@ -211,23 +209,18 @@ public class CreateProfileFragment extends LoggingFragment { binding.profileDescriptionText.setLinkColor(ContextCompat.getColor(requireContext(), R.color.signal_colorPrimary)); binding.profileDescriptionText.setOnLinkClickListener(v -> CommunicationActions.openBrowserLink(requireContext(), getString(R.string.EditProfileFragment__support_link))); - if (FeatureFlags.phoneNumberPrivacy()) { - getParentFragmentManager().setFragmentResultListener(WhoCanFindMeByPhoneNumberFragment.REQUEST_KEY, getViewLifecycleOwner(), (requestKey, result) -> { - if (WhoCanFindMeByPhoneNumberFragment.REQUEST_KEY.equals(requestKey)) { - presentWhoCanFindMeDescription(SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode()); - } - }); + getParentFragmentManager().setFragmentResultListener(WhoCanFindMeByPhoneNumberFragment.REQUEST_KEY, getViewLifecycleOwner(), (requestKey, result) -> { + if (WhoCanFindMeByPhoneNumberFragment.REQUEST_KEY.equals(requestKey)) { + presentWhoCanFindMeDescription(SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode()); + } + }); - binding.whoCanFindMeContainer.setVisibility(View.VISIBLE); - binding.whoCanFindMeContainer.setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(v), CreateProfileFragmentDirections.actionCreateProfileFragmentToPhoneNumberPrivacy())); - presentWhoCanFindMeDescription(SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode()); - } + binding.whoCanFindMeContainer.setVisibility(View.VISIBLE); + binding.whoCanFindMeContainer.setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(v), CreateProfileFragmentDirections.actionCreateProfileFragmentToPhoneNumberPrivacy())); + presentWhoCanFindMeDescription(SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode()); } binding.finishButton.setOnClickListener(v -> { - //**TM_SA**//Start - savePrefName(); - //**TM_SA**//End binding.finishButton.setSpinning(); handleUpload(); }); @@ -241,12 +234,6 @@ public class CreateProfileFragment extends LoggingFragment { } } - //**TM_SA**//Start - private void savePrefName() { - PrefManager.setStringPref(getContext(), ArchivePreferenceConstants.PREF_KEY_DEVICE_NAME, binding.givenName.getText() + " " + binding.familyName.getText()); - } - //**TM_SA**//End - private void initializeProfileName() { viewModel.isFormValid().observe(getViewLifecycleOwner(), isValid -> { binding.finishButton.setEnabled(isValid); @@ -263,11 +250,11 @@ public class CreateProfileFragment extends LoggingFragment { private void initializeProfileAvatar() { viewModel.avatar().observe(getViewLifecycleOwner(), bytes -> { if (bytes == null) { - GlideApp.with(this).clear(binding.avatar); + Glide.with(this).clear(binding.avatar); return; } - GlideApp.with(this) + Glide.with(this) .load(bytes) .circleCrop() .into(binding.avatar); @@ -296,12 +283,15 @@ public class CreateProfileFragment extends LoggingFragment { } } - private void presentWhoCanFindMeDescription(PhoneNumberPrivacyValues.PhoneNumberListingMode phoneNumberListingMode) { + private void presentWhoCanFindMeDescription(PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode phoneNumberListingMode) { switch (phoneNumberListingMode) { - case LISTED: + case DISCOVERABLE: + case UNDECIDED: + binding.whoCanFindMeIcon.setImageResource(R.drawable.symbol_group_24); binding.whoCanFindMeDescription.setText(R.string.PhoneNumberPrivacy_everyone); break; - case UNLISTED: + case NOT_DISCOVERABLE: + binding.whoCanFindMeIcon.setImageResource(R.drawable.symbol_lock_24); binding.whoCanFindMeDescription.setText(R.string.PhoneNumberPrivacy_nobody); break; } diff --git a/app/src/main/java/org/tm/archive/profiles/edit/EditProfileViewModel.java b/app/src/main/java/org/tm/archive/profiles/edit/EditProfileViewModel.java index aa60f9dd..b7040a60 100644 --- a/app/src/main/java/org/tm/archive/profiles/edit/EditProfileViewModel.java +++ b/app/src/main/java/org/tm/archive/profiles/edit/EditProfileViewModel.java @@ -8,8 +8,12 @@ import androidx.lifecycle.Transformations; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; +import org.signal.core.util.logging.Log; import org.tm.archive.conversation.colors.AvatarColor; import org.tm.archive.groups.GroupId; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode; +import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.mediasend.Media; import org.tm.archive.profiles.ProfileName; import org.tm.archive.profiles.edit.EditProfileRepository.UploadResult; @@ -22,6 +26,8 @@ import java.util.Objects; class EditProfileViewModel extends ViewModel { + private static final String TAG = Log.tag(EditProfileViewModel.class); + private final MutableLiveData givenName = new MutableLiveData<>(); private final MutableLiveData familyName = new MutableLiveData<>(); private final LiveData trimmedGivenName = Transformations.map(givenName, StringUtil::trimToVisualBounds); @@ -112,10 +118,6 @@ class EditProfileViewModel extends ViewModel { return groupId; } - public boolean canRemoveProfilePhoto() { - return hasAvatar(); - } - public SingleLiveEvent getUploadResult() { return uploadResult; } @@ -146,6 +148,11 @@ class EditProfileViewModel extends ViewModel { String oldDisplayName = isGroup() ? originalDisplayName.getValue() : null; String oldDescription = isGroup() ? originalDescription : null; + if (!isGroup() && SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode() == PhoneNumberDiscoverabilityMode.UNDECIDED) { + Log.i(TAG, "Phone number discoverability mode is still UNDECIDED. Setting to DISCOVERABLE."); + SignalStore.phoneNumberPrivacy().setPhoneNumberDiscoverabilityMode(PhoneNumberDiscoverabilityMode.DISCOVERABLE); + } + repository.uploadProfile(profileName, displayName, !Objects.equals(StringUtil.stripBidiProtection(oldDisplayName), displayName), diff --git a/app/src/main/java/org/tm/archive/profiles/edit/EditSelfProfileRepository.java b/app/src/main/java/org/tm/archive/profiles/edit/EditSelfProfileRepository.java index f0313617..9f9292c6 100644 --- a/app/src/main/java/org/tm/archive/profiles/edit/EditSelfProfileRepository.java +++ b/app/src/main/java/org/tm/archive/profiles/edit/EditSelfProfileRepository.java @@ -8,6 +8,8 @@ import androidx.annotation.Nullable; import androidx.core.util.Consumer; import org.signal.core.util.StreamUtil; +import org.signal.core.util.concurrent.ListenableFuture; +import org.signal.core.util.concurrent.SimpleTask; import org.signal.core.util.logging.Log; import org.tm.archive.conversation.colors.AvatarColor; import org.tm.archive.database.SignalDatabase; @@ -23,8 +25,6 @@ import org.tm.archive.profiles.SystemProfileUtil; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; import org.tm.archive.registration.RegistrationUtil; -import org.tm.archive.util.concurrent.ListenableFuture; -import org.signal.core.util.concurrent.SimpleTask; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -148,7 +148,7 @@ public class EditSelfProfileRepository implements EditProfileRepository { RegistrationUtil.maybeMarkRegistrationComplete(); if (avatar != null) { - SignalStore.misc().markHasEverHadAnAvatar(); + SignalStore.misc().setHasEverHadAnAvatar(true); } return UploadResult.SUCCESS; diff --git a/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberFragment.kt b/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberFragment.kt index 992b897a..2ad063cd 100644 --- a/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberFragment.kt +++ b/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberFragment.kt @@ -14,7 +14,6 @@ import org.tm.archive.components.settings.DSLSettingsFragment import org.tm.archive.components.settings.DSLSettingsText import org.tm.archive.components.settings.configure import org.tm.archive.databinding.WhoCanFindMeByPhoneNumberFragmentBinding -import org.tm.archive.util.FeatureFlags import org.tm.archive.util.adapter.mapping.MappingAdapter /** @@ -38,8 +37,6 @@ class WhoCanFindMeByPhoneNumberFragment : DSLSettingsFragment( private val binding by ViewBinderDelegate(WhoCanFindMeByPhoneNumberFragmentBinding::bind) override fun bindAdapter(adapter: MappingAdapter) { - require(FeatureFlags.phoneNumberPrivacy()) - lifecycleDisposable += viewModel.state.subscribe { adapter.submitList(getConfiguration(it).toMappingModelList()) } @@ -70,8 +67,8 @@ class WhoCanFindMeByPhoneNumberFragment : DSLSettingsFragment( textPref( title = DSLSettingsText.from( when (state) { - WhoCanFindMeByPhoneNumberState.EVERYONE -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has - WhoCanFindMeByPhoneNumberState.NOBODY -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal + WhoCanFindMeByPhoneNumberState.EVERYONE -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has_your + WhoCanFindMeByPhoneNumberState.NOBODY -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_will_be_able }, DSLSettingsText.TextAppearanceModifier(R.style.Signal_Text_BodyMedium), DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant)) diff --git a/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberRepository.kt b/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberRepository.kt index 6740d251..cb1de87e 100644 --- a/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberRepository.kt +++ b/app/src/main/java/org/tm/archive/profiles/edit/pnp/WhoCanFindMeByPhoneNumberRepository.kt @@ -14,9 +14,10 @@ import org.tm.archive.storage.StorageSyncHelper class WhoCanFindMeByPhoneNumberRepository { fun getCurrentState(): WhoCanFindMeByPhoneNumberState { - return when (SignalStore.phoneNumberPrivacy().phoneNumberListingMode) { - PhoneNumberPrivacyValues.PhoneNumberListingMode.LISTED -> WhoCanFindMeByPhoneNumberState.EVERYONE - PhoneNumberPrivacyValues.PhoneNumberListingMode.UNLISTED -> WhoCanFindMeByPhoneNumberState.NOBODY + return when (SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode) { + PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.DISCOVERABLE -> WhoCanFindMeByPhoneNumberState.EVERYONE + PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE -> WhoCanFindMeByPhoneNumberState.NOBODY + PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.UNDECIDED -> WhoCanFindMeByPhoneNumberState.EVERYONE } } @@ -24,11 +25,11 @@ class WhoCanFindMeByPhoneNumberRepository { return Completable.fromAction { when (whoCanFindMeByPhoneNumberState) { WhoCanFindMeByPhoneNumberState.EVERYONE -> { - SignalStore.phoneNumberPrivacy().phoneNumberListingMode = PhoneNumberPrivacyValues.PhoneNumberListingMode.LISTED + SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode = PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.DISCOVERABLE } WhoCanFindMeByPhoneNumberState.NOBODY -> { SignalStore.phoneNumberPrivacy().phoneNumberSharingMode = PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY - SignalStore.phoneNumberPrivacy().phoneNumberListingMode = PhoneNumberPrivacyValues.PhoneNumberListingMode.UNLISTED + SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode = PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE } } diff --git a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileActivity.java b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileActivity.java index e4ddc250..30213313 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileActivity.java +++ b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileActivity.java @@ -13,7 +13,6 @@ import androidx.navigation.fragment.NavHostFragment; import org.tm.archive.PassphraseRequiredActivity; import org.tm.archive.R; -import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment; import org.tm.archive.util.DynamicNoActionBarTheme; import org.tm.archive.util.DynamicTheme; @@ -64,13 +63,8 @@ public class EditProfileActivity extends PassphraseRequiredActivity implements R navController.setGraph(graph, extras != null ? extras : new Bundle()); if (extras != null && extras.getBoolean(START_AT_USERNAME, false)) { - if (SignalStore.uiHints().hasSeenUsernameEducation()) { - NavDirections action = EditProfileFragmentDirections.actionManageUsername(); - SafeNavigation.safeNavigate(navController, action); - } else { - NavDirections action = EditProfileFragmentDirections.actionManageProfileFragmentToUsernameEducationFragment(); - SafeNavigation.safeNavigate(navController, action); - } + NavDirections action = EditProfileFragmentDirections.actionManageUsername(); + SafeNavigation.safeNavigate(navController, action); } if (extras != null && extras.getBoolean(START_AT_AVATAR, false)) { diff --git a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileFragment.kt b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileFragment.kt index 91906a06..3d1c71e2 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileFragment.kt +++ b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileFragment.kt @@ -37,12 +37,12 @@ import org.tm.archive.profiles.ProfileName import org.tm.archive.profiles.manage.EditProfileViewModel.AvatarState import org.tm.archive.profiles.manage.UsernameRepository.UsernameDeleteResult import org.tm.archive.recipients.Recipient -import org.tm.archive.util.FeatureFlags +import org.tm.archive.registration.RegistrationNavigationActivity import org.tm.archive.util.NameUtil.getAbbreviation +import org.tm.archive.util.PlayStoreUtil import org.tm.archive.util.livedata.LiveDataUtil import org.tm.archive.util.navigation.safeNavigate import org.tm.archive.util.views.SimpleProgressDialog -import org.tm.archive.util.visible import java.util.Arrays import java.util.Optional @@ -57,6 +57,8 @@ class EditProfileFragment : LoggingFragment() { private lateinit var binding: EditProfileFragmentBinding private lateinit var disposables: LifecycleDisposable + private val DISABLED_ALPHA = 0.4f + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { binding = EditProfileFragmentBinding.inflate(inflater, container, false) return binding.root @@ -77,33 +79,53 @@ class EditProfileFragment : LoggingFragment() { initializeViewModel() binding.toolbar.setNavigationOnClickListener { requireActivity().finish() } - binding.manageProfileEditPhoto.setOnClickListener { onEditAvatarClicked() } - binding.manageProfileNameContainer.setOnClickListener { v: View -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileName()) } - binding.manageProfileUsernameContainer.setOnClickListener { v: View -> - if (SignalStore.uiHints().hasSeenUsernameEducation()) { - if (SignalStore.account().username != null) { - MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Signal_MaterialAlertDialog_List) - .setItems(R.array.username_edit_entries) { _: DialogInterface?, w: Int -> - when (w) { - 0 -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageUsername()) - 1 -> displayConfirmUsernameDeletionDialog() - else -> throw IllegalStateException() - } - } - .show() - } else { - findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageUsername()) - } + binding.manageProfileEditPhoto.setOnClickListener { + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() } else { - findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToUsernameEducationFragment()) + onEditAvatarClicked() } } - binding.manageProfileAboutContainer.setOnClickListener { v: View -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageAbout()) } + binding.manageProfileNameContainer.setOnClickListener { v: View -> + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() + } else { + findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileName()) + } + } + + binding.manageProfileUsernameContainer.setOnClickListener { v: View -> + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() + } else if (SignalStore.account().username != null) { + MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Signal_MaterialAlertDialog_List) + .setItems(R.array.username_edit_entries) { _: DialogInterface?, w: Int -> + when (w) { + 0 -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageUsername()) + 1 -> displayConfirmUsernameDeletionDialog() + else -> throw IllegalStateException() + } + } + .show() + } else { + findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageUsername()) + } + } + + binding.manageProfileAboutContainer.setOnClickListener { v: View -> + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() + } else { + findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageAbout()) + } + } parentFragmentManager.setFragmentResultListener(AvatarPickerFragment.REQUEST_KEY_SELECT_AVATAR, viewLifecycleOwner) { _: String?, bundle: Bundle -> - if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) { + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() + } else if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) { viewModel.onAvatarSelected(requireContext(), null) } else { val result = bundle.getParcelable(AvatarPickerFragment.SELECT_AVATAR_MEDIA) @@ -119,7 +141,9 @@ class EditProfileFragment : LoggingFragment() { } binding.manageProfileBadgesContainer.setOnClickListener { v: View -> - if (Recipient.self().badges.isEmpty()) { + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() + } else if (Recipient.self().badges.isEmpty()) { show(parentFragmentManager) } else { findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToBadgeManageFragment()) @@ -127,32 +151,14 @@ class EditProfileFragment : LoggingFragment() { } binding.manageProfileAvatar.setOnClickListener { - startActivity( - AvatarPreviewActivity.intentFromRecipientId(requireContext(), Recipient.self().id), - AvatarPreviewActivity.createTransitionBundle(requireActivity(), binding.manageProfileAvatar) - ) - } - - if (FeatureFlags.usernames() && SignalStore.account().username != null && SignalStore.account().usernameSyncState != AccountValues.UsernameSyncState.USERNAME_AND_LINK_CORRUPTED) { - binding.usernameLinkContainer.setOnClickListener { - findNavController().safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToUsernameLinkFragment()) - } - - if (SignalStore.account().usernameSyncState == AccountValues.UsernameSyncState.LINK_CORRUPTED) { - binding.linkErrorIndicator.visibility = View.VISIBLE + if (!viewModel.isRegisteredAndUpToDate) { + onClickWhenUnregisteredOrDeprecated() } else { - binding.linkErrorIndicator.visibility = View.GONE + startActivity( + AvatarPreviewActivity.intentFromRecipientId(requireContext(), Recipient.self().id), + AvatarPreviewActivity.createTransitionBundle(requireActivity(), binding.manageProfileAvatar) + ) } - - if (SignalStore.tooltips().showProfileSettingsQrCodeTooltop()) { - binding.usernameLinkTooltip.visibility = View.VISIBLE - binding.linkTooltipCloseButton.setOnClickListener { - binding.usernameLinkTooltip.visibility = View.GONE - SignalStore.tooltips().markProfileSettingsQrCodeTooltipSeen() - } - } - } else { - binding.usernameLinkContainer.visibility = View.GONE } } @@ -170,12 +176,7 @@ class EditProfileFragment : LoggingFragment() { viewModel.about.observe(viewLifecycleOwner) { presentAbout(it) } viewModel.aboutEmoji.observe(viewLifecycleOwner) { presentAboutEmoji(it) } viewModel.badge.observe(viewLifecycleOwner) { presentBadge(it) } - - if (viewModel.shouldShowUsername()) { - viewModel.username.observe(viewLifecycleOwner) { presentUsername(it) } - } else { - binding.manageProfileUsernameContainer.visibility = View.GONE - } + viewModel.username.observe(viewLifecycleOwner) { presentUsername(it) } } private fun presentAvatarImage(avatarData: Optional) { @@ -187,6 +188,10 @@ class EditProfileFragment : LoggingFragment() { } else { Glide.with(this).load(null as Drawable?).into(binding.manageProfileAvatar) } + + binding.manageProfileAvatar.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA + binding.manageProfileAvatarInitials.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA + binding.manageProfileEditPhoto.isEnabled = viewModel.isRegisteredAndUpToDate } private fun presentAvatarPlaceholder(avatarState: AvatarState) { @@ -238,6 +243,9 @@ class EditProfileFragment : LoggingFragment() { } else { binding.manageProfileName.text = profileName.toString() } + + binding.manageProfileName.isEnabled = viewModel.isRegisteredAndUpToDate + binding.manageProfileNameIcon.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA } private fun presentUsername(username: String?) { @@ -252,6 +260,34 @@ class EditProfileFragment : LoggingFragment() { } else { binding.usernameErrorIndicator.visibility = View.GONE } + + if (SignalStore.account().username != null && SignalStore.account().usernameSyncState != AccountValues.UsernameSyncState.USERNAME_AND_LINK_CORRUPTED) { + binding.usernameLinkContainer.setOnClickListener { + findNavController().safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToUsernameLinkFragment()) + } + + if (SignalStore.account().usernameSyncState == AccountValues.UsernameSyncState.LINK_CORRUPTED) { + binding.linkErrorIndicator.visibility = View.VISIBLE + } else { + binding.linkErrorIndicator.visibility = View.GONE + } + + if (SignalStore.tooltips().showProfileSettingsQrCodeTooltop()) { + binding.usernameLinkTooltip.visibility = View.VISIBLE + binding.linkTooltipCloseButton.setOnClickListener { + binding.usernameLinkTooltip.visibility = View.GONE + SignalStore.tooltips().markProfileSettingsQrCodeTooltipSeen() + } + } + + binding.usernameInfoText.setText(R.string.ManageProfileFragment__your_username) + } else { + binding.usernameLinkContainer.visibility = View.GONE + binding.usernameInfoText.setText(R.string.ManageProfileFragment__username_footer_no_username) + } + + binding.manageProfileUsername.isEnabled = viewModel.isRegisteredAndUpToDate + binding.manageProfileUsernameIcon.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA } private fun presentAbout(about: String?) { @@ -260,6 +296,9 @@ class EditProfileFragment : LoggingFragment() { } else { binding.manageProfileAbout.text = about } + + binding.manageProfileAbout.isEnabled = viewModel.isRegisteredAndUpToDate + binding.manageProfileAboutIcon.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA } private fun presentAboutEmoji(aboutEmoji: String?) { @@ -281,6 +320,14 @@ class EditProfileFragment : LoggingFragment() { } else { binding.manageProfileBadge.setBadge(null) } + + binding.manageProfileBadges.isEnabled = viewModel.isRegisteredAndUpToDate + binding.manageProfileBadge.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA + binding.manageProfileBadgesIcon.alpha = if (viewModel.isRegisteredAndUpToDate) 1.0f else DISABLED_ALPHA + + if (!viewModel.isRegisteredAndUpToDate) { + binding.manageProfileBadge.setOnClickListener { onClickWhenUnregisteredOrDeprecated() } + } } private fun presentEvent(event: EditProfileViewModel.Event) { @@ -320,7 +367,32 @@ class EditProfileFragment : LoggingFragment() { Snackbar.make(requireView(), R.string.ManageProfileFragment__username_deleted, Snackbar.LENGTH_SHORT).show() binding.usernameLinkContainer.visibility = View.GONE } + UsernameDeleteResult.NETWORK_ERROR -> Snackbar.make(requireView(), R.string.ManageProfileFragment__couldnt_delete_username, Snackbar.LENGTH_SHORT).show() } } + + private fun onClickWhenUnregisteredOrDeprecated() { + if (viewModel.isDeprecated) { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.EditProfileFragment_deprecated_dialog_title) + .setMessage(R.string.EditProfileFragment_deprecated_dialog_body) + .setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() } + .setPositiveButton(R.string.EditProfileFragment_deprecated_dialog_update_button) { d, _ -> + PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext()) + d.dismiss() + } + .show() + } else { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.EditProfileFragment_unregistered_dialog_title) + .setMessage(R.string.EditProfileFragment_unregistered_dialog_body) + .setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() } + .setPositiveButton(R.string.EditProfileFragment_unregistered_dialog_reregister_button) { d, _ -> + startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext())) + d.dismiss() + } + .show() + } + } } diff --git a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileRepository.java b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileRepository.java index 7a93aeeb..318d6a57 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileRepository.java +++ b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileRepository.java @@ -59,7 +59,7 @@ final class EditProfileRepository { try { ProfileUtil.uploadProfileWithAvatar(new StreamDetails(new ByteArrayInputStream(data), contentType, data.length)); AvatarHelper.setAvatar(context, Recipient.self().getId(), new ByteArrayInputStream(data)); - SignalStore.misc().markHasEverHadAnAvatar(); + SignalStore.misc().setHasEverHadAnAvatar(true); ApplicationDependencies.getJobManager().add(new MultiDeviceProfileContentUpdateJob()); callback.accept(Result.SUCCESS); diff --git a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileViewModel.java b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileViewModel.java index 6be20e74..98c314b8 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/EditProfileViewModel.java +++ b/app/src/main/java/org/tm/archive/profiles/manage/EditProfileViewModel.java @@ -24,8 +24,8 @@ import org.tm.archive.providers.BlobProvider; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientForeverObserver; import org.tm.archive.util.DefaultValueLiveData; -import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.SingleLiveEvent; +import org.tm.archive.util.TextSecurePreferences; import org.tm.archive.util.livedata.LiveDataUtil; import org.whispersystems.signalservice.api.util.StreamDetails; @@ -107,8 +107,12 @@ class EditProfileViewModel extends ViewModel { return UsernameRepository.deleteUsernameAndLink().observeOn(AndroidSchedulers.mainThread()); } - public boolean shouldShowUsername() { - return FeatureFlags.usernames(); + public boolean isRegisteredAndUpToDate() { + return !TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()) && SignalStore.account().isRegistered() && !SignalStore.misc().isClientDeprecated(); + } + + public boolean isDeprecated() { + return SignalStore.misc().isClientDeprecated(); } public void onAvatarSelected(@NonNull Context context, @Nullable Media media) { diff --git a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditFragment.java b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditFragment.java index 05e1b317..91162861 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditFragment.java +++ b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditFragment.java @@ -1,7 +1,7 @@ package org.tm.archive.profiles.manage; import android.animation.LayoutTransition; -import android.content.Intent; +import android.app.Activity; import android.content.res.ColorStateList; import android.os.Bundle; import android.view.LayoutInflater; @@ -14,7 +14,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; -import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.Navigation; @@ -26,10 +25,10 @@ import com.google.android.material.textfield.TextInputLayout; import org.signal.core.util.EditTextUtil; import org.signal.core.util.concurrent.LifecycleDisposable; import org.tm.archive.LoggingFragment; -import org.tm.archive.PassphraseRequiredActivity; import org.tm.archive.R; import org.tm.archive.contactshare.SimpleTextWatcher; import org.tm.archive.databinding.UsernameEditFragmentBinding; +import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.util.FragmentResultContract; import org.tm.archive.util.UsernameUtil; import org.tm.archive.util.ViewUtil; @@ -40,6 +39,8 @@ public class UsernameEditFragment extends LoggingFragment { private static final float DISABLED_ALPHA = 0.5f; public static final String IGNORE_TEXT_CHANGE_EVENT = "ignore.text.change.event"; + public static final int REQUEST_CODE = 4242; + private UsernameEditViewModel viewModel; private UsernameEditFragmentBinding binding; private LifecycleDisposable lifecycleDisposable; @@ -75,30 +76,29 @@ public class UsernameEditFragment extends LoggingFragment { args = new UsernameEditFragmentArgs.Builder().build(); } - if (args.getIsInRegistration()) { - binding.toolbar.setNavigationIcon(null); - binding.toolbar.setTitle(R.string.UsernameEditFragment__add_a_username); - binding.usernameSkipButton.setVisibility(View.VISIBLE); - binding.usernameDoneButton.setVisibility(View.VISIBLE); - } else { - binding.toolbar.setNavigationOnClickListener(v -> Navigation.findNavController(view).popBackStack()); - binding.usernameSubmitButton.setVisibility(View.VISIBLE); - } + binding.toolbar.setNavigationOnClickListener(v -> { + if (args.getMode() == UsernameEditMode.RECOVERY) { + getActivity().finish(); + } else { + Navigation.findNavController(view).popBackStack(); + } + }); + binding.usernameSubmitButton.setVisibility(View.VISIBLE); binding.usernameTextWrapper.setErrorIconDrawable(null); lifecycleDisposable = new LifecycleDisposable(); lifecycleDisposable.bindTo(getViewLifecycleOwner()); - viewModel = new ViewModelProvider(this, new UsernameEditViewModel.Factory(args.getIsInRegistration())).get(UsernameEditViewModel.class); + viewModel = new ViewModelProvider(this, new UsernameEditViewModel.Factory(args.getMode())).get(UsernameEditViewModel.class); lifecycleDisposable.add(viewModel.getUiState().subscribe(this::onUiStateChanged)); lifecycleDisposable.add(viewModel.getEvents().subscribe(this::onEvent)); lifecycleDisposable.add(viewModel.getUsernameInputState().subscribe(this::presentUsernameInputState)); - binding.usernameSubmitButton.setOnClickListener(v -> viewModel.onUsernameSubmitted()); + binding.usernameSubmitButton.setOnClickListener(v -> promptOrSubmitUsername()); binding.usernameDeleteButton.setOnClickListener(v -> viewModel.onUsernameDeleted()); - binding.usernameDoneButton.setOnClickListener(v -> viewModel.onUsernameSubmitted()); + binding.usernameDoneButton.setOnClickListener(v -> viewModel.onUsernameSubmitted(false)); binding.usernameSkipButton.setOnClickListener(v -> viewModel.onUsernameSkipped()); binding.usernameText.addTextChangedListener(new SimpleTextWatcher() { @@ -121,7 +121,7 @@ public class UsernameEditFragment extends LoggingFragment { binding.discriminatorText.setOnEditorActionListener((v, actionId, event) -> { if (actionId == EditorInfo.IME_ACTION_DONE) { - viewModel.onUsernameSubmitted(); + promptOrSubmitUsername(); return true; } return false; @@ -140,17 +140,31 @@ public class UsernameEditFragment extends LoggingFragment { binding = null; } + private void promptOrSubmitUsername() { + if (viewModel.isSameUsernameRecovery()) { + new MaterialAlertDialogBuilder(requireContext()) + .setMessage(R.string.UsernameEditFragment_recovery_dialog_confirmation) + .setPositiveButton(android.R.string.ok, ((dialog, which) -> { + viewModel.onUsernameSubmitted(true); + dialog.dismiss(); + })) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) + .show(); + } else { + viewModel.onUsernameSubmitted(false); + } + } + + private void onLearnMore(@Nullable View unused) { new MaterialAlertDialogBuilder(requireContext()) - .setTitle(new StringBuilder("#\n").append(getString(R.string.UsernameEditFragment__what_is_this_number))) + .setTitle(getString(R.string.UsernameEditFragment__what_is_this_number)) .setMessage(R.string.UsernameEditFragment__these_digits_help_keep) .setPositiveButton(android.R.string.ok, (dialog, which) -> {}) .show(); } private void onUiStateChanged(@NonNull UsernameEditViewModel.State state) { - TextInputLayout usernameInputWrapper = binding.usernameTextWrapper; - presentProgressState(state.usernameState); presentButtonState(state.buttonState); presentSummary(state.usernameState); @@ -167,6 +181,8 @@ public class UsernameEditFragment extends LoggingFragment { case DISCRIMINATOR_HAS_INVALID_CHARACTERS, DISCRIMINATOR_NOT_AVAILABLE -> getString(R.string.UsernameEditFragment__this_username_is_not_available_try_another_number); case DISCRIMINATOR_TOO_LONG -> getString(R.string.UsernameEditFragment__invalid_username_enter_a_maximum_of_d_digits, UsernameUtil.MAX_DISCRIMINATOR_LENGTH); case DISCRIMINATOR_TOO_SHORT -> getString(R.string.UsernameEditFragment__invalid_username_enter_a_minimum_of_d_digits, UsernameUtil.MIN_DISCRIMINATOR_LENGTH); + case DISCRIMINATOR_CANNOT_BE_00 -> getString(R.string.UsernameEditFragment__this_number_cant_be_00); + case DISCRIMINATOR_CANNOT_START_WITH_0 -> getString(R.string.UsernameEditFragment__this_number_cant_start_with_0); }; int colorRes = error != null ? R.color.signal_colorError : R.color.signal_colorPrimary; @@ -179,50 +195,17 @@ public class UsernameEditFragment extends LoggingFragment { binding.usernameError.setVisibility(error != null ? View.VISIBLE : View.GONE); binding.usernameError.setText(error); binding.root.setLayoutTransition(STATIC_LAYOUT); + + if (state.usernameState.getDiscriminator() == null && SignalStore.account().getUsername() == null) { + binding.discriminatorText.setVisibility(View.GONE); + binding.divider.setVisibility(View.GONE); + } else { + binding.discriminatorText.setVisibility(View.VISIBLE); + binding.divider.setVisibility(View.VISIBLE); + } } private void presentButtonState(@NonNull UsernameEditViewModel.ButtonState buttonState) { - if (args.getIsInRegistration()) { - presentRegistrationButtonState(buttonState); - } else { - presentProfileUpdateButtonState(buttonState); - } - } - - private void presentSummary(@NonNull UsernameState usernameState) { - if (usernameState.getUsername() != null) { - binding.summary.setText(usernameState.getUsername().getUsername()); - binding.summary.setAlpha(1f); - } else if (!(usernameState instanceof UsernameState.Loading)) { - binding.summary.setText(R.string.UsernameEditFragment__choose_your_username); - binding.summary.setAlpha(1f); - } - } - - private void presentRegistrationButtonState(@NonNull UsernameEditViewModel.ButtonState buttonState) { - binding.usernameText.setEnabled(true); - binding.usernameProgressCard.setVisibility(View.GONE); - - switch (buttonState) { - case SUBMIT: - binding.usernameDoneButton.setEnabled(true); - binding.usernameDoneButton.setAlpha(1f); - break; - case SUBMIT_DISABLED: - binding.usernameDoneButton.setEnabled(false); - binding.usernameDoneButton.setAlpha(DISABLED_ALPHA); - break; - case SUBMIT_LOADING: - binding.usernameDoneButton.setEnabled(false); - binding.usernameDoneButton.setAlpha(DISABLED_ALPHA); - binding.usernameProgressCard.setVisibility(View.VISIBLE); - break; - default: - throw new IllegalStateException("Delete functionality is not available during registration."); - } - } - - private void presentProfileUpdateButtonState(@NonNull UsernameEditViewModel.ButtonState buttonState) { CircularProgressMaterialButton submitButton = binding.usernameSubmitButton; CircularProgressMaterialButton deleteButton = binding.usernameDeleteButton; EditText usernameInput = binding.usernameText; @@ -274,6 +257,16 @@ public class UsernameEditFragment extends LoggingFragment { } } + private void presentSummary(@NonNull UsernameState usernameState) { + if (usernameState.getUsername() != null) { + binding.summary.setText(usernameState.getUsername().getUsername()); + binding.summary.setAlpha(1f); + } else if (!(usernameState instanceof UsernameState.Loading)) { + binding.summary.setText(R.string.UsernameEditFragment__choose_your_username); + binding.summary.setAlpha(1f); + } + } + private void presentUsernameInputState(@NonNull UsernameEditStateMachine.State state) { binding.usernameText.setTag(IGNORE_TEXT_CHANGE_EVENT); String nickname = state.getNickname(); @@ -306,6 +299,9 @@ public class UsernameEditFragment extends LoggingFragment { switch (event) { case SUBMIT_SUCCESS: ResultContract.setUsernameCreated(getParentFragmentManager()); + if (getActivity() != null) { + getActivity().setResult(Activity.RESULT_OK); + } closeScreen(); break; case SUBMIT_FAIL_TAKEN: @@ -321,39 +317,29 @@ public class UsernameEditFragment extends LoggingFragment { case NETWORK_FAILURE: Toast.makeText(requireContext(), R.string.UsernameEditFragment_encountered_a_network_error, Toast.LENGTH_SHORT).show(); break; + case RATE_LIMIT_EXCEEDED: + Toast.makeText(requireContext(), R.string.UsernameEditFragment_rate_limit_exceeded_error, Toast.LENGTH_SHORT).show(); + break; case SKIPPED: closeScreen(); break; + case NEEDS_CONFIRM_RESET: + new MaterialAlertDialogBuilder(requireContext()) + .setMessage(R.string.UsernameEditFragment_change_confirmation_message) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) + .setPositiveButton(R.string.UsernameEditFragment_continue, (dialog, which) -> viewModel.onUsernameSubmitted(true)) + .show(); } } private void closeScreen() { - if (args.getIsInRegistration()) { - finishAndStartNextIntent(); + if (args.getMode() == UsernameEditMode.RECOVERY) { + getActivity().finish(); } else { NavHostFragment.findNavController(this).popBackStack(); } } - private void finishAndStartNextIntent() { - FragmentActivity activity = requireActivity(); - boolean didLaunch = false; - Intent activityIntent = activity.getIntent(); - - if (activityIntent != null) { - Intent nextIntent = activityIntent.getParcelableExtra(PassphraseRequiredActivity.NEXT_INTENT_EXTRA); - if (nextIntent != null) { - activity.startActivity(nextIntent); - activity.finish(); - didLaunch = true; - } - } - - if (!didLaunch) { - activity.finish(); - } - } - static class ResultContract extends FragmentResultContract { private static final String REQUEST_KEY = "username_created"; diff --git a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditMode.kt b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditMode.kt new file mode 100644 index 00000000..3975ea16 --- /dev/null +++ b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditMode.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.profiles.manage + +enum class UsernameEditMode { + /** A typical launch, no special conditions. */ + NORMAL, + + /** Screen was launched because the username was in a bad state and needs to be recovered. Shows a special dialog. */ + RECOVERY +} diff --git a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditViewModel.kt b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditViewModel.kt index 867c70ea..cab10d55 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditViewModel.kt +++ b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEditViewModel.kt @@ -12,14 +12,17 @@ import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.subjects.PublishSubject import org.signal.core.util.Result +import org.signal.core.util.isNotNullOrBlank import org.signal.core.util.logging.Log import org.signal.libsignal.usernames.Username +import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.keyvalue.SignalStore import org.tm.archive.profiles.manage.UsernameRepository.UsernameDeleteResult import org.tm.archive.profiles.manage.UsernameRepository.UsernameSetResult +import org.tm.archive.util.NetworkUtil import org.tm.archive.util.UsernameUtil.InvalidReason import org.tm.archive.util.UsernameUtil.checkDiscriminator -import org.tm.archive.util.UsernameUtil.checkUsername +import org.tm.archive.util.UsernameUtil.checkNickname import org.tm.archive.util.rx.RxStore import org.whispersystems.signalservice.api.util.Usernames import java.util.concurrent.TimeUnit @@ -31,11 +34,9 @@ import java.util.concurrent.TimeUnit * A note on naming conventions: * Usernames are made up of two discrete components, a nickname and a discriminator. They are formatted thusly: * - * [nickname].[discriminator] - * - * The nickname is user-controlled, whereas the discriminator is controlled by the server. + * nickname.discriminator */ -internal class UsernameEditViewModel private constructor(private val isInRegistration: Boolean) : ViewModel() { +internal class UsernameEditViewModel private constructor(private val mode: UsernameEditMode) : ViewModel() { private val events: PublishSubject = PublishSubject.create() private val disposables: CompositeDisposable = CompositeDisposable() @@ -65,6 +66,11 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr .filter { it.stateModifier == UsernameEditStateMachine.StateModifier.USER } .debounce(NICKNAME_PUBLISHER_DEBOUNCE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) .subscribeBy(onNext = this::onUsernameStateUpdateDebounced) + + if (mode == UsernameEditMode.RECOVERY) { + onNicknameUpdated(SignalStore.account().username?.split(Usernames.DELIMITER)?.first() ?: "") + onDiscriminatorUpdated(SignalStore.account().username?.split(Usernames.DELIMITER)?.last() ?: "") + } } override fun onCleared() { @@ -77,7 +83,7 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr uiState.update { state: State -> if (nickname.isBlank() && SignalStore.account().username != null) { return@update State( - buttonState = if (isInRegistration) ButtonState.SUBMIT_DISABLED else ButtonState.DELETE, + buttonState = ButtonState.DELETE, usernameStatus = UsernameStatus.NONE, usernameState = UsernameState.NoUsername ) @@ -99,7 +105,7 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr uiState.update { state: State -> if (discriminator.isBlank() && SignalStore.account().username != null) { return@update State( - buttonState = if (isInRegistration) ButtonState.SUBMIT_DISABLED else ButtonState.DELETE, + buttonState = ButtonState.DELETE, usernameStatus = UsernameStatus.NONE, usernameState = UsernameState.NoUsername ) @@ -122,24 +128,44 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr events.onNext(Event.SKIPPED) } - fun onUsernameSubmitted() { + fun isSameUsernameRecovery(): Boolean { + val usernameState = uiState.state.usernameState + return mode == UsernameEditMode.RECOVERY && + usernameState is UsernameState.Reserved && + usernameState.requireUsername().username.lowercase() == SignalStore.account().username?.lowercase() + } + + /** + * @param userConfirmedResetOk True if the user is submitting this after confirming that they're ok with resetting their username via [Event.NEEDS_CONFIRM_RESET]. + */ + fun onUsernameSubmitted(userConfirmedResetOk: Boolean) { + if (!NetworkUtil.isConnected(ApplicationDependencies.getApplication())) { + events.onNext(Event.NETWORK_FAILURE) + return + } + val editState = stateMachineStore.state val usernameState = uiState.state.usernameState val isCaseChange = isCaseChange(editState) + if (!isCaseChange && SignalStore.account().username.isNotNullOrBlank() && !userConfirmedResetOk) { + events.onNext(Event.NEEDS_CONFIRM_RESET) + return + } + if (usernameState !is UsernameState.Reserved && usernameState !is UsernameState.CaseChange) { Log.w(TAG, "Username was submitted, current state is invalid! State: ${usernameState.javaClass.simpleName}") uiState.update { it.copy(buttonState = ButtonState.SUBMIT_DISABLED, usernameStatus = UsernameStatus.NONE) } return } - if (usernameState.requireUsername().username == SignalStore.account().username) { + if (usernameState.requireUsername().username == SignalStore.account().username && mode != UsernameEditMode.RECOVERY) { Log.d(TAG, "Username was submitted, but was identical to the current username. Ignoring.") uiState.update { it.copy(buttonState = ButtonState.SUBMIT_DISABLED, usernameStatus = UsernameStatus.NONE) } return } - val invalidReason: InvalidReason? = checkUsername(usernameState.getNickname()) + val invalidReason: InvalidReason? = checkNickname(usernameState.getNickname()) if (invalidReason != null) { Log.w(TAG, "Username was submitted, but did not pass validity checks. Reason: $invalidReason") uiState.update { it.copy(buttonState = ButtonState.SUBMIT_DISABLED, usernameStatus = mapNicknameError(invalidReason)) } @@ -181,6 +207,11 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr uiState.update { State(ButtonState.SUBMIT, UsernameStatus.NONE, it.usernameState) } events.onNext(Event.NETWORK_FAILURE) } + + UsernameSetResult.RATE_LIMIT_ERROR -> { + uiState.update { State(ButtonState.SUBMIT, UsernameStatus.NONE, it.usernameState) } + events.onNext(Event.RATE_LIMIT_EXCEEDED) + } } } } @@ -212,6 +243,10 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr } private fun isCaseChange(state: UsernameEditStateMachine.State): Boolean { + if (mode == UsernameEditMode.RECOVERY) { + return false + } + if (state is UsernameEditStateMachine.UserEnteredDiscriminator || state is UsernameEditStateMachine.UserEnteredNicknameAndDiscriminator) { return false } @@ -233,7 +268,7 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr return } - val invalidReason: InvalidReason? = checkUsername(nickname) + val invalidReason: InvalidReason? = checkNickname(nickname) if (invalidReason != null) { uiState.update { uiState -> uiState.copy( @@ -313,6 +348,11 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr events.onNext(Event.NETWORK_FAILURE) } + UsernameSetResult.RATE_LIMIT_ERROR -> { + uiState.update { State(ButtonState.SUBMIT, UsernameStatus.NONE, UsernameState.NoUsername) } + events.onNext(Event.RATE_LIMIT_EXCEEDED) + } + UsernameSetResult.CANDIDATE_GENERATION_ERROR -> { // TODO -- Retry uiState.update { State(ButtonState.SUBMIT_DISABLED, UsernameStatus.TAKEN, UsernameState.NoUsername) } @@ -340,7 +380,9 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr DISCRIMINATOR_NOT_AVAILABLE, DISCRIMINATOR_TOO_SHORT, DISCRIMINATOR_TOO_LONG, - DISCRIMINATOR_HAS_INVALID_CHARACTERS + DISCRIMINATOR_HAS_INVALID_CHARACTERS, + DISCRIMINATOR_CANNOT_BE_00, + DISCRIMINATOR_CANNOT_START_WITH_0 } enum class ButtonState { @@ -348,19 +390,19 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr } enum class Event { - NETWORK_FAILURE, SUBMIT_SUCCESS, DELETE_SUCCESS, SUBMIT_FAIL_INVALID, SUBMIT_FAIL_TAKEN, SKIPPED + NETWORK_FAILURE, SUBMIT_SUCCESS, DELETE_SUCCESS, SUBMIT_FAIL_INVALID, SUBMIT_FAIL_TAKEN, SKIPPED, NEEDS_CONFIRM_RESET, RATE_LIMIT_EXCEEDED } - class Factory(private val isInRegistration: Boolean) : ViewModelProvider.Factory { + class Factory(private val mode: UsernameEditMode) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { - return modelClass.cast(UsernameEditViewModel(isInRegistration))!! + return modelClass.cast(UsernameEditViewModel(mode))!! } } companion object { private val TAG = Log.tag(UsernameEditViewModel::class.java) - private const val NICKNAME_PUBLISHER_DEBOUNCE_TIMEOUT_MILLIS: Long = 1000 + private const val NICKNAME_PUBLISHER_DEBOUNCE_TIMEOUT_MILLIS: Long = 500 private fun mapNicknameError(invalidReason: InvalidReason): UsernameStatus { return when (invalidReason) { @@ -368,6 +410,9 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr InvalidReason.TOO_LONG -> UsernameStatus.TOO_LONG InvalidReason.STARTS_WITH_NUMBER -> UsernameStatus.CANNOT_START_WITH_NUMBER InvalidReason.INVALID_CHARACTERS -> UsernameStatus.INVALID_CHARACTERS + InvalidReason.INVALID_NUMBER, + InvalidReason.INVALID_NUMBER_00, + InvalidReason.INVALID_NUMBER_PREFIX_0 -> error("Unexpected reason $invalidReason") } } @@ -376,6 +421,8 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr InvalidReason.TOO_SHORT -> UsernameStatus.DISCRIMINATOR_TOO_SHORT InvalidReason.TOO_LONG -> UsernameStatus.DISCRIMINATOR_TOO_LONG InvalidReason.INVALID_CHARACTERS -> UsernameStatus.DISCRIMINATOR_HAS_INVALID_CHARACTERS + InvalidReason.INVALID_NUMBER_00 -> UsernameStatus.DISCRIMINATOR_CANNOT_BE_00 + InvalidReason.INVALID_NUMBER_PREFIX_0 -> UsernameStatus.DISCRIMINATOR_CANNOT_START_WITH_0 else -> UsernameStatus.INVALID_GENERIC } } diff --git a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEducationFragment.kt b/app/src/main/java/org/tm/archive/profiles/manage/UsernameEducationFragment.kt deleted file mode 100644 index fe10c27a..00000000 --- a/app/src/main/java/org/tm/archive/profiles/manage/UsernameEducationFragment.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.tm.archive.profiles.manage - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import org.tm.archive.R -import org.tm.archive.components.ViewBinderDelegate -import org.tm.archive.databinding.UsernameEducationFragmentBinding -import org.tm.archive.dependencies.ApplicationDependencies -import org.tm.archive.keyvalue.SignalStore -import org.tm.archive.megaphone.Megaphones -import org.tm.archive.util.CommunicationActions -import org.tm.archive.util.navigation.safeNavigate - -/** - * Displays a Username education screen which displays some basic information - * about usernames and provides a learn-more link. - */ -class UsernameEducationFragment : Fragment(R.layout.username_education_fragment) { - private val binding by ViewBinderDelegate(UsernameEducationFragmentBinding::bind) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - binding.toolbar.setNavigationOnClickListener { - findNavController().popBackStack() - } - - binding.usernameEducationLearnMore.setOnClickListener { - CommunicationActions.openBrowserLink(requireContext(), getString(R.string.username_support_url)) - } - - binding.continueButton.setOnClickListener { - SignalStore.uiHints().markHasSeenUsernameEducation() - ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.SET_UP_YOUR_USERNAME) - findNavController().safeNavigate(UsernameEducationFragmentDirections.actionUsernameEducationFragmentToUsernameManageFragment()) - } - } -} diff --git a/app/src/main/java/org/tm/archive/profiles/manage/UsernameRepository.kt b/app/src/main/java/org/tm/archive/profiles/manage/UsernameRepository.kt index 04c3ded2..e8ed8ca4 100644 --- a/app/src/main/java/org/tm/archive/profiles/manage/UsernameRepository.kt +++ b/app/src/main/java/org/tm/archive/profiles/manage/UsernameRepository.kt @@ -23,6 +23,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.UsernameLinkComponents import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException +import org.whispersystems.signalservice.api.push.exceptions.RateLimitException import org.whispersystems.signalservice.api.push.exceptions.UsernameIsNotAssociatedWithAnAccountException import org.whispersystems.signalservice.api.push.exceptions.UsernameIsNotReservedException import org.whispersystems.signalservice.api.push.exceptions.UsernameMalformedException @@ -129,7 +130,7 @@ object UsernameRepository { @WorkerThread @JvmStatic fun reclaimUsernameIfNecessary(): UsernameReclaimResult { - if (!SignalStore.misc().needsUsernameRestore()) { + if (!SignalStore.misc().needsUsernameRestore) { Log.d(TAG, "[reclaimUsernameIfNecessary] No need to restore username. Skipping.") return UsernameReclaimResult.SUCCESS } @@ -139,7 +140,7 @@ object UsernameRepository { if (username == null || link == null) { Log.d(TAG, "[reclaimUsernameIfNecessary] No username or link to restore. Skipping.") - SignalStore.misc().setNeedsUsernameRestore(false) + SignalStore.misc().needsUsernameRestore = false return UsernameReclaimResult.SUCCESS } @@ -148,13 +149,13 @@ object UsernameRepository { when (result) { UsernameReclaimResult.SUCCESS -> { Log.i(TAG, "[reclaimUsernameIfNecessary] Successfully reclaimed username and link.") - SignalStore.misc().setNeedsUsernameRestore(false) + SignalStore.misc().needsUsernameRestore = false } UsernameReclaimResult.PERMANENT_ERROR -> { Log.w(TAG, "[reclaimUsernameIfNecessary] Permanently failed to reclaim username and link. User will see an error.") SignalStore.account().usernameSyncState = AccountValues.UsernameSyncState.USERNAME_AND_LINK_CORRUPTED - SignalStore.misc().setNeedsUsernameRestore(false) + SignalStore.misc().needsUsernameRestore = false } UsernameReclaimResult.NETWORK_ERROR -> { @@ -310,6 +311,10 @@ object UsernameRepository { return BASE_URL + base64 } + fun isValidLink(url: String): Boolean { + return parseLink(url) != null + } + @JvmStatic fun onUsernameConsistencyValidated() { SignalStore.account().usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC @@ -379,6 +384,9 @@ object UsernameRepository { } catch (e: UsernameMalformedException) { Log.w(TAG, "[reserveUsername] Username malformed.") failure(UsernameSetResult.USERNAME_INVALID) + } catch (e: RateLimitException) { + Log.w(TAG, "[reserveUsername] Rate limit exceeded.") + failure(UsernameSetResult.RATE_LIMIT_ERROR) } catch (e: IOException) { Log.w(TAG, "[reserveUsername] Generic network exception.", e) failure(UsernameSetResult.NETWORK_ERROR) @@ -389,6 +397,11 @@ object UsernameRepository { private fun updateUsernameDisplayForCurrentLinkInternal(updatedUsername: Username): UsernameSetResult { Log.i(TAG, "[updateUsernameDisplayForCurrentLink] Beginning username update...") + if (!NetworkUtil.isConnected(ApplicationDependencies.getApplication())) { + Log.w(TAG, "[deleteUsernameInternal] No network connection! Not attempting the request.") + return UsernameSetResult.NETWORK_ERROR + } + return try { val oldUsernameLink = SignalStore.account().usernameLink ?: return UsernameSetResult.USERNAME_INVALID val newUsernameLink = updatedUsername.generateLink(oldUsernameLink.entropy) @@ -415,6 +428,11 @@ object UsernameRepository { private fun confirmUsernameAndCreateNewLinkInternal(username: Username): UsernameSetResult { Log.i(TAG, "[confirmUsernameAndCreateNewLink] Beginning username confirmation...") + if (!NetworkUtil.isConnected(ApplicationDependencies.getApplication())) { + Log.w(TAG, "[confirmUsernameAndCreateNewLink] No network connection! Not attempting the request.") + return UsernameSetResult.NETWORK_ERROR + } + return try { val linkComponents: UsernameLinkComponents = accountManager.confirmUsernameAndCreateNewLink(username) @@ -446,6 +464,11 @@ object UsernameRepository { @WorkerThread private fun deleteUsernameInternal(): UsernameDeleteResult { + if (!NetworkUtil.isConnected(ApplicationDependencies.getApplication())) { + Log.w(TAG, "[deleteUsernameInternal] No network connection! Not attempting the request.") + return UsernameDeleteResult.NETWORK_ERROR + } + return try { accountManager.deleteUsername() SignalDatabase.recipients.setUsername(Recipient.self().id, null) @@ -486,7 +509,7 @@ object UsernameRepository { } enum class UsernameSetResult { - SUCCESS, USERNAME_UNAVAILABLE, USERNAME_INVALID, NETWORK_ERROR, CANDIDATE_GENERATION_ERROR + SUCCESS, USERNAME_UNAVAILABLE, USERNAME_INVALID, NETWORK_ERROR, CANDIDATE_GENERATION_ERROR, RATE_LIMIT_ERROR } enum class UsernameReclaimResult { diff --git a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewBannerView.java b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewBannerView.java index 1f7ee053..3cd740dc 100644 --- a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewBannerView.java +++ b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewBannerView.java @@ -12,6 +12,7 @@ import org.tm.archive.R; import org.tm.archive.contacts.avatars.FallbackContactPhoto; import org.tm.archive.contacts.avatars.FallbackPhoto20dp; import org.tm.archive.contacts.avatars.GeneratedContactPhoto; +import org.tm.archive.contacts.avatars.ResourceContactPhoto; import org.tm.archive.conversation.colors.AvatarColor; import org.tm.archive.databinding.ReviewBannerViewBinding; import org.tm.archive.recipients.Recipient; @@ -69,9 +70,9 @@ public class ReviewBannerView extends FrameLayout { binding.bannerAvatarStroke.setVisibility(GONE); } - public void setBannerRecipient(@NonNull Recipient recipient) { - binding.bannerTopLeftAvatar.setAvatar(recipient); - binding.bannerBottomRightAvatar.setAvatar(recipient); + public void setBannerRecipients(@NonNull Recipient target, @NonNull Recipient dupe) { + binding.bannerTopLeftAvatar.setAvatar(target); + binding.bannerBottomRightAvatar.setAvatar(dupe); binding.bannerIcon.setVisibility(GONE); binding.bannerTopLeftAvatar.setVisibility(VISIBLE); @@ -99,7 +100,7 @@ public class ReviewBannerView extends FrameLayout { @Override public @NonNull FallbackContactPhoto getPhotoForLocalNumber() { - throw new UnsupportedOperationException("This provider does not support local number"); + return new ResourceContactPhoto(R.drawable.symbol_note_light_24, R.drawable.symbol_note_light_24); } @NonNull diff --git a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardDialogFragment.java b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardDialogFragment.java index 7b680ce9..522b1add 100644 --- a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardDialogFragment.java +++ b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardDialogFragment.java @@ -175,8 +175,7 @@ public class ReviewCardDialogFragment extends FullScreenDialogFragment { @Override public void onCardClicked(@NonNull ReviewCard card) { - RecipientBottomSheetDialogFragment.create(card.getReviewRecipient().getId(), null) - .show(requireFragmentManager(), null); + RecipientBottomSheetDialogFragment.show(getParentFragmentManager(), card.getReviewRecipient().getId(), null); } @Override diff --git a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardViewHolder.java b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardViewHolder.java index 29984161..d9439772 100644 --- a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardViewHolder.java +++ b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewCardViewHolder.java @@ -83,13 +83,6 @@ class ReviewCardViewHolder extends RecyclerView.ViewHolder { binding.cardName.setText(name); - int titleTextResId = getTitleResId(reviewCard.getCardType()); - if (titleTextResId > 0) { - binding.cardTitle.setText(getTitleResId(reviewCard.getCardType())); - } else { - binding.cardTitle.setVisibility(View.GONE); - } - List rows = switch (reviewCard.getCardType()) { case MEMBER, REQUEST -> getNonContactSublines(reviewCard); case YOUR_CONTACT -> getContactSublines(reviewCard); @@ -253,14 +246,6 @@ class ReviewCardViewHolder extends RecyclerView.ViewHolder { void onSignalConnectionClicked(); } - private static @StringRes int getTitleResId(@NonNull ReviewCard.CardType cardType) { - return switch (cardType) { - case MEMBER -> -1; - case REQUEST -> R.string.ReviewCard__request; - case YOUR_CONTACT -> R.string.ReviewCard__your_contact; - }; - } - private static @StringRes int getActionLabelResId(@NonNull ReviewCard.Action action) { return switch (action) { case UPDATE_CONTACT -> R.string.ReviewCard__update_contact; diff --git a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewUtil.java b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewUtil.java index 1ac1960c..d87f1b2d 100644 --- a/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewUtil.java +++ b/app/src/main/java/org/tm/archive/profiles/spoofing/ReviewUtil.java @@ -39,15 +39,17 @@ public final class ReviewUtil { * @return Whether or not multiple recipients share this profile name. */ @WorkerThread - public static boolean isRecipientReviewSuggested(@NonNull RecipientId recipientId) + public static List getRecipientsToPromptForReview(@NonNull RecipientId recipientId) { Recipient recipient = Recipient.resolved(recipientId); if (recipient.isGroup() || recipient.isSystemContact()) { - return false; + return Collections.emptyList(); } - return SignalDatabase.recipients().getSimilarRecipientIds(recipient).size() > 1; + return Stream.of(SignalDatabase.recipients().getSimilarRecipientIds(recipient)) + .filter(id -> !id.equals(recipientId)) + .toList(); } @WorkerThread diff --git a/app/src/main/java/org/tm/archive/profiles/username/AddAUsernameActivity.kt b/app/src/main/java/org/tm/archive/profiles/username/AddAUsernameActivity.kt deleted file mode 100644 index f813d26d..00000000 --- a/app/src/main/java/org/tm/archive/profiles/username/AddAUsernameActivity.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.tm.archive.profiles.username - -import android.os.Bundle -import androidx.navigation.fragment.NavHostFragment -import org.tm.archive.BaseActivity -import org.tm.archive.R -import org.tm.archive.profiles.manage.UsernameEditFragmentArgs -import org.tm.archive.util.DynamicNoActionBarTheme -import org.tm.archive.util.DynamicTheme - -class AddAUsernameActivity : BaseActivity() { - private val dynamicTheme: DynamicTheme = DynamicNoActionBarTheme() - private val contentViewId: Int = R.layout.fragment_container - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(contentViewId) - dynamicTheme.onCreate(this) - - if (savedInstanceState == null) { - supportFragmentManager.beginTransaction() - .replace( - R.id.fragment_container, - NavHostFragment.create( - R.navigation.create_username, - UsernameEditFragmentArgs.Builder().setIsInRegistration(true).build().toBundle() - ) - ) - .commit() - } - } - - override fun onResume() { - super.onResume() - dynamicTheme.onResume(this) - } -} diff --git a/app/src/main/java/org/tm/archive/profiles/username/NewWaysToConnectDialogFragment.kt b/app/src/main/java/org/tm/archive/profiles/username/NewWaysToConnectDialogFragment.kt new file mode 100644 index 00000000..06ec316e --- /dev/null +++ b/app/src/main/java/org/tm/archive/profiles/username/NewWaysToConnectDialogFragment.kt @@ -0,0 +1,204 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.profiles.username + +import android.os.Bundle +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.ui.Scaffolds +import org.tm.archive.R +import org.tm.archive.compose.ComposeDialogFragment +import org.tm.archive.profiles.manage.EditProfileActivity + +/** + * Displays an explanation page about usernames and gives the user + * the opportunity to set one up now. + */ +class NewWaysToConnectDialogFragment : ComposeDialogFragment() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen) + } + + @Composable + override fun DialogContent() { + NewWaysToConnectDialogContent( + onSetUpUsernameClick = { + startActivity(EditProfileActivity.getIntentForUsernameEdit(requireContext())) + dismissAllowingStateLoss() + }, + onNotNowClick = { dismissAllowingStateLoss() } + ) + } +} + +@Preview +@Composable +private fun PreviewNewWaysToConnectDialogContent() { + Previews.Preview { + NewWaysToConnectDialogContent( + onSetUpUsernameClick = {}, + onNotNowClick = {} + ) + } +} + +@Composable +private fun NewWaysToConnectDialogContent( + onSetUpUsernameClick: () -> Unit, + onNotNowClick: () -> Unit +) { + Scaffolds.Settings( + title = "", + onNavigationClick = onNotNowClick, + navigationIconPainter = painterResource(id = R.drawable.symbol_x_24) + ) { + Column(modifier = Modifier.padding(it)) { + LazyColumn(modifier = Modifier.weight(1f)) { + item { + Text( + text = stringResource(id = R.string.NewWaysToConnectDialogFragment__new_ways_to_connect), + style = MaterialTheme.typography.headlineMedium, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + .padding(top = 4.dp, bottom = 36.dp) + ) + } + + item { + NewWaysToConnectRowItem( + title = stringResource(id = R.string.NewWaysToConnectDialogFragment__phone_number_privacy), + description = stringResource(id = R.string.NewWaysToConnectDialogFragment__your_phone_number_is_no_longer_shared), + image = painterResource(id = R.drawable.phone_48_color) + ) + } + + item { + NewWaysToConnectRowItem( + title = stringResource(id = R.string.NewWaysToConnectDialogFragment__usernames), + description = stringResource(id = R.string.NewWaysToConnectDialogFragment__people_can_now_message_you_using_your_optional_username), + image = painterResource(id = R.drawable.usernames_48_color) + ) + } + + item { + NewWaysToConnectRowItem( + title = stringResource(id = R.string.NewWaysToConnectDialogFragment__qr_codes_and_links), + description = stringResource(id = R.string.NewWaysToConnectDialogFragment__usernames_have_a_unique_qr_code), + image = painterResource(id = R.drawable.qr_codes_48_color) + ) + } + } + + Buttons.LargeTonal( + onClick = onSetUpUsernameClick, + modifier = Modifier + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + .padding(top = 16.dp) + .defaultMinSize(minWidth = 221.dp) + .align(alignment = Alignment.CenterHorizontally) + ) { + Text( + text = stringResource(id = R.string.NewWaysToConnectDialogFragment__set_up_your_username) + ) + } + + TextButton( + onClick = onNotNowClick, + modifier = Modifier + .padding( + start = dimensionResource(id = R.dimen.core_ui__gutter), + end = dimensionResource(id = R.dimen.core_ui__gutter), + top = 8.dp, + bottom = 16.dp + ) + .defaultMinSize(minWidth = 221.dp) + .align(alignment = Alignment.CenterHorizontally) + ) { + Text(text = stringResource(id = R.string.NewWaysToConnectDialogFragment__not_now)) + } + } + } +} + +@Preview +@Composable +private fun PreviewNewWaysToConnectRowItem() { + Previews.Preview { + NewWaysToConnectRowItem( + title = "Example Item", + description = "Sample text for the subtitle of the example", + image = painterResource(id = R.drawable.symbol_album_tilt_24) + ) + } +} + +@Composable +private fun NewWaysToConnectRowItem( + title: String, + description: String, + image: Painter, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .padding( + horizontal = dimensionResource(id = R.dimen.core_ui__gutter) + ) + .padding( + bottom = 40.dp + ) + ) { + Image( + painter = image, + contentDescription = null, + modifier = Modifier + .padding( + start = 12.dp, + top = 4.dp, + end = 24.dp + ) + .size(48.dp) + ) + Column { + Text( + text = title, + style = MaterialTheme.typography.titleMedium + ) + Text( + text = description, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 2.dp, end = 8.dp) + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/providers/MmsBodyProvider.java b/app/src/main/java/org/tm/archive/providers/MmsBodyProvider.java deleted file mode 100644 index 3a4818b8..00000000 --- a/app/src/main/java/org/tm/archive/providers/MmsBodyProvider.java +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (C) 2015 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.tm.archive.providers; - -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.database.Cursor; -import android.net.Uri; -import android.os.ParcelFileDescriptor; - -import androidx.annotation.NonNull; - -import org.signal.core.util.logging.Log; -import org.tm.archive.BuildConfig; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStream; - -public final class MmsBodyProvider extends BaseContentProvider { - private static final String TAG = Log.tag(MmsBodyProvider.class); - private static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID + ".mms"; - private static final String CONTENT_URI_STRING = "content://" + CONTENT_AUTHORITY + "/mms"; - public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING); - private static final int SINGLE_ROW = 1; - - private static final UriMatcher uriMatcher; - - static { - uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - uriMatcher.addURI(CONTENT_AUTHORITY, "mms/#", SINGLE_ROW); - } - - @Override - public boolean onCreate() { - return true; - } - - - private File getFile(Uri uri) { - long id = Long.parseLong(uri.getPathSegments().get(1)); - return new File(getContext().getCacheDir(), id + ".mmsbody"); - } - - @Override - public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { - Log.i(TAG, "openFile(" + uri + ", " + mode + ")"); - - switch (uriMatcher.match(uri)) { - case SINGLE_ROW: - Log.i(TAG, "Fetching message body for a single row..."); - File tmpFile = getFile(uri); - - final int fileMode; - switch (mode) { - case "w": fileMode = ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_WRITE_ONLY; break; - case "r": fileMode = ParcelFileDescriptor.MODE_READ_ONLY; break; - default: throw new IllegalArgumentException("requested file mode unsupported"); - } - - Log.i(TAG, "returning file " + tmpFile.getAbsolutePath()); - return ParcelFileDescriptor.open(tmpFile, fileMode); - } - - throw new FileNotFoundException("Request for bad message."); - } - - @Override - public int delete(@NonNull Uri uri, String arg1, String[] arg2) { - switch (uriMatcher.match(uri)) { - case SINGLE_ROW: - return getFile(uri).delete() ? 1 : 0; - } - return 0; - } - - @Override - public String getType(@NonNull Uri arg0) { - return null; - } - - @Override - public Uri insert(@NonNull Uri arg0, ContentValues arg1) { - return null; - } - - @Override - public Cursor query(@NonNull Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { - return null; - } - - @Override - public int update(@NonNull Uri arg0, ContentValues arg1, String arg2, String[] arg3) { - return 0; - } - public static Pointer makeTemporaryPointer(Context context) { - return new Pointer(context, ContentUris.withAppendedId(MmsBodyProvider.CONTENT_URI, System.currentTimeMillis())); - } - - public static class Pointer { - private final Context context; - private final Uri uri; - - public Pointer(Context context, Uri uri) { - this.context = context; - this.uri = uri; - } - - public Uri getUri() { - return uri; - } - - public OutputStream getOutputStream() throws FileNotFoundException { - return context.getContentResolver().openOutputStream(uri, "w"); - } - - public InputStream getInputStream() throws FileNotFoundException { - return context.getContentResolver().openInputStream(uri); - } - - public void close() { - context.getContentResolver().delete(uri, null, null); - } - } -} diff --git a/app/src/main/java/org/tm/archive/providers/PartProvider.java b/app/src/main/java/org/tm/archive/providers/PartProvider.java index ad8f5e61..10aafd56 100644 --- a/app/src/main/java/org/tm/archive/providers/PartProvider.java +++ b/app/src/main/java/org/tm/archive/providers/PartProvider.java @@ -68,7 +68,7 @@ public final class PartProvider extends BaseContentProvider { static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - uriMatcher.addURI(CONTENT_AUTHORITY, "part/*/#", SINGLE_ROW); + uriMatcher.addURI(CONTENT_AUTHORITY, "part/#", SINGLE_ROW); } @Override diff --git a/app/src/main/java/org/tm/archive/reactions/ReactionRecipientsAdapter.java b/app/src/main/java/org/tm/archive/reactions/ReactionRecipientsAdapter.java index cdbb678d..b547470b 100644 --- a/app/src/main/java/org/tm/archive/reactions/ReactionRecipientsAdapter.java +++ b/app/src/main/java/org/tm/archive/reactions/ReactionRecipientsAdapter.java @@ -8,10 +8,11 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; + import org.tm.archive.R; import org.tm.archive.badges.BadgeImageView; import org.tm.archive.components.AvatarImageView; -import org.tm.archive.mms.GlideApp; import org.tm.archive.util.AvatarUtil; import java.util.Collections; @@ -65,12 +66,12 @@ final class ReactionRecipientsAdapter extends RecyclerView.Adapter extras; private final boolean hasGroupsInCommon; @@ -140,6 +139,8 @@ public class Recipient { private final CallLinkRoomId callLinkRoomId; private final Optional groupRecord; private final PhoneNumberSharingState phoneNumberSharing; + private final ProfileName nickname; + private final String note; /** * Returns a {@link LiveRecipient}, which contains a {@link Recipient} that may or may not be @@ -430,6 +431,8 @@ public class Recipient { this.callLinkRoomId = null; this.groupRecord = Optional.empty(); this.phoneNumberSharing = PhoneNumberSharingState.UNKNOWN; + this.nickname = ProfileName.EMPTY; + this.note = null; } public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) { @@ -486,6 +489,8 @@ public class Recipient { this.callLinkRoomId = details.callLinkRoomId; this.groupRecord = details.groupRecord; this.phoneNumberSharing = details.phoneNumberSharing; + this.nickname = details.nickname; + this.note = details.note; } public @NonNull RecipientId getId() { @@ -500,6 +505,10 @@ public class Recipient { return contactUri; } + public @Nullable String getNote() { + return note; + } + public @Nullable String getGroupName(@NonNull Context context) { if (groupId != null && Util.isEmpty(this.groupName)) { RecipientId selfId = ApplicationDependencies.getRecipientCache().getSelfId(); @@ -545,15 +554,12 @@ public class Recipient { } } - public boolean hasName() { - return groupName != null; - } - /** * False iff it {@link #getDisplayName} would fall back to e164, email or unknown. */ public boolean hasAUserSetDisplayName(@NonNull Context context) { return !TextUtils.isEmpty(getGroupName(context)) || + !TextUtils.isEmpty(getNickname().toString()) || !TextUtils.isEmpty(systemContactName) || !TextUtils.isEmpty(getProfileName().toString()); } @@ -562,21 +568,11 @@ public class Recipient { String name = getNameFromLocalData(context); if (Util.isEmpty(name)) { - name = context.getString(R.string.Recipient_unknown); - } - - return StringUtil.isolateBidi(name); - } - - public @NonNull String getDisplayNameOrUsername(@NonNull Context context) { - String name = getNameFromLocalData(context); - - if (Util.isEmpty(name)) { - name = StringUtil.isolateBidi(username); + name = username; } if (Util.isEmpty(name)) { - name = StringUtil.isolateBidi(context.getString(R.string.Recipient_unknown)); + name = getUnknownDisplayName(context); } return StringUtil.isolateBidi(name); @@ -592,6 +588,10 @@ public class Recipient { private @Nullable String getNameFromLocalData(@NonNull Context context) { String name = getGroupName(context); + if (Util.isEmpty(name)) { + name = getNickname().toString(); + } + if (Util.isEmpty(name)) { name = systemContactName; } @@ -615,6 +615,11 @@ public class Recipient { String name = isSelf ? getProfileName().toString() : getGroupName(context); name = StringUtil.isolateBidi(name); + if (Util.isEmpty(name)) { + name = isSelf ? getGroupName(context) : getNickname().toString(); + name = StringUtil.isolateBidi(name); + } + if (Util.isEmpty(name)) { name = isSelf ? getGroupName(context) : systemContactName; name = StringUtil.isolateBidi(name); @@ -642,22 +647,24 @@ public class Recipient { public @NonNull String getShortDisplayName(@NonNull Context context) { String name = Util.getFirstNonEmpty(getGroupName(context), + getNickname().getGivenName(), + getNickname().toString(), getSystemProfileName().getGivenName(), + getSystemProfileName().toString(), getProfileName().getGivenName(), + getProfileName().toString(), + getUsername().orElse(null), getDisplayName(context)); return StringUtil.isolateBidi(name); } - public @NonNull String getShortDisplayNameIncludingUsername(@NonNull Context context) { - String name = Util.getFirstNonEmpty(getGroupName(context), - getSystemProfileName().getGivenName(), - getProfileName().getGivenName(), - getE164().orElse(null), - getUsername().orElse(null), - getDisplayName(context)); - - return StringUtil.isolateBidi(name); + private String getUnknownDisplayName(@NonNull Context context) { + if (getRegistered() == RegisteredState.NOT_REGISTERED) { + return context.getString(R.string.Recipient_deleted_account); + } else { + return context.getString(R.string.Recipient_unknown); + } } public @NonNull Optional getServiceId() { @@ -673,11 +680,7 @@ public class Recipient { } public @NonNull Optional getUsername() { - if (FeatureFlags.usernames()) { - return OptionalUtil.absentIfEmpty(username); - } else { - return Optional.empty(); - } + return OptionalUtil.absentIfEmpty(username); } public @NonNull Optional getE164() { @@ -688,7 +691,7 @@ public class Recipient { * Whether or not we should show this user's e164 in the interface. */ public boolean shouldShowE164() { - return hasE164() && (isSystemContact() || getPhoneNumberSharing() != PhoneNumberSharingState.DISABLED); + return hasE164() && (isSystemContact() || getPhoneNumberSharing() == PhoneNumberSharingState.ENABLED); } public @NonNull Optional getEmail() { @@ -846,6 +849,10 @@ public class Recipient { return requireSmsAddress(); } + public @NonNull ProfileName getNickname() { + return nickname; + } + public @NonNull ProfileName getProfileName() { return signalProfileName; } @@ -981,6 +988,7 @@ public class Recipient { else if (isGroupInternal()) return fallbackPhotoProvider.getPhotoForGroup(); else if (isGroup()) return fallbackPhotoProvider.getPhotoForGroup(); else if (!TextUtils.isEmpty(groupName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(groupName, targetSize); + else if (!nickname.isEmpty()) return fallbackPhotoProvider.getPhotoForRecipientWithName(nickname.toString(), targetSize); else if (!TextUtils.isEmpty(systemContactName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(systemContactName, targetSize); else if (!signalProfileName.isEmpty()) return fallbackPhotoProvider.getPhotoForRecipientWithName(signalProfileName.toString(), targetSize); else return fallbackPhotoProvider.getPhotoForRecipientWithoutName(); @@ -1242,6 +1250,18 @@ public class Recipient { return Objects.requireNonNull(callLinkRoomId); } + public @NonNull byte[] requireCallConversationId() { + if (isPushGroup()) { + return requireGroupId().getDecodedId(); + } else if (isCallLink()) { + return requireCallLinkRoomId().encodeForProto().toByteArray(); + } else if (isIndividual()) { + return requireServiceId().toByteArray(); + } else { + throw new IllegalStateException("Recipient does not support conversation id"); + } + } + public PhoneNumberSharingState getPhoneNumberSharing() { return phoneNumberSharing; } @@ -1403,7 +1423,9 @@ public class Recipient { Objects.equals(badges, other.badges) && isActiveGroup == other.isActiveGroup && Objects.equals(callLinkRoomId, other.callLinkRoomId) && - phoneNumberSharing == other.phoneNumberSharing; + phoneNumberSharing == other.phoneNumberSharing && + Objects.equals(nickname, other.nickname) && + Objects.equals(note, other.note); } private static boolean allContentsAreTheSame(@NonNull List a, @NonNull List b) { diff --git a/app/src/main/java/org/tm/archive/recipients/RecipientDetails.kt b/app/src/main/java/org/tm/archive/recipients/RecipientDetails.kt index 64819ccc..876a09de 100644 --- a/app/src/main/java/org/tm/archive/recipients/RecipientDetails.kt +++ b/app/src/main/java/org/tm/archive/recipients/RecipientDetails.kt @@ -81,7 +81,9 @@ class RecipientDetails private constructor( @JvmField val needsPniSignature: Boolean, @JvmField val callLinkRoomId: CallLinkRoomId?, @JvmField val groupRecord: Optional, - @JvmField val phoneNumberSharing: PhoneNumberSharingState + @JvmField val phoneNumberSharing: PhoneNumberSharingState, + @JvmField val nickname: ProfileName, + @JvmField val note: String? ) { @VisibleForTesting @@ -146,7 +148,9 @@ class RecipientDetails private constructor( needsPniSignature = record.needsPniSignature, callLinkRoomId = record.callLinkRoomId, groupRecord = groupRecord, - phoneNumberSharing = record.phoneNumberSharing + phoneNumberSharing = record.phoneNumberSharing, + nickname = record.nickname, + note = record.note ) companion object { @@ -275,7 +279,9 @@ class RecipientDetails private constructor( isActiveGroup = false, callLinkRoomId = null, groupRecord = Optional.empty(), - phoneNumberSharing = PhoneNumberSharingState.UNKNOWN + phoneNumberSharing = PhoneNumberSharingState.UNKNOWN, + nickname = ProfileName.EMPTY, + note = "" ) } } diff --git a/app/src/main/java/org/tm/archive/recipients/RecipientRepository.kt b/app/src/main/java/org/tm/archive/recipients/RecipientRepository.kt new file mode 100644 index 00000000..24cb2f89 --- /dev/null +++ b/app/src/main/java/org/tm/archive/recipients/RecipientRepository.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.recipients + +import android.content.Context +import androidx.annotation.WorkerThread +import org.signal.core.util.logging.Log +import org.tm.archive.contacts.sync.ContactDiscovery +import org.tm.archive.database.SignalDatabase +import org.tm.archive.phonenumbers.NumberUtil +import org.tm.archive.phonenumbers.PhoneNumberFormatter +import java.io.IOException + +/** + * We operate on recipients many places, but sometimes we find ourselves performing the same recipient-related operations in several locations. + * This is meant to be a place to put those common operations. + */ +object RecipientRepository { + + private val TAG = Log.tag(RecipientRepository::class.java) + + /** + * Attempts to lookup a potentially-new recipient by their e164. + * We will check locally first for a potential match, but may end up hitting the network. + * This will not create a new recipient if we could not find it in the CDSI directory. + */ + @WorkerThread + @JvmStatic + fun lookupNewE164(context: Context, inputE164: String): LookupResult { + val e164 = PhoneNumberFormatter.get(context).format(inputE164) + + if (!NumberUtil.isVisuallyValidNumber(e164)) { + return LookupResult.InvalidEntry + } + + val matchingFullRecipientId = SignalDatabase.recipients.getByE164IfRegisteredAndDiscoverable(e164) + if (matchingFullRecipientId != null) { + Log.i(TAG, "Already have a full, discoverable recipient for $e164. $matchingFullRecipientId") + return LookupResult.Success(matchingFullRecipientId) + } + + Log.i(TAG, "Need to lookup up $e164 with CDSI.") + + return try { + val result = ContactDiscovery.lookupE164(e164) + if (result == null) { + LookupResult.NotFound() + } else { + LookupResult.Success(result.recipientId) + } + } catch (e: IOException) { + return LookupResult.NetworkError + } + } + + sealed interface LookupResult { + data class Success(val recipientId: RecipientId) : LookupResult + object InvalidEntry : LookupResult + data class NotFound(val recipientId: RecipientId = RecipientId.UNKNOWN) : LookupResult + object NetworkError : LookupResult + } +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheet.kt b/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheet.kt index 6d8e77d1..91337658 100644 --- a/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheet.kt +++ b/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheet.kt @@ -5,10 +5,12 @@ package org.tm.archive.recipients.ui.about +import android.content.res.Configuration import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -16,6 +18,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -26,9 +29,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -37,11 +42,13 @@ import androidx.core.widget.TextViewCompat import org.signal.core.ui.BottomSheets import org.signal.core.ui.theme.SignalTheme import org.signal.core.util.getParcelableCompat +import org.signal.core.util.isNotNullOrBlank import org.tm.archive.AvatarPreviewActivity import org.tm.archive.R import org.tm.archive.avatar.AvatarImage import org.tm.archive.components.emoji.EmojiTextView import org.tm.archive.compose.ComposeBottomSheetDialogFragment +import org.tm.archive.nicknames.ViewNoteSheet import org.tm.archive.phonenumbers.PhoneNumberFormatter import org.tm.archive.recipients.Recipient import org.tm.archive.recipients.RecipientId @@ -80,13 +87,32 @@ class AboutSheet : ComposeBottomSheetDialogFragment() { override fun SheetContent() { val recipient by viewModel.recipient val groupsInCommonCount by viewModel.groupsInCommonCount + val verified by viewModel.verified if (recipient.isPresent) { - AboutSheetContent( - recipient = recipient.get(), - groupsInCommonCount = groupsInCommonCount, + Content( + model = AboutModel( + isSelf = recipient.get().isSelf, + displayName = recipient.get().getDisplayName(requireContext()), + shortName = recipient.get().getShortDisplayName(requireContext()), + profileName = recipient.get().profileName.toString(), + about = recipient.get().about, + verified = verified, + hasAvatar = recipient.get().profileAvatarFileDetails.hasFile(), + recipientForAvatar = recipient.get(), + formattedE164 = if (recipient.get().hasE164() && recipient.get().shouldShowE164()) { + PhoneNumberFormatter.get(requireContext()).prettyPrintFormat(recipient.get().requireE164()) + } else { + null + }, + profileSharing = recipient.get().isProfileSharing, + systemContact = recipient.get().isSystemContact, + groupsInCommon = groupsInCommonCount, + note = recipient.get().note ?: "" + ), onClickSignalConnections = this::openSignalConnectionsSheet, - onAvatarClicked = this::openProfilePhotoViewer + onAvatarClicked = this::openProfilePhotoViewer, + onNoteClicked = this::openNoteSheet ) } } @@ -99,29 +125,35 @@ class AboutSheet : ComposeBottomSheetDialogFragment() { private fun openProfilePhotoViewer() { startActivity(AvatarPreviewActivity.intentFromRecipientId(requireContext(), recipientId)) } -} -@Preview -@Composable -private fun AboutSheetContentPreview() { - SignalTheme { - Surface { - AboutSheetContent( - recipient = Recipient.UNKNOWN, - groupsInCommonCount = 0, - onClickSignalConnections = {}, - onAvatarClicked = {} - ) - } + private fun openNoteSheet() { + dismiss() + ViewNoteSheet.create(recipientId).show(parentFragmentManager, null) } } +private data class AboutModel( + val isSelf: Boolean, + val displayName: String, + val shortName: String, + val profileName: String, + val about: String?, + val verified: Boolean, + val hasAvatar: Boolean, + val recipientForAvatar: Recipient, + val formattedE164: String?, + val profileSharing: Boolean, + val systemContact: Boolean, + val groupsInCommon: Int, + val note: String +) + @Composable -private fun AboutSheetContent( - recipient: Recipient, - groupsInCommonCount: Int, +private fun Content( + model: AboutModel, onClickSignalConnections: () -> Unit, - onAvatarClicked: () -> Unit + onAvatarClicked: () -> Unit, + onNoteClicked: () -> Unit ) { Box( contentAlignment = Alignment.Center, @@ -130,8 +162,8 @@ private fun AboutSheetContent( BottomSheets.Handle(modifier = Modifier.padding(top = 6.dp)) } - val avatarOnClick = remember(recipient.profileAvatarFileDetails.hasFile()) { - if (recipient.profileAvatarFileDetails.hasFile()) { + val avatarOnClick = remember(model.hasAvatar) { + if (model.hasAvatar) { onAvatarClicked } else { { } @@ -140,7 +172,7 @@ private fun AboutSheetContent( Column(horizontalAlignment = Alignment.CenterHorizontally) { AvatarImage( - recipient = recipient, + recipient = model.recipientForAvatar, modifier = Modifier .padding(top = 56.dp) .size(240.dp) @@ -149,7 +181,7 @@ private fun AboutSheetContent( ) Text( - text = stringResource(id = if (recipient.isSelf) R.string.AboutSheet__you else R.string.AboutSheet__about), + text = stringResource(id = if (model.isSelf) R.string.AboutSheet__you else R.string.AboutSheet__about), style = MaterialTheme.typography.headlineMedium, modifier = Modifier .fillMaxWidth() @@ -157,22 +189,26 @@ private fun AboutSheetContent( .padding(top = 20.dp, bottom = 14.dp) ) - val context = LocalContext.current - val displayName = remember(recipient) { recipient.getDisplayName(context) } - AboutRow( startIcon = painterResource(R.drawable.symbol_person_24), - text = displayName, + text = if (!model.isSelf && model.displayName.isNotBlank() && model.profileName.isNotBlank() && model.displayName != model.profileName) { + stringResource(id = R.string.AboutSheet__user_set_display_name_and_profile_name, model.displayName, model.profileName) + } else { + model.displayName + }, modifier = Modifier.fillMaxWidth() ) - if (!recipient.about.isNullOrBlank()) { + if (model.about.isNotNullOrBlank()) { + val textColor = LocalContentColor.current + AboutRow( startIcon = painterResource(R.drawable.symbol_edit_24), text = { Row { AndroidView(factory = ::EmojiTextView) { - it.text = recipient.combinedAboutAndEmoji + it.text = model.about + it.setTextColor(textColor.toArgb()) TextViewCompat.setTextAppearance(it, R.style.Signal_Text_BodyLarge) } @@ -182,7 +218,16 @@ private fun AboutSheetContent( ) } - if (recipient.isProfileSharing) { + if (model.verified) { + AboutRow( + startIcon = painterResource(id = R.drawable.check), + text = stringResource(id = R.string.AboutSheet__verified), + modifier = Modifier.align(alignment = Alignment.Start), + onClick = onClickSignalConnections + ) + } + + if (model.profileSharing || model.systemContact) { AboutRow( startIcon = painterResource(id = R.drawable.symbol_connections_24), text = stringResource(id = R.string.AboutSheet__signal_connection), @@ -190,46 +235,56 @@ private fun AboutSheetContent( modifier = Modifier.align(alignment = Alignment.Start), onClick = onClickSignalConnections ) + } else { + AboutRow( + startIcon = painterResource(id = R.drawable.chat_x), + text = stringResource(id = R.string.AboutSheet__no_direct_message, model.shortName), + modifier = Modifier.align(alignment = Alignment.Start), + onClick = onClickSignalConnections + ) } - val shortName = remember(recipient) { recipient.getShortDisplayName(context) } - if (recipient.isSystemContact) { + if (model.systemContact) { AboutRow( startIcon = painterResource(id = R.drawable.symbol_person_circle_24), - text = stringResource(id = R.string.AboutSheet__s_is_in_your_system_contacts, shortName), + text = stringResource(id = R.string.AboutSheet__s_is_in_your_system_contacts, model.shortName), modifier = Modifier.fillMaxWidth() ) } - if (recipient.e164.isPresent && recipient.shouldShowE164()) { - val e164 = remember(recipient.e164.get()) { - PhoneNumberFormatter.get(context).prettyPrintFormat(recipient.e164.get()) - } - + if (model.formattedE164.isNotNullOrBlank()) { AboutRow( startIcon = painterResource(R.drawable.symbol_phone_24), - text = e164, + text = model.formattedE164, modifier = Modifier.fillMaxWidth() ) } - val groupsInCommonText = if (recipient.hasGroupsInCommon()) { - stringResource(id = R.string.AboutSheet__d_groups_in_common, groupsInCommonCount) + val groupsInCommonText = if (model.groupsInCommon > 0) { + pluralStringResource(id = R.plurals.AboutSheet__d_groups_in, model.groupsInCommon, model.groupsInCommon) } else { stringResource(id = R.string.AboutSheet__you_have_no_groups_in_common) } + val groupsInCommonIcon = if (!model.profileSharing && model.groupsInCommon == 0) { + painterResource(R.drawable.symbol_error_circle_24) + } else { + painterResource(R.drawable.symbol_group_24) + } + AboutRow( - startIcon = painterResource(R.drawable.symbol_group_24), + startIcon = groupsInCommonIcon, text = groupsInCommonText, modifier = Modifier.fillMaxWidth() ) - if (!recipient.isProfileSharing) { + if (model.note.isNotBlank()) { AboutRow( - startIcon = painterResource(R.drawable.symbol_error_circle_24), - text = stringResource(id = R.string.AboutSheet__review_requests_carefully), - modifier = Modifier.fillMaxWidth() + startIcon = painterResource(id = R.drawable.symbol_note_light_24), + text = model.note, + modifier = Modifier.fillMaxWidth(), + endIcon = painterResource(id = R.drawable.symbol_chevron_right_compact_bold_16), + onClick = onNoteClicked ) } @@ -237,20 +292,6 @@ private fun AboutSheetContent( } } -@Preview -@Composable -private fun AboutRowPreview() { - SignalTheme { - Surface { - AboutRow( - startIcon = painterResource(R.drawable.symbol_person_24), - text = "Maya Johnson", - endIcon = painterResource(id = R.drawable.symbol_chevron_right_compact_bold_16) - ) - } - } -} - @Composable private fun AboutRow( startIcon: Painter, @@ -264,7 +305,10 @@ private fun AboutRow( text = { Text( text = text, - style = MaterialTheme.typography.bodyLarge + style = MaterialTheme.typography.bodyLarge, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f, false) ) }, modifier = modifier, @@ -276,7 +320,7 @@ private fun AboutRow( @Composable private fun AboutRow( startIcon: Painter, - text: @Composable () -> Unit, + text: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, endIcon: Painter? = null, onClick: (() -> Unit)? = null @@ -319,3 +363,198 @@ private fun AboutRow( } } } + +@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewDefault() { + SignalTheme { + Surface { + Content( + model = AboutModel( + isSelf = false, + displayName = "Peter Parker", + shortName = "Peter", + profileName = "Peter Parker", + about = "Photographer for the Daily Bugle.", + verified = true, + hasAvatar = true, + recipientForAvatar = Recipient.UNKNOWN, + formattedE164 = "(123) 456-7890", + profileSharing = true, + systemContact = true, + groupsInCommon = 0, + note = "GET ME SPIDERMAN BEFORE I BLOW A DANG GASKET" + ), + onClickSignalConnections = {}, + onAvatarClicked = {}, + onNoteClicked = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewWithUserSetDisplayName() { + SignalTheme { + Surface { + Content( + model = AboutModel( + isSelf = false, + displayName = "Amazing Spider-man", + shortName = "Spiderman", + profileName = "Peter Parker", + about = "Photographer for the Daily Bugle.", + verified = true, + hasAvatar = true, + recipientForAvatar = Recipient.UNKNOWN, + formattedE164 = "(123) 456-7890", + profileSharing = true, + systemContact = true, + groupsInCommon = 0, + note = "Weird Things Happen To Me All The Time." + ), + onClickSignalConnections = {}, + onAvatarClicked = {}, + onNoteClicked = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewForSelf() { + SignalTheme { + Surface { + Content( + model = AboutModel( + isSelf = true, + displayName = "Amazing Spider-man", + shortName = "Spiderman", + profileName = "Peter Parker", + about = "Photographer for the Daily Bugle.", + verified = true, + hasAvatar = true, + recipientForAvatar = Recipient.UNKNOWN, + formattedE164 = "(123) 456-7890", + profileSharing = true, + systemContact = true, + groupsInCommon = 0, + note = "Weird Things Happen To Me All The Time." + ), + onClickSignalConnections = {}, + onAvatarClicked = {}, + onNoteClicked = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewInContactsNotProfileSharing() { + SignalTheme { + Surface { + Content( + model = AboutModel( + isSelf = false, + displayName = "Peter Parker", + shortName = "Peter", + profileName = "Peter Parker", + about = "Photographer for the Daily Bugle.", + verified = false, + hasAvatar = true, + recipientForAvatar = Recipient.UNKNOWN, + formattedE164 = null, + profileSharing = false, + systemContact = true, + groupsInCommon = 3, + note = "GET ME SPIDER MAN" + ), + onClickSignalConnections = {}, + onAvatarClicked = {}, + onNoteClicked = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewGroupsInCommonNoE164() { + SignalTheme { + Surface { + Content( + model = AboutModel( + isSelf = false, + displayName = "Peter Parker", + shortName = "Peter", + profileName = "Peter Parker", + about = "Photographer for the Daily Bugle.", + verified = false, + hasAvatar = true, + recipientForAvatar = Recipient.UNKNOWN, + formattedE164 = null, + profileSharing = true, + systemContact = false, + groupsInCommon = 3, + note = "GET ME SPIDERMAN" + ), + onClickSignalConnections = {}, + onAvatarClicked = {}, + onNoteClicked = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewNotAConnection() { + SignalTheme { + Surface { + Content( + model = AboutModel( + isSelf = false, + displayName = "Peter Parker", + shortName = "Peter", + profileName = "Peter Parker", + about = "Photographer for the Daily Bugle.", + verified = false, + hasAvatar = true, + recipientForAvatar = Recipient.UNKNOWN, + formattedE164 = null, + profileSharing = false, + systemContact = false, + groupsInCommon = 3, + note = "GET ME SPIDERMAN" + ), + onClickSignalConnections = {}, + onAvatarClicked = {}, + onNoteClicked = {} + ) + } + } +} + +@Preview(name = "Light Theme", group = "about row", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "about row", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun AboutRowPreview() { + SignalTheme { + Surface { + AboutRow( + startIcon = painterResource(R.drawable.symbol_person_24), + text = "Maya Johnson", + endIcon = painterResource(id = R.drawable.symbol_chevron_right_compact_bold_16) + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetRepository.kt b/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetRepository.kt index cb5f766f..ea3b556a 100644 --- a/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetRepository.kt +++ b/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetRepository.kt @@ -7,7 +7,9 @@ package org.tm.archive.recipients.ui.about import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers +import org.tm.archive.database.IdentityTable import org.tm.archive.database.SignalDatabase +import org.tm.archive.dependencies.ApplicationDependencies import org.tm.archive.recipients.RecipientId class AboutSheetRepository { @@ -16,4 +18,11 @@ class AboutSheetRepository { SignalDatabase.groups.getPushGroupsContainingMember(recipientId).size }.subscribeOn(Schedulers.io()) } + + fun getVerified(recipientId: RecipientId): Single { + return Single.fromCallable { + val identityRecord = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecord(recipientId) + identityRecord.isPresent && identityRecord.get().verifiedStatus == IdentityTable.VerifiedStatus.VERIFIED + }.subscribeOn(Schedulers.io()) + } } diff --git a/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetViewModel.kt b/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetViewModel.kt index 97f0516b..56d7cb89 100644 --- a/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetViewModel.kt +++ b/app/src/main/java/org/tm/archive/recipients/ui/about/AboutSheetViewModel.kt @@ -30,6 +30,9 @@ class AboutSheetViewModel( private val _groupsInCommonCount: MutableIntState = mutableIntStateOf(0) val groupsInCommonCount: IntState = _groupsInCommonCount + private val _verified: MutableState = mutableStateOf(false) + val verified: State = _verified + private val recipientDisposable: Disposable = Recipient .observable(recipientId) .observeOn(AndroidSchedulers.mainThread()) @@ -44,6 +47,13 @@ class AboutSheetViewModel( _groupsInCommonCount.intValue = it } + private val verifiedDisposable: Disposable = repository + .getVerified(recipientId) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy { + _verified.value = it + } + override fun onCleared() { recipientDisposable.dispose() groupsInCommonDisposable.dispose() diff --git a/app/src/main/java/org/tm/archive/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java b/app/src/main/java/org/tm/archive/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java index 2f96323f..0e16fc1d 100644 --- a/app/src/main/java/org/tm/archive/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java +++ b/app/src/main/java/org/tm/archive/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -15,6 +14,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; @@ -33,9 +33,9 @@ import org.tm.archive.components.settings.DSLSettingsIcon; import org.tm.archive.components.settings.conversation.preferences.ButtonStripPreference; import org.tm.archive.contacts.avatars.FallbackContactPhoto; import org.tm.archive.contacts.avatars.FallbackPhoto80dp; +import org.tm.archive.fonts.SignalSymbols; import org.tm.archive.groups.GroupId; -import org.tm.archive.keyvalue.SignalStore; -import org.tm.archive.phonenumbers.PhoneNumberFormatter; +import org.tm.archive.nicknames.NicknameActivity; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientExporter; import org.tm.archive.recipients.RecipientId; @@ -43,8 +43,7 @@ import org.tm.archive.recipients.RecipientUtil; import org.tm.archive.recipients.ui.about.AboutSheet; import org.tm.archive.util.BottomSheetUtil; import org.tm.archive.util.ContextUtil; -import org.tm.archive.util.DrawableUtil; -import org.tm.archive.util.ServiceUtil; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.SpanUtil; import org.tm.archive.util.ThemeUtil; import org.tm.archive.util.Util; @@ -73,7 +72,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF private AvatarView avatar; private TextView fullName; private TextView about; - private TextView usernameNumber; + private TextView nickname; private TextView blockButton; private TextView unblockButton; private TextView addContactButton; @@ -92,20 +91,25 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF private ButtonStripPreference.ViewHolder buttonStripViewHolder; - public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId, - @Nullable GroupId groupId) - { - Bundle args = new Bundle(); - RecipientBottomSheetDialogFragment fragment = new RecipientBottomSheetDialogFragment(); + private ActivityResultLauncher nicknameLauncher; - args.putString(ARGS_RECIPIENT_ID, recipientId.serialize()); - if (groupId != null) { - args.putString(ARGS_GROUP_ID, groupId.toString()); + public static void show(FragmentManager fragmentManager, @NonNull RecipientId recipientId, @Nullable GroupId groupId) { + Recipient recipient = Recipient.resolved(recipientId); + if (recipient.isSelf()) { + AboutSheet.create(recipient).show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG); + } else { + Bundle args = new Bundle(); + RecipientBottomSheetDialogFragment fragment = new RecipientBottomSheetDialogFragment(); + + args.putString(ARGS_RECIPIENT_ID, recipientId.serialize()); + if (groupId != null) { + args.putString(ARGS_GROUP_ID, groupId.toString()); + } + + fragment.setArguments(args); + + fragment.show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG); } - - fragment.setArguments(args); - - return fragment; } @Override @@ -124,7 +128,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF avatar = view.findViewById(R.id.rbs_recipient_avatar); fullName = view.findViewById(R.id.rbs_full_name); about = view.findViewById(R.id.rbs_about); - usernameNumber = view.findViewById(R.id.rbs_username_number); + nickname = view.findViewById(R.id.rbs_nickname_button); blockButton = view.findViewById(R.id.rbs_block_button); unblockButton = view.findViewById(R.id.rbs_unblock_button); addContactButton = view.findViewById(R.id.rbs_add_contact_button); @@ -148,6 +152,8 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF public void onViewCreated(@NonNull View fragmentView, @Nullable Bundle savedInstanceState) { super.onViewCreated(fragmentView, savedInstanceState); + nicknameLauncher = registerForActivityResult(new NicknameActivity.Contract(), (b) -> {}); + Bundle arguments = requireArguments(); RecipientId recipientId = RecipientId.from(Objects.requireNonNull(arguments.getString(ARGS_RECIPIENT_ID))); GroupId groupId = GroupId.parseNullableOrThrow(arguments.getString(ARGS_GROUP_ID)); @@ -186,20 +192,43 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF : recipient.getDisplayName(requireContext()); fullName.setVisibility(TextUtils.isEmpty(name) ? View.GONE : View.VISIBLE); SpannableStringBuilder nameBuilder = new SpannableStringBuilder(name); - if (recipient.isSystemContact() && !recipient.isSelf()) { - Drawable systemContact = DrawableUtil.tint(ContextUtil.requireDrawable(requireContext(), R.drawable.ic_profile_circle_outline_16), - ContextCompat.getColor(requireContext(), R.color.signal_text_primary)); - SpanUtil.appendCenteredImageSpan(nameBuilder, systemContact, 16, 16); - } else if (recipient.showVerified()) { - SpanUtil.appendCenteredImageSpan(nameBuilder, ContextUtil.requireDrawable(requireContext(), R.drawable.ic_official_28), 28, 28); + if (recipient.showVerified()) { + SpanUtil.appendSpacer(nameBuilder, 8); + SpanUtil.appendCenteredImageSpanWithoutSpace(nameBuilder, ContextUtil.requireDrawable(requireContext(), R.drawable.ic_official_28), 28, 28); + } else if (recipient.isSystemContact()) { + CharSequence systemContactGlyph = SignalSymbols.INSTANCE.getSpannedString(requireContext(), + SignalSymbols.Weight.BOLD, + SignalSymbols.Glyph.PERSON_CIRCLE); + + nameBuilder.append(" "); + nameBuilder.append(SpanUtil.ofSize(systemContactGlyph, 20)); } - SpanUtil.appendCenteredImageSpan(nameBuilder, ContextUtil.requireDrawable(requireContext(), R.drawable.symbol_chevron_right_24_color_on_secondary_container), 24, 24); - fullName.setText(nameBuilder); - fullName.setOnClickListener(v -> { - dismiss(); - AboutSheet.create(recipient).show(getParentFragmentManager(), null); - }); + if (!recipient.isSelf() && recipient.isIndividual()) { + CharSequence chevronGlyph = SignalSymbols.INSTANCE.getSpannedString(requireContext(), + SignalSymbols.Weight.BOLD, + SignalSymbols.Glyph.CHEVRON_RIGHT); + + nameBuilder.append(" "); + nameBuilder.append(SpanUtil.color(ContextCompat.getColor(requireContext(), R.color.signal_colorOutline), + SpanUtil.ofSize(chevronGlyph, 24))); + + fullName.setText(nameBuilder); + fullName.setOnClickListener(v -> { + dismiss(); + AboutSheet.create(recipient).show(getParentFragmentManager(), null); + }); + + if (FeatureFlags.nicknames()) { + nickname.setVisibility(View.VISIBLE); + nickname.setOnClickListener(v -> { + nicknameLauncher.launch(new NicknameActivity.Args( + recipientId, + false + )); + }); + } + } String aboutText = recipient.getCombinedAboutAndEmoji(); if (recipient.isReleaseNotes()) { @@ -213,18 +242,6 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF about.setVisibility(View.GONE); } - String usernameNumberString = recipient.hasAUserSetDisplayName(requireContext()) && !recipient.isSelf() && recipient.shouldShowE164() - ? recipient.getSmsAddress().map(PhoneNumberFormatter::prettyPrint).orElse("").trim() - : ""; - usernameNumber.setText(usernameNumberString); - usernameNumber.setVisibility(TextUtils.isEmpty(usernameNumberString) ? View.GONE : View.VISIBLE); - usernameNumber.setOnLongClickListener(v -> { - Util.copyToClipboard(v.getContext(), usernameNumber.getText().toString()); - ServiceUtil.getVibrator(v.getContext()).vibrate(250); - Toast.makeText(v.getContext(), R.string.RecipientBottomSheet_copied_to_clipboard, Toast.LENGTH_SHORT).show(); - return true; - }); - noteToSelfDescription.setVisibility(recipient.isSelf() ? View.VISIBLE : View.GONE); if (RecipientUtil.isBlockable(recipient)) { @@ -237,7 +254,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF unblockButton.setVisibility(View.GONE); } - boolean isAudioAvailable = (recipient.isRegistered() || SignalStore.misc().getSmsExportPhase().allowSmsFeatures()) && + boolean isAudioAvailable = recipient.isRegistered() && !recipient.isGroup() && !recipient.isBlocked() && !recipient.isSelf() && @@ -286,7 +303,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF buttonStrip.setVisibility(View.GONE); } - if (recipient.isSystemContact() || recipient.isGroup() || recipient.isSelf() || recipient.isBlocked() || recipient.isReleaseNotes() || !recipient.hasE164()) { + if (recipient.isSystemContact() || recipient.isGroup() || recipient.isSelf() || recipient.isBlocked() || recipient.isReleaseNotes() || !recipient.hasE164() || !recipient.shouldShowE164()) { addContactButton.setVisibility(View.GONE); } else { addContactButton.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByActivity.kt b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByActivity.kt new file mode 100644 index 00000000..45271669 --- /dev/null +++ b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByActivity.kt @@ -0,0 +1,654 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.recipients.ui.findby + +import android.content.Context +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContract +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.lifecycleScope +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.dialog +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import kotlinx.coroutines.launch +import org.signal.core.ui.Animations.navHostSlideInTransition +import org.signal.core.ui.Animations.navHostSlideOutTransition +import org.signal.core.ui.Buttons +import org.signal.core.ui.Dialogs +import org.signal.core.ui.Dividers +import org.signal.core.ui.Previews +import org.signal.core.ui.Scaffolds +import org.signal.core.ui.TextFields +import org.signal.core.ui.theme.SignalTheme +import org.signal.core.util.getParcelableExtraCompat +import org.tm.archive.PassphraseRequiredActivity +import org.tm.archive.R +import org.tm.archive.components.settings.app.usernamelinks.main.UsernameQrScannerActivity +import org.tm.archive.invites.InviteActions +import org.tm.archive.permissions.compose.Permissions +import org.tm.archive.phonenumbers.PhoneNumberVisualTransformation +import org.tm.archive.recipients.RecipientId +import org.tm.archive.registration.util.CountryPrefix +import org.tm.archive.util.DynamicNoActionBarTheme +import org.tm.archive.util.viewModel +import org.whispersystems.signalservice.api.util.PhoneNumberFormatter + +/** + * Allows the user to look up another Signal user by phone number or username and + * retrieve a RecipientId for that data. + */ +class FindByActivity : PassphraseRequiredActivity() { + + private val theme = DynamicNoActionBarTheme() + + companion object { + private const val MODE = "FindByActivity.mode" + private const val RECIPIENT_ID = "FindByActivity.recipientId" + } + + private val viewModel: FindByViewModel by viewModel { + FindByViewModel(FindByMode.valueOf(intent.getStringExtra(MODE)!!)) + } + + override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { + theme.onCreate(this) + + val qrScanLauncher: ActivityResultLauncher = registerForActivityResult(UsernameQrScannerActivity.Contract()) { recipientId -> + if (recipientId != null) { + setResult(RESULT_OK, Intent().putExtra(RECIPIENT_ID, recipientId)) + finishAfterTransition() + } + } + + setContent { + val state by viewModel.state + + val navController = rememberNavController() + + SignalTheme { + NavHost( + navController = navController, + startDestination = "find-by-content", + enterTransition = { navHostSlideInTransition { it } }, + exitTransition = { navHostSlideOutTransition { -it } }, + popEnterTransition = { navHostSlideInTransition { -it } }, + popExitTransition = { navHostSlideOutTransition { it } } + ) { + composable("find-by-content") { + val title = remember(state.mode) { + if (state.mode == FindByMode.USERNAME) R.string.FindByActivity__find_by_username else R.string.FindByActivity__find_by_phone_number + } + + Scaffolds.Settings( + title = stringResource(id = title), + onNavigationClick = { finishAfterTransition() }, + navigationIconPainter = painterResource(id = R.drawable.symbol_arrow_left_24) + ) { + val context = LocalContext.current + + val cameraPermissionController = Permissions.cameraPermissionHandler( + rationale = stringResource(id = R.string.PaymentsTransferFragment__to_scan_a_qr_code_signal_needs_access_to_the_camera), + onPermissionGranted = { + qrScanLauncher.launch(Unit) + } + ) + + Content( + paddingValues = it, + state = state, + onUserEntryChanged = viewModel::onUserEntryChanged, + onNextClick = { + lifecycleScope.launch { + when (val result = viewModel.onNextClicked(context)) { + is FindByResult.Success -> { + setResult(RESULT_OK, Intent().putExtra(RECIPIENT_ID, result.recipientId)) + finishAfterTransition() + } + + FindByResult.InvalidEntry -> navController.navigate("invalid-entry") + is FindByResult.NotFound -> navController.navigate("not-found/${result.recipientId.toLong()}") + is FindByResult.NetworkError -> navController.navigate("network-error") + } + } + }, + onSelectCountryPrefixClick = { + navController.navigate("select-country-prefix") + }, + onQrCodeScanClicked = { + cameraPermissionController.request() + } + ) + } + } + + composable("select-country-prefix") { + Scaffolds.Settings( + title = stringResource(id = R.string.FindByActivity__select_country_code), + onNavigationClick = { navController.popBackStack() }, + navigationIconPainter = painterResource(id = R.drawable.symbol_arrow_left_24) + ) { paddingValues -> + SelectCountryScreen( + paddingValues = paddingValues, + searchEntry = state.countryPrefixSearchEntry, + onSearchEntryChanged = viewModel::onCountryPrefixSearchEntryChanged, + supportedCountryPrefixes = state.supportedCountryPrefixes, + onCountryPrefixSelected = { + navController.popBackStack() + viewModel.onCountryPrefixSelected(it) + viewModel.onCountryPrefixSearchEntryChanged("") + } + ) + } + } + + dialog("invalid-entry") { + val title = if (state.mode == FindByMode.USERNAME) { + stringResource(id = R.string.FindByActivity__invalid_username) + } else { + stringResource(id = R.string.FindByActivity__invalid_phone_number) + } + + val body = if (state.mode == FindByMode.USERNAME) { + stringResource(id = R.string.FindByActivity__s_is_not_a_valid_username, state.userEntry) + } else { + val formattedNumber = remember(state.userEntry) { + val cleansed = state.userEntry.removePrefix(state.selectedCountryPrefix.digits.toString()) + PhoneNumberFormatter.formatE164(state.selectedCountryPrefix.digits.toString(), cleansed) + } + stringResource(id = R.string.FindByActivity__s_is_not_a_valid_phone_number, formattedNumber) + } + + Dialogs.SimpleAlertDialog( + title = title, + body = body, + confirm = stringResource(id = android.R.string.ok), + onConfirm = {}, + onDismiss = { navController.popBackStack() } + ) + } + + dialog( + route = "network-error" + ) { + Dialogs.SimpleMessageDialog( + message = getString(R.string.FindByActivity__network_error_dialog), + dismiss = getString(android.R.string.ok), + onDismiss = { navController.popBackStack() } + ) + } + + dialog( + route = "not-found/{recipientId}", + arguments = listOf(navArgument("recipientId") { type = NavType.LongType }) + ) { navBackStackEntry -> + val title = if (state.mode == FindByMode.USERNAME) { + stringResource(id = R.string.FindByActivity__username_not_found) + } else { + stringResource(id = R.string.FindByActivity__invite_to_signal) + } + + val body = if (state.mode == FindByMode.USERNAME) { + stringResource(id = R.string.FindByActivity__s_is_not_a_signal_user, state.userEntry) + } else { + val formattedNumber = remember(state.userEntry) { + val cleansed = state.userEntry.removePrefix(state.selectedCountryPrefix.digits.toString()) + PhoneNumberFormatter.formatE164(state.selectedCountryPrefix.digits.toString(), cleansed) + } + stringResource(id = R.string.FindByActivity__s_is_not_a_signal_user_would, formattedNumber) + } + + val confirm = if (state.mode == FindByMode.USERNAME) { + stringResource(id = android.R.string.ok) + } else { + stringResource(id = R.string.FindByActivity__invite) + } + + val dismiss = if (state.mode == FindByMode.USERNAME) { + Dialogs.NoDismiss + } else { + stringResource(id = android.R.string.cancel) + } + + val context = LocalContext.current + Dialogs.SimpleAlertDialog( + title = title, + body = body, + confirm = confirm, + dismiss = dismiss, + onConfirm = { + if (state.mode == FindByMode.PHONE_NUMBER) { + InviteActions.inviteUserToSignal( + context, + this@FindByActivity::startActivity + ) + } + }, + onDismiss = { navController.popBackStack() } + ) + } + } + } + } + } + + override fun onResume() { + super.onResume() + theme.onResume(this) + } + + class Contract : ActivityResultContract() { + override fun createIntent(context: Context, input: FindByMode): Intent { + return Intent(context, FindByActivity::class.java) + .putExtra(MODE, input.name) + } + + override fun parseResult(resultCode: Int, intent: Intent?): RecipientId? { + return intent?.getParcelableExtraCompat(RECIPIENT_ID, RecipientId::class.java) + } + } +} + +@Composable +private fun Content( + paddingValues: PaddingValues, + state: FindByState, + onUserEntryChanged: (String) -> Unit, + onNextClick: () -> Unit, + onSelectCountryPrefixClick: () -> Unit, + onQrCodeScanClicked: () -> Unit +) { + val placeholderLabel = remember(state.mode) { + if (state.mode == FindByMode.PHONE_NUMBER) R.string.FindByActivity__phone_number else R.string.FindByActivity__username + } + + val focusRequester = remember { + FocusRequester() + } + + val keyboardType = remember(state.mode) { + if (state.mode == FindByMode.PHONE_NUMBER) { + KeyboardType.Phone + } else { + KeyboardType.Text + } + } + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + val onNextAction = remember(state.isLookupInProgress) { + KeyboardActions(onNext = { + if (!state.isLookupInProgress) { + onNextClick() + } + }) + } + + val visualTransformation = if (state.mode == FindByMode.USERNAME) { + VisualTransformation.None + } else { + remember(state.selectedCountryPrefix) { + PhoneNumberVisualTransformation(state.selectedCountryPrefix.regionCode) + } + } + + TextFields.TextField( + enabled = !state.isLookupInProgress, + value = state.userEntry, + onValueChange = onUserEntryChanged, + singleLine = true, + placeholder = { Text(text = stringResource(id = placeholderLabel)) }, + prefix = if (state.mode == FindByMode.USERNAME) { + null + } else { + { + PhoneNumberEntryPrefix( + enabled = !state.isLookupInProgress, + selectedCountryPrefix = state.selectedCountryPrefix, + onSelectCountryPrefixClick = onSelectCountryPrefixClick + ) + } + }, + visualTransformation = visualTransformation, + keyboardOptions = KeyboardOptions( + keyboardType = keyboardType, + imeAction = ImeAction.Next + ), + shape = RoundedCornerShape(32.dp), + colors = TextFieldDefaults.colors( + unfocusedIndicatorColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + errorIndicatorColor = Color.Transparent, + cursorColor = MaterialTheme.colorScheme.onSurface + ), + keyboardActions = onNextAction, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 10.dp) + .focusRequester(focusRequester) + .heightIn(min = 44.dp), + contentPadding = if (state.mode == FindByMode.PHONE_NUMBER) { + TextFieldDefaults.contentPaddingWithoutLabel(start = 4.dp, top = 10.dp, bottom = 10.dp) + } else { + TextFieldDefaults.contentPaddingWithoutLabel(top = 10.dp, bottom = 10.dp) + } + ) + + if (state.mode == FindByMode.USERNAME) { + Text( + text = stringResource(id = R.string.FindByActivity__enter_username_description), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + .padding(top = 8.dp) + ) + + Spacer(modifier = Modifier.height(32.dp)) + + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.Center + ) { + Buttons.Small(onClick = onQrCodeScanClicked) { + Icon(painter = painterResource(id = R.drawable.symbol_qrcode_24), contentDescription = stringResource(id = R.string.FindByActivity__qr_scan_button)) + Spacer(modifier = Modifier.width(10.dp)) + Text( + text = stringResource(id = R.string.FindByActivity__qr_scan_button), + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSurface + ) + } + } + } + + Spacer(modifier = Modifier.weight(1f)) + + Box( + contentAlignment = Alignment.BottomEnd, + modifier = Modifier.fillMaxWidth() + ) { + Buttons.LargeTonal( + enabled = !state.isLookupInProgress && state.userEntry.isNotBlank(), + onClick = onNextClick, + contentPadding = PaddingValues(0.dp), + modifier = Modifier + .padding(16.dp) + .size(48.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.symbol_arrow_right_24), + contentDescription = stringResource(id = R.string.FindByActivity__next) + ) + } + } + + if (state.isLookupInProgress) { + Dialogs.IndeterminateProgressDialog() + } + + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } + } +} + +@Composable +private fun PhoneNumberEntryPrefix( + enabled: Boolean, + selectedCountryPrefix: CountryPrefix, + onSelectCountryPrefixClick: () -> Unit +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(end = 16.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clip(RoundedCornerShape(1000.dp)) + .clickable(onClick = onSelectCountryPrefixClick, enabled = enabled) + ) { + Text( + text = selectedCountryPrefix.toString(), + modifier = Modifier + .padding(start = 12.dp, top = 6.dp, bottom = 6.dp) + ) + Icon( + painter = painterResource(id = R.drawable.symbol_dropdown_triangle_24), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .size(24.dp) + .padding(end = 1.dp) + ) + } + Dividers.Vertical( + thickness = 1.dp, + color = MaterialTheme.colorScheme.outline, + modifier = Modifier + .padding(vertical = 2.dp) + .padding(start = 7.dp) + .height(20.dp) + ) + } +} + +@Composable +private fun SelectCountryScreen( + paddingValues: PaddingValues, + searchEntry: String, + onSearchEntryChanged: (String) -> Unit, + onCountryPrefixSelected: (CountryPrefix) -> Unit, + supportedCountryPrefixes: List +) { + val focusRequester = remember { + FocusRequester() + } + + Column( + modifier = Modifier.padding(paddingValues) + ) { + TextFields.TextField( + value = searchEntry, + onValueChange = onSearchEntryChanged, + placeholder = { Text(text = stringResource(id = R.string.FindByActivity__search)) }, + shape = RoundedCornerShape(32.dp), + colors = TextFieldDefaults.colors( + unfocusedIndicatorColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + errorIndicatorColor = Color.Transparent, + cursorColor = MaterialTheme.colorScheme.onSurface + ), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 10.dp) + .focusRequester(focusRequester) + .heightIn(min = 44.dp), + contentPadding = TextFieldDefaults.contentPaddingWithoutLabel(top = 10.dp, bottom = 10.dp) + ) + + LazyColumn { + items( + items = supportedCountryPrefixes + ) { + CountryPrefixRowItem( + searchTerm = searchEntry, + countryPrefix = it, + onClick = { onCountryPrefixSelected(it) } + ) + } + } + } + + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } +} + +@Composable +private fun CountryPrefixRowItem( + searchTerm: String, + countryPrefix: CountryPrefix, + onClick: () -> Unit +) { + val regionDisplayName = remember(countryPrefix.regionCode, Locale.current) { + PhoneNumberFormatter.getRegionDisplayName(countryPrefix.regionCode).orElse(countryPrefix.regionCode) + } + + if (searchTerm.isNotBlank() && !regionDisplayName.contains(searchTerm, ignoreCase = true)) { + return + } + + val highlightedName: AnnotatedString = remember(regionDisplayName, searchTerm) { + if (searchTerm.isBlank()) { + AnnotatedString(regionDisplayName) + } else { + buildAnnotatedString { + append(regionDisplayName) + + val startIndex = regionDisplayName.indexOf(searchTerm, ignoreCase = true) + + addStyle( + style = SpanStyle( + fontWeight = FontWeight.Bold + ), + start = startIndex, + end = startIndex + searchTerm.length + ) + } + } + } + + Column( + verticalArrangement = spacedBy((-2).dp), + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter)) + .padding(top = 16.dp, bottom = 14.dp) + ) { + Text( + text = highlightedName + ) + + Text( + text = countryPrefix.toString(), + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyMedium + ) + } +} + +@Preview(name = "Light Theme", group = "content - phone", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content - phone", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewPhoneNumber() { + Previews.Preview { + Content( + paddingValues = PaddingValues(0.dp), + state = FindByState( + mode = FindByMode.PHONE_NUMBER, + userEntry = "" + ), + onUserEntryChanged = {}, + onNextClick = {}, + onSelectCountryPrefixClick = {}, + onQrCodeScanClicked = {} + ) + } +} + +@Preview(name = "Light Theme", group = "content - username", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "content - username", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun ContentPreviewUsername() { + Previews.Preview { + Content( + paddingValues = PaddingValues(0.dp), + state = FindByState( + mode = FindByMode.USERNAME, + userEntry = "" + ), + onUserEntryChanged = {}, + onNextClick = {}, + onSelectCountryPrefixClick = {}, + onQrCodeScanClicked = {} + ) + } +} + +@Preview(name = "Light Theme", group = "select country", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Theme", group = "select country", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun SelectCountryScreenPreview() { + Previews.Preview { + SelectCountryScreen( + paddingValues = PaddingValues(0.dp), + searchEntry = "", + onSearchEntryChanged = {}, + supportedCountryPrefixes = FindByState(mode = FindByMode.PHONE_NUMBER).supportedCountryPrefixes, + onCountryPrefixSelected = {} + ) + } +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByMode.kt b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByMode.kt new file mode 100644 index 00000000..7a725863 --- /dev/null +++ b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByMode.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.recipients.ui.findby + +enum class FindByMode { + PHONE_NUMBER, + USERNAME +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByResult.kt b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByResult.kt new file mode 100644 index 00000000..c8038018 --- /dev/null +++ b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByResult.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.recipients.ui.findby + +import org.tm.archive.recipients.RecipientId + +sealed interface FindByResult { + data class Success(val recipientId: RecipientId) : FindByResult + object InvalidEntry : FindByResult + data class NotFound(val recipientId: RecipientId = RecipientId.UNKNOWN) : FindByResult + object NetworkError : FindByResult +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByState.kt b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByState.kt new file mode 100644 index 00000000..3c3e5f2a --- /dev/null +++ b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByState.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.recipients.ui.findby + +import com.google.i18n.phonenumbers.NumberParseException +import com.google.i18n.phonenumbers.PhoneNumberUtil +import org.signal.core.util.orNull +import org.tm.archive.recipients.Recipient +import org.tm.archive.registration.util.CountryPrefix + +/** + * State for driving find by number/username screen. + */ +data class FindByState( + val mode: FindByMode, + val userEntry: String = "", + val supportedCountryPrefixes: List = PhoneNumberUtil.getInstance().supportedCallingCodes + .map { CountryPrefix(it, PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(it)) } + .sortedBy { it.digits.toString() }, + val selectedCountryPrefix: CountryPrefix = supportedCountryPrefixes.first(), + val countryPrefixSearchEntry: String = "", + val isLookupInProgress: Boolean = false +) { + companion object { + fun startingState(self: Recipient, mode: FindByMode): FindByState { + val countryCode: Int = try { + PhoneNumberUtil.getInstance() + .parse(self.e164.orNull(), null) + .countryCode + } catch (e: NumberParseException) { + -1 + } + + val state = FindByState(mode = mode) + return state.copy( + selectedCountryPrefix = state.supportedCountryPrefixes.firstOrNull { it.digits == countryCode } ?: state.supportedCountryPrefixes.first() + ) + } + } +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByViewModel.kt b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByViewModel.kt new file mode 100644 index 00000000..d8c3e15e --- /dev/null +++ b/app/src/main/java/org/tm/archive/recipients/ui/findby/FindByViewModel.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.recipients.ui.findby + +import android.content.Context +import androidx.annotation.WorkerThread +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import org.signal.core.util.concurrent.safeBlockingGet +import org.tm.archive.profiles.manage.UsernameRepository +import org.tm.archive.recipients.Recipient +import org.tm.archive.recipients.RecipientRepository +import org.tm.archive.registration.util.CountryPrefix +import org.tm.archive.util.UsernameUtil + +class FindByViewModel( + mode: FindByMode +) : ViewModel() { + + private val internalState = mutableStateOf( + FindByState.startingState(self = Recipient.self(), mode = mode) + ) + + val state: State = internalState + + fun onUserEntryChanged(userEntry: String) { + val cleansed = if (state.value.mode == FindByMode.PHONE_NUMBER) { + userEntry.filter { it.isDigit() } + } else { + userEntry + } + + internalState.value = state.value.copy(userEntry = cleansed) + } + + fun onCountryPrefixSearchEntryChanged(searchEntry: String) { + internalState.value = state.value.copy(countryPrefixSearchEntry = searchEntry) + } + + fun onCountryPrefixSelected(countryPrefix: CountryPrefix) { + internalState.value = state.value.copy(selectedCountryPrefix = countryPrefix) + } + + suspend fun onNextClicked(context: Context): FindByResult { + internalState.value = state.value.copy(isLookupInProgress = true) + val findByResult = viewModelScope.async(context = Dispatchers.IO) { + if (state.value.mode == FindByMode.USERNAME) { + performUsernameLookup() + } else { + performPhoneLookup(context) + } + }.await() + + internalState.value = state.value.copy(isLookupInProgress = false) + return findByResult + } + + @WorkerThread + private fun performUsernameLookup(): FindByResult { + val username = state.value.userEntry + + if (!UsernameUtil.isValidUsernameForSearch(username)) { + return FindByResult.InvalidEntry + } + + return when (val result = UsernameRepository.fetchAciForUsername(username = username).safeBlockingGet()) { + UsernameRepository.UsernameAciFetchResult.NetworkError -> FindByResult.NotFound() + UsernameRepository.UsernameAciFetchResult.NotFound -> FindByResult.NotFound() + is UsernameRepository.UsernameAciFetchResult.Success -> FindByResult.Success(Recipient.externalUsername(result.aci, username).id) + } + } + + @WorkerThread + private fun performPhoneLookup(context: Context): FindByResult { + val stateSnapshot = state.value + val countryCode = stateSnapshot.selectedCountryPrefix.digits + val nationalNumber = stateSnapshot.userEntry.removePrefix(countryCode.toString()) + + val e164 = "+$countryCode$nationalNumber" + + return when (val result = RecipientRepository.lookupNewE164(context, e164)) { + RecipientRepository.LookupResult.InvalidEntry -> FindByResult.InvalidEntry + RecipientRepository.LookupResult.NetworkError -> FindByResult.NetworkError + is RecipientRepository.LookupResult.NotFound -> FindByResult.NotFound(result.recipientId) + is RecipientRepository.LookupResult.Success -> FindByResult.Success(result.recipientId) + } + } +} diff --git a/app/src/main/java/org/tm/archive/recipients/ui/sharablegrouplink/GroupLinkBottomSheetDialogFragment.java b/app/src/main/java/org/tm/archive/recipients/ui/sharablegrouplink/GroupLinkBottomSheetDialogFragment.java index 5b0be98a..0e1a68d9 100644 --- a/app/src/main/java/org/tm/archive/recipients/ui/sharablegrouplink/GroupLinkBottomSheetDialogFragment.java +++ b/app/src/main/java/org/tm/archive/recipients/ui/sharablegrouplink/GroupLinkBottomSheetDialogFragment.java @@ -83,7 +83,6 @@ public final class GroupLinkBottomSheetDialogFragment extends BottomSheetDialogF MultiselectForwardFragment.showBottomSheet( getParentFragmentManager(), new MultiselectForwardFragmentArgs( - true, Collections.singletonList(new MultiShareArgs.Builder() .withDraftText(groupLink.getUrl()) .build()), diff --git a/app/src/main/java/org/tm/archive/registration/RegistrationRepository.java b/app/src/main/java/org/tm/archive/registration/RegistrationRepository.java index da20af36..d66c2ada 100644 --- a/app/src/main/java/org/tm/archive/registration/RegistrationRepository.java +++ b/app/src/main/java/org/tm/archive/registration/RegistrationRepository.java @@ -135,6 +135,8 @@ public final class RegistrationRepository { SignalStore.account().setAci(aci); SignalStore.account().setPni(pni); + ApplicationDependencies.resetProtocolStores(); + ApplicationDependencies.getProtocolStore().aci().sessions().archiveAllSessions(); ApplicationDependencies.getProtocolStore().pni().sessions().archiveAllSessions(); SenderKeyUtil.clearAllState(); @@ -159,7 +161,6 @@ public final class RegistrationRepository { ApplicationDependencies.getRecipientCache().clearSelf(); SignalStore.account().setE164(registrationData.getE164()); - Log.i("RegistrationRepository","registerAccountInternal -> fcmToken: "+registrationData.getFcmToken());//**TM_SA TODO remove ASAP!**// SignalStore.account().setFcmToken(registrationData.getFcmToken()); SignalStore.account().setFcmEnabled(registrationData.isFcm()); @@ -182,7 +183,7 @@ public final class RegistrationRepository { public static PreKeyCollection generateSignedAndLastResortPreKeys(IdentityKeyPair identity, PreKeyMetadataStore metadataStore) { SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(metadataStore.getNextSignedPreKeyId(), identity.getPrivateKey()); - KyberPreKeyRecord lastResortKyberPreKey = PreKeyUtil.generateLastRestortKyberPreKey(metadataStore.getNextKyberPreKeyId(), identity.getPrivateKey()); + KyberPreKeyRecord lastResortKyberPreKey = PreKeyUtil.generateLastResortKyberPreKey(metadataStore.getNextKyberPreKeyId(), identity.getPrivateKey()); return new PreKeyCollection( identity.getPublicKey(), diff --git a/app/src/main/java/org/tm/archive/registration/RegistrationUtil.java b/app/src/main/java/org/tm/archive/registration/RegistrationUtil.java index f406ea88..119686cb 100644 --- a/app/src/main/java/org/tm/archive/registration/RegistrationUtil.java +++ b/app/src/main/java/org/tm/archive/registration/RegistrationUtil.java @@ -3,7 +3,10 @@ package org.tm.archive.registration; import org.signal.core.util.logging.Log; import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobs.DirectoryRefreshJob; +import org.tm.archive.jobs.RefreshAttributesJob; import org.tm.archive.jobs.StorageSyncJob; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues; +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.Recipient; @@ -26,9 +29,17 @@ public final class RegistrationUtil { { Log.i(TAG, "Marking registration completed.", new Throwable()); SignalStore.registrationValues().setRegistrationComplete(); - ApplicationDependencies.getJobManager().startChain(new StorageSyncJob()) + + if (SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode() == PhoneNumberDiscoverabilityMode.UNDECIDED) { + Log.w(TAG, "Phone number discoverability mode is still UNDECIDED. Setting to DISCOVERABLE."); + SignalStore.phoneNumberPrivacy().setPhoneNumberDiscoverabilityMode(PhoneNumberDiscoverabilityMode.DISCOVERABLE); + } + + ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob()) + .then(new StorageSyncJob()) .then(new DirectoryRefreshJob(false)) .enqueue(); + } else if (!SignalStore.registrationValues().isRegistrationComplete()) { Log.i(TAG, "Registration is not yet complete.", new Throwable()); } diff --git a/app/src/main/java/org/tm/archive/registration/VerifyAccountRepository.kt b/app/src/main/java/org/tm/archive/registration/VerifyAccountRepository.kt index 9c5596ea..a8ff7d0f 100644 --- a/app/src/main/java/org/tm/archive/registration/VerifyAccountRepository.kt +++ b/app/src/main/java/org/tm/archive/registration/VerifyAccountRepository.kt @@ -9,6 +9,7 @@ import org.signal.core.util.logging.Log import org.signal.libsignal.protocol.IdentityKeyPair import org.tm.archive.AppCapabilities import org.tm.archive.gcm.FcmUtil +import org.tm.archive.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode import org.tm.archive.keyvalue.SignalStore import org.tm.archive.pin.SvrWrongPinException import org.tm.archive.push.AccountManagerFactory @@ -72,7 +73,6 @@ class VerifyAccountRepository(private val context: Application) { val subscriber = PushTokenChallengeSubscriber() val eventBus = EventBus.getDefault() eventBus.register(subscriber) - Log.d("VerifyAccountRepository", "createSessionAndBlockForPushChallenge -> fcmToken: $fcmToken" )//**TM_SA**// @@ -183,7 +183,7 @@ class VerifyAccountRepository(private val context: Application) { unidentifiedAccessKey = unidentifiedAccessKey, unrestrictedUnidentifiedAccess = universalUnidentifiedAccess, capabilities = AppCapabilities.getCapabilities(true), - discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberListingMode.isDiscoverable, + discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberDiscoverabilityMode == PhoneNumberDiscoverabilityMode.DISCOVERABLE, name = null, pniRegistrationId = registrationData.pniRegistrationId, recoveryPassword = registrationData.recoveryPassword diff --git a/app/src/main/java/org/tm/archive/registration/fragments/RegistrationConstants.java b/app/src/main/java/org/tm/archive/registration/fragments/RegistrationConstants.java index 160e6c29..5bc0e0d2 100644 --- a/app/src/main/java/org/tm/archive/registration/fragments/RegistrationConstants.java +++ b/app/src/main/java/org/tm/archive/registration/fragments/RegistrationConstants.java @@ -1,11 +1,11 @@ -package org.tm.archive.registration.fragments; - -final class RegistrationConstants { - - private RegistrationConstants() { - } - - static final String TERMS_AND_CONDITIONS_URL = "https://signal.org/legal"; - static final String SIGNAL_CAPTCHA_SCHEME = "signalcaptcha://"; - -} +package org.tm.archive.registration.fragments; + +final class RegistrationConstants { + + private RegistrationConstants() { + } + + static final String TERMS_AND_CONDITIONS_URL = "https://signal.org/legal"; + static final String SIGNAL_CAPTCHA_SCHEME = "signalcaptcha://"; + +} diff --git a/app/src/main/java/org/tm/archive/registration/fragments/EnterPhoneNumberFragment.java b/app/src/main/java/org/tm/archive/registration/fragments/SignalEnterPhoneNumberFragment.java similarity index 68% rename from app/src/main/java/org/tm/archive/registration/fragments/EnterPhoneNumberFragment.java rename to app/src/main/java/org/tm/archive/registration/fragments/SignalEnterPhoneNumberFragment.java index a42c708a..bfa3821a 100644 --- a/app/src/main/java/org/tm/archive/registration/fragments/EnterPhoneNumberFragment.java +++ b/app/src/main/java/org/tm/archive/registration/fragments/SignalEnterPhoneNumberFragment.java @@ -1,9 +1,5 @@ package org.tm.archive.registration.fragments; -import static org.tm.archive.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView; -import static org.tm.archive.registration.fragments.RegistrationViewDelegate.showConfirmNumberDialogIfTranslated; - -import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; @@ -16,7 +12,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; -import android.widget.LinearLayout; import android.widget.ScrollView; import androidx.annotation.NonNull; @@ -24,7 +19,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import androidx.constraintlayout.widget.ConstraintLayout; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavController; import androidx.navigation.Navigation; @@ -37,36 +31,13 @@ import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.tasks.Task; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.textfield.TextInputLayout; -import com.google.firebase.FirebaseApp; import com.google.i18n.phonenumbers.NumberParseException; import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.i18n.phonenumbers.Phonenumber; -import com.tm.androidcopysdk.AndroidCopySDK; -import com.tm.androidcopysdk.BackupService; -import com.tm.androidcopysdk.CommonUtils; -import com.tm.androidcopysdk.network.appSettings.UpdateEvent; -import com.tm.androidcopysdk.utils.PrefManager; -import com.tm.authenticatorsdk.mamsdk.IMDMAuthenticator; -import com.tm.authenticatorsdk.mamsdk.MDMAuthenticator; -import com.tm.authenticatorsdk.selfAuthenticator.AuthenticatorConstants; -import com.tm.authenticatorsdk.selfAuthenticator.IAuthenticationStatus; -import org.selfAuthentication.SelfAuthenticationDialogBuilder; -import org.archiver.ArchiveConstants; -import org.archiver.ArchiveLogger; -import org.archiver.ArchivePreferenceConstants; -import org.archiver.ArchiveUtil; -import org.archiver.FCMConnector; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import org.intune.IntuneAuthManager; -import org.jetbrains.annotations.NotNull; -import org.selfAuthentication.SelfAuthenticatorManager; import org.signal.core.util.ThreadUtil; import org.signal.core.util.concurrent.LifecycleDisposable; import org.signal.core.util.logging.Log; -import org.tm.archive.BuildConfig; import org.tm.archive.LoggingFragment; import org.tm.archive.R; import org.tm.archive.keyvalue.SignalStore; @@ -93,28 +64,20 @@ import java.util.concurrent.atomic.AtomicBoolean; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.disposables.Disposable; -public final class EnterPhoneNumberFragment extends LoggingFragment implements RegistrationNumberInputController.Callbacks -, IAuthenticationStatus, IMDMAuthenticator //*TM_SA*// +import static org.tm.archive.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView; +import static org.tm.archive.registration.fragments.RegistrationViewDelegate.showConfirmNumberDialogIfTranslated; + +public class SignalEnterPhoneNumberFragment extends LoggingFragment implements RegistrationNumberInputController.Callbacks //**TM_SA**//change name, delete final { - private static final String TAG = Log.tag(EnterPhoneNumberFragment.class); + private static final String TAG = Log.tag(SignalEnterPhoneNumberFragment.class); private TextInputLayout countryCode; private TextInputLayout number; private CircularProgressMaterialButton register; private View cancel; private ScrollView scrollView; - private RegistrationViewModel viewModel; - - //**TM_SA**// START - private Context mContext; - private boolean progressBarShown; - - public static boolean mIsLoginAuthenticationInProgress = false; - private ConstraintLayout constraintLayout; - private View progressBarCustomView; - String mobileNumber; - //**TM_SA**// END + RegistrationViewModel viewModel;//**TM_SA**//delete private private final LifecycleDisposable disposables = new LifecycleDisposable(); @@ -122,13 +85,6 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); - - // START - mContext = getActivity(); - if(!EventBus.getDefault().isRegistered(this)) { - EventBus.getDefault().register(this); - } - // END } @Override @@ -147,9 +103,6 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R cancel = view.findViewById(R.id.cancel_button); scrollView = view.findViewById(R.id.scroll_view); register = view.findViewById(R.id.registerButton); - constraintLayout = view.findViewById(R.id.constraint_layout); //**TM_SA**// - - initProgressBar(); //**TM_SA**// RegistrationNumberInputController controller = new RegistrationNumberInputController(requireContext(), this, @@ -192,50 +145,8 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R viewModel.setAutoShowSmsConfirmDialog(false); ThreadUtil.runOnMainDelayed(() -> handleRegister(requireContext()), 250); } - - constraintLayout.addView(progressBarCustomView);//**TM_SA**// } - //**TM_SA**// START - @Override public void onDestroy() { - super.onDestroy(); - if(EventBus.getDefault().isRegistered(this)) { - EventBus.getDefault().unregister(this); - } - } - private void initProgressBar(){ - progressBarShown = false; - - progressBarCustomView = LayoutInflater.from(getContext()).inflate(R.layout.progress_bar_layout_with_background, null, false); - LinearLayout.LayoutParams backgroundLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - progressBarCustomView.setLayoutParams(backgroundLayoutParams); - progressBarCustomView.setVisibility(View.GONE); - } - - - private void hideProgressBar(){ - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - progressBarCustomView.setVisibility(View.GONE); - progressBarShown = false; - Log.d(TAG, "Registration progress hidden"); - } - }); - } - - private void showProgressBar(){ - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - progressBarCustomView.setVisibility(View.VISIBLE); - progressBarShown = true; - Log.d(TAG, "Registration progress shown"); - } - }); - } - //**TM_SA**// END - private void showKeyboard(View viewToFocus) { viewToFocus.requestFocus(); InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE); @@ -250,14 +161,14 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (item.getItemId() == R.id.phone_menu_use_proxy) { - SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), EnterPhoneNumberFragmentDirections.actionEditProxy()); + SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), TMEnterPhoneNumberFragmentDirections.actionEditProxy());//*TM_SA*/ change to TM.. return true; } else { return false; } } - private void handleRegister(@NonNull Context context) { + void handleRegister(@NonNull Context context) {//**TM_SA**//delete private if (viewModel.getNumber().getCountryCode() == 0) { showErrorDialog(context, getString(R.string.RegistrationActivity_you_must_specify_your_country_code)); return; @@ -281,43 +192,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R PlayServicesUtil.PlayServicesStatus fcmStatus = PlayServicesUtil.getPlayServicesStatus(context); if (fcmStatus == PlayServicesUtil.PlayServicesStatus.SUCCESS) { - //**TM_SA**//Start - Activity activity = requireActivity(); - if (BuildConfig.DEBUG) { - if (CommonUtils.isMyServiceRunning(activity, BackupService.class)) { - CommonUtils.stopBackupService(activity, false); - } - - PrefManager.setStringPref(getContext(), ArchiveConstants.SHARED_PREFERENCE_SELECTED_BASE_URL_PRODUCTION_KEY, AuthenticatorConstants.Companion.getBASE_URL().getFirst()); - PrefManager.setStringPref(getContext(), ArchiveConstants.SHARED_PREFERENCE_SELECTED_BASE_URL_KEEPER_KEY, AuthenticatorConstants.Companion.getBASE_URL().getSecond()); - - CommonUtils.setUrl(activity.getApplicationContext(), AuthenticatorConstants.Companion.getBASE_URL().getFirst(), AuthenticatorConstants.Companion.getBASE_URL().getSecond()); - CommonUtils.startBackupService(activity); - } - ArchiveLogger.Companion.sendArchiveLog("Register success with " + e164number + " Phone number" ); - String lastNumber = PrefManager.getStringPref(context, ArchivePreferenceConstants.PREF_KEY_DEVICE_PHONE_NUMBER, ""); - if (!lastNumber.equals(e164number)) { - CommonUtils.setActivatedUser(requireContext(), false); - PrefManager.setStringPref(context, ArchivePreferenceConstants.PREF_KEY_DEVICE_PHONE_NUMBER, e164number); - } - - AndroidCopySDK.getInstance(context).savePhoneNumber(ArchiveUtil.Companion.getPhoneNumberInTestMode(context)); - mIsLoginAuthenticationInProgress = true; -// startAutoAuthentication(requireContext(), e164number); - mobileNumber = e164number; - int authStatus = PrefManager.getIntPref(requireContext(), - IntuneAuthManager.MDM_Auth_Status_String, IntuneAuthManager.MdmAuthStatus.START_INTUNE_AUTH.ordinal()); - - if(CommonUtils.isActivatedUser(context)) { - confirmNumberPrompt(context, e164number, () -> handleRequestVerification(context, true)); - } else { - if (MDMAuthenticator.INSTANCE.isMDM(context) && authStatus == IntuneAuthManager.MdmAuthStatus.START_INTUNE_AUTH.ordinal()) {// mdm auth skip this fragment and work on EnterSmsCodeFragment - startMdm(); - } else { - startAutoAuthentication(e164number); //start self auth - } - } - //**TM_SA**//End + confirmNumberPrompt(context, e164number, () -> onE164EnteredSuccessfully(context, true)); } else if (fcmStatus == PlayServicesUtil.PlayServicesStatus.MISSING) { confirmNumberPrompt(context, e164number, () -> handlePromptForNoPlayServices(context)); } else if (fcmStatus == PlayServicesUtil.PlayServicesStatus.NEEDS_UPDATE) { @@ -329,73 +204,6 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R } } - //**TM_SA**//START - private void startMdm() { - Log.d(TAG, "startMdm"); - FCMConnector.initTeleMessageSignalFirebaseAccount(requireContext(), null, true); - MDMAuthenticator.INSTANCE.startMDMAuthenticator(requireActivity(), mobileNumber, BuildConfig.signal_teleMessage_version, this); - } - - - @Override - public void failureMDMAuth(String reason) { - final String onCancel = "onCancel", server = "server"; - Log.d(TAG, "failureMDMAuth, reason: " + reason); - if(reason.equals(onCancel)) { - IntuneAuthManager.INSTANCE.showDialog(requireActivity(), this::startMdm); - } //update app that intune signed failed: two cases. 1. try intune auth again 2. move to self auth - else if(reason.contains(server) || reason.contains("Authentication failed") - /*|| reason.contains("managerID")*/) { //try intune auth again - PrefManager.setIntPref(requireContext(), IntuneAuthManager.MDM_Auth_Status_String,IntuneAuthManager.MdmAuthStatus.START_INTUNE_AUTH.ordinal()); - Log.d(TAG, "status auth is " + IntuneAuthManager.MdmAuthStatus.START_INTUNE_AUTH.ordinal()); - requireActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - confirmNumberPrompt(requireContext(), mobileNumber, () -> handleRequestVerification(requireContext(), true)); - } - }); - }else { //this case should pass to self-auth - PrefManager.setIntPref(requireContext(),IntuneAuthManager.MDM_Auth_Status_String,IntuneAuthManager.MdmAuthStatus.START_SELF_AUTH.ordinal()); - Log.d(TAG, "status auth is " + IntuneAuthManager.MdmAuthStatus.START_SELF_AUTH.ordinal()); - requireActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - confirmNumberPrompt(requireContext(), mobileNumber, () -> handleRequestVerification(requireContext(), true)); - } - }); - } - - } - - @Override - public void successMDMAuth() { - Log.d(TAG, "successMDMAuth"); - startIntuneAutoAuthentication(mobileNumber); - } - - /** - * intune - * - * @param e164number - */ - private void startIntuneAutoAuthentication(String e164number) { - Log.d(TAG, "startAutoAuthentication"); - SelfAuthenticatorManager.INSTANCE.initAuthenticator(e164number); - IntuneAuthManager.INSTANCE.continueIntuneAuthentication(this); - } - - private void startAutoAuthentication(String e164number) { - Log.i(TAG , "startAutoAuthentication"); - FCMConnector.initTeleMessageSignalFirebaseAccount(requireContext(), null, true); - Log.i(TAG, "current FCM: " + FirebaseApp.getInstance().getOptions().getProjectId()); - SelfAuthenticatorManager.INSTANCE.initAuthenticator(e164number); - SelfAuthenticatorManager.INSTANCE.startAuthentication(this); - if (!progressBarShown) { - showProgressBar(); - } - } - //**TM_SA**//END - private void onE164EnteredSuccessfully(@NonNull Context context, boolean fcmSupported) { enterInProgressUiState(); Log.d(TAG, "E164 entered successfully."); @@ -405,7 +213,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R .subscribe(canEnter -> { if (canEnter) { Log.i(TAG, "Entering skip flow."); - SafeNavigation.safeNavigate(NavHostFragment.findNavController(this), EnterPhoneNumberFragmentDirections.actionReRegisterWithPinFragment()); + SafeNavigation.safeNavigate(NavHostFragment.findNavController(this), TMEnterPhoneNumberFragmentDirections.actionReRegisterWithPinFragment());//*TM_SA*/ change to TM.. } else { Log.i(TAG, "Unable to collect necessary data to enter skip flow, returning to normal"); handleRequestVerification(context, fcmSupported); @@ -414,7 +222,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R disposables.add(disposable); } - private void handleRequestVerification(@NonNull Context context, boolean fcmSupported) { + void handleRequestVerification(@NonNull Context context, boolean fcmSupported) {//**TM_SA**//delete private if (fcmSupported) { SmsRetrieverClient client = SmsRetriever.getClient(context); Task task = client.startSmsRetriever(); @@ -483,7 +291,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R private void requestVerificationCode(@NonNull Mode mode) { NavController navController = NavHostFragment.findNavController(this); MccMncProducer mccMncProducer = new MccMncProducer(requireContext()); - final DialogInterface.OnClickListener proceedToNextScreen = (dialog, which) -> SafeNavigation.safeNavigate(navController, EnterPhoneNumberFragmentDirections.actionEnterVerificationCode()); + final DialogInterface.OnClickListener proceedToNextScreen = (dialog, which) -> SafeNavigation.safeNavigate(navController, TMEnterPhoneNumberFragmentDirections.actionEnterVerificationCode());//*TM_SA*/ change to TM.. Disposable request = viewModel.requestVerificationCode(mode, mccMncProducer.getMcc(), mccMncProducer.getMnc()) .doOnSubscribe(unused -> SignalStore.account().setRegistered(false)) .observeOn(AndroidSchedulers.mainThread()) @@ -496,10 +304,10 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R if (processor.verificationCodeRequestSuccess()) { disposables.add(updateFcmTokenValue()); - SafeNavigation.safeNavigate(navController, EnterPhoneNumberFragmentDirections.actionEnterVerificationCode()); + SafeNavigation.safeNavigate(navController, TMEnterPhoneNumberFragmentDirections.actionEnterVerificationCode());//*TM_SA*/ change to TM.. } else if (processor.captchaRequired(viewModel.getExcludedChallenges())) { Log.i(TAG, "Unable to request sms code due to captcha required"); - SafeNavigation.safeNavigate(navController, EnterPhoneNumberFragmentDirections.actionRequestCaptcha()); + SafeNavigation.safeNavigate(navController, TMEnterPhoneNumberFragmentDirections.actionRequestCaptcha());//*TM_SA*/ change to TM.. } else if (processor.exhaustedVerificationCodeAttempts()) { Log.i(TAG, "Unable to request sms code due to exhausting attempts"); showErrorDialog(context, context.getString(R.string.RegistrationActivity_rate_limited_to_service)); @@ -561,7 +369,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R } public void showErrorDialog(Context context, String msg, DialogInterface.OnClickListener positiveButtonListener) { - new MaterialAlertDialogBuilder(context).setMessage(msg).setPositiveButton(R.string.ok, positiveButtonListener).show(); + new MaterialAlertDialogBuilder(context).setMessage(msg).setPositiveButton(android.R.string.ok, positiveButtonListener).show(); } @Override @@ -602,7 +410,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R if (processor.hasResult() && processor.canSubmitProofImmediately()) { try { viewModel.restorePhoneNumberStateFromE164(sessionE164); - SafeNavigation.safeNavigate(navController, EnterPhoneNumberFragmentDirections.actionEnterVerificationCode()); + SafeNavigation.safeNavigate(navController, TMEnterPhoneNumberFragmentDirections.actionEnterVerificationCode());//*TM_SA*/ change to TM.. } catch (NumberParseException numberParseException) { viewModel.resetSession(); } @@ -645,7 +453,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R } } - private void handlePromptForNoPlayServices(@NonNull Context context) { + void handlePromptForNoPlayServices(@NonNull Context context) {//**TM_SA**//delete private Log.d(TAG, "Device does not have Play Services, showing consent dialog."); new MaterialAlertDialogBuilder(context) .setTitle(R.string.RegistrationActivity_missing_google_play_services) @@ -655,7 +463,7 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R .show(); } - private void confirmNumberPrompt(@NonNull Context context, + void confirmNumberPrompt(@NonNull Context context,//**TM_SA**//delete private @NonNull String e164number, @NonNull Runnable onConfirmed) { @@ -691,47 +499,4 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R ) ); } - - //**TM_SA**//START - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEvent(UpdateEvent event) { - if (event == null) { - return; - } - Log.d("EnterPhoneNumberFragment", "UpdateEvent -> onEvent: " + event.type); - - if (event.type == UpdateEvent.EVENTS_TYPE.activated) { - CommonUtils.setActivatedUser(requireContext(), true); - final NumberViewState number = viewModel.getNumber(); - final String e164number = number.getE164Number(); - confirmNumberPrompt(mContext, e164number, () -> handleRequestVerification(mContext, true)); - - } else if (event.type == UpdateEvent.EVENTS_TYPE.suspension) { - CommonUtils.setActivatedUser(requireContext(), false); - SelfAuthenticationDialogBuilder dialog = new SelfAuthenticationDialogBuilder(); - dialog.doSendLogsClicked(requireActivity(), progressBarCustomView); - } - - Log.i(TAG, "onMessageEvent -> 1 current FCM: " + FirebaseApp.getInstance().getOptions().getProjectId()); - Log.d("SelfAuthenticator", "initOfficialSignalFirebaseAccount!!! "); - FCMConnector.initOfficialSignalFirebaseAccount(mContext); - Log.i(TAG, "onMessageEvent -> 2 current FCM: " + FirebaseApp.getInstance().getOptions().getProjectId()); - - if (progressBarShown) { - hideProgressBar(); - } - } - - - @Override - public void authenticationProcessMessage(@NotNull String message) { - Log.d(TAG, "authenticationProcessMessage = " + message); - if (!message.isEmpty()) { - mIsLoginAuthenticationInProgress = false; -// EventBus.getDefault().post(new MessageEvent(SelfAuthenticatorConstants.Companion.getSelfAuthenticationFailed())); - EventBus.getDefault().post(new UpdateEvent(UpdateEvent.EVENTS_TYPE.suspension)); - } - } - //**TM_SA**//End } diff --git a/app/src/main/java/org/tm/archive/registration/fragments/WelcomeFragment.java b/app/src/main/java/org/tm/archive/registration/fragments/WelcomeFragment.java index 44e8187e..5a3abbcd 100644 --- a/app/src/main/java/org/tm/archive/registration/fragments/WelcomeFragment.java +++ b/app/src/main/java/org/tm/archive/registration/fragments/WelcomeFragment.java @@ -152,8 +152,7 @@ public final class WelcomeFragment extends LoggingFragment { @NonNull NavDirections actionRestore) { boolean isUserSelectionRequired = BackupUtil.isUserSelectionRequired(fragment.requireContext()); - - //**TM_SA**// START +//**TM_SA**// START if (!environmentAlreadySelected && BuildConfig.DEBUG) { ApiUtil.Companion.selectServerEnvironment(fragment.getContext()); environmentAlreadySelected = true; @@ -161,7 +160,6 @@ public final class WelcomeFragment extends LoggingFragment { //**TM_SA**// END - Permissions.with(fragment) .request(WelcomePermissions.getWelcomePermissions(isUserSelectionRequired)) .ifNecessary() @@ -260,9 +258,10 @@ public final class WelcomeFragment extends LoggingFragment { } private void onTermsClicked() { - CommunicationActions.openBrowserLink(requireContext(), requireContext().getString(R.string.telemessage_privacy_url)/*TM_TA RegistrationConstants.TERMS_AND_CONDITIONS_URL*/); + CommunicationActions.openBrowserLink(requireContext(), requireContext().getString(R.string.telemessage_privacy_url)/*TM_SA RegistrationConstants.TERMS_AND_CONDITIONS_URL*/); } + private boolean canUserSelectBackup() { return BackupUtil.isUserSelectionRequired(requireContext()) && !viewModel.isReregister() && diff --git a/app/src/main/java/org/tm/archive/registration/secondary/DeviceNameCipher.kt b/app/src/main/java/org/tm/archive/registration/secondary/DeviceNameCipher.kt index 7ea2c04d..5c9e4151 100644 --- a/app/src/main/java/org/tm/archive/registration/secondary/DeviceNameCipher.kt +++ b/app/src/main/java/org/tm/archive/registration/secondary/DeviceNameCipher.kt @@ -1,11 +1,17 @@ package org.tm.archive.registration.secondary import okio.ByteString.Companion.toByteString +import org.signal.core.util.logging.Log import org.signal.libsignal.protocol.IdentityKeyPair +import org.signal.libsignal.protocol.InvalidKeyException import org.signal.libsignal.protocol.ecc.Curve import org.signal.libsignal.protocol.ecc.ECKeyPair +import org.signal.libsignal.protocol.ecc.ECPrivateKey +import org.signal.libsignal.protocol.util.ByteUtil import org.tm.archive.devicelist.protos.DeviceName import java.nio.charset.Charset +import java.security.GeneralSecurityException +import java.security.MessageDigest import javax.crypto.Cipher import javax.crypto.Mac import javax.crypto.spec.IvParameterSpec @@ -16,6 +22,8 @@ import javax.crypto.spec.SecretKeySpec */ object DeviceNameCipher { + private val TAG = Log.tag(DeviceNameCipher::class.java) + private const val SYNTHETIC_IV_LENGTH = 16 @JvmStatic @@ -37,6 +45,54 @@ object DeviceNameCipher { ).encode() } + /** + * Decrypts a [DeviceName]. Returns null if data is invalid/undecryptable. + */ + @JvmStatic + fun decryptDeviceName(deviceName: DeviceName, identityKeyPair: IdentityKeyPair): ByteArray? { + if (deviceName.ephemeralPublic == null || deviceName.syntheticIv == null || deviceName.ciphertext == null) { + return null + } + + return try { + val syntheticIv = deviceName.syntheticIv.toByteArray() + val cipherText = deviceName.ciphertext.toByteArray() + val identityKey: ECPrivateKey = identityKeyPair.privateKey + val ephemeralPublic = Curve.decodePoint(deviceName.ephemeralPublic.toByteArray(), 0) + val masterSecret = Curve.calculateAgreement(ephemeralPublic, identityKey) + + val mac = Mac.getInstance("HmacSHA256") + mac.init(SecretKeySpec(masterSecret, "HmacSHA256")) + val cipherKeyPart1 = mac.doFinal("cipher".toByteArray()) + + mac.init(SecretKeySpec(cipherKeyPart1, "HmacSHA256")) + val cipherKey = mac.doFinal(syntheticIv) + + val cipher = Cipher.getInstance("AES/CTR/NoPadding") + cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(ByteArray(16))) + val plaintext = cipher.doFinal(cipherText) + + mac.init(SecretKeySpec(masterSecret, "HmacSHA256")) + val verificationPart1 = mac.doFinal("auth".toByteArray()) + + mac.init(SecretKeySpec(verificationPart1, "HmacSHA256")) + val verificationPart2 = mac.doFinal(plaintext) + val ourSyntheticIv = ByteUtil.trim(verificationPart2, 16) + + if (!MessageDigest.isEqual(ourSyntheticIv, syntheticIv)) { + throw GeneralSecurityException("The computed syntheticIv didn't match the actual syntheticIv.") + } + + plaintext + } catch (e: GeneralSecurityException) { + Log.w(TAG, "Failed to decrypt device name.", e) + null + } catch (e: InvalidKeyException) { + Log.w(TAG, "Failed to decrypt device name.", e) + null + } + } + private fun computeCipherKey(masterSecret: ByteArray, syntheticIv: ByteArray): ByteArray { val input = "cipher".toByteArray(Charset.forName("UTF-8")) diff --git a/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageActivity.java b/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageActivity.java index 8add9e08..1c57aa4d 100644 --- a/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageActivity.java +++ b/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageActivity.java @@ -16,11 +16,12 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatDelegate; import androidx.lifecycle.ViewModelProvider; +import com.bumptech.glide.Glide; + import org.signal.core.util.logging.Log; import org.tm.archive.PassphraseRequiredActivity; import org.tm.archive.R; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideApp; import org.tm.archive.mms.PartAuthority; import org.tm.archive.mms.VideoSlide; import org.tm.archive.providers.BlobProvider; @@ -141,7 +142,7 @@ public class ViewOnceMessageActivity extends PassphraseRequiredActivity implemen image.setVisibility(View.VISIBLE); duration.setVisibility(View.GONE); - GlideApp.with(this) + Glide.with(this) .load(new DecryptableUri(uri)) .fitCenter() .into(image); diff --git a/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageView.java b/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageView.java index 95ef35cb..7f85d746 100644 --- a/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageView.java +++ b/app/src/main/java/org/tm/archive/revealable/ViewOnceMessageView.java @@ -122,16 +122,16 @@ public class ViewOnceMessageView extends LinearLayout { if (messageRecord.isViewed()) { iconColor = openedIconColor; text.setText(R.string.RevealableMessageView_viewed); - icon.setImageResource(R.drawable.ic_viewed_once_24); + icon.setImageResource(R.drawable.symbol_view_once_dash_24); } else { iconColor = unopenedIconColor; text.setText(R.string.RevealableMessageView_media); - icon.setImageResource(R.drawable.ic_view_once_24); + icon.setImageResource(R.drawable.symbol_view_once_24); } } else if (ViewOnceUtil.isViewable(messageRecord)) { iconColor = unopenedIconColor; text.setText(getDescriptionId(messageRecord)); - icon.setImageResource(R.drawable.ic_view_once_24); + icon.setImageResource(R.drawable.symbol_view_once_24); } else if (networkInProgress(messageRecord)) { iconColor = unopenedIconColor; text.setText(""); @@ -140,11 +140,11 @@ public class ViewOnceMessageView extends LinearLayout { } else if (requiresTapToDownload(messageRecord)) { iconColor = unopenedIconColor; text.setText(formatFileSize(messageRecord)); - icon.setImageResource(R.drawable.ic_arrow_down_circle_outline_24); + icon.setImageResource(R.drawable.symbol_arrow_circle_down_24); } else { iconColor = openedIconColor; text.setText(R.string.RevealableMessageView_viewed); - icon.setImageResource(R.drawable.ic_viewed_once_24); + icon.setImageResource(R.drawable.symbol_view_once_dash_24); } text.setTextColor(textColor); diff --git a/app/src/main/java/org/tm/archive/scribbles/HSVColorSlider.kt b/app/src/main/java/org/tm/archive/scribbles/HSVColorSlider.kt index c76825c6..1e7209b4 100644 --- a/app/src/main/java/org/tm/archive/scribbles/HSVColorSlider.kt +++ b/app/src/main/java/org/tm/archive/scribbles/HSVColorSlider.kt @@ -155,6 +155,11 @@ object HSVColorSlider { val radii: FloatArray = (1..8).map { 50f }.toFloatArray() val bounds = RectF() val clipPath = Path() + val paint = Paint().apply { + color = Color.WHITE + style = Paint.Style.STROKE + strokeWidth = ViewUtil.dpToPx(4).toFloat() + } return customizeOnDraw { wrapped, canvas -> canvas.save() @@ -164,6 +169,7 @@ object HSVColorSlider { clipPath.rewind() clipPath.addRoundRect(bounds, radii, Path.Direction.CW) + canvas.drawPath(clipPath, paint) canvas.clipPath(clipPath) wrapped.draw(canvas) canvas.restore() diff --git a/app/src/main/java/org/tm/archive/scribbles/ImageEditorFragment.java b/app/src/main/java/org/tm/archive/scribbles/ImageEditorFragment.java index 7d8e2f0c..48ce9e44 100644 --- a/app/src/main/java/org/tm/archive/scribbles/ImageEditorFragment.java +++ b/app/src/main/java/org/tm/archive/scribbles/ImageEditorFragment.java @@ -320,12 +320,6 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu return imageUri; } - @Nullable - @Override - public View getPlaybackControls() { - return null; - } - @Override public Object saveState() { Data data = new Data(); diff --git a/app/src/main/java/org/tm/archive/scribbles/ImageEditorHudV2.kt b/app/src/main/java/org/tm/archive/scribbles/ImageEditorHudV2.kt index 3154ab34..fc97979f 100644 --- a/app/src/main/java/org/tm/archive/scribbles/ImageEditorHudV2.kt +++ b/app/src/main/java/org/tm/archive/scribbles/ImageEditorHudV2.kt @@ -146,9 +146,9 @@ class ImageEditorHudV2 @JvmOverloads constructor( cropAspectLockButton.setOnClickListener { listener?.onCropAspectLock() if (listener?.isCropAspectLocked == true) { - cropAspectLockButton.setImageResource(R.drawable.ic_crop_lock_24) + cropAspectLockButton.setImageResource(R.drawable.symbol_crop_lock_24) } else { - cropAspectLockButton.setImageResource(R.drawable.ic_crop_unlock_24) + cropAspectLockButton.setImageResource(R.drawable.symbol_crop_unlock_24) } } @@ -355,7 +355,7 @@ class ImageEditorHudV2 @JvmOverloads constructor( private fun presentModeDraw() { drawButton.isSelected = true - brushToggle.setImageResource(R.drawable.ic_draw_white_24) + brushToggle.setImageResource(R.drawable.symbol_brush_pen_24) widthSeekBar.progress = SignalStore.imageEditorValues().getMarkerPercentage() listener?.onColorChange(getActiveColor()) updateColorIndicator() @@ -368,7 +368,7 @@ class ImageEditorHudV2 @JvmOverloads constructor( private fun presentModeHighlight() { drawButton.isSelected = true - brushToggle.setImageResource(R.drawable.ic_marker_24) + brushToggle.setImageResource(R.drawable.symbol_brush_highlighter_24) widthSeekBar.progress = SignalStore.imageEditorValues().getHighlighterPercentage() listener?.onColorChange(getActiveColor()) updateColorIndicator() diff --git a/app/src/main/java/org/tm/archive/scribbles/UriGlideRenderer.java b/app/src/main/java/org/tm/archive/scribbles/UriGlideRenderer.java index 1daa6974..7ba9b320 100644 --- a/app/src/main/java/org/tm/archive/scribbles/UriGlideRenderer.java +++ b/app/src/main/java/org/tm/archive/scribbles/UriGlideRenderer.java @@ -19,6 +19,8 @@ import android.renderscript.ScriptIntrinsicBlur; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; @@ -31,8 +33,6 @@ import org.signal.imageeditor.core.SelectableRenderer; import org.signal.imageeditor.core.model.EditorElement; import org.signal.imageeditor.core.model.EditorModel; import org.tm.archive.mms.DecryptableStreamUriLoader; -import org.tm.archive.mms.GlideApp; -import org.tm.archive.mms.GlideRequest; import org.tm.archive.util.BitmapUtil; import java.util.concurrent.ExecutionException; @@ -94,13 +94,13 @@ public final class UriGlideRenderer implements SelectableRenderer { if (getBitmap() == null) { if (rendererContext.isBlockingLoad()) { try { - Bitmap bitmap = getBitmapGlideRequest(rendererContext.context, false).submit().get(); + Bitmap bitmap = getGlideRequestBuilder(rendererContext.context, false).submit().get(); setBitmap(rendererContext, bitmap); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } } else { - getBitmapGlideRequest(rendererContext.context, true).into(new CustomTarget() { + getGlideRequestBuilder(rendererContext.context, true).into(new CustomTarget() { @Override public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition transition) { setBitmap(rendererContext, resource); @@ -181,7 +181,7 @@ public final class UriGlideRenderer implements SelectableRenderer { } } - private GlideRequest getBitmapGlideRequest(@NonNull Context context, boolean preview) { + private RequestBuilder getGlideRequestBuilder(@NonNull Context context, boolean preview) { int width = this.maxWidth; int height = this.maxHeight; @@ -190,7 +190,7 @@ public final class UriGlideRenderer implements SelectableRenderer { height = Math.min(height, PREVIEW_DIMENSION_LIMIT); } - return GlideApp.with(context) + return Glide.with(context) .asBitmap() .override(width, height) .centerInside() diff --git a/app/src/main/java/org/tm/archive/scribbles/VideoEditorHud.java b/app/src/main/java/org/tm/archive/scribbles/VideoEditorHud.java deleted file mode 100644 index 049efc48..00000000 --- a/app/src/main/java/org/tm/archive/scribbles/VideoEditorHud.java +++ /dev/null @@ -1,225 +0,0 @@ -package org.tm.archive.scribbles; - -import android.animation.Animator; -import android.content.Context; -import android.database.Cursor; -import android.graphics.Rect; -import android.net.Uri; -import android.provider.OpenableColumns; -import android.util.AttributeSet; -import android.view.View; -import android.view.animation.OvershootInterpolator; -import android.widget.LinearLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.core.view.ViewCompat; - -import org.signal.core.util.logging.Log; -import org.tm.archive.R; -import org.tm.archive.media.DecryptableUriMediaInput; -import org.tm.archive.mms.VideoSlide; -import org.tm.archive.util.MediaUtil; -import org.tm.archive.video.VideoBitRateCalculator; -import org.tm.archive.video.VideoUtil; -import org.tm.archive.video.videoconverter.VideoThumbnailsRangeSelectorView; - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * The HUD (heads-up display) that contains all of the tools for editing video. - */ -public final class VideoEditorHud extends LinearLayout { - - @SuppressWarnings("unused") - private static final String TAG = Log.tag(VideoEditorHud.class); - - private final List exclusionZone = List.of(new Rect()); - - private VideoThumbnailsRangeSelectorView videoTimeLine; - private EventListener eventListener; - private View playOverlay; - - public VideoEditorHud(@NonNull Context context) { - super(context); - initialize(); - } - - public VideoEditorHud(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - public VideoEditorHud(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - initialize(); - } - - private void initialize() { - View root = inflate(getContext(), R.layout.video_editor_hud, this); - setOrientation(VERTICAL); - - videoTimeLine = root.findViewById(R.id.video_timeline); - playOverlay = root.findViewById(R.id.play_overlay); - - playOverlay.setOnClickListener(v -> eventListener.onPlay()); - } - - public void setEventListener(EventListener eventListener) { - this.eventListener = eventListener; - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - final Rect outRect = exclusionZone.get(0); - videoTimeLine.getHitRect(outRect); - outRect.left = l; - outRect.right = r; - ViewCompat.setSystemGestureExclusionRects(this, exclusionZone); - super.onLayout(changed, l, t, r, b); - } - - @RequiresApi(api = 23) - public void setVideoSource(@NonNull VideoSlide slide, @NonNull VideoBitRateCalculator videoBitRateCalculator, long maxSendSize) - throws IOException - { - Uri uri = slide.getUri(); - - if (uri == null || !slide.hasVideo()) { - return; - } - - videoTimeLine.setInput(DecryptableUriMediaInput.createForUri(getContext(), uri)); - - long size = tryGetUriSize(getContext(), uri, Long.MAX_VALUE); - - if (size > maxSendSize) { - videoTimeLine.setTimeLimit(VideoUtil.getMaxVideoUploadDurationInSeconds(), TimeUnit.SECONDS); - } - - videoTimeLine.setOnRangeChangeListener(new VideoThumbnailsRangeSelectorView.OnRangeChangeListener() { - - @Override - public void onPositionDrag(long position) { - if (eventListener != null) { - eventListener.onSeek(position, false); - } - } - - @Override - public void onEndPositionDrag(long position) { - if (eventListener != null) { - eventListener.onSeek(position, true); - } - } - - @Override - public void onRangeDrag(long minValueUs, long maxValueUs, long durationUs, VideoThumbnailsRangeSelectorView.Thumb thumb) { - if (eventListener != null) { - eventListener.onEditVideoDuration(durationUs, minValueUs, maxValueUs, thumb == VideoThumbnailsRangeSelectorView.Thumb.MIN, false); - } - } - - @Override - public void onRangeDragEnd(long minValueUs, long maxValueUs, long durationUs, VideoThumbnailsRangeSelectorView.Thumb thumb) { - if (eventListener != null) { - eventListener.onEditVideoDuration(durationUs, minValueUs, maxValueUs, thumb == VideoThumbnailsRangeSelectorView.Thumb.MIN, true); - } - } - - @Override - public VideoThumbnailsRangeSelectorView.Quality getQuality(long clipDurationUs, long totalDurationUs) { - int inputBitRate = VideoBitRateCalculator.bitRate(size, TimeUnit.MICROSECONDS.toMillis(totalDurationUs)); - - VideoBitRateCalculator.Quality targetQuality = videoBitRateCalculator.getTargetQuality(TimeUnit.MICROSECONDS.toMillis(clipDurationUs), inputBitRate); - return new VideoThumbnailsRangeSelectorView.Quality(targetQuality.getFileSizeEstimate(), (int) (100 * targetQuality.getQuality())); - } - }); - } - - public void showPlayButton() { - playOverlay.setVisibility(VISIBLE); - playOverlay.animate() - .setListener(null) - .alpha(1) - .scaleX(1).scaleY(1) - .setInterpolator(new OvershootInterpolator()) - .start(); - } - - public void fadePlayButton() { - playOverlay.animate() - .setListener(new Animator.AnimatorListener() { - @Override - public void onAnimationEnd(Animator animation) { - playOverlay.setVisibility(GONE); - } - - @Override - public void onAnimationStart(Animator animation) {} - - @Override - public void onAnimationCancel(Animator animation) {} - - @Override - public void onAnimationRepeat(Animator animation) {} - }) - .alpha(0) - .scaleX(0.8f).scaleY(0.8f) - .start(); - } - - public void hidePlayButton() { - playOverlay.setVisibility(GONE); - playOverlay.setAlpha(0); - playOverlay.setScaleX(0.8f); - playOverlay.setScaleY(0.8f); - } - - @RequiresApi(api = 23) - public void setDurationRange(long totalDuration, long fromDuration, long toDuration) { - videoTimeLine.setRange(fromDuration, toDuration); - } - - @RequiresApi(api = 23) - public void setPosition(long playbackPositionUs) { - videoTimeLine.setActualPosition(playbackPositionUs); - } - - public interface EventListener { - - void onEditVideoDuration(long totalDurationUs, long startTimeUs, long endTimeUs, boolean fromEdited, boolean editingComplete); - - void onPlay(); - - void onSeek(long position, boolean dragComplete); - } - - private long tryGetUriSize(@NonNull Context context, @NonNull Uri uri, long defaultValue) { - try { - return getSize(context, uri); - } catch (IOException e) { - Log.w(TAG, e); - return defaultValue; - } - } - - private static long getSize(@NonNull Context context, @NonNull Uri uri) throws IOException { - long size = 0; - - try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) { - if (cursor != null && cursor.moveToFirst() && cursor.getColumnIndex(OpenableColumns.SIZE) >= 0) { - size = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)); - } - } - - if (size <= 0) { - size = MediaUtil.getMediaSize(context, uri); - } - - return size; - } -} diff --git a/app/src/main/java/org/tm/archive/scribbles/VideoEditorPlayButtonLayout.kt b/app/src/main/java/org/tm/archive/scribbles/VideoEditorPlayButtonLayout.kt new file mode 100644 index 00000000..1b2b9e64 --- /dev/null +++ b/app/src/main/java/org/tm/archive/scribbles/VideoEditorPlayButtonLayout.kt @@ -0,0 +1,55 @@ +package org.tm.archive.scribbles + +import android.animation.Animator +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import org.signal.core.util.logging.Log.tag +import org.tm.archive.R +import org.tm.archive.util.createDefaultCubicBezierInterpolator + +/** + * The play button overlay for controlling playback in the video editor. + */ +class VideoEditorPlayButtonLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) { + private val playOverlay: View = inflate(this.context, R.layout.video_editor_hud, this).findViewById(R.id.play_overlay) + + fun setPlayClickListener(listener: OnClickListener?) { + playOverlay.setOnClickListener(listener) + } + + fun showPlayButton() { + playOverlay.visibility = VISIBLE + playOverlay.animate() + .setListener(null) + .alpha(1f) + .setInterpolator(createDefaultCubicBezierInterpolator()) + .setDuration(500) + .start() + } + + fun fadePlayButton() { + playOverlay.animate() + .setListener(object : Animator.AnimatorListener { + override fun onAnimationEnd(animation: Animator) { playOverlay.visibility = GONE } + override fun onAnimationStart(animation: Animator) = Unit + override fun onAnimationCancel(animation: Animator) = Unit + override fun onAnimationRepeat(animation: Animator) = Unit + }) + .alpha(0f) + .setInterpolator(createDefaultCubicBezierInterpolator()) + .setDuration(200) + .start() + } + + fun hidePlayButton() { + playOverlay.visibility = GONE + playOverlay.setAlpha(0f) + } + + companion object { + @Suppress("unused") + private val TAG = tag(VideoEditorPlayButtonLayout::class.java) + } +} diff --git a/app/src/main/java/org/tm/archive/search/ContactSearchResult.kt b/app/src/main/java/org/tm/archive/search/ContactSearchResult.kt deleted file mode 100644 index 429b8c7c..00000000 --- a/app/src/main/java/org/tm/archive/search/ContactSearchResult.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.tm.archive.search - -import org.tm.archive.recipients.Recipient - -data class ContactSearchResult(val results: List, val query: String) diff --git a/app/src/main/java/org/tm/archive/search/SearchRepository.java b/app/src/main/java/org/tm/archive/search/SearchRepository.java index 838655df..ee00f99b 100644 --- a/app/src/main/java/org/tm/archive/search/SearchRepository.java +++ b/app/src/main/java/org/tm/archive/search/SearchRepository.java @@ -2,7 +2,6 @@ package org.tm.archive.search; import android.content.Context; import android.database.Cursor; -import android.database.MergeCursor; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -14,7 +13,6 @@ import androidx.annotation.WorkerThread; import org.signal.core.util.CursorUtil; import org.signal.core.util.StringUtil; -import org.signal.core.util.concurrent.LatestPrioritizedSerialExecutor; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; import org.tm.archive.contacts.ContactRepository; @@ -52,7 +50,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; -import java.util.function.Consumer; import static org.tm.archive.database.SearchTable.SNIPPET_WRAP; @@ -72,8 +69,7 @@ public class SearchRepository { private final MentionTable mentionTable; private final MessageTable messageTable; - private final LatestPrioritizedSerialExecutor searchExecutor; - private final Executor serialExecutor; + private final Executor serialExecutor; public SearchRepository(@NonNull String noteToSelfTitle) { this.context = ApplicationDependencies.getApplication().getApplicationContext(); @@ -84,7 +80,6 @@ public class SearchRepository { this.mentionTable = SignalDatabase.mentions(); this.messageTable = SignalDatabase.messages(); this.contactRepository = new ContactRepository(context, noteToSelfTitle); - this.searchExecutor = new LatestPrioritizedSerialExecutor(SignalExecutors.BOUNDED); this.serialExecutor = new SerialExecutor(SignalExecutors.BOUNDED); } @@ -98,17 +93,6 @@ public class SearchRepository { return new ThreadSearchResult(result, query); } - public void queryContacts(@NonNull String query, @NonNull Consumer callback) { - searchExecutor.execute(1, () -> { - long start = System.currentTimeMillis(); - List result = queryContacts(query); - - Log.d(TAG, "[contacts] Search took " + (System.currentTimeMillis() - start) + " ms"); - - callback.accept(new ContactSearchResult(result, query)); - }); - } - @WorkerThread public @NonNull MessageSearchResult queryMessagesSync(@NonNull String query) { long start = System.currentTimeMillis(); @@ -139,27 +123,6 @@ public class SearchRepository { }); } - private List queryContacts(String query) { - if (Util.isEmpty(query)) { - return Collections.emptyList(); - } - - Cursor contacts = null; - - try { - Cursor textSecureContacts = contactRepository.querySignalContacts(query); - Cursor systemContacts = contactRepository.queryNonSignalContacts(query); - - contacts = new MergeCursor(new Cursor[] { textSecureContacts, systemContacts }); - - return readToList(contacts, new RecipientModelBuilder(), 250); - } finally { - if (contacts != null) { - contacts.close(); - } - } - } - private @NonNull List queryConversations(@NonNull String query, boolean unreadOnly) { if (Util.isEmpty(query)) { return Collections.emptyList(); diff --git a/app/src/main/java/org/tm/archive/search/SearchResult.kt b/app/src/main/java/org/tm/archive/search/SearchResult.kt deleted file mode 100644 index 32a57e3e..00000000 --- a/app/src/main/java/org/tm/archive/search/SearchResult.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.tm.archive.search - -import org.tm.archive.conversationlist.model.ConversationFilter -import org.tm.archive.database.model.ThreadRecord -import org.tm.archive.recipients.Recipient - -/** - * Represents an all-encompassing search result that can contain various result for different - * subcategories. - */ -data class SearchResult( - val query: String, - val contacts: List, - val conversations: List, - val messages: List, - val conversationFilter: ConversationFilter -) { - fun size(): Int { - return contacts.size + conversations.size + messages.size - } - - val isEmpty: Boolean - get() = size() == 0 - - fun merge(result: ContactSearchResult): SearchResult { - return this.copy(contacts = result.results, query = result.query) - } - - fun merge(result: ThreadSearchResult): SearchResult { - return this.copy(conversations = result.results, query = result.query) - } - - fun merge(result: MessageSearchResult): SearchResult { - return this.copy(messages = result.results, query = result.query) - } - - fun merge(conversationFilter: ConversationFilter): SearchResult { - return this.copy(conversationFilter = conversationFilter) - } - - companion object { - @JvmField - val EMPTY = SearchResult("", emptyList(), emptyList(), emptyList(), ConversationFilter.OFF) - } -} diff --git a/app/src/main/java/org/tm/archive/service/KeyCachingService.java b/app/src/main/java/org/tm/archive/service/KeyCachingService.java index 0a09e25e..cd15c781 100644 --- a/app/src/main/java/org/tm/archive/service/KeyCachingService.java +++ b/app/src/main/java/org/tm/archive/service/KeyCachingService.java @@ -272,7 +272,7 @@ public class KeyCachingService extends Service { builder.setPriority(Notification.PRIORITY_MIN); builder.setOngoing(true); - builder.addAction(R.drawable.ic_menu_lock_dark, getString(R.string.KeyCachingService_lock), buildLockIntent()); + builder.addAction(R.drawable.symbol_lock_24, getString(R.string.KeyCachingService_lock), buildLockIntent()); builder.setContentIntent(buildLaunchIntent()); stopForeground(true); diff --git a/app/src/main/java/org/tm/archive/service/QuickResponseService.java b/app/src/main/java/org/tm/archive/service/QuickResponseService.java deleted file mode 100644 index a0a8c24e..00000000 --- a/app/src/main/java/org/tm/archive/service/QuickResponseService.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.tm.archive.service; - -import android.app.IntentService; -import android.content.Intent; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.widget.Toast; - -import org.signal.core.util.logging.Log; -import org.tm.archive.R; -import org.tm.archive.mms.OutgoingMessage; -import org.tm.archive.recipients.Recipient; -import org.tm.archive.sms.MessageSender; -import org.tm.archive.util.Rfc5724Uri; - -import java.net.URISyntaxException; -import java.net.URLDecoder; - -public class QuickResponseService extends IntentService { - - private static final String TAG = Log.tag(QuickResponseService.class); - - public QuickResponseService() { - super("QuickResponseService"); - } - - @Override - protected void onHandleIntent(Intent intent) { - if (!TelephonyManager.ACTION_RESPOND_VIA_MESSAGE.equals(intent.getAction())) { - Log.w(TAG, "Received unknown intent: " + intent.getAction()); - return; - } - - if (KeyCachingService.isLocked(this)) { - Log.w(TAG, "Got quick response request when locked..."); - Toast.makeText(this, R.string.QuickResponseService_quick_response_unavailable_when_Signal_is_locked, Toast.LENGTH_LONG).show(); - return; - } - - try { - Rfc5724Uri uri = new Rfc5724Uri(intent.getDataString()); - String content = intent.getStringExtra(Intent.EXTRA_TEXT); - String number = uri.getPath(); - - if (number.contains("%")){ - number = URLDecoder.decode(number); - } - - Recipient recipient = Recipient.external(this, number); - - if (!TextUtils.isEmpty(content)) { - MessageSender.send(this, OutgoingMessage.sms(recipient, content), -1, MessageSender.SendType.SIGNAL, null, null); - } - } catch (URISyntaxException e) { - Toast.makeText(this, R.string.QuickResponseService_problem_sending_message, Toast.LENGTH_LONG).show(); - Log.w(TAG, e); - } - } -} diff --git a/app/src/main/java/org/tm/archive/service/SafeForegroundService.kt b/app/src/main/java/org/tm/archive/service/SafeForegroundService.kt index 75aceeb3..abbda399 100644 --- a/app/src/main/java/org/tm/archive/service/SafeForegroundService.kt +++ b/app/src/main/java/org/tm/archive/service/SafeForegroundService.kt @@ -9,6 +9,7 @@ import android.app.Notification import android.app.Service import android.content.Context import android.content.Intent +import android.os.Bundle import android.os.IBinder import androidx.core.app.ServiceCompat import org.signal.core.util.logging.Log @@ -39,7 +40,7 @@ abstract class SafeForegroundService : Service() { * @return False if we tried to start the service but failed, otherwise true. */ @CheckReturnValue - fun start(context: Context, serviceClass: Class): Boolean { + fun start(context: Context, serviceClass: Class, extras: Bundle = Bundle.EMPTY): Boolean { stateLock.withLock { val state = currentState(serviceClass) @@ -57,7 +58,10 @@ abstract class SafeForegroundService : Service() { try { ForegroundServiceUtil.startWhenCapable( context = context, - intent = Intent(context, serviceClass).apply { action = ACTION_START } + intent = Intent(context, serviceClass).apply { + action = ACTION_START + putExtras(extras) + } ) true } catch (e: UnableToStartException) { @@ -79,14 +83,15 @@ abstract class SafeForegroundService : Service() { * Safely stops the service by starting it with an action to stop itself. * This is done to prevent scenarios where you stop the service while * a start is pending, preventing the posting of a foreground notification. + * @return true if service was running previously */ - fun stop(context: Context, serviceClass: Class) { + fun stop(context: Context, serviceClass: Class): Boolean { stateLock.withLock { val state = currentState(serviceClass) Log.d(TAG, "[stop] Current state: $state") - when (state) { + return when (state) { State.STARTING -> { Log.d(TAG, "[stop] Stopping service.") states[serviceClass] = State.STOPPING @@ -99,16 +104,19 @@ abstract class SafeForegroundService : Service() { Log.w(TAG, "Failed to start service class $serviceClass", e) states[serviceClass] = State.STOPPED } + true } State.STOPPED, State.STOPPING -> { Log.d(TAG, "[stop] No need to stop the service. Current state: $state") + false } State.NEEDS_RESTART -> { Log.i(TAG, "[stop] Clearing pending restart.") states[serviceClass] = State.STOPPING + false } } } diff --git a/app/src/main/java/org/tm/archive/service/SmsDeliveryListener.java b/app/src/main/java/org/tm/archive/service/SmsDeliveryListener.java deleted file mode 100644 index fbd77f7f..00000000 --- a/app/src/main/java/org/tm/archive/service/SmsDeliveryListener.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.tm.archive.service; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.telephony.SmsMessage; - -import org.signal.core.util.logging.Log; -import org.tm.archive.database.MessageTable; -import org.tm.archive.dependencies.ApplicationDependencies; -import org.tm.archive.jobmanager.JobManager; -import org.tm.archive.jobs.SmsSentJob; - -public class SmsDeliveryListener extends BroadcastReceiver { - - private static final String TAG = Log.tag(SmsDeliveryListener.class); - - public static final String SENT_SMS_ACTION = "org.tm.archive.SendReceiveService.SENT_SMS_ACTION"; - public static final String DELIVERED_SMS_ACTION = "org.tm.archive.SendReceiveService.DELIVERED_SMS_ACTION"; - - @Override - public void onReceive(Context context, Intent intent) { - JobManager jobManager = ApplicationDependencies.getJobManager(); - long messageId = intent.getLongExtra("message_id", -1); - int runAttempt = intent.getIntExtra("run_attempt", 0); - boolean isMultipart = intent.getBooleanExtra("is_multipart", true); - - switch (intent.getAction()) { - case SENT_SMS_ACTION: - int result = getResultCode(); - - jobManager.add(new SmsSentJob(messageId, isMultipart, SENT_SMS_ACTION, result, runAttempt)); - break; - case DELIVERED_SMS_ACTION: - byte[] pdu = intent.getByteArrayExtra("pdu"); - - if (pdu == null) { - Log.w(TAG, "No PDU in delivery receipt!"); - break; - } - - SmsMessage message = SmsMessage.createFromPdu(pdu); - - if (message == null) { - Log.w(TAG, "Delivery receipt failed to parse!"); - break; - } - - int status = message.getStatus(); - - Log.i(TAG, "Original status: " + status); - - // Note: https://developer.android.com/reference/android/telephony/SmsMessage.html#getStatus() - // " CDMA: For not interfering with status codes from GSM, the value is shifted to the bits 31-16" - // Note: https://stackoverflow.com/a/33240109 - if ("3gpp2".equals(intent.getStringExtra("format"))) { - Log.w(TAG, "Correcting for CDMA delivery receipt..."); - if (status >> 24 <= 0) status = MessageTable.Status.STATUS_COMPLETE; - else if (status >> 24 == 2) status = MessageTable.Status.STATUS_PENDING; - else if (status >> 24 == 3) status = MessageTable.Status.STATUS_FAILED; - } - - jobManager.add(new SmsSentJob(messageId, isMultipart, DELIVERED_SMS_ACTION, status, runAttempt)); - break; - default: - Log.w(TAG, "Unknown action: " + intent.getAction()); - } - } -} diff --git a/app/src/main/java/org/tm/archive/service/webrtc/ActiveCallManager.kt b/app/src/main/java/org/tm/archive/service/webrtc/ActiveCallManager.kt new file mode 100644 index 00000000..a324c7e9 --- /dev/null +++ b/app/src/main/java/org/tm/archive/service/webrtc/ActiveCallManager.kt @@ -0,0 +1,356 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.tm.archive.service.webrtc + +import android.app.Notification +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.net.ConnectivityManager +import android.os.Build +import android.telephony.PhoneStateListener +import android.telephony.TelephonyManager +import androidx.annotation.MainThread +import androidx.core.app.NotificationManagerCompat +import androidx.core.os.bundleOf +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.disposables.Disposable +import io.reactivex.rxjava3.kotlin.subscribeBy +import io.reactivex.rxjava3.schedulers.Schedulers +import org.signal.core.util.ThreadUtil +import org.signal.core.util.logging.Log +import org.tm.archive.dependencies.ApplicationDependencies +import org.tm.archive.jobs.UnableToStartException +import org.tm.archive.recipients.Recipient +import org.tm.archive.recipients.RecipientId +import org.tm.archive.service.SafeForegroundService +import org.tm.archive.util.TelephonyUtil +import org.tm.archive.webrtc.CallNotificationBuilder +import org.tm.archive.webrtc.UncaughtExceptionHandlerManager +import org.tm.archive.webrtc.audio.AudioManagerCommand +import org.tm.archive.webrtc.audio.SignalAudioManager +import org.tm.archive.webrtc.audio.SignalAudioManager.Companion.create +import org.tm.archive.webrtc.locks.LockManager +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes + +/** + * Entry point for [SignalCallManager] and friends to interact with the Android system as + * previously done via [WebRtcCallService]. + * + * This tries to limit the use of a foreground service until a call has been fully established + * and the user has likely foregrounded us by accepting a call. + */ +class ActiveCallManager( + private val application: Context +) : SignalAudioManager.EventListener { + + companion object { + private val TAG = Log.tag(ActiveCallManager::class.java) + } + + private val callManager = ApplicationDependencies.getSignalCallManager() + + private var networkReceiver: NetworkReceiver? = null + private var powerButtonReceiver: PowerButtonReceiver? = null + private var uncaughtExceptionHandlerManager: UncaughtExceptionHandlerManager? = null + private val webSocketKeepAliveTask: WebSocketKeepAliveTask = WebSocketKeepAliveTask() + private var signalAudioManager: SignalAudioManager? = null + private var previousNotificationId = -1 + + init { + registerUncaughtExceptionHandler() + registerNetworkReceiver() + + webSocketKeepAliveTask.start() + } + + fun stop() { + Log.v(TAG, "stop") + + uncaughtExceptionHandlerManager?.unregister() + uncaughtExceptionHandlerManager = null + + signalAudioManager?.shutdown() + signalAudioManager = null + + unregisterNetworkReceiver() + unregisterPowerButtonReceiver() + + webSocketKeepAliveTask.stop() + + if (!ActiveCallForegroundService.stop(application) && previousNotificationId != -1) { + NotificationManagerCompat.from(application).cancel(previousNotificationId) + } + } + + fun update(type: Int, recipientId: RecipientId, isVideoCall: Boolean) { + Log.i(TAG, "update $type $recipientId $isVideoCall") + + val notificationId = CallNotificationBuilder.getNotificationId(type) + + if (previousNotificationId != notificationId && previousNotificationId != -1) { + NotificationManagerCompat.from(application).cancel(previousNotificationId) + } + + previousNotificationId = notificationId + + if (type != CallNotificationBuilder.TYPE_ESTABLISHED) { + val notification = CallNotificationBuilder.getCallInProgressNotification(application, type, Recipient.resolved(recipientId), isVideoCall, false) + NotificationManagerCompat.from(application).notify(notificationId, notification) + } else { + ActiveCallForegroundService.start(application, recipientId, isVideoCall) + } + } + + fun sendAudioCommand(audioCommand: AudioManagerCommand) { + if (signalAudioManager == null) { + signalAudioManager = create(application, this) + } + + Log.i(TAG, "Sending audio command [" + audioCommand.javaClass.simpleName + "] to " + signalAudioManager?.javaClass?.simpleName) + signalAudioManager!!.handleCommand(audioCommand) + } + + fun changePowerButton(enabled: Boolean) { + if (enabled) { + registerPowerButtonReceiver() + } else { + unregisterPowerButtonReceiver() + } + } + + private fun registerUncaughtExceptionHandler() { + uncaughtExceptionHandlerManager = UncaughtExceptionHandlerManager() + uncaughtExceptionHandlerManager!!.registerHandler(ProximityLockRelease(callManager.lockManager)) + } + + private fun registerNetworkReceiver() { + if (networkReceiver == null) { + networkReceiver = NetworkReceiver() + application.registerReceiver(networkReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)) + } + } + + private fun unregisterNetworkReceiver() { + if (networkReceiver != null) { + application.unregisterReceiver(networkReceiver) + networkReceiver = null + } + } + + private fun registerPowerButtonReceiver() { + if (!AndroidTelecomUtil.telecomSupported && powerButtonReceiver == null) { + powerButtonReceiver = PowerButtonReceiver() + application.registerReceiver(powerButtonReceiver, IntentFilter(Intent.ACTION_SCREEN_OFF)) + } + } + + private fun unregisterPowerButtonReceiver() { + if (powerButtonReceiver != null) { + application.unregisterReceiver(powerButtonReceiver) + powerButtonReceiver = null + } + } + + override fun onAudioDeviceChanged(activeDevice: SignalAudioManager.AudioDevice, devices: Set) { + callManager.onAudioDeviceChanged(activeDevice, devices) + } + + override fun onBluetoothPermissionDenied() { + callManager.onBluetoothPermissionDenied() + } + + /** Foreground service started only after a call is established */ + class ActiveCallForegroundService : SafeForegroundService() { + companion object { + private const val EXTRA_RECIPIENT_ID = "RECIPIENT_ID" + private const val EXTRA_IS_VIDEO_CALL = "IS_VIDEO_CALL" + + fun start(context: Context, recipientId: RecipientId, isVideoCall: Boolean) { + val extras = bundleOf( + EXTRA_RECIPIENT_ID to recipientId, + EXTRA_IS_VIDEO_CALL to isVideoCall + ) + + if (!SafeForegroundService.start(context, ActiveCallForegroundService::class.java, extras)) { + throw UnableToStartException(Exception()) + } + } + + fun stop(context: Context): Boolean { + return SafeForegroundService.stop(context, ActiveCallForegroundService::class.java) + } + } + + override val tag: String + get() = TAG + + override val notificationId: Int + get() = CallNotificationBuilder.WEBRTC_NOTIFICATION + + private var hangUpRtcOnDeviceCallAnswered: PhoneStateListener? = null + private var notification: Notification? = null + private var notificationDisposable: Disposable = Disposable.disposed() + + override fun onCreate() { + super.onCreate() + hangUpRtcOnDeviceCallAnswered = HangUpRtcOnPstnCallAnsweredListener() + + if (!AndroidTelecomUtil.telecomSupported) { + try { + TelephonyUtil.getManager(application).listen(hangUpRtcOnDeviceCallAnswered, PhoneStateListener.LISTEN_CALL_STATE) + } catch (e: SecurityException) { + Log.w(TAG, "Failed to listen to PSTN call answers!", e) + } + } + } + + override fun onDestroy() { + notificationDisposable.dispose() + + super.onDestroy() + + if (!AndroidTelecomUtil.telecomSupported) { + TelephonyUtil.getManager(application).listen(hangUpRtcOnDeviceCallAnswered, PhoneStateListener.LISTEN_NONE) + } + } + + override fun getForegroundNotification(intent: Intent): Notification { + if (notification != null) { + return notification!! + } else if (!intent.hasExtra(EXTRA_RECIPIENT_ID)) { + return CallNotificationBuilder.getStoppingNotification(this) + } + + val recipient: Recipient = Recipient.resolved(intent.getParcelableExtra(EXTRA_RECIPIENT_ID)!!) + val isVideoCall = intent.getBooleanExtra(EXTRA_IS_VIDEO_CALL, false) + val requiresAsyncNotificationLoad = Build.VERSION.SDK_INT <= 29 + + notification = createNotification(recipient, isVideoCall, skipAvatarLoad = requiresAsyncNotificationLoad) + + if (requiresAsyncNotificationLoad) { + notificationDisposable = Single.fromCallable { createNotification(recipient, isVideoCall, skipAvatarLoad = false) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy { + notification = it + if (NotificationManagerCompat.from(this).activeNotifications.any { n -> n.id == notificationId }) { + NotificationManagerCompat.from(application).notify(notificationId, notification!!) + } + } + } + + return notification!! + } + + private fun createNotification(recipient: Recipient, isVideoCall: Boolean, skipAvatarLoad: Boolean): Notification { + return CallNotificationBuilder.getCallInProgressNotification( + this, + CallNotificationBuilder.TYPE_ESTABLISHED, + recipient, + isVideoCall, + skipAvatarLoad + ) + } + + @Suppress("deprecation") + private class HangUpRtcOnPstnCallAnsweredListener : PhoneStateListener() { + override fun onCallStateChanged(state: Int, phoneNumber: String) { + super.onCallStateChanged(state, phoneNumber) + if (state == TelephonyManager.CALL_STATE_OFFHOOK) { + hangup() + Log.i(TAG, "Device phone call ended Signal call.") + } + } + + private fun hangup() { + ApplicationDependencies.getSignalCallManager().localHangup() + } + } + } + + class ActiveCallServiceReceiver : BroadcastReceiver() { + + companion object { + const val ACTION_DENY = "org.tm.archive.service.webrtc.ActiveCallAction.DENY" + const val ACTION_HANGUP = "org.tm.archive.service.webrtc.ActiveCallAction.HANGUP" + } + + override fun onReceive(context: Context?, intent: Intent?) { + Log.d(TAG, "action: ${intent?.action}") + when (intent?.action) { + ACTION_DENY -> ApplicationDependencies.getSignalCallManager().denyCall() + ACTION_HANGUP -> ApplicationDependencies.getSignalCallManager().localHangup() + } + } + } + + /** + * Periodically request the web socket stay open if we are doing anything call related. + */ + private class WebSocketKeepAliveTask : Runnable { + + companion object { + private val REQUEST_WEBSOCKET_STAY_OPEN_DELAY: Duration = 1.minutes + private val WEBSOCKET_KEEP_ALIVE_TOKEN: String = WebSocketKeepAliveTask::class.java.simpleName + } + + private var keepRunning = false + + @MainThread + fun start() { + if (!keepRunning) { + keepRunning = true + run() + } + } + + @MainThread + fun stop() { + keepRunning = false + ThreadUtil.cancelRunnableOnMain(this) + ApplicationDependencies.getIncomingMessageObserver().removeKeepAliveToken(WEBSOCKET_KEEP_ALIVE_TOKEN) + } + + @MainThread + override fun run() { + if (keepRunning) { + ApplicationDependencies.getIncomingMessageObserver().registerKeepAliveToken(WEBSOCKET_KEEP_ALIVE_TOKEN) + ThreadUtil.runOnMainDelayed(this, REQUEST_WEBSOCKET_STAY_OPEN_DELAY.inWholeMilliseconds) + } + } + } + + private class NetworkReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val activeNetworkInfo = connectivityManager.activeNetworkInfo + + ApplicationDependencies.getSignalCallManager().apply { + networkChange(activeNetworkInfo != null && activeNetworkInfo.isConnected) + dataModeUpdate() + } + } + } + + private class PowerButtonReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (Intent.ACTION_SCREEN_OFF == intent.action) { + ApplicationDependencies.getSignalCallManager().screenOff() + } + } + } + + private class ProximityLockRelease(private val lockManager: LockManager) : Thread.UncaughtExceptionHandler { + override fun uncaughtException(thread: Thread, throwable: Throwable) { + Log.i(TAG, "Uncaught exception - releasing proximity lock", throwable) + lockManager.updatePhoneState(LockManager.PhoneState.IDLE) + } + } +} diff --git a/app/src/main/java/org/tm/archive/service/webrtc/RingRtcDynamicConfiguration.kt b/app/src/main/java/org/tm/archive/service/webrtc/RingRtcDynamicConfiguration.kt index 82d35685..b7dd6cc6 100644 --- a/app/src/main/java/org/tm/archive/service/webrtc/RingRtcDynamicConfiguration.kt +++ b/app/src/main/java/org/tm/archive/service/webrtc/RingRtcDynamicConfiguration.kt @@ -11,21 +11,19 @@ import org.tm.archive.util.FeatureFlags */ object RingRtcDynamicConfiguration { + private val KNOWN_ISSUE_ROMS = "(lineage|calyxos)".toRegex(RegexOption.IGNORE_CASE) + @JvmStatic fun getAudioProcessingMethod(): AudioProcessingMethod { if (SignalStore.internalValues().callingAudioProcessingMethod() != AudioProcessingMethod.Default) { return SignalStore.internalValues().callingAudioProcessingMethod() } - val useAec3: Boolean = FeatureFlags.useAec3() - return when { - isHardwareBlocklisted() && useAec3 -> AudioProcessingMethod.ForceSoftwareAec3 - isHardwareBlocklisted() -> AudioProcessingMethod.ForceSoftwareAecM + isHardwareBlocklisted() || isKnownFaultyHardwareImplementation() -> AudioProcessingMethod.ForceSoftwareAec3 isSoftwareBlocklisted() -> AudioProcessingMethod.ForceHardware Build.VERSION.SDK_INT < 29 && FeatureFlags.useHardwareAecIfOlderThanApi29() -> AudioProcessingMethod.ForceHardware - Build.VERSION.SDK_INT < 29 && useAec3 -> AudioProcessingMethod.ForceSoftwareAec3 - Build.VERSION.SDK_INT < 29 -> AudioProcessingMethod.ForceSoftwareAecM + Build.VERSION.SDK_INT < 29 -> AudioProcessingMethod.ForceSoftwareAec3 else -> AudioProcessingMethod.ForceHardware } } @@ -39,6 +37,12 @@ object RingRtcDynamicConfiguration { return FeatureFlags.hardwareAecBlocklistModels().asListContains(Build.MODEL) } + fun isKnownFaultyHardwareImplementation(): Boolean { + return Build.PRODUCT.contains(KNOWN_ISSUE_ROMS) || + Build.DISPLAY.contains(KNOWN_ISSUE_ROMS) || + Build.HOST.contains(KNOWN_ISSUE_ROMS) + } + private fun isSoftwareBlocklisted(): Boolean { return FeatureFlags.softwareAecBlocklistModels().asListContains(Build.MODEL) } diff --git a/app/src/main/java/org/tm/archive/service/webrtc/SignalCallManager.java b/app/src/main/java/org/tm/archive/service/webrtc/SignalCallManager.java index 9bc57717..2f30a539 100644 --- a/app/src/main/java/org/tm/archive/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/tm/archive/service/webrtc/SignalCallManager.java @@ -3,6 +3,7 @@ package org.tm.archive.service.webrtc; import android.app.Application; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Build; import android.os.ResultReceiver; @@ -11,8 +12,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.annimon.stream.Stream; +import com.tm.androidcopysdk.CommonUtils; -import org.archiver.annotation.TeleMessageUnfinalize; import org.greenrobot.eventbus.EventBus; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; @@ -118,10 +119,7 @@ import static org.tm.archive.service.webrtc.WebRtcUtil.getUrgencyFromCallUrgency * Entry point for all things calling. Lives for the life of the app instance and will spin up a foreground service when needed to * handle "active" calls. */ - -//*TM_SA*/ -@TeleMessageUnfinalize -public class SignalCallManager implements CallManager.Observer, GroupCall.Observer, CameraEventListener, AppForegroundObserver.Listener { +public class SignalCallManager implements CallManager.Observer, GroupCall.Observer, CameraEventListener, AppForegroundObserver.Listener {//**TM_SA**/ delete final private static final String TAG = Log.tag(SignalCallManager.class); @@ -129,14 +127,14 @@ public class SignalCallManager implements CallManager.Observer, GroupCall.Observ @Nullable private final CallManager callManager; - private final Context context; - private final ExecutorService serviceExecutor; - private final Executor networkExecutor; - private final LockManager lockManager; + private final Context context; + private final ExecutorService serviceExecutor; + private final Executor networkExecutor; + private final LockManager lockManager; private WebRtcServiceState serviceState; private RxStore ephemeralStateStore; - private boolean needsToSetSelfUuid = true; + private boolean needsToSetSelfUuid = true; private RxStore> linkPeekInfoStore; @@ -186,14 +184,19 @@ public class SignalCallManager implements CallManager.Observer, GroupCall.Observ } private void process(@NonNull ProcessAction action) { - Throwable t = new Throwable(); - String caller = t.getStackTrace().length > 1 ? t.getStackTrace()[1].getMethodName() : "unknown"; + Throwable t = new Throwable(); + String caller = t.getStackTrace().length > 1 ? t.getStackTrace()[1].getMethodName() : "unknown"; if (callManager == null) { Log.w(TAG, "Unable to process action, call manager is not initialized"); return; } + if (!CommonUtils.isActivatedUser(context)) {//**TM_SA**//Start + Log.d(TAG, "stop notifications for messages when suspend"); + return; + }//**TM_SA**//End + serviceExecutor.execute(() -> { if (needsToSetSelfUuid) { try { @@ -542,6 +545,11 @@ public class SignalCallManager implements CallManager.Observer, GroupCall.Observ return; } + if (!CommonUtils.isActivatedUser(context)) {//**TM_SA**//Start + Log.d(TAG, "stop notifications for messages when suspend"); + return; + }//**TM_SA**//End + process((s, p) -> { RemotePeer remotePeer = (RemotePeer) remote; if (s.getCallInfoState().getPeer(remotePeer.hashCode()) == null) { @@ -1155,6 +1163,10 @@ public class SignalCallManager implements CallManager.Observer, GroupCall.Observ return new SignalCallLinkManager(Objects.requireNonNull(callManager)); } + public void relaunchPipOnForeground() { + ApplicationDependencies.getAppForegroundObserver().addListener(new RelaunchListener(ApplicationDependencies.getAppForegroundObserver().isForegrounded())); + } + private void processSendMessageFailureWithChangeDetection(@NonNull RemotePeer remotePeer, @NonNull ProcessAction failureProcessAction) { @@ -1173,6 +1185,44 @@ public class SignalCallManager implements CallManager.Observer, GroupCall.Observ }); } + private class RelaunchListener implements AppForegroundObserver.Listener { + private boolean canRelaunch; + + public RelaunchListener(boolean isForegrounded) { + canRelaunch = !isForegrounded; + } + + @Override + public void onForeground() { + if (canRelaunch) { + if (isSystemPipEnabledAndAvailable()) { + process((s, p) -> { + WebRtcViewModel.State callState = s.getCallInfoState().getCallState(); + + if (callState.getInOngoingCall()) { + Intent intent = new Intent(context, WebRtcCallActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(WebRtcCallActivity.EXTRA_LAUNCH_IN_PIP, true); + context.startActivity(intent); + } + + return s; + }); + } + ApplicationDependencies.getAppForegroundObserver().removeListener(this); + } + } + + @Override + public void onBackground() { + canRelaunch = true; + } + + private boolean isSystemPipEnabledAndAvailable() { + return Build.VERSION.SDK_INT >= 26 && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); + } + } + interface ProcessAction { @NonNull WebRtcServiceState process(@NonNull WebRtcServiceState currentState, @NonNull WebRtcActionProcessor processor); } diff --git a/app/src/main/java/org/tm/archive/service/webrtc/WebRtcCallService.java b/app/src/main/java/org/tm/archive/service/webrtc/WebRtcCallService.java index 6d93712b..4752f0be 100644 --- a/app/src/main/java/org/tm/archive/service/webrtc/WebRtcCallService.java +++ b/app/src/main/java/org/tm/archive/service/webrtc/WebRtcCallService.java @@ -1,6 +1,7 @@ package org.tm.archive.service.webrtc; import android.app.Notification; +import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; @@ -18,6 +19,7 @@ import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.signal.core.util.PendingIntentFlags; import org.signal.core.util.ThreadUtil; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; @@ -25,6 +27,7 @@ import org.tm.archive.dependencies.ApplicationDependencies; import org.tm.archive.jobs.ForegroundServiceUtil; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientId; +import org.tm.archive.util.FeatureFlags; import org.tm.archive.util.TelephonyUtil; import org.tm.archive.webrtc.CallNotificationBuilder; import org.tm.archive.webrtc.UncaughtExceptionHandlerManager; @@ -84,7 +87,18 @@ public final class WebRtcCallService extends Service implements SignalAudioManag private Disposable lastNotificationDisposable = Disposable.disposed(); private boolean stopping = false; - public static void update(@NonNull Context context, int type, @NonNull RecipientId recipientId, boolean isVideoCall) { + private static ActiveCallManager activeCallManager = null; + + public synchronized static void update(@NonNull Context context, int type, @NonNull RecipientId recipientId, boolean isVideoCall) { + if (FeatureFlags.useActiveCallManager()) { + if (activeCallManager == null) { + activeCallManager = new ActiveCallManager(context); + } + activeCallManager.update(type, recipientId, isVideoCall); + + return; + } + Intent intent = new Intent(context, WebRtcCallService.class); intent.setAction(ACTION_UPDATE) .putExtra(EXTRA_UPDATE_TYPE, type) @@ -95,36 +109,84 @@ public final class WebRtcCallService extends Service implements SignalAudioManag } public static void denyCall(@NonNull Context context) { - ForegroundServiceUtil.tryToStartWhenCapable(context, denyCallIntent(context), FOREGROUND_SERVICE_TIMEOUT); + if (FeatureFlags.useActiveCallManager()) { + ApplicationDependencies.getSignalCallManager().denyCall(); + return; + } + + ForegroundServiceUtil.tryToStartWhenCapable(context, new Intent(context, WebRtcCallService.class).setAction(ACTION_DENY_CALL), FOREGROUND_SERVICE_TIMEOUT); } public static void hangup(@NonNull Context context) { - ForegroundServiceUtil.tryToStartWhenCapable(context, hangupIntent(context), FOREGROUND_SERVICE_TIMEOUT); + if (FeatureFlags.useActiveCallManager()) { + ApplicationDependencies.getSignalCallManager().localHangup(); + return; + } + + ForegroundServiceUtil.tryToStartWhenCapable(context, new Intent(context, WebRtcCallService.class).setAction(ACTION_LOCAL_HANGUP), FOREGROUND_SERVICE_TIMEOUT); } - public static void stop(@NonNull Context context) { + public synchronized static void stop(@NonNull Context context) { + if (FeatureFlags.useActiveCallManager()) { + if (activeCallManager != null) { + activeCallManager.stop(); + activeCallManager = null; + } + return; + } + Intent intent = new Intent(context, WebRtcCallService.class); intent.setAction(ACTION_STOP); ForegroundServiceUtil.tryToStartWhenCapable(context, intent, FOREGROUND_SERVICE_TIMEOUT); } - public static @NonNull Intent denyCallIntent(@NonNull Context context) { - return new Intent(context, WebRtcCallService.class).setAction(ACTION_DENY_CALL); + public synchronized static @NonNull PendingIntent denyCallIntent(@NonNull Context context) { + if (FeatureFlags.useActiveCallManager()) { + Intent intent = new Intent(context, ActiveCallManager.ActiveCallServiceReceiver.class); + intent.setAction(ActiveCallManager.ActiveCallServiceReceiver.ACTION_DENY); + return PendingIntent.getBroadcast(context, 0, intent, PendingIntentFlags.mutable()); + } + + return getServicePendingIntent(context, new Intent(context, WebRtcCallService.class).setAction(ACTION_DENY_CALL)); } - public static @NonNull Intent hangupIntent(@NonNull Context context) { - return new Intent(context, WebRtcCallService.class).setAction(ACTION_LOCAL_HANGUP); + public synchronized static @NonNull PendingIntent hangupIntent(@NonNull Context context) { + if (FeatureFlags.useActiveCallManager()) { + Intent intent = new Intent(context, ActiveCallManager.ActiveCallServiceReceiver.class); + intent.setAction(ActiveCallManager.ActiveCallServiceReceiver.ACTION_HANGUP); + return PendingIntent.getBroadcast(context, 0, intent, PendingIntentFlags.mutable()); + } + + return getServicePendingIntent(context, new Intent(context, WebRtcCallService.class).setAction(ACTION_LOCAL_HANGUP)); } - public static void sendAudioManagerCommand(@NonNull Context context, @NonNull AudioManagerCommand command) { + public synchronized static void sendAudioManagerCommand(@NonNull Context context, @NonNull AudioManagerCommand command) { + if (FeatureFlags.useActiveCallManager()) { + if (activeCallManager == null) { + activeCallManager = new ActiveCallManager(context); + } + activeCallManager.sendAudioCommand(command); + + return; + } + Intent intent = new Intent(context, WebRtcCallService.class); intent.setAction(ACTION_SEND_AUDIO_COMMAND) .putExtra(EXTRA_AUDIO_COMMAND, command); ForegroundServiceUtil.tryToStartWhenCapable(context, intent, FOREGROUND_SERVICE_TIMEOUT); } - public static void changePowerButtonReceiver(@NonNull Context context, boolean register) { + public synchronized static void changePowerButtonReceiver(@NonNull Context context, boolean register) { + if (FeatureFlags.useActiveCallManager()) { + if (activeCallManager == null) { + activeCallManager = new ActiveCallManager(context); + } + activeCallManager.changePowerButton(register); + + return; + } + Intent intent = new Intent(context, WebRtcCallService.class); intent.setAction(ACTION_CHANGE_POWER_BUTTON) .putExtra(EXTRA_ENABLED, register); @@ -178,7 +240,7 @@ public final class WebRtcCallService extends Service implements SignalAudioManag @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent == null || intent.getAction() == null) { - setCallNotification(true); + Log.w(TAG, "Service running with null intent/action likely from system restart, stopping"); stop(); return START_NOT_STICKY; } @@ -234,9 +296,11 @@ public final class WebRtcCallService extends Service implements SignalAudioManag if (!stopping && lastNotificationId != INVALID_NOTIFICATION_ID) { startForegroundCompat(lastNotificationId, lastNotification); } else { - Log.w(TAG, "Service running without having called start first, show temp notification and terminate service."); - startForegroundCompat(CallNotificationBuilder.getStartingStoppingNotificationId(), CallNotificationBuilder.getStoppingNotification(this)); - stop(); + if (!stopping) { + Log.i(TAG, "Service was started without calling UPDATE first, using temporary notification."); + } + startForegroundCompat(CallNotificationBuilder.getStartingStoppingNotificationId(), stopping ? CallNotificationBuilder.getStoppingNotification(this) + : CallNotificationBuilder.getStartingNotification(this)); } } @@ -335,6 +399,11 @@ public final class WebRtcCallService extends Service implements SignalAudioManag callManager.onBluetoothPermissionDenied(); } + public static PendingIntent getServicePendingIntent(@NonNull Context context, @NonNull Intent intent) { + return Build.VERSION.SDK_INT >= 26 ? PendingIntent.getForegroundService(context, 0, intent, PendingIntentFlags.mutable()) + : PendingIntent.getService(context, 0, intent, PendingIntentFlags.mutable()); + } + @SuppressWarnings("deprecation") private class HangUpRtcOnPstnCallAnsweredListener extends PhoneStateListener { @Override diff --git a/app/src/main/java/org/tm/archive/service/webrtc/links/SignalCallLinkManager.kt b/app/src/main/java/org/tm/archive/service/webrtc/links/SignalCallLinkManager.kt index 85ba4d08..bdae90aa 100644 --- a/app/src/main/java/org/tm/archive/service/webrtc/links/SignalCallLinkManager.kt +++ b/app/src/main/java/org/tm/archive/service/webrtc/links/SignalCallLinkManager.kt @@ -171,7 +171,7 @@ class SignalCallLinkManager( name ) { result -> if (result.isSuccess) { - emitter.onSuccess(UpdateCallLinkResult.Success(result.value!!.toAppState())) + emitter.onSuccess(UpdateCallLinkResult.Update(result.value!!.toAppState())) } else { emitter.onSuccess(UpdateCallLinkResult.Failure(result.status)) } @@ -198,7 +198,7 @@ class SignalCallLinkManager( restrictions ) { result -> if (result.isSuccess) { - emitter.onSuccess(UpdateCallLinkResult.Success(result.value!!.toAppState())) + emitter.onSuccess(UpdateCallLinkResult.Update(result.value!!.toAppState())) } else { emitter.onSuccess(UpdateCallLinkResult.Failure(result.status)) } @@ -206,9 +206,8 @@ class SignalCallLinkManager( } } - fun updateCallLinkRevoked( - credentials: CallLinkCredentials, - revoked: Boolean + fun deleteCallLink( + credentials: CallLinkCredentials ): Single { if (credentials.adminPassBytes == null) { return Single.just(UpdateCallLinkResult.NotAuthorized) @@ -217,15 +216,14 @@ class SignalCallLinkManager( return Single.create { emitter -> val credentialPresentation = requestCallLinkAuthCredentialPresentation(credentials.linkKeyBytes) - callManager.updateCallLinkRevoked( + callManager.deleteCallLink( SignalStore.internalValues().groupCallingServer(), credentialPresentation.serialize(), CallLinkRootKey(credentials.linkKeyBytes), - credentials.adminPassBytes, - revoked + credentials.adminPassBytes ) { result -> - if (result.isSuccess) { - emitter.onSuccess(UpdateCallLinkResult.Success(result.value!!.toAppState())) + if (result.isSuccess && result.value == true) { + emitter.onSuccess(UpdateCallLinkResult.Delete(credentials.roomId)) } else { emitter.onSuccess(UpdateCallLinkResult.Failure(result.status)) } diff --git a/app/src/main/java/org/tm/archive/service/webrtc/links/UpdateCallLinkResult.kt b/app/src/main/java/org/tm/archive/service/webrtc/links/UpdateCallLinkResult.kt index 1ac52ba0..9dc21cff 100644 --- a/app/src/main/java/org/tm/archive/service/webrtc/links/UpdateCallLinkResult.kt +++ b/app/src/main/java/org/tm/archive/service/webrtc/links/UpdateCallLinkResult.kt @@ -9,10 +9,14 @@ package org.tm.archive.service.webrtc.links * Result type for call link updates. */ sealed interface UpdateCallLinkResult { - data class Success( + data class Update( val state: SignalCallLinkState ) : UpdateCallLinkResult + data class Delete( + val roomId: CallLinkRoomId + ) : UpdateCallLinkResult + data class Failure( val status: Short ) : UpdateCallLinkResult diff --git a/app/src/main/java/org/tm/archive/shakereport/ShakeToReport.java b/app/src/main/java/org/tm/archive/shakereport/ShakeToReport.java index 27982f16..f20cb9b9 100644 --- a/app/src/main/java/org/tm/archive/shakereport/ShakeToReport.java +++ b/app/src/main/java/org/tm/archive/shakereport/ShakeToReport.java @@ -129,7 +129,6 @@ public final class ShakeToReport implements ShakeDetector.Listener { MultiselectForwardFragment.showFullScreen( activity.getSupportFragmentManager(), new MultiselectForwardFragmentArgs( - true, Collections.singletonList(new MultiShareArgs.Builder() .withDraftText(url) .build()), diff --git a/app/src/main/java/org/tm/archive/sharing/MultiShareSender.java b/app/src/main/java/org/tm/archive/sharing/MultiShareSender.java index 80a5570f..3a693f8a 100644 --- a/app/src/main/java/org/tm/archive/sharing/MultiShareSender.java +++ b/app/src/main/java/org/tm/archive/sharing/MultiShareSender.java @@ -85,7 +85,6 @@ public final class MultiShareSender { public static MultiShareSendResultCollection sendSync(@NonNull MultiShareArgs multiShareArgs) { List results = new ArrayList<>(multiShareArgs.getContactSearchKeys().size()); Context context = ApplicationDependencies.getApplication(); - boolean isMmsEnabled = Util.isMmsCapable(context); String message = multiShareArgs.getDraftText(); SlideDeck slideDeck; List storiesBatch = new LinkedList<>(); @@ -111,8 +110,7 @@ public final class MultiShareSender { MessageSendType sendType = MessageSendType.SignalMessageSendType.INSTANCE; long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds()); List contacts = multiShareArgs.getSharedContacts(); - boolean needsSplit = !sendType.usesSmsTransport() && - message != null && + boolean needsSplit = message != null && message.length() > sendType.calculateCharacters(message).maxPrimaryMessageSize; boolean hasMmsMedia = !multiShareArgs.getMedia().isEmpty() || (multiShareArgs.getDataUri() != null && multiShareArgs.getDataUri() != Uri.EMPTY) || @@ -128,9 +126,9 @@ public final class MultiShareSender { MultiShareTimestampProvider sentTimestamp = recipient.isDistributionList() ? distributionListSentTimestamps : MultiShareTimestampProvider.create(); boolean canSendAsTextStory = recipientSearchKey.isStory() && multiShareArgs.isValidForTextStoryGeneration(); - if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !isMmsEnabled) { + if ((recipient.isMmsGroup() || recipient.getEmail().isPresent())) { results.add(new MultiShareSendResult(recipientSearchKey, MultiShareSendResult.Type.MMS_NOT_ENABLED)); - } else if (hasMmsMedia && sendType.usesSmsTransport() || hasPushMedia && !sendType.usesSmsTransport() || canSendAsTextStory) { + } else if (hasPushMedia || canSendAsTextStory) { sendMediaMessageOrCollectStoryToBatch(context, multiShareArgs, recipient, @@ -345,7 +343,8 @@ public final class MultiShareSender { private static Slide ensureDefaultQuality(@NonNull Context context, @NonNull ImageSlide imageSlide) { Attachment attachment = imageSlide.asAttachment(); - if (attachment.transformProperties.sentMediaQuality == SentMediaQuality.HIGH.getCode()) { + final AttachmentTable.TransformProperties transformProperties = attachment.transformProperties; + if (transformProperties != null && transformProperties.sentMediaQuality == SentMediaQuality.HIGH.getCode()) { return new ImageSlide( context, attachment.getUri(), diff --git a/app/src/main/java/org/tm/archive/sharing/ShareSelectionMappingModel.java b/app/src/main/java/org/tm/archive/sharing/ShareSelectionMappingModel.java index dfb699c1..fa2f45e8 100644 --- a/app/src/main/java/org/tm/archive/sharing/ShareSelectionMappingModel.java +++ b/app/src/main/java/org/tm/archive/sharing/ShareSelectionMappingModel.java @@ -22,7 +22,7 @@ public class ShareSelectionMappingModel implements MappingModel recipient.isSelf() ? context.getString(R.string.note_to_self) - : recipient.getShortDisplayNameIncludingUsername(context)) + : recipient.getShortDisplayName(context)) .orElseGet(shareContact::getNumber); return isFirst ? name : context.getString(R.string.ShareActivity__comma_s, name); diff --git a/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialActivity.java b/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialActivity.java index dad6d207..9e62f12c 100644 --- a/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialActivity.java +++ b/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialActivity.java @@ -11,6 +11,7 @@ import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; import com.annimon.stream.Stream; +import com.bumptech.glide.Glide; import org.tm.archive.PassphraseRequiredActivity; import org.tm.archive.R; @@ -18,7 +19,6 @@ import org.tm.archive.components.LinkPreviewView; import org.tm.archive.components.SelectionAwareEmojiEditText; import org.tm.archive.linkpreview.LinkPreviewRepository; import org.tm.archive.linkpreview.LinkPreviewViewModel; -import org.tm.archive.mms.GlideApp; import org.tm.archive.recipients.Recipient; import org.tm.archive.sharing.MultiShareArgs; import org.tm.archive.sharing.MultiShareDialogs; @@ -156,7 +156,7 @@ public class ShareInterstitialActivity extends PassphraseRequiredActivity { preview.setLoading(); viewModel.onLinkPreviewChanged(null); } else if (linkPreviewState.linkPreview.isPresent()) { - preview.setLinkPreview(GlideApp.with(this), linkPreviewState.linkPreview.get(), true); + preview.setLinkPreview(Glide.with(this), linkPreviewState.linkPreview.get(), true); viewModel.onLinkPreviewChanged(linkPreviewState.linkPreview.get()); } else if (!linkPreviewState.hasLinks()) { preview.setVisibility(View.GONE); diff --git a/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialMappingModel.java b/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialMappingModel.java index 0e80debc..817a19d4 100644 --- a/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialMappingModel.java +++ b/app/src/main/java/org/tm/archive/sharing/interstitial/ShareInterstitialMappingModel.java @@ -21,7 +21,7 @@ class ShareInterstitialMappingModel extends RecipientMappingModel, - override val isMmsOrSmsSupported: Boolean + val media: List ) : ResolvedShareData() { override fun toMultiShareArgs(): MultiShareArgs { return MultiShareArgs.Builder(setOf()).withMedia(media).build() @@ -39,7 +33,6 @@ sealed class ResolvedShareData { } object Failure : ResolvedShareData() { - override val isMmsOrSmsSupported: Boolean get() = throw UnsupportedOperationException() override fun toMultiShareArgs(): MultiShareArgs = throw UnsupportedOperationException() } } diff --git a/app/src/main/java/org/tm/archive/sharing/v2/ShareActivity.kt b/app/src/main/java/org/tm/archive/sharing/v2/ShareActivity.kt index 210e1855..94a77f7b 100644 --- a/app/src/main/java/org/tm/archive/sharing/v2/ShareActivity.kt +++ b/app/src/main/java/org/tm/archive/sharing/v2/ShareActivity.kt @@ -232,7 +232,6 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C R.id.fragment_container, MultiselectForwardFragment.create( MultiselectForwardFragmentArgs( - canSendToNonPush = resolvedShareData.isMmsOrSmsSupported, multiShareArgs = listOf(resolvedShareData.toMultiShareArgs()), title = getTitleFromExtras(), forceDisableAddMessage = true, diff --git a/app/src/main/java/org/tm/archive/sharing/v2/ShareRepository.kt b/app/src/main/java/org/tm/archive/sharing/v2/ShareRepository.kt index 737d938c..0f7338cf 100644 --- a/app/src/main/java/org/tm/archive/sharing/v2/ShareRepository.kt +++ b/app/src/main/java/org/tm/archive/sharing/v2/ShareRepository.kt @@ -1,28 +1,19 @@ package org.tm.archive.sharing.v2 -import android.Manifest import android.content.Context -import android.content.pm.PackageManager import android.net.Uri import android.provider.OpenableColumns import androidx.annotation.NonNull import androidx.annotation.WorkerThread -import androidx.core.content.ContextCompat import androidx.core.util.toKotlinPair import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log -import org.tm.archive.attachments.Attachment -import org.tm.archive.attachments.UriAttachment -import org.tm.archive.conversation.MessageSendType -import org.tm.archive.keyvalue.SignalStore import org.tm.archive.mediasend.Media -import org.tm.archive.mms.MediaConstraints import org.tm.archive.providers.BlobProvider import org.tm.archive.util.FeatureFlags import org.tm.archive.util.MediaUtil import org.tm.archive.util.UriUtil -import org.tm.archive.util.Util import java.io.IOException import java.io.InputStream import java.util.Optional @@ -73,8 +64,7 @@ class ShareRepository(context: Context) { return ResolvedShareData.ExternalUri( uri = blobUri, mimeType = mimeType, - text = multiShareExternal.text, - isMmsOrSmsSupported = isMmsSupported(appContext, asUriAttachment(blobUri, mimeType, size)) + text = multiShareExternal.text ) } @@ -131,9 +121,7 @@ class ShareRepository(context: Context) { }.filterNotNull() return if (media.isNotEmpty()) { - val isMmsSupported = media.all { isMmsSupported(appContext, asUriAttachment(it.uri, it.mimeType, it.size)) } - - ResolvedShareData.Media(media, isMmsSupported) + ResolvedShareData.Media(media) } else { ResolvedShareData.Failure } @@ -179,21 +167,5 @@ class ShareRepository(context: Context) { } return null } - - private fun asUriAttachment(uri: Uri, mimeType: String, size: Long): UriAttachment { - return UriAttachment(uri, mimeType, -1, size, null, false, false, false, false, null, null, null, null, null) - } - - private fun isMmsSupported(context: Context, attachment: Attachment): Boolean { - val canReadPhoneState = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED - - if (!Util.isDefaultSmsProvider(context) || !canReadPhoneState || !Util.isMmsCapable(context) || !SignalStore.misc().smsExportPhase.allowSmsFeatures()) { - return false - } - - val sendType: MessageSendType = MessageSendType.getFirstForTransport(MessageSendType.TransportType.SMS) - val mmsConstraints = MediaConstraints.getMmsMediaConstraints(sendType.simSubscriptionId ?: -1) - return mmsConstraints.isSatisfied(context, attachment) || mmsConstraints.canResize(attachment) - } } } diff --git a/app/src/main/java/org/tm/archive/sms/MessageSender.java b/app/src/main/java/org/tm/archive/sms/MessageSender.java index 254bb890..93769b64 100644 --- a/app/src/main/java/org/tm/archive/sms/MessageSender.java +++ b/app/src/main/java/org/tm/archive/sms/MessageSender.java @@ -52,14 +52,12 @@ import org.tm.archive.jobs.AttachmentCompressionJob; import org.tm.archive.jobs.AttachmentCopyJob; import org.tm.archive.jobs.AttachmentMarkUploadedJob; import org.tm.archive.jobs.AttachmentUploadJob; -import org.tm.archive.jobs.MmsSendJob; import org.tm.archive.jobs.ProfileKeySendJob; import org.tm.archive.jobs.PushDistributionListSendJob; import org.tm.archive.jobs.PushGroupSendJob; import org.tm.archive.jobs.IndividualSendJob; import org.tm.archive.jobs.ReactionSendJob; import org.tm.archive.jobs.RemoteDeleteSendJob; -import org.tm.archive.jobs.SmsSendJob; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.linkpreview.LinkPreview; import org.tm.archive.mediasend.Media; @@ -232,10 +230,14 @@ public class MessageSender { Recipient recipient = message.getThreadRecipient(); long messageId = database.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), allocatedThreadId, sendType != SendType.SIGNAL, insertListener); - if (message.getThreadRecipient().isGroup() && message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) { - SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId); + if (message.getThreadRecipient().isGroup()) { + if (message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) { + SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId); + } else { + SignalLocalMetrics.GroupMessageSend.cancel(messageId); + } } else { - SignalLocalMetrics.GroupMessageSend.cancel(metricId); + SignalLocalMetrics.IndividualMessageSend.onInsertedIntoDatabase(messageId, metricId); } sendMessageInternal(context, recipient, sendType, messageId, Collections.emptyList(), message.getScheduledDate() > 0); @@ -532,10 +534,8 @@ public class MessageSender { sendDistributionList(context, recipient, messageId, Collections.emptySet(), uploadJobIds); } else if (sendType == SendType.SIGNAL && isPushMediaSend(context, recipient)) { sendMediaPush(context, recipient, messageId, uploadJobIds); - } else if (sendType == SendType.MMS) { - sendMms(context, messageId); } else { - sendSms(recipient, messageId); + Log.w(TAG, "Unknown send type!"); } } @@ -572,16 +572,6 @@ public class MessageSender { } } - private static void sendMms(Context context, long messageId) { - JobManager jobManager = ApplicationDependencies.getJobManager(); - MmsSendJob.enqueue(context, jobManager, messageId); - } - - private static void sendSms(Recipient recipient, long messageId) { - JobManager jobManager = ApplicationDependencies.getJobManager(); - jobManager.add(new SmsSendJob(messageId, recipient)); - } - private static boolean isPushMediaSend(Context context, Recipient recipient) { if (!SignalStore.account().isRegistered()) { return false; diff --git a/app/src/main/java/org/tm/archive/stickers/StickerManagementActivity.java b/app/src/main/java/org/tm/archive/stickers/StickerManagementActivity.java index fd79e489..fd9fae7f 100644 --- a/app/src/main/java/org/tm/archive/stickers/StickerManagementActivity.java +++ b/app/src/main/java/org/tm/archive/stickers/StickerManagementActivity.java @@ -11,11 +11,12 @@ import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; + import org.tm.archive.PassphraseRequiredActivity; import org.tm.archive.R; import org.tm.archive.conversation.mutiselect.forward.MultiselectForwardFragment; import org.tm.archive.conversation.mutiselect.forward.MultiselectForwardFragmentArgs; -import org.tm.archive.mms.GlideApp; import org.tm.archive.sharing.MultiShareArgs; import org.tm.archive.util.DeviceProperties; import org.tm.archive.util.DynamicTheme; @@ -99,7 +100,6 @@ public final class StickerManagementActivity extends PassphraseRequiredActivity MultiselectForwardFragment.showBottomSheet( getSupportFragmentManager(), new MultiselectForwardFragmentArgs( - true, Collections.singletonList(new MultiShareArgs.Builder() .withDraftText(StickerUrl.createShareLink(packId, packKey)) .build()), @@ -110,7 +110,7 @@ public final class StickerManagementActivity extends PassphraseRequiredActivity private void initView() { this.list = findViewById(R.id.sticker_management_list); - this.adapter = new StickerManagementAdapter(GlideApp.with(this), this, DeviceProperties.shouldAllowApngStickerAnimation(this)); + this.adapter = new StickerManagementAdapter(Glide.with(this), this, DeviceProperties.shouldAllowApngStickerAnimation(this)); list.setLayoutManager(new LinearLayoutManager(this)); list.setAdapter(adapter); diff --git a/app/src/main/java/org/tm/archive/stickers/StickerManagementAdapter.java b/app/src/main/java/org/tm/archive/stickers/StickerManagementAdapter.java index 054dcada..2d20926a 100644 --- a/app/src/main/java/org/tm/archive/stickers/StickerManagementAdapter.java +++ b/app/src/main/java/org/tm/archive/stickers/StickerManagementAdapter.java @@ -17,6 +17,7 @@ import androidx.annotation.StringRes; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import org.tm.archive.R; @@ -24,7 +25,8 @@ import org.tm.archive.components.emoji.EmojiTextView; import org.tm.archive.database.model.StickerPackRecord; import org.tm.archive.glide.cache.ApngOptions; import org.tm.archive.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.tm.archive.mms.GlideRequests; +import org.tm.archive.util.DrawableUtil; +import org.tm.archive.util.ViewUtil; import org.tm.archive.util.adapter.SectionedRecyclerViewAdapter; import org.tm.archive.util.adapter.StableIdGenerator; @@ -38,7 +40,7 @@ final class StickerManagementAdapter extends SectionedRecyclerViewAdapter eventListener.onStickerPackShareClicked(stickerPack.getPackId(), stickerPack.getPackKey())); } else { - actionButtonImage.setImageResource(R.drawable.ic_arrow_down); + actionButtonImage.setImageResource(R.drawable.symbol_arrow_down_24); actionButton.setOnClickListener(v -> eventListener.onStickerPackInstallClicked(stickerPack.getPackId(), stickerPack.getPackKey())); shareButton.setVisibility(View.GONE); @@ -304,10 +306,10 @@ final class StickerManagementAdapter extends SectionedRecyclerViewAdapter { - private final GlideRequests glideRequests; + private final RequestManager requestManager; private final EventListener eventListener; private final List list; private final boolean allowApngAnimation; - public StickerPackPreviewAdapter(@NonNull GlideRequests glideRequests, @NonNull EventListener eventListener, boolean allowApngAnimation) { - this.glideRequests = glideRequests; + public StickerPackPreviewAdapter(@NonNull RequestManager requestManager, @NonNull EventListener eventListener, boolean allowApngAnimation) { + this.requestManager = requestManager; this.eventListener = eventListener; this.allowApngAnimation = allowApngAnimation; this.list = new ArrayList<>(); @@ -40,7 +40,7 @@ public final class StickerPackPreviewAdapter extends RecyclerView.Adapter(null); popup.setAnimationStyle(R.style.StickerPopupAnimation); diff --git a/app/src/main/java/org/tm/archive/stickers/StickerSearchRepository.java b/app/src/main/java/org/tm/archive/stickers/StickerSearchRepository.java index e469e66b..b4e70b9a 100644 --- a/app/src/main/java/org/tm/archive/stickers/StickerSearchRepository.java +++ b/app/src/main/java/org/tm/archive/stickers/StickerSearchRepository.java @@ -64,11 +64,6 @@ public final class StickerSearchRepository { return out; } - public @NonNull Single getStickerFeatureAvailability() { - return Single.fromCallable(this::getStickerFeatureAvailabilitySync) - .observeOn(Schedulers.io()); - } - public void getStickerFeatureAvailability(@NonNull Callback callback) { SignalExecutors.BOUNDED.execute(() -> { callback.onResult(getStickerFeatureAvailabilitySync()); diff --git a/app/src/main/java/org/tm/archive/storage/AccountRecordProcessor.java b/app/src/main/java/org/tm/archive/storage/AccountRecordProcessor.java index 28ebd891..c1aeca0c 100644 --- a/app/src/main/java/org/tm/archive/storage/AccountRecordProcessor.java +++ b/app/src/main/java/org/tm/archive/storage/AccountRecordProcessor.java @@ -116,7 +116,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor defaultReactions = remote.getDefaultReactions().size() > 0 ? remote.getDefaultReactions() : local.getDefaultReactions(); boolean displayBadgesOnProfile = remote.isDisplayBadgesOnProfile(); boolean subscriptionManuallyCancelled = remote.isSubscriptionManuallyCancelled(); @@ -125,10 +125,11 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor remoteRecords, @NonNull StorageKeyGenerator keyGenerator) throws IOException { List unregisteredAciOnly = new ArrayList<>(); - List pniE164Only = new ArrayList<>(); for (SignalContactRecord remoteRecord : remoteRecords) { if (isInvalid(remoteRecord)) { @@ -75,39 +72,15 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor 0 && remoteRecord.getAci().isPresent() && remoteRecord.getPni().isEmpty() && remoteRecord.getNumber().isEmpty()) { unregisteredAciOnly.add(remoteRecord); - } else if (remoteRecord.getAci().isEmpty()) { - pniE164Only.add(remoteRecord); } } - if (unregisteredAciOnly.isEmpty() || pniE164Only.isEmpty()) { - super.process(remoteRecords, keyGenerator); - return; - } - - Log.i(TAG, "We have some unregistered ACI-only contacts as well as some PNI-only contacts. Need to do an intersection to detect any possible required splits."); - - TreeSet localMatches = new TreeSet<>(this); - - for (SignalContactRecord aciOnly : unregisteredAciOnly) { - Optional localMatch = getMatching(aciOnly, keyGenerator); - - if (localMatch.isPresent()) { - localMatches.add(localMatch.get()); + if (unregisteredAciOnly.size() > 0) { + for (SignalContactRecord aciOnly : unregisteredAciOnly) { + SignalDatabase.recipients().splitForStorageSyncIfNecessary(aciOnly.getAci().get()); } } - for (SignalContactRecord pniOnly : pniE164Only) { - Optional localMatch = getMatching(pniOnly, keyGenerator); - - if (localMatch.isPresent() && localMatches.contains(localMatch.get())) { - Log.w(TAG, "Found a situation where we need to split our local record in two in order to match the remote state."); - - SignalDatabase.recipients().splitForStorageSync(localMatch.get().getId().getRaw()); - } - } - - super.process(remoteRecords, keyGenerator); } @@ -244,8 +217,12 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor