uris = new ArrayList<>();
+ for (File file : files) {
+ uris.add(FileBackend.getUriForFile(this, file));
+ }
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType(MIME_TYPE);
+ final Intent chooser =
+ Intent.createChooser(intent, getString(R.string.share_backup_files));
+ shareFilesIntent =
+ PendingIntent.getActivity(
+ this,
+ 190,
+ chooser,
+ s()
+ ? PendingIntent.FLAG_IMMUTABLE
+ | PendingIntent.FLAG_UPDATE_CURRENT
+ : PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ NotificationCompat.Builder mBuilder =
+ new NotificationCompat.Builder(getBaseContext(), "backup");
+ mBuilder.setContentTitle(getString(R.string.notification_backup_created_title))
+ .setContentText(getString(R.string.notification_backup_created_subtitle, path))
+ .setStyle(
+ new NotificationCompat.BigTextStyle()
+ .bigText(
+ getString(
+ R.string.notification_backup_created_subtitle,
+ FileBackend.getBackupDirectory(this)
+ .getAbsolutePath())))
+ .setAutoCancel(true)
+ .setContentIntent(openFolderIntent)
+ .setSmallIcon(R.drawable.ic_archive_white_24dp);
+
+ if (shareFilesIntent != null) {
+ mBuilder.addAction(
+ R.drawable.ic_share_white_24dp,
+ getString(R.string.share_backup_files),
+ shareFilesIntent);
+ }
+
+ notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private static class Progress {
+ private final NotificationCompat.Builder builder;
+ private final int max;
+ private final int count;
+
+ private Progress(NotificationCompat.Builder builder, int max, int count) {
+ this.builder = builder;
+ this.max = max;
+ this.count = count;
+ }
+
+ private Notification build(int percentage) {
+ builder.setProgress(max * 100, count * 100 + percentage, false);
+ return builder.build();
+ }
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/services/MemorizingTrustManager.java b/src/main/java/eu/siacs/conversations/services/MemorizingTrustManager.java
index d05fa4ac3..520348943 100644
--- a/src/main/java/eu/siacs/conversations/services/MemorizingTrustManager.java
+++ b/src/main/java/eu/siacs/conversations/services/MemorizingTrustManager.java
@@ -33,7 +33,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
-import android.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Base64;
@@ -44,21 +43,9 @@ import androidx.appcompat.app.AppCompatActivity;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.crypto.BundledTrustManager;
-import eu.siacs.conversations.crypto.CombiningTrustManager;
-import eu.siacs.conversations.crypto.TrustManagers;
-import eu.siacs.conversations.crypto.XmppDomainVerifier;
-import eu.siacs.conversations.entities.MTMDecision;
-import eu.siacs.conversations.http.HttpConnectionManager;
-import eu.siacs.conversations.persistance.FileBackend;
-import eu.siacs.conversations.ui.MemorizingActivity;
-
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -91,40 +78,39 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.XmppDomainVerifier;
+import eu.siacs.conversations.entities.MTMDecision;
+import eu.siacs.conversations.http.HttpConnectionManager;
+import eu.siacs.conversations.persistance.FileBackend;
+import eu.siacs.conversations.ui.MemorizingActivity;
+
/**
- * A X509 trust manager implementation which asks the user about invalid certificates and memorizes
- * their decision.
- *
- * The certificate validity is checked using the system default X509 TrustManager, creating a
- * query Dialog if the check fails.
- *
- *
WARNING: This only works if a dedicated thread is used for opening sockets!
+ * A X509 trust manager implementation which asks the user about invalid
+ * certificates and memorizes their decision.
+ *
+ * The certificate validity is checked using the system default X509
+ * TrustManager, creating a query Dialog if the check fails.
+ *
+ * WARNING: This only works if a dedicated thread is used for
+ * opening sockets!
*/
public class MemorizingTrustManager {
- private static final SimpleDateFormat DATE_FORMAT =
- new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
- static final String DECISION_INTENT = "de.duenndns.ssl.DECISION";
- public static final String DECISION_INTENT_ID = DECISION_INTENT + ".decisionId";
- public static final String DECISION_INTENT_CERT = DECISION_INTENT + ".cert";
- public static final String DECISION_TITLE_ID = DECISION_INTENT + ".titleId";
- static final String NO_TRUST_ANCHOR = "Trust anchor for certification path not found.";
- private static final Pattern PATTERN_IPV4 =
- Pattern.compile(
- "\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
- private static final Pattern PATTERN_IPV6_HEX4DECCOMPRESSED =
- Pattern.compile(
- "\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
- private static final Pattern PATTERN_IPV6_6HEX4DEC =
- Pattern.compile(
- "\\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
- private static final Pattern PATTERN_IPV6_HEXCOMPRESSED =
- Pattern.compile(
- "\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\\z");
- private static final Pattern PATTERN_IPV6 =
- Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");
- private static final Logger LOGGER = Logger.getLogger(MemorizingTrustManager.class.getName());
+ final static String DECISION_INTENT = "de.duenndns.ssl.DECISION";
+ public final static String DECISION_INTENT_ID = DECISION_INTENT + ".decisionId";
+ public final static String DECISION_INTENT_CERT = DECISION_INTENT + ".cert";
+ public final static String DECISION_TITLE_ID = DECISION_INTENT + ".titleId";
+ final static String NO_TRUST_ANCHOR = "Trust anchor for certification path not found.";
+ private static final Pattern PATTERN_IPV4 = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
+ private static final Pattern PATTERN_IPV6_HEX4DECCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
+ private static final Pattern PATTERN_IPV6_6HEX4DEC = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
+ private static final Pattern PATTERN_IPV6_HEXCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\\z");
+ private static final Pattern PATTERN_IPV6 = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");
+ private final static Logger LOGGER = Logger.getLogger(MemorizingTrustManager.class.getName());
static String KEYSTORE_DIR = "KeyStore";
static String KEYSTORE_FILE = "KeyStore.bks";
private static int decisionId = 0;
@@ -140,65 +126,54 @@ public class MemorizingTrustManager {
private String poshCacheDir;
/**
- * Creates an instance of the MemorizingTrustManager class that falls back to a custom
- * TrustManager.
+ * Creates an instance of the MemorizingTrustManager class that falls back to a custom TrustManager.
+ *
+ * You need to supply the application context. This has to be one of:
+ * - Application
+ * - Activity
+ * - Service
+ *
+ * The context is used for file management, to display the dialog /
+ * notification and for obtaining translated strings.
*
- *
You need to supply the application context. This has to be one of: - Application -
- * Activity - Service
- *
- *
The context is used for file management, to display the dialog / notification and for
- * obtaining translated strings.
- *
- * @param context Context for the application.
- * @param defaultTrustManager Delegate trust management to this TM. If null, the user must
- * accept every certificate.
+ * @param m Context for the application.
+ * @param defaultTrustManager Delegate trust management to this TM. If null, the user must accept every certificate.
*/
- public MemorizingTrustManager(
- final Context context, final X509TrustManager defaultTrustManager) {
- init(context);
+ public MemorizingTrustManager(Context m, X509TrustManager defaultTrustManager) {
+ init(m);
this.appTrustManager = getTrustManager(appKeyStore);
this.defaultTrustManager = defaultTrustManager;
}
/**
* Creates an instance of the MemorizingTrustManager class using the system X509TrustManager.
+ *
+ * You need to supply the application context. This has to be one of:
+ * - Application
+ * - Activity
+ * - Service
+ *
+ * The context is used for file management, to display the dialog /
+ * notification and for obtaining translated strings.
*
- *
You need to supply the application context. This has to be one of: - Application -
- * Activity - Service
- *
- *
The context is used for file management, to display the dialog / notification and for
- * obtaining translated strings.
- *
- * @param context Context for the application.
+ * @param m Context for the application.
*/
- public MemorizingTrustManager(final Context context) {
- init(context);
+ public MemorizingTrustManager(Context m) {
+ init(m);
this.appTrustManager = getTrustManager(appKeyStore);
- try {
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
- this.defaultTrustManager = TrustManagers.defaultWithBundledLetsEncrypt(context);
- } else {
- this.defaultTrustManager = TrustManagers.createDefaultTrustManager();
- }
- } catch (final NoSuchAlgorithmException
- | KeyStoreException
- | CertificateException
- | IOException e) {
- throw new RuntimeException(e);
- }
+ this.defaultTrustManager = getTrustManager(null);
}
private static boolean isIp(final String server) {
- return server != null
- && (PATTERN_IPV4.matcher(server).matches()
+ return server != null && (
+ PATTERN_IPV4.matcher(server).matches()
|| PATTERN_IPV6.matcher(server).matches()
|| PATTERN_IPV6_6HEX4DEC.matcher(server).matches()
|| PATTERN_IPV6_HEX4DECCOMPRESSED.matcher(server).matches()
|| PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches());
}
- private static String getBase64Hash(X509Certificate certificate, String digest)
- throws CertificateEncodingException {
+ private static String getBase64Hash(X509Certificate certificate, String digest) throws CertificateEncodingException {
MessageDigest md;
try {
md = MessageDigest.getInstance(digest);
@@ -213,7 +188,8 @@ public class MemorizingTrustManager {
StringBuffer si = new StringBuffer();
for (int i = 0; i < data.length; i++) {
si.append(String.format("%02x", data[i]));
- if (i < data.length - 1) si.append(":");
+ if (i < data.length - 1)
+ si.append(":");
}
return si.toString();
}
@@ -244,22 +220,20 @@ public class MemorizingTrustManager {
}
}
- void init(final Context context) {
- master = context;
- masterHandler = new Handler(context.getMainLooper());
- notificationManager =
- (NotificationManager) master.getSystemService(Context.NOTIFICATION_SERVICE);
+ void init(final Context m) {
+ master = m;
+ masterHandler = new Handler(m.getMainLooper());
+ notificationManager = (NotificationManager) master.getSystemService(Context.NOTIFICATION_SERVICE);
Application app;
- if (context instanceof Application) {
- app = (Application) context;
- } else if (context instanceof Service) {
- app = ((Service) context).getApplication();
- } else if (context instanceof AppCompatActivity) {
- app = ((AppCompatActivity) context).getApplication();
+ if (m instanceof Application) {
+ app = (Application) m;
+ } else if (m instanceof Service) {
+ app = ((Service) m).getApplication();
+ } else if (m instanceof AppCompatActivity) {
+ app = ((AppCompatActivity) m).getApplication();
} else
- throw new ClassCastException(
- "MemorizingTrustManager context must be either Activity or Service!");
+ throw new ClassCastException("MemorizingTrustManager context must be either Activity or Service!");
File dir = app.getDir(KEYSTORE_DIR, Context.MODE_PRIVATE);
keyStoreFile = new File(dir + File.separator + KEYSTORE_FILE);
@@ -286,9 +260,12 @@ public class MemorizingTrustManager {
/**
* Removes the given certificate from MTMs key store.
*
- *
WARNING: this does not immediately invalidate the certificate. It is well possible
- * that (a) data is transmitted over still existing connections or (b) new connections are
- * created using TLS renegotiation, without a new cert check.
+ *
+ * WARNING: this does not immediately invalidate the certificate. It is
+ * well possible that (a) data is transmitted over still existing connections or
+ * (b) new connections are created using TLS renegotiation, without a new cert
+ * check.
+ *
*
* @param alias the certificate's alias as returned by {@link #getCertificates()}.
* @throws KeyStoreException if the certificate could not be deleted.
@@ -298,21 +275,20 @@ public class MemorizingTrustManager {
keyStoreUpdated();
}
- private X509TrustManager getTrustManager(final KeyStore keyStore) {
- Preconditions.checkNotNull(keyStore);
+ X509TrustManager getTrustManager(KeyStore ks) {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
- tmf.init(keyStore);
+ tmf.init(ks);
for (TrustManager t : tmf.getTrustManagers()) {
if (t instanceof X509TrustManager) {
return (X509TrustManager) t;
}
}
- } catch (final Exception e) {
+ } catch (Exception e) {
// Here, we are covering up errors. It might be more useful
// however to throw them out of the constructor so the
// embedding app knows something went wrong.
- LOGGER.log(Level.SEVERE, "getTrustManager(" + keyStore + ")", e);
+ LOGGER.log(Level.SEVERE, "getTrustManager(" + ks + ")", e);
}
return null;
}
@@ -385,60 +361,45 @@ public class MemorizingTrustManager {
}
}
- private void checkCertTrusted(
- X509Certificate[] chain,
- String authType,
- String domain,
- boolean isServer,
- boolean interactive)
+
+ private void checkCertTrusted(X509Certificate[] chain, String authType, String domain, boolean isServer, boolean interactive)
throws CertificateException {
- LOGGER.log(
- Level.FINE, "checkCertTrusted(" + chain + ", " + authType + ", " + isServer + ")");
+ LOGGER.log(Level.FINE, "checkCertTrusted(" + chain + ", " + authType + ", " + isServer + ")");
try {
LOGGER.log(Level.FINE, "checkCertTrusted: trying appTrustManager");
- if (isServer) appTrustManager.checkServerTrusted(chain, authType);
- else appTrustManager.checkClientTrusted(chain, authType);
+ if (isServer)
+ appTrustManager.checkServerTrusted(chain, authType);
+ else
+ appTrustManager.checkClientTrusted(chain, authType);
} catch (final CertificateException ae) {
LOGGER.log(Level.FINER, "checkCertTrusted: appTrustManager failed", ae);
if (isCertKnown(chain[0])) {
- LOGGER.log(
- Level.INFO, "checkCertTrusted: accepting cert already stored in keystore");
+ LOGGER.log(Level.INFO, "checkCertTrusted: accepting cert already stored in keystore");
return;
}
try {
- if (defaultTrustManager == null) throw ae;
+ if (defaultTrustManager == null)
+ throw ae;
LOGGER.log(Level.FINE, "checkCertTrusted: trying defaultTrustManager");
- if (isServer) defaultTrustManager.checkServerTrusted(chain, authType);
- else defaultTrustManager.checkClientTrusted(chain, authType);
+ if (isServer)
+ defaultTrustManager.checkServerTrusted(chain, authType);
+ else
+ defaultTrustManager.checkClientTrusted(chain, authType);
} catch (final CertificateException e) {
- final SharedPreferences preferences =
- PreferenceManager.getDefaultSharedPreferences(master);
- final boolean trustSystemCAs =
- !preferences.getBoolean("dont_trust_system_cas", false);
- if (domain != null
- && isServer
- && trustSystemCAs
- && !isIp(domain)
- && !domain.endsWith(".onion")) {
+ final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(master);
+ final boolean trustSystemCAs = !preferences.getBoolean("dont_trust_system_cas", false);
+ if (domain != null && isServer && trustSystemCAs && !isIp(domain) && !domain.endsWith(".onion")) {
final String hash = getBase64Hash(chain[0], "SHA-256");
final List fingerprints = getPoshFingerprints(domain);
if (hash != null && fingerprints.size() > 0) {
if (fingerprints.contains(hash)) {
- Log.d(
- Config.LOGTAG,
- "trusted cert fingerprint of " + domain + " via posh");
+ Log.d(Config.LOGTAG, "trusted cert fingerprint of " + domain + " via posh");
return;
} else {
- Log.d(
- Config.LOGTAG,
- "fingerprint " + hash + " not found in " + fingerprints);
+ Log.d(Config.LOGTAG, "fingerprint " + hash + " not found in " + fingerprints);
}
if (getPoshCacheFile(domain).delete()) {
- Log.d(
- Config.LOGTAG,
- "deleted posh file for "
- + domain
- + " after not being able to verify");
+ Log.d(Config.LOGTAG, "deleted posh file for " + domain + " after not being able to verify");
}
}
}
@@ -461,25 +422,17 @@ public class MemorizingTrustManager {
}
private List getPoshFingerprintsFromServer(String domain) {
- return getPoshFingerprintsFromServer(
- domain, "https://" + domain + "/.well-known/posh/xmpp-client.json", -1, true);
+ return getPoshFingerprintsFromServer(domain, "https://" + domain + "/.well-known/posh/xmpp-client.json", -1, true);
}
- private List getPoshFingerprintsFromServer(
- String domain, String url, int maxTtl, boolean followUrl) {
+ private List getPoshFingerprintsFromServer(String domain, String url, int maxTtl, boolean followUrl) {
Log.d(Config.LOGTAG, "downloading json for " + domain + " from " + url);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(master);
- final boolean useTor =
- QuickConversationsService.isConversations()
- && preferences.getBoolean(
- "use_tor", master.getResources().getBoolean(R.bool.use_tor));
+ final boolean useTor = QuickConversationsService.isConversations() && preferences.getBoolean("use_tor", master.getResources().getBoolean(R.bool.use_tor));
try {
final List results = new ArrayList<>();
final InputStream inputStream = HttpConnectionManager.open(url, useTor);
- final String body =
- CharStreams.toString(
- new InputStreamReader(
- ByteStreams.limit(inputStream, 10_000), Charsets.UTF_8));
+ final String body = CharStreams.toString(new InputStreamReader(ByteStreams.limit(inputStream,10_000), Charsets.UTF_8));
final JSONObject jsonObject = new JSONObject(body);
int expires = jsonObject.getInt("expires");
if (expires <= 0) {
@@ -506,7 +459,7 @@ public class MemorizingTrustManager {
writeFingerprintsToCache(domain, results, 1000L * expires + System.currentTimeMillis());
return results;
} catch (final Exception e) {
- Log.d(Config.LOGTAG, "error fetching posh", e);
+ Log.d(Config.LOGTAG, "error fetching posh",e);
return new ArrayList<>();
}
}
@@ -536,8 +489,7 @@ public class MemorizingTrustManager {
final File file = getPoshCacheFile(domain);
try {
final InputStream inputStream = new FileInputStream(file);
- final String json =
- CharStreams.toString(new InputStreamReader(inputStream, Charsets.UTF_8));
+ final String json = CharStreams.toString(new InputStreamReader(inputStream, Charsets.UTF_8));
final JSONObject jsonObject = new JSONObject(json);
long expires = jsonObject.getLong("expires");
long expiresIn = expires - System.currentTimeMillis();
@@ -562,9 +514,7 @@ public class MemorizingTrustManager {
}
private X509Certificate[] getAcceptedIssuers() {
- return defaultTrustManager == null
- ? new X509Certificate[0]
- : defaultTrustManager.getAcceptedIssuers();
+ return defaultTrustManager == null ? new X509Certificate[0] : defaultTrustManager.getAcceptedIssuers();
}
private int createDecisionId(MTMDecision d) {
@@ -577,8 +527,7 @@ public class MemorizingTrustManager {
return myId;
}
- private void certDetails(
- final StringBuffer si, final X509Certificate c, final boolean showValidFor) {
+ private void certDetails(final StringBuffer si, final X509Certificate c, final boolean showValidFor) {
si.append("\n");
if (showValidFor) {
@@ -615,7 +564,8 @@ public class MemorizingTrustManager {
// not found", so we use string comparison.
if (NO_TRUST_ANCHOR.equals(e.getMessage())) {
si.append(master.getString(R.string.mtm_trust_anchor));
- } else si.append(e.getLocalizedMessage());
+ } else
+ si.append(e.getLocalizedMessage());
si.append("\n");
}
si.append("\n");
@@ -623,7 +573,7 @@ public class MemorizingTrustManager {
si.append("\n\n");
si.append(master.getString(R.string.mtm_cert_details));
si.append('\n');
- for (int i = 0; i < chain.length; ++i) {
+ for(int i = 0; i < chain.length; ++i) {
certDetails(si, chain[i], i == 0);
}
return si.toString();
@@ -643,25 +593,24 @@ public class MemorizingTrustManager {
MTMDecision choice = new MTMDecision();
final int myId = createDecisionId(choice);
- masterHandler.post(
- new Runnable() {
- public void run() {
- Intent ni = new Intent(master, MemorizingActivity.class);
- ni.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ni.setData(Uri.parse(MemorizingTrustManager.class.getName() + "/" + myId));
- ni.putExtra(DECISION_INTENT_ID, myId);
- ni.putExtra(DECISION_INTENT_CERT, message);
- ni.putExtra(DECISION_TITLE_ID, titleId);
+ masterHandler.post(new Runnable() {
+ public void run() {
+ Intent ni = new Intent(master, MemorizingActivity.class);
+ ni.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ni.setData(Uri.parse(MemorizingTrustManager.class.getName() + "/" + myId));
+ ni.putExtra(DECISION_INTENT_ID, myId);
+ ni.putExtra(DECISION_INTENT_CERT, message);
+ ni.putExtra(DECISION_TITLE_ID, titleId);
- // we try to directly start the activity and fall back to
- // making a notification
- try {
- getUI().startActivity(ni);
- } catch (Exception e) {
- LOGGER.log(Level.FINE, "startActivity(MemorizingActivity)", e);
- }
- }
- });
+ // we try to directly start the activity and fall back to
+ // making a notification
+ try {
+ getUI().startActivity(ni);
+ } catch (Exception e) {
+ LOGGER.log(Level.FINE, "startActivity(MemorizingActivity)", e);
+ }
+ }
+ });
LOGGER.log(Level.FINE, "openDecisions: " + openDecisions + ", waiting on " + myId);
try {
@@ -712,8 +661,7 @@ public class MemorizingTrustManager {
}
@Override
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
MemorizingTrustManager.this.checkCertTrusted(chain, authType, domain, false, false);
}
@@ -727,6 +675,7 @@ public class MemorizingTrustManager {
public X509Certificate[] getAcceptedIssuers() {
return MemorizingTrustManager.this.getAcceptedIssuers();
}
+
}
private class InteractiveMemorizingTrustManager implements X509TrustManager {
@@ -737,8 +686,7 @@ public class MemorizingTrustManager {
}
@Override
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
MemorizingTrustManager.this.checkCertTrusted(chain, authType, domain, false, true);
}
diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
index 44d16a0d7..10cfdcb04 100644
--- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
+++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
@@ -4,7 +4,7 @@ import static eu.siacs.conversations.utils.Random.SECURE_RANDOM;
import android.util.Log;
-import androidx.annotation.NonNull;
+import org.jetbrains.annotations.NotNull;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -286,18 +286,10 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
if (conversation != null) {
conversation.sort();
conversation.setHasMessagesLeftOnServer(!done);
- final var displayState = conversation.getDisplayState();
- if (displayState != null) {
- mXmppConnectionService.markReadUpToStanzaId(conversation, displayState);
- }
} else {
- for (final Conversation tmp : this.mXmppConnectionService.getConversations()) {
+ for (Conversation tmp : this.mXmppConnectionService.getConversations()) {
if (tmp.getAccount() == query.getAccount()) {
tmp.sort();
- final var displayState = tmp.getDisplayState();
- if (displayState != null) {
- mXmppConnectionService.markReadUpToStanzaId(tmp, displayState);
- }
}
}
}
@@ -644,7 +636,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
}
}
- @NonNull
+ @NotNull
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index 7027ee2cc..0742215d1 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -2,7 +2,6 @@ package eu.siacs.conversations.services;
import static eu.siacs.conversations.utils.Compatibility.s;
-import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -11,17 +10,17 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.media.AudioAttributes;
-import android.media.AudioManager;
+import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.SystemClock;
+import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.SpannableString;
@@ -29,9 +28,7 @@ import android.text.style.StyleSpan;
import android.util.DisplayMetrics;
import android.util.Log;
-import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationCompat.BigPictureStyle;
import androidx.core.app.NotificationCompat.Builder;
@@ -44,14 +41,29 @@ import androidx.core.graphics.drawable.IconCompat;
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
-import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
-import com.google.common.primitives.Ints;
-import eu.siacs.conversations.AppSettings;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -63,6 +75,7 @@ import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.EditAccountActivity;
import eu.siacs.conversations.ui.RtpSessionActivity;
+import eu.siacs.conversations.ui.TimePreference;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.GeoHelper;
@@ -73,28 +86,16 @@ import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
import eu.siacs.conversations.xmpp.jingle.Media;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
public class NotificationService {
+ private static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE =
+ Executors.newSingleThreadScheduledExecutor();
+
public static final Object CATCHUP_LOCK = new Object();
private static final int LED_COLOR = 0xff0000ff;
- private static final long[] CALL_PATTERN = {0, 500, 300, 600, 3000};
+ private static final long[] CALL_PATTERN = {0, 500, 300, 600};
private static final String MESSAGES_GROUP = "eu.siacs.conversations.messages";
private static final String MISSED_CALLS_GROUP = "eu.siacs.conversations.missed_calls";
@@ -106,8 +107,6 @@ public class NotificationService {
public static final int ONGOING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 10;
public static final int MISSED_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 12;
private static final int DELIVERY_FAILED_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 13;
- public static final int ONGOING_VIDEO_TRANSCODING_NOTIFICATION_ID =
- NOTIFICATION_ID_MULTIPLIER * 14;
private final XmppConnectionService mXmppConnectionService;
private final LinkedHashMap> notifications = new LinkedHashMap<>();
private final HashMap mBacklogMessageCounter = new HashMap<>();
@@ -118,9 +117,8 @@ public class NotificationService {
private long mLastNotification;
private static final String INCOMING_CALLS_NOTIFICATION_CHANNEL = "incoming_calls_channel";
- private static final String INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX =
- "incoming_calls_channel#";
- private static final String MESSAGES_NOTIFICATION_CHANNEL = "messages";
+ private Ringtone currentlyPlayingRingtone = null;
+ private ScheduledFuture> vibrationFuture;
NotificationService(final XmppConnectionService service) {
this.mXmppConnectionService = service;
@@ -161,7 +159,6 @@ public class NotificationService {
notificationManager.deleteNotificationChannel("export");
notificationManager.deleteNotificationChannel("incoming_calls");
- notificationManager.deleteNotificationChannel(INCOMING_CALLS_NOTIFICATION_CHANNEL);
notificationManager.createNotificationChannelGroup(
new NotificationChannelGroup(
@@ -212,7 +209,19 @@ public class NotificationService {
exportChannel.setGroup("status");
notificationManager.createNotificationChannel(exportChannel);
- createInitialIncomingCallChannelIfNecessary(c);
+ final NotificationChannel incomingCallsChannel =
+ new NotificationChannel(
+ INCOMING_CALLS_NOTIFICATION_CHANNEL,
+ c.getString(R.string.incoming_calls_channel_name),
+ NotificationManager.IMPORTANCE_HIGH);
+ incomingCallsChannel.setSound(null, null);
+ incomingCallsChannel.setShowBadge(false);
+ incomingCallsChannel.setLightColor(LED_COLOR);
+ incomingCallsChannel.enableLights(true);
+ incomingCallsChannel.setGroup("calls");
+ incomingCallsChannel.setBypassDnd(true);
+ incomingCallsChannel.enableVibration(false);
+ notificationManager.createNotificationChannel(incomingCallsChannel);
final NotificationChannel ongoingCallsChannel =
new NotificationChannel(
@@ -237,7 +246,7 @@ public class NotificationService {
final NotificationChannel messagesChannel =
new NotificationChannel(
- MESSAGES_NOTIFICATION_CHANNEL,
+ "messages",
c.getString(R.string.messages_channel_name),
NotificationManager.IMPORTANCE_HIGH);
messagesChannel.setShowBadge(true);
@@ -245,7 +254,7 @@ public class NotificationService {
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
.build());
messagesChannel.setLightColor(LED_COLOR);
final int dat = 70;
@@ -268,6 +277,20 @@ public class NotificationService {
silentMessagesChannel.setGroup("chats");
notificationManager.createNotificationChannel(silentMessagesChannel);
+ final NotificationChannel quietHoursChannel =
+ new NotificationChannel(
+ "quiet_hours",
+ c.getString(R.string.title_pref_quiet_hours),
+ NotificationManager.IMPORTANCE_LOW);
+ quietHoursChannel.setShowBadge(true);
+ quietHoursChannel.setLightColor(LED_COLOR);
+ quietHoursChannel.enableLights(true);
+ quietHoursChannel.setGroup("chats");
+ quietHoursChannel.enableVibration(false);
+ quietHoursChannel.setSound(null, null);
+
+ notificationManager.createNotificationChannel(quietHoursChannel);
+
final NotificationChannel deliveryFailedChannel =
new NotificationChannel(
"delivery_failed",
@@ -284,98 +307,6 @@ public class NotificationService {
notificationManager.createNotificationChannel(deliveryFailedChannel);
}
- @RequiresApi(api = Build.VERSION_CODES.O)
- private static void createInitialIncomingCallChannelIfNecessary(final Context context) {
- final var currentIteration = getCurrentIncomingCallChannelIteration(context);
- if (currentIteration.isPresent()) {
- return;
- }
- createInitialIncomingCallChannel(context);
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O)
- public static Optional getCurrentIncomingCallChannelIteration(final Context context) {
- final var notificationManager = context.getSystemService(NotificationManager.class);
- for (final NotificationChannel channel : notificationManager.getNotificationChannels()) {
- final String id = channel.getId();
- if (Strings.isNullOrEmpty(id)) {
- continue;
- }
- if (id.startsWith(INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX)) {
- final var parts = Splitter.on('#').splitToList(id);
- if (parts.size() == 2) {
- final var iteration = Ints.tryParse(parts.get(1));
- if (iteration != null) {
- return Optional.of(iteration);
- }
- }
- }
- }
- return Optional.absent();
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O)
- public static Optional getCurrentIncomingCallChannel(
- final Context context) {
- final var iteration = getCurrentIncomingCallChannelIteration(context);
- return iteration.transform(
- i -> {
- final var notificationManager =
- context.getSystemService(NotificationManager.class);
- return notificationManager.getNotificationChannel(
- INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX + i);
- });
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O)
- private static void createInitialIncomingCallChannel(final Context context) {
- final var appSettings = new AppSettings(context);
- final var ringtoneUri = appSettings.getRingtone();
- createIncomingCallChannel(context, ringtoneUri, 0);
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O)
- public static void recreateIncomingCallChannel(final Context context, final Uri ringtone) {
- final var currentIteration = getCurrentIncomingCallChannelIteration(context);
- final int nextIteration;
- if (currentIteration.isPresent()) {
- final var notificationManager = context.getSystemService(NotificationManager.class);
- notificationManager.deleteNotificationChannel(
- INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX + currentIteration.get());
- nextIteration = currentIteration.get() + 1;
- } else {
- nextIteration = 0;
- }
- createIncomingCallChannel(context, ringtone, nextIteration);
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O)
- private static void createIncomingCallChannel(
- final Context context, final Uri ringtoneUri, final int iteration) {
- final var notificationManager = context.getSystemService(NotificationManager.class);
- final var id = INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX + iteration;
- Log.d(Config.LOGTAG, "creating incoming call channel with id " + id);
- final NotificationChannel incomingCallsChannel =
- new NotificationChannel(
- id,
- context.getString(R.string.incoming_calls_channel_name),
- NotificationManager.IMPORTANCE_HIGH);
- incomingCallsChannel.setSound(
- ringtoneUri,
- new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .build());
- incomingCallsChannel.setShowBadge(false);
- incomingCallsChannel.setLightColor(LED_COLOR);
- incomingCallsChannel.enableLights(true);
- incomingCallsChannel.setGroup("calls");
- incomingCallsChannel.setBypassDnd(true);
- incomingCallsChannel.enableVibration(true);
- incomingCallsChannel.setVibrationPattern(CALL_PATTERN);
- notificationManager.createNotificationChannel(incomingCallsChannel);
- }
-
private boolean notifyMessage(final Message message) {
final Conversation conversation = (Conversation) message.getConversation();
return message.getStatus() == Message.STATUS_RECEIVED
@@ -395,6 +326,28 @@ public class NotificationService {
"notifications_from_strangers", R.bool.notifications_from_strangers);
}
+ private boolean isQuietHours() {
+ if (!mXmppConnectionService.getBooleanPreference(
+ "enable_quiet_hours", R.bool.enable_quiet_hours)) {
+ return false;
+ }
+ final SharedPreferences preferences =
+ PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService);
+ final long startTime =
+ TimePreference.minutesToTimestamp(
+ preferences.getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE));
+ final long endTime =
+ TimePreference.minutesToTimestamp(
+ preferences.getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE));
+ final long nowTime = Calendar.getInstance().getTimeInMillis();
+
+ if (endTime < startTime) {
+ return nowTime > startTime || nowTime < endTime;
+ } else {
+ return nowTime > startTime && nowTime < endTime;
+ }
+ }
+
public void pushFromBacklog(final Message message) {
if (notifyMessage(message)) {
synchronized (notifications) {
@@ -549,13 +502,54 @@ public class NotificationService {
public synchronized void startRinging(
final AbstractJingleConnection.Id id, final Set media) {
- showIncomingCallNotification(id, media, false);
+ showIncomingCallNotification(id, media);
+ final NotificationManager notificationManager =
+ (NotificationManager)
+ mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE);
+ final int currentInterruptionFilter;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && notificationManager != null) {
+ currentInterruptionFilter = notificationManager.getCurrentInterruptionFilter();
+ } else {
+ currentInterruptionFilter = 1; // INTERRUPTION_FILTER_ALL
+ }
+ if (currentInterruptionFilter != 1) {
+ Log.d(
+ Config.LOGTAG,
+ "do not ring or vibrate because interruption filter has been set to "
+ + currentInterruptionFilter);
+ return;
+ }
+ final ScheduledFuture> currentVibrationFuture = this.vibrationFuture;
+ this.vibrationFuture =
+ SCHEDULED_EXECUTOR_SERVICE.scheduleAtFixedRate(
+ new VibrationRunnable(), 0, 3, TimeUnit.SECONDS);
+ if (currentVibrationFuture != null) {
+ currentVibrationFuture.cancel(true);
+ }
+ final SharedPreferences preferences =
+ PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService);
+ final Resources resources = mXmppConnectionService.getResources();
+ final String ringtonePreference =
+ preferences.getString(
+ "call_ringtone", resources.getString(R.string.incoming_call_ringtone));
+ if (Strings.isNullOrEmpty(ringtonePreference)) {
+ Log.d(Config.LOGTAG, "ringtone has been set to none");
+ return;
+ }
+ final Uri uri = Uri.parse(ringtonePreference);
+ this.currentlyPlayingRingtone = RingtoneManager.getRingtone(mXmppConnectionService, uri);
+ if (this.currentlyPlayingRingtone == null) {
+ Log.d(Config.LOGTAG, "unable to find ringtone for uri " + uri);
+ return;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ this.currentlyPlayingRingtone.setLooping(true);
+ }
+ this.currentlyPlayingRingtone.play();
}
private void showIncomingCallNotification(
- final AbstractJingleConnection.Id id,
- final Set media,
- final boolean onlyAlertOnce) {
+ final AbstractJingleConnection.Id id, final Set media) {
final Intent fullScreenIntent =
new Intent(mXmppConnectionService, RtpSessionActivity.class);
fullScreenIntent.putExtra(
@@ -565,27 +559,15 @@ public class NotificationService {
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- final int channelIteration;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
- channelIteration = getCurrentIncomingCallChannelIteration(mXmppConnectionService).or(0);
- } else {
- channelIteration = 0;
- }
- final var channelId = INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX + channelIteration;
- Log.d(
- Config.LOGTAG,
- "showing incoming call notification on channel "
- + channelId
- + ", onlyAlertOnce="
- + onlyAlertOnce);
final NotificationCompat.Builder builder =
- new NotificationCompat.Builder(mXmppConnectionService, channelId);
+ new NotificationCompat.Builder(
+ mXmppConnectionService, INCOMING_CALLS_NOTIFICATION_CHANNEL);
if (media.contains(Media.VIDEO)) {
- builder.setSmallIcon(R.drawable.ic_videocam_24dp);
+ builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
builder.setContentTitle(
mXmppConnectionService.getString(R.string.rtp_state_incoming_video_call));
} else {
- builder.setSmallIcon(R.drawable.ic_call_24dp);
+ builder.setSmallIcon(R.drawable.ic_call_white_24dp);
builder.setContentTitle(
mXmppConnectionService.getString(R.string.rtp_state_incoming_call));
}
@@ -598,20 +580,11 @@ public class NotificationService {
if (systemAccount != null) {
builder.addPerson(systemAccount.toString());
}
- if (!onlyAlertOnce) {
- final var appSettings = new AppSettings(mXmppConnectionService);
- final var ringtone = appSettings.getRingtone();
- if (ringtone != null) {
- builder.setSound(ringtone, AudioManager.STREAM_RING);
- }
- builder.setVibrate(CALL_PATTERN);
- }
- builder.setOnlyAlertOnce(onlyAlertOnce);
builder.setContentText(id.account.getRoster().getContact(id.with).getDisplayName());
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
builder.setCategory(NotificationCompat.CATEGORY_CALL);
- final PendingIntent pendingIntent = createPendingRtpSession(id, Intent.ACTION_VIEW, 101);
+ PendingIntent pendingIntent = createPendingRtpSession(id, Intent.ACTION_VIEW, 101);
builder.setFullScreenIntent(pendingIntent, true);
builder.setContentIntent(pendingIntent); // old androids need this?
builder.setOngoing(true);
@@ -633,10 +606,6 @@ public class NotificationService {
.build());
modifyIncomingCall(builder);
final Notification notification = builder.build();
- notification.audioAttributes = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
- .build();
notification.flags = notification.flags | Notification.FLAG_INSISTENT;
notify(INCOMING_CALL_NOTIFICATION_ID, notification);
}
@@ -647,7 +616,7 @@ public class NotificationService {
final NotificationCompat.Builder builder =
new NotificationCompat.Builder(mXmppConnectionService, "ongoing_calls");
if (ongoingCall.media.contains(Media.VIDEO)) {
- builder.setSmallIcon(R.drawable.ic_videocam_24dp);
+ builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
if (ongoingCall.reconnecting) {
builder.setContentTitle(
mXmppConnectionService.getString(R.string.reconnecting_video_call));
@@ -656,7 +625,7 @@ public class NotificationService {
mXmppConnectionService.getString(R.string.ongoing_video_call));
}
} else {
- builder.setSmallIcon(R.drawable.ic_call_24dp);
+ builder.setSmallIcon(R.drawable.ic_call_white_24dp);
if (ongoingCall.reconnecting) {
builder.setContentTitle(
mXmppConnectionService.getString(R.string.reconnecting_call));
@@ -701,25 +670,25 @@ public class NotificationService {
}
public void cancelIncomingCallNotification() {
+ stopSoundAndVibration();
cancel(INCOMING_CALL_NOTIFICATION_ID);
}
public boolean stopSoundAndVibration() {
- final var jingleRtpConnection =
- mXmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection();
- if (jingleRtpConnection == null) {
- return false;
+ int stopped = 0;
+ if (this.currentlyPlayingRingtone != null) {
+ if (this.currentlyPlayingRingtone.isPlaying()) {
+ Log.d(Config.LOGTAG, "stop playing ring tone");
+ ++stopped;
+ }
+ this.currentlyPlayingRingtone.stop();
}
- final var notificationManager = mXmppConnectionService.getSystemService(NotificationManager.class);
- if (Iterables.any(
- Arrays.asList(notificationManager.getActiveNotifications()),
- n -> n.getId() == INCOMING_CALL_NOTIFICATION_ID)) {
- Log.d(Config.LOGTAG, "stopping sound and vibration for incoming call notification");
- showIncomingCallNotification(
- jingleRtpConnection.getId(), jingleRtpConnection.getMedia(), true);
- return true;
+ if (this.vibrationFuture != null && !this.vibrationFuture.isCancelled()) {
+ Log.d(Config.LOGTAG, "stop vibration");
+ this.vibrationFuture.cancel(true);
+ ++stopped;
}
- return false;
+ return stopped > 0;
}
public static void cancelIncomingCallNotification(final Context context) {
@@ -810,8 +779,7 @@ public class NotificationService {
public void clearMissedCall(final Message message) {
synchronized (mMissedCalls) {
- final Iterator> iterator =
- mMissedCalls.entrySet().iterator();
+ final Iterator> iterator = mMissedCalls.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry entry = iterator.next();
final Conversational conversational = entry.getKey();
@@ -819,10 +787,7 @@ public class NotificationService {
if (conversational.getUuid().equals(message.getConversation().getUuid())) {
if (missedCallsInfo.removeMissedCall()) {
cancel(conversational.getUuid(), MISSED_CALL_NOTIFICATION_ID);
- Log.d(
- Config.LOGTAG,
- conversational.getAccount().getJid().asBareJid()
- + ": dismissed missed call because call was picked up on other device");
+ Log.d(Config.LOGTAG,conversational.getAccount().getJid().asBareJid()+": dismissed missed call because call was picked up on other device");
iterator.remove();
}
}
@@ -855,7 +820,7 @@ public class NotificationService {
}
private void markAsReadIfHasDirectReply(final ArrayList messages) {
- if (messages != null && !messages.isEmpty()) {
+ if (messages != null && messages.size() > 0) {
Message last = messages.get(messages.size() - 1);
if (last.getStatus() != Message.STATUS_RECEIVED) {
if (mXmppConnectionService.markRead((Conversation) last.getConversation(), false)) {
@@ -889,6 +854,8 @@ public class NotificationService {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService);
+ final boolean quiteHours = isQuietHours();
+
final boolean notifyOnlyOneChild =
notify
&& conversations != null
@@ -896,7 +863,7 @@ public class NotificationService {
== 1; // if this check is changed to > 0 catchup messages will
// create one notification per conversation
- if (notifications.isEmpty()) {
+ if (notifications.size() == 0) {
cancel(NOTIFICATION_ID);
} else {
if (notify) {
@@ -905,27 +872,29 @@ public class NotificationService {
final Builder mBuilder;
if (notifications.size() == 1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
mBuilder =
- buildSingleConversations(notifications.values().iterator().next(), notify);
- modifyForSoundVibrationAndLight(mBuilder, notify, preferences);
+ buildSingleConversations(
+ notifications.values().iterator().next(), notify, quiteHours);
+ modifyForSoundVibrationAndLight(mBuilder, notify, quiteHours, preferences);
notify(NOTIFICATION_ID, mBuilder.build());
} else {
- mBuilder = buildMultipleConversation(notify);
+ mBuilder = buildMultipleConversation(notify, quiteHours);
if (notifyOnlyOneChild) {
mBuilder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN);
}
- modifyForSoundVibrationAndLight(mBuilder, notify, preferences);
+ modifyForSoundVibrationAndLight(mBuilder, notify, quiteHours, preferences);
if (!summaryOnly) {
for (Map.Entry> entry : notifications.entrySet()) {
String uuid = entry.getKey();
final boolean notifyThis =
notifyOnlyOneChild ? conversations.contains(uuid) : notify;
Builder singleBuilder =
- buildSingleConversations(entry.getValue(), notifyThis);
+ buildSingleConversations(entry.getValue(), notifyThis, quiteHours);
if (!notifyOnlyOneChild) {
singleBuilder.setGroupAlertBehavior(
NotificationCompat.GROUP_ALERT_SUMMARY);
}
- modifyForSoundVibrationAndLight(singleBuilder, notifyThis, preferences);
+ modifyForSoundVibrationAndLight(
+ singleBuilder, notifyThis, quiteHours, preferences);
singleBuilder.setGroup(MESSAGES_GROUP);
setNotificationColor(singleBuilder);
notify(entry.getKey(), NOTIFICATION_ID, singleBuilder.build());
@@ -962,24 +931,21 @@ public class NotificationService {
}
private void modifyForSoundVibrationAndLight(
- final Builder mBuilder, final boolean notify, final SharedPreferences preferences) {
+ Builder mBuilder, boolean notify, boolean quietHours, SharedPreferences preferences) {
final Resources resources = mXmppConnectionService.getResources();
final String ringtone =
preferences.getString(
- AppSettings.NOTIFICATION_RINGTONE,
+ "notification_ringtone",
resources.getString(R.string.notification_ringtone));
final boolean vibrate =
preferences.getBoolean(
- AppSettings.NOTIFICATION_VIBRATE,
+ "vibrate_on_notification",
resources.getBoolean(R.bool.vibrate_on_notification));
- final boolean led =
- preferences.getBoolean(
- AppSettings.NOTIFICATION_LED, resources.getBoolean(R.bool.led));
+ final boolean led = preferences.getBoolean("led", resources.getBoolean(R.bool.led));
final boolean headsup =
preferences.getBoolean(
- AppSettings.NOTIFICATION_HEADS_UP,
- resources.getBoolean(R.bool.headsup_notifications));
- if (notify) {
+ "notification_headsup", resources.getBoolean(R.bool.headsup_notifications));
+ if (notify && !quietHours) {
if (vibrate) {
final int dat = 70;
final long[] pattern = {0, 3 * dat, dat, dat};
@@ -1145,11 +1111,11 @@ public class NotificationService {
setNotificationColor(builder);
}
- private Builder buildMultipleConversation(final boolean notify) {
+ private Builder buildMultipleConversation(final boolean notify, final boolean quietHours) {
final Builder mBuilder =
new NotificationCompat.Builder(
mXmppConnectionService,
- notify ? MESSAGES_NOTIFICATION_CHANNEL : "silent_messages");
+ quietHours ? "quiet_hours" : (notify ? "messages" : "silent_messages"));
final NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
style.setBigContentTitle(
mXmppConnectionService
@@ -1214,162 +1180,161 @@ public class NotificationService {
}
private Builder buildSingleConversations(
- final ArrayList messages, final boolean notify) {
- final var channel = notify ? MESSAGES_NOTIFICATION_CHANNEL : "silent_messages";
- final Builder notificationBuilder =
- new NotificationCompat.Builder(mXmppConnectionService, channel);
- if (messages.isEmpty()) {
- return notificationBuilder;
- }
- final Conversation conversation = (Conversation) messages.get(0).getConversation();
- notificationBuilder.setLargeIcon(
- mXmppConnectionService
- .getAvatarService()
- .get(
- conversation,
- AvatarService.getSystemUiAvatarSize(mXmppConnectionService)));
- notificationBuilder.setContentTitle(getConversationName(conversation));
- if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
- int count = messages.size();
- notificationBuilder.setContentText(
+ final ArrayList messages, final boolean notify, final boolean quietHours) {
+ final Builder mBuilder =
+ new NotificationCompat.Builder(
+ mXmppConnectionService,
+ quietHours ? "quiet_hours" : (notify ? "messages" : "silent_messages"));
+ if (messages.size() >= 1) {
+ final Conversation conversation = (Conversation) messages.get(0).getConversation();
+ mBuilder.setLargeIcon(
mXmppConnectionService
- .getResources()
- .getQuantityString(R.plurals.x_messages, count, count));
- } else {
- final Message message;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P
- && (message = getImage(messages)) != null) {
- modifyForImage(notificationBuilder, message, messages);
+ .getAvatarService()
+ .get(
+ conversation,
+ AvatarService.getSystemUiAvatarSize(mXmppConnectionService)));
+ mBuilder.setContentTitle(getConversationName(conversation));
+ if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
+ int count = messages.size();
+ mBuilder.setContentText(
+ mXmppConnectionService
+ .getResources()
+ .getQuantityString(R.plurals.x_messages, count, count));
} else {
- modifyForTextOnly(notificationBuilder, messages);
- }
- RemoteInput remoteInput =
- new RemoteInput.Builder("text_reply")
- .setLabel(UIHelper.getMessageHint(mXmppConnectionService, conversation))
- .build();
- PendingIntent markAsReadPendingIntent = createReadPendingIntent(conversation);
- NotificationCompat.Action markReadAction =
- new NotificationCompat.Action.Builder(
- R.drawable.ic_mark_chat_read_24dp,
- mXmppConnectionService.getString(R.string.mark_as_read),
- markAsReadPendingIntent)
- .setSemanticAction(
- NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ)
- .setShowsUserInterface(false)
- .build();
- final String replyLabel = mXmppConnectionService.getString(R.string.reply);
- final String lastMessageUuid = Iterables.getLast(messages).getUuid();
- final NotificationCompat.Action replyAction =
- new NotificationCompat.Action.Builder(
- R.drawable.ic_send_24dp,
- replyLabel,
- createReplyIntent(conversation, lastMessageUuid, false))
- .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
- .setShowsUserInterface(false)
- .addRemoteInput(remoteInput)
- .build();
- final NotificationCompat.Action wearReplyAction =
- new NotificationCompat.Action.Builder(
- R.drawable.ic_reply_24dp,
- replyLabel,
- createReplyIntent(conversation, lastMessageUuid, true))
- .addRemoteInput(remoteInput)
- .build();
- notificationBuilder.extend(
- new NotificationCompat.WearableExtender().addAction(wearReplyAction));
- int addedActionsCount = 1;
- notificationBuilder.addAction(markReadAction);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- notificationBuilder.addAction(replyAction);
- ++addedActionsCount;
- }
-
- if (displaySnoozeAction(messages)) {
- String label = mXmppConnectionService.getString(R.string.snooze);
- PendingIntent pendingSnoozeIntent = createSnoozeIntent(conversation);
- NotificationCompat.Action snoozeAction =
- new NotificationCompat.Action.Builder(
- R.drawable.ic_notifications_paused_24dp,
- label,
- pendingSnoozeIntent)
+ Message message;
+ // TODO starting with Android 9 we might want to put images in MessageStyle
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P
+ && (message = getImage(messages)) != null) {
+ modifyForImage(mBuilder, message, messages);
+ } else {
+ modifyForTextOnly(mBuilder, messages);
+ }
+ RemoteInput remoteInput =
+ new RemoteInput.Builder("text_reply")
+ .setLabel(
+ UIHelper.getMessageHint(
+ mXmppConnectionService, conversation))
.build();
- notificationBuilder.addAction(snoozeAction);
- ++addedActionsCount;
- }
- if (addedActionsCount < 3) {
- final Message firstLocationMessage = getFirstLocationMessage(messages);
- if (firstLocationMessage != null) {
- final PendingIntent pendingShowLocationIntent =
- createShowLocationIntent(firstLocationMessage);
- if (pendingShowLocationIntent != null) {
- final String label =
+ PendingIntent markAsReadPendingIntent = createReadPendingIntent(conversation);
+ NotificationCompat.Action markReadAction =
+ new NotificationCompat.Action.Builder(
+ R.drawable.ic_drafts_white_24dp,
+ mXmppConnectionService.getString(R.string.mark_as_read),
+ markAsReadPendingIntent)
+ .setSemanticAction(
+ NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ)
+ .setShowsUserInterface(false)
+ .build();
+ final String replyLabel = mXmppConnectionService.getString(R.string.reply);
+ final String lastMessageUuid = Iterables.getLast(messages).getUuid();
+ final NotificationCompat.Action replyAction =
+ new NotificationCompat.Action.Builder(
+ R.drawable.ic_send_text_offline,
+ replyLabel,
+ createReplyIntent(conversation, lastMessageUuid, false))
+ .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
+ .setShowsUserInterface(false)
+ .addRemoteInput(remoteInput)
+ .build();
+ final NotificationCompat.Action wearReplyAction =
+ new NotificationCompat.Action.Builder(
+ R.drawable.ic_wear_reply,
+ replyLabel,
+ createReplyIntent(conversation, lastMessageUuid, true))
+ .addRemoteInput(remoteInput)
+ .build();
+ mBuilder.extend(
+ new NotificationCompat.WearableExtender().addAction(wearReplyAction));
+ int addedActionsCount = 1;
+ mBuilder.addAction(markReadAction);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ mBuilder.addAction(replyAction);
+ ++addedActionsCount;
+ }
+
+ if (displaySnoozeAction(messages)) {
+ String label = mXmppConnectionService.getString(R.string.snooze);
+ PendingIntent pendingSnoozeIntent = createSnoozeIntent(conversation);
+ NotificationCompat.Action snoozeAction =
+ new NotificationCompat.Action.Builder(
+ R.drawable.ic_notifications_paused_white_24dp,
+ label,
+ pendingSnoozeIntent)
+ .build();
+ mBuilder.addAction(snoozeAction);
+ ++addedActionsCount;
+ }
+ if (addedActionsCount < 3) {
+ final Message firstLocationMessage = getFirstLocationMessage(messages);
+ if (firstLocationMessage != null) {
+ final PendingIntent pendingShowLocationIntent =
+ createShowLocationIntent(firstLocationMessage);
+ if (pendingShowLocationIntent != null) {
+ final String label =
+ mXmppConnectionService
+ .getResources()
+ .getString(R.string.show_location);
+ NotificationCompat.Action locationAction =
+ new NotificationCompat.Action.Builder(
+ R.drawable.ic_room_white_24dp,
+ label,
+ pendingShowLocationIntent)
+ .build();
+ mBuilder.addAction(locationAction);
+ ++addedActionsCount;
+ }
+ }
+ }
+ if (addedActionsCount < 3) {
+ Message firstDownloadableMessage = getFirstDownloadableMessage(messages);
+ if (firstDownloadableMessage != null) {
+ String label =
mXmppConnectionService
.getResources()
- .getString(R.string.show_location);
- NotificationCompat.Action locationAction =
+ .getString(
+ R.string.download_x_file,
+ UIHelper.getFileDescriptionString(
+ mXmppConnectionService,
+ firstDownloadableMessage));
+ PendingIntent pendingDownloadIntent =
+ createDownloadIntent(firstDownloadableMessage);
+ NotificationCompat.Action downloadAction =
new NotificationCompat.Action.Builder(
- R.drawable.ic_location_pin_24dp,
- label,
- pendingShowLocationIntent)
+ R.drawable.ic_file_download_white_24dp,
+ label,
+ pendingDownloadIntent)
.build();
- notificationBuilder.addAction(locationAction);
+ mBuilder.addAction(downloadAction);
++addedActionsCount;
}
}
}
- if (addedActionsCount < 3) {
- Message firstDownloadableMessage = getFirstDownloadableMessage(messages);
- if (firstDownloadableMessage != null) {
- String label =
- mXmppConnectionService
- .getResources()
- .getString(
- R.string.download_x_file,
- UIHelper.getFileDescriptionString(
- mXmppConnectionService,
- firstDownloadableMessage));
- PendingIntent pendingDownloadIntent =
- createDownloadIntent(firstDownloadableMessage);
- NotificationCompat.Action downloadAction =
- new NotificationCompat.Action.Builder(
- R.drawable.ic_download_24dp,
- label,
- pendingDownloadIntent)
- .build();
- notificationBuilder.addAction(downloadAction);
- ++addedActionsCount;
+ final ShortcutInfoCompat info;
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ final Contact contact = conversation.getContact();
+ final Uri systemAccount = contact.getSystemAccount();
+ if (systemAccount != null) {
+ mBuilder.addPerson(systemAccount.toString());
}
+ info = mXmppConnectionService.getShortcutService().getShortcutInfoCompat(contact);
+ } else {
+ info =
+ mXmppConnectionService
+ .getShortcutService()
+ .getShortcutInfoCompat(conversation.getMucOptions(), conversation.getNextCounterpart());
}
- }
- final ShortcutInfoCompat info;
- if (conversation.getMode() == Conversation.MODE_SINGLE) {
- final Contact contact = conversation.getContact();
- final Uri systemAccount = contact.getSystemAccount();
- if (systemAccount != null) {
- notificationBuilder.addPerson(systemAccount.toString());
- }
- info = mXmppConnectionService.getShortcutService().getShortcutInfoCompat(contact);
- } else {
- info =
- mXmppConnectionService
- .getShortcutService()
- .getShortcutInfoCompat(conversation.getMucOptions());
- }
- notificationBuilder.setWhen(conversation.getLatestMessage().getTimeSent());
- notificationBuilder.setSmallIcon(R.drawable.ic_app_icon_notification);
- notificationBuilder.setDeleteIntent(createDeleteIntent(conversation));
- notificationBuilder.setContentIntent(createContentIntent(conversation));
- if (channel.equals(MESSAGES_NOTIFICATION_CHANNEL)) {
- // when do not want 'customized' notifications for silent notifications in their
- // respective channels
- notificationBuilder.setShortcutInfo(info);
+ mBuilder.setWhen(conversation.getLatestMessage().getTimeSent());
+ mBuilder.setSmallIcon(R.drawable.ic_notification);
+ mBuilder.setDeleteIntent(createDeleteIntent(conversation));
+ mBuilder.setContentIntent(createContentIntent(conversation));
+ mBuilder.setShortcutInfo(info);
if (Build.VERSION.SDK_INT >= 30) {
mXmppConnectionService
.getSystemService(ShortcutManager.class)
.pushDynamicShortcut(info.toShortcutInfo());
}
}
- return notificationBuilder;
+ return mBuilder;
}
private void modifyForImage(
@@ -1701,34 +1666,21 @@ public class NotificationService {
}
private PendingIntent createCallAction(String sessionId, final String action, int requestCode) {
- return pendingServiceIntent(
- mXmppConnectionService,
- action,
- requestCode,
- ImmutableMap.of(RtpSessionActivity.EXTRA_SESSION_ID, sessionId));
+ return pendingServiceIntent(mXmppConnectionService, action, requestCode, ImmutableMap.of(RtpSessionActivity.EXTRA_SESSION_ID, sessionId));
}
private PendingIntent createSnoozeIntent(final Conversation conversation) {
- return pendingServiceIntent(
- mXmppConnectionService,
- XmppConnectionService.ACTION_SNOOZE,
- generateRequestCode(conversation, 22),
- ImmutableMap.of("uuid", conversation.getUuid()));
+ return pendingServiceIntent(mXmppConnectionService, XmppConnectionService.ACTION_SNOOZE, generateRequestCode(conversation,22),ImmutableMap.of("uuid",conversation.getUuid()));
}
- private static PendingIntent pendingServiceIntent(
- final Context context, final String action, final int requestCode) {
+ private static PendingIntent pendingServiceIntent(final Context context, final String action, final int requestCode) {
return pendingServiceIntent(context, action, requestCode, ImmutableMap.of());
}
- private static PendingIntent pendingServiceIntent(
- final Context context,
- final String action,
- final int requestCode,
- final Map extras) {
+ private static PendingIntent pendingServiceIntent(final Context context, final String action, final int requestCode, final Map extras) {
final Intent intent = new Intent(context, XmppConnectionService.class);
intent.setAction(action);
- for (final Map.Entry entry : extras.entrySet()) {
+ for(final Map.Entry entry : extras.entrySet()) {
intent.putExtra(entry.getKey(), entry.getValue());
}
return PendingIntent.getService(
@@ -1741,7 +1693,8 @@ public class NotificationService {
}
private boolean wasHighlightedOrPrivate(final Message message) {
- if (message.getConversation() instanceof Conversation conversation) {
+ if (message.getConversation() instanceof Conversation) {
+ Conversation conversation = (Conversation) message.getConversation();
final String nick = conversation.getMucOptions().getActualNick();
final Pattern highlight = generateNickHighlightPattern(nick);
if (message.getBody() == null || nick == null) {
@@ -1790,7 +1743,8 @@ public class NotificationService {
connected = 0;
} else {
enabled = Iterables.size(Iterables.filter(accounts, Account::isEnabled));
- connected = Iterables.size(Iterables.filter(accounts, Account::isOnlineAndConnected));
+ connected =
+ Iterables.size(Iterables.filter(accounts, Account::isOnlineAndConnected));
}
mBuilder.setContentText(
mXmppConnectionService.getString(R.string.connected_accounts, connected, enabled));
@@ -1800,7 +1754,10 @@ public class NotificationService {
}
mBuilder.setWhen(0)
.setPriority(Notification.PRIORITY_MIN)
- .setSmallIcon(connected > 0 ? R.drawable.ic_link_24dp : R.drawable.ic_link_off_24dp)
+ .setSmallIcon(
+ connected > 0
+ ? R.drawable.ic_link_white_24dp
+ : R.drawable.ic_link_off_white_24dp)
.setLocalOnly(true);
if (Compatibility.runsTwentySix()) {
@@ -1867,17 +1824,10 @@ public class NotificationService {
}
}
if (mXmppConnectionService.foregroundNotificationNeedsUpdatingWhenErrorStateChanges()) {
- try {
- notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
- } catch (final RuntimeException e) {
- Log.d(
- Config.LOGTAG,
- "not refreshing foreground service notification because service has died",
- e);
- }
+ notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
}
final Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService);
- if (errors.isEmpty()) {
+ if (errors.size() == 0) {
cancel(ERROR_NOTIFICATION_ID);
return;
} else if (errors.size() == 1) {
@@ -1889,27 +1839,14 @@ public class NotificationService {
mXmppConnectionService.getString(R.string.problem_connecting_to_accounts));
mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_fix));
}
- try {
- mBuilder.addAction(
- R.drawable.ic_autorenew_24dp,
- mXmppConnectionService.getString(R.string.try_again),
- pendingServiceIntent(
- mXmppConnectionService, XmppConnectionService.ACTION_TRY_AGAIN, 45));
- mBuilder.setDeleteIntent(
- pendingServiceIntent(
- mXmppConnectionService,
- XmppConnectionService.ACTION_DISMISS_ERROR_NOTIFICATIONS,
- 69));
- } catch (final RuntimeException e) {
- Log.d(
- Config.LOGTAG,
- "not including some actions in error notification because service has died",
- e);
- }
+ mBuilder.addAction(
+ R.drawable.ic_autorenew_white_24dp,
+ mXmppConnectionService.getString(R.string.try_again),
+ pendingServiceIntent(mXmppConnectionService, XmppConnectionService.ACTION_TRY_AGAIN, 45));
if (torNotAvailable) {
if (TorServiceUtils.isOrbotInstalled(mXmppConnectionService)) {
mBuilder.addAction(
- R.drawable.ic_play_circle_24dp,
+ R.drawable.ic_play_circle_filled_white_48dp,
mXmppConnectionService.getString(R.string.start_orbot),
PendingIntent.getActivity(
mXmppConnectionService,
@@ -1921,7 +1858,7 @@ public class NotificationService {
: PendingIntent.FLAG_UPDATE_CURRENT));
} else {
mBuilder.addAction(
- R.drawable.ic_download_24dp,
+ R.drawable.ic_file_download_white_24dp,
mXmppConnectionService.getString(R.string.install_orbot),
PendingIntent.getActivity(
mXmppConnectionService,
@@ -1933,6 +1870,7 @@ public class NotificationService {
: PendingIntent.FLAG_UPDATE_CURRENT));
}
}
+ mBuilder.setDeleteIntent(pendingServiceIntent(mXmppConnectionService,XmppConnectionService.ACTION_DISMISS_ERROR_NOTIFICATIONS, 69));
mBuilder.setVisibility(Notification.VISIBILITY_PRIVATE);
mBuilder.setSmallIcon(R.drawable.ic_warning_white_24dp);
mBuilder.setLocalOnly(true);
@@ -1959,66 +1897,41 @@ public class NotificationService {
notify(ERROR_NOTIFICATION_ID, mBuilder.build());
}
- void updateFileAddingNotification(final int current, final Message message) {
-
- final Notification notification = videoTranscoding(current, message);
- notify(ONGOING_VIDEO_TRANSCODING_NOTIFICATION_ID, notification);
- }
-
- private Notification videoTranscoding(final int current, @Nullable final Message message) {
- final Notification.Builder builder = new Notification.Builder(mXmppConnectionService);
- builder.setContentTitle(mXmppConnectionService.getString(R.string.transcoding_video));
- if (current >= 0) {
- builder.setProgress(100, current, false);
- } else {
- builder.setProgress(100, 0, true);
- }
- builder.setSmallIcon(R.drawable.ic_hourglass_top_24dp);
- if (message != null) {
- builder.setContentIntent(createContentIntent(message.getConversation()));
- }
- builder.setOngoing(true);
+ void updateFileAddingNotification(int current, Message message) {
+ Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService);
+ mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.transcoding_video));
+ mBuilder.setProgress(100, current, false);
+ mBuilder.setSmallIcon(R.drawable.ic_hourglass_empty_white_24dp);
+ mBuilder.setContentIntent(createContentIntent(message.getConversation()));
+ mBuilder.setOngoing(true);
if (Compatibility.runsTwentySix()) {
- builder.setChannelId("compression");
+ mBuilder.setChannelId("compression");
}
- return builder.build();
+ Notification notification = mBuilder.build();
+ notify(FOREGROUND_NOTIFICATION_ID, notification);
}
- public Notification getIndeterminateVideoTranscoding() {
- return videoTranscoding(-1, null);
- }
-
- private void notify(final String tag, final int id, final Notification notification) {
- if (ActivityCompat.checkSelfPermission(
- mXmppConnectionService, Manifest.permission.POST_NOTIFICATIONS)
- != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- final var notificationManager =
- mXmppConnectionService.getSystemService(NotificationManager.class);
+ private void notify(String tag, int id, Notification notification) {
+ final NotificationManagerCompat notificationManager =
+ NotificationManagerCompat.from(mXmppConnectionService);
try {
notificationManager.notify(tag, id, notification);
- } catch (final RuntimeException e) {
+ } catch (RuntimeException e) {
Log.d(Config.LOGTAG, "unable to make notification", e);
}
}
- public void notify(final int id, final Notification notification) {
- if (ActivityCompat.checkSelfPermission(
- mXmppConnectionService, Manifest.permission.POST_NOTIFICATIONS)
- != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- final var notificationManager =
- mXmppConnectionService.getSystemService(NotificationManager.class);
+ public void notify(int id, Notification notification) {
+ final NotificationManagerCompat notificationManager =
+ NotificationManagerCompat.from(mXmppConnectionService);
try {
notificationManager.notify(id, notification);
- } catch (final RuntimeException e) {
+ } catch (RuntimeException e) {
Log.d(Config.LOGTAG, "unable to make notification", e);
}
}
- public void cancel(final int id) {
+ public void cancel(int id) {
final NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(mXmppConnectionService);
try {
@@ -2073,4 +1986,14 @@ public class NotificationService {
return lastTime;
}
}
+
+ private class VibrationRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ final Vibrator vibrator =
+ (Vibrator) mXmppConnectionService.getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(CALL_PATTERN, -1);
+ }
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java
index 4aab05cee..d152c5d07 100644
--- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java
+++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java
@@ -12,7 +12,6 @@ import android.preference.PreferenceManager;
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
@@ -28,7 +27,6 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.parser.AbstractParser;
import eu.siacs.conversations.persistance.UnifiedPushDatabase;
-import eu.siacs.conversations.receiver.UnifiedPushDistributor;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
@@ -87,24 +85,24 @@ public class UnifiedPushBroker {
service.sendPresencePacket(account, presence);
}
- public void renewUnifiedPushEndpoints() {
- renewUnifiedPushEndpoints(null);
+ public Optional renewUnifiedPushEndpoints() {
+ return renewUnifiedPushEndpoints(null);
}
- public Optional renewUnifiedPushEndpoints(@Nullable final PushTargetMessenger pushTargetMessenger) {
+ public Optional renewUnifiedPushEndpoints(final PushTargetMessenger pushTargetMessenger) {
final Optional transportOptional = getTransport();
if (transportOptional.isPresent()) {
final Transport transport = transportOptional.get();
if (transport.account.isEnabled()) {
renewUnifiedEndpoint(transportOptional.get(), pushTargetMessenger);
} else {
- if (pushTargetMessenger != null && pushTargetMessenger.messenger != null) {
+ if (pushTargetMessenger.messenger != null) {
sendRegistrationDelayed(pushTargetMessenger.messenger,"account is disabled");
}
Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. Account is disabled");
}
} else {
- if (pushTargetMessenger != null && pushTargetMessenger.messenger != null) {
+ if (pushTargetMessenger.messenger != null) {
sendRegistrationDelayed(pushTargetMessenger.messenger,"no transport selected");
}
Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. No transport selected");
@@ -405,12 +403,7 @@ public class UnifiedPushBroker {
updateIntent.putExtra("token", target.instance);
updateIntent.putExtra("bytesMessage", payload);
updateIntent.putExtra("message", new String(payload, StandardCharsets.UTF_8));
- final var distributorVerificationIntent = new Intent();
- distributorVerificationIntent.setPackage(service.getPackageName());
- final var pendingIntent =
- PendingIntent.getBroadcast(
- service, 0, distributorVerificationIntent, PendingIntent.FLAG_IMMUTABLE);
- updateIntent.putExtra("distributor", pendingIntent);
+ // TODO add distributor verification?
service.sendBroadcast(updateIntent);
}
diff --git a/src/main/java/eu/siacs/conversations/receiver/UnifiedPushDistributor.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java
similarity index 85%
rename from src/main/java/eu/siacs/conversations/receiver/UnifiedPushDistributor.java
rename to src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java
index ace71ddb5..b47a61a53 100644
--- a/src/main/java/eu/siacs/conversations/receiver/UnifiedPushDistributor.java
+++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java
@@ -1,4 +1,4 @@
-package eu.siacs.conversations.receiver;
+package eu.siacs.conversations.services;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -25,7 +25,6 @@ import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.persistance.UnifiedPushDatabase;
-import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.Compatibility;
public class UnifiedPushDistributor extends BroadcastReceiver {
@@ -36,9 +35,9 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
public static final String ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER";
public static final String ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER";
+
// connector actions (these are actions used for distributor->connector broadcasts)
- public static final String ACTION_UNREGISTERED =
- "org.unifiedpush.android.connector.UNREGISTERED";
+ public static final String ACTION_UNREGISTERED = "org.unifiedpush.android.connector.UNREGISTERED";
public static final String ACTION_BYTE_MESSAGE =
"org.unifiedpush.android.distributor.feature.BYTES_MESSAGE";
public static final String ACTION_REGISTRATION_FAILED =
@@ -70,7 +69,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
final Parcelable appVerification = intent.getParcelableExtra("app");
if (appVerification instanceof PendingIntent pendingIntent) {
application = pendingIntent.getIntentSender().getCreatorPackage();
- Log.d(Config.LOGTAG, "received application name via pending intent " + application);
+ Log.d(Config.LOGTAG,"received application name via pending intent "+ application);
} else {
application = intent.getStringExtra("application");
}
@@ -80,10 +79,10 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
switch (Strings.nullToEmpty(action)) {
case ACTION_REGISTER -> register(context, application, instance, features, messenger);
case ACTION_UNREGISTER -> unregister(context, instance);
- case Intent.ACTION_PACKAGE_FULLY_REMOVED -> unregisterApplication(
- context, intent.getData());
- default -> Log.d(
- Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action);
+ case Intent.ACTION_PACKAGE_FULLY_REMOVED ->
+ unregisterApplication(context, intent.getData());
+ default ->
+ Log.d(Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action);
}
}
@@ -112,11 +111,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
Log.d(
Config.LOGTAG,
"successfully created UnifiedPush entry. waking up XmppConnectionService");
- quickLog(
- context,
- String.format(
- "successfully registered %s (token = %s) for UnifiedPushed",
- application, instance));
+ quickLog(context, String.format("successfully registered %s (token = %s) for UnifiedPushed", application, instance));
final Intent serviceIntent = new Intent(context, XmppConnectionService.class);
serviceIntent.setAction(XmppConnectionService.ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS);
serviceIntent.putExtra("instance", instance);
@@ -145,7 +140,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
}
} else {
if (messenger instanceof Messenger m) {
- sendRegistrationFailed(m, "Your application is not registered to receive messages");
+ sendRegistrationFailed(m,"Your application is not registered to receive messages");
}
Log.d(
Config.LOGTAG,
@@ -162,7 +157,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
try {
messenger.send(message);
} catch (final RemoteException e) {
- Log.d(Config.LOGTAG, "unable to tell messenger of failed registration", e);
+ Log.d(Config.LOGTAG,"unable to tell messenger of failed registration",e);
}
}
@@ -182,11 +177,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
}
final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(context);
if (unifiedPushDatabase.deleteInstance(instance)) {
- quickLog(
- context,
- String.format(
- "successfully unregistered token %s from UnifiedPushed (application requested unregister)",
- instance));
+ quickLog(context, String.format("successfully unregistered token %s from UnifiedPushed (application requested unregister)", instance));
Log.d(Config.LOGTAG, "successfully removed " + instance + " from UnifiedPush");
// TODO send UNREGISTERED broadcast back to app?!
}
@@ -201,11 +192,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
Log.d(Config.LOGTAG, "app " + application + " has been removed from the system");
final UnifiedPushDatabase database = UnifiedPushDatabase.getInstance(context);
if (database.deleteApplication(application)) {
- quickLog(
- context,
- String.format(
- "successfully removed %s from UnifiedPushed (ACTION_PACKAGE_FULLY_REMOVED)",
- application));
+ quickLog(context, String.format("successfully removed %s from UnifiedPushed (ACTION_PACKAGE_FULLY_REMOVED)", application));
Log.d(Config.LOGTAG, "successfully removed " + application + " from UnifiedPush");
}
}
@@ -223,6 +210,6 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
final Intent intent = new Intent(context, XmppConnectionService.class);
intent.setAction(XmppConnectionService.ACTION_QUICK_LOG);
intent.putExtra("message", message);
- Compatibility.startService(context, intent);
+ context.startService(intent);
}
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 9492645f5..f66e29a96 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -42,6 +42,8 @@ import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.security.KeyChain;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -51,7 +53,6 @@ import android.util.Pair;
import androidx.annotation.BoolRes;
import androidx.annotation.IntegerRes;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.core.app.RemoteInput;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
@@ -59,8 +60,6 @@ import androidx.core.util.Consumer;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Iterables;
import org.conscrypt.Conscrypt;
import org.jxmpp.stringprep.libidn.LibIdnXmppStringprep;
@@ -89,14 +88,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
-import eu.siacs.conversations.AppSettings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.android.JabberIdContact;
@@ -131,10 +128,10 @@ import eu.siacs.conversations.parser.PresenceParser;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.persistance.UnifiedPushDatabase;
-import eu.siacs.conversations.receiver.SystemEventReceiver;
import eu.siacs.conversations.ui.ChooseAccountForProfilePictureActivity;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.RtpSessionActivity;
+import eu.siacs.conversations.ui.SettingsActivity;
import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
import eu.siacs.conversations.ui.interfaces.OnMediaLoaded;
@@ -160,7 +157,6 @@ import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.LocalizedContent;
import eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
@@ -207,7 +203,6 @@ public class XmppConnectionService extends Service {
public static final String ACTION_DISMISS_CALL = "dismiss_call";
public static final String ACTION_END_CALL = "end_call";
public static final String ACTION_PROVISION_ACCOUNT = "provision_account";
- public static final String ACTION_CALL_INTEGRATION_SERVICE_STARTED = "call_integration_service_started";
private static final String ACTION_POST_CONNECTIVITY_CHANGE = "eu.siacs.conversations.POST_CONNECTIVITY_CHANGE";
public static final String ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS = "eu.siacs.conversations.UNIFIED_PUSH_RENEW";
public static final String ACTION_QUICK_LOG = "eu.siacs.conversations.QUICK_LOG";
@@ -249,7 +244,7 @@ public class XmppConnectionService extends Service {
private final ChannelDiscoveryService mChannelDiscoveryService = new ChannelDiscoveryService(this);
private final ShortcutService mShortcutService = new ShortcutService(this);
private final AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false);
- private final AtomicBoolean mOngoingVideoTranscoding = new AtomicBoolean(false);
+ private final AtomicBoolean mForceForegroundService = new AtomicBoolean(false);
private final AtomicBoolean mForceDuringOnCreate = new AtomicBoolean(false);
private final AtomicReference ongoingCall = new AtomicReference<>();
private final OnMessagePacketReceived mMessageParser = new MessageParser(this);
@@ -313,6 +308,16 @@ public class XmppConnectionService extends Service {
return false;
}
};
+ private final AtomicBoolean isPhoneInCall = new AtomicBoolean(false);
+ private final PhoneStateListener phoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onCallStateChanged(final int state, final String phoneNumber) {
+ isPhoneInCall.set(state != TelephonyManager.CALL_STATE_IDLE);
+ if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
+ mJingleConnectionManager.notifyPhoneCallStarted();
+ }
+ }
+ };
private boolean destroyed = false;
@@ -378,27 +383,16 @@ public class XmppConnectionService extends Service {
} else if (!account.getXmppConnection().getFeatures().bookmarksConversion()) {
fetchBookmarks(account);
}
-
- if (connection.getFeatures().mds()) {
- fetchMessageDisplayedSynchronization(account);
- } else {
- Log.d(Config.LOGTAG,account.getJid()+": server has no support for mds");
- }
final boolean flexible = account.getXmppConnection().getFeatures().flexibleOfflineMessageRetrieval();
final boolean catchup = getMessageArchiveService().inCatchup(account);
- final boolean trackOfflineMessageRetrieval;
if (flexible && catchup && account.getXmppConnection().isMamPreferenceAlways()) {
- trackOfflineMessageRetrieval = false;
sendIqPacket(account, mIqGenerator.purgeOfflineMessages(), (acc, packet) -> {
if (packet.getType() == IqPacket.TYPE.RESULT) {
Log.d(Config.LOGTAG, acc.getJid().asBareJid() + ": successfully purged offline messages");
}
});
- } else {
- trackOfflineMessageRetrieval = true;
}
sendPresence(account);
- account.getXmppConnection().trackOfflineMessageRetrieval(trackOfflineMessageRetrieval);
if (mPushManagementService.available(account)) {
mPushManagementService.registerPushTokenOnServer(account);
}
@@ -408,7 +402,6 @@ public class XmppConnectionService extends Service {
unifiedPushBroker.renewUnifiedPushEndpointsOnBind(account);
}
};
-
private final AtomicLong mLastExpiryRun = new AtomicLong(0);
private final LruCache, ServiceDiscoveryResult> discoCache = new LruCache<>(20);
private final OnStatusChanged statusListener = new OnStatusChanged() {
@@ -533,13 +526,13 @@ public class XmppConnectionService extends Service {
}
}
- public void startOngoingVideoTranscodingForegroundNotification() {
- mOngoingVideoTranscoding.set(true);
+ public void startForcingForegroundNotification() {
+ mForceForegroundService.set(true);
toggleForegroundService();
}
- public void stopOngoingVideoTranscodingForegroundNotification() {
- mOngoingVideoTranscoding.set(false);
+ public void stopForcingForegroundNotification() {
+ mForceForegroundService.set(false);
toggleForegroundService();
}
@@ -706,7 +699,7 @@ public class XmppConnectionService extends Service {
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
final String action = Strings.nullToEmpty(intent == null ? null : intent.getAction());
- final boolean needsForegroundService = intent != null && intent.getBooleanExtra(SystemEventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, false);
+ final boolean needsForegroundService = intent != null && intent.getBooleanExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, false);
if (needsForegroundService) {
Log.d(Config.LOGTAG, "toggle forced foreground service after receiving event (action=" + action + ")");
toggleForegroundService(true);
@@ -893,7 +886,9 @@ public class XmppConnectionService extends Service {
}
break;
case ACTION_IDLE_PING:
- scheduleNextIdlePing();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ scheduleNextIdlePing();
+ }
break;
case ACTION_FCM_MESSAGE_RECEIVED:
Log.d(Config.LOGTAG, "push message arrived in service. account");
@@ -917,12 +912,7 @@ public class XmppConnectionService extends Service {
}
return START_NOT_STICKY;
}
- final var extras = intent == null ? null : intent.getExtras();
- try {
- internalPingExecutor.execute(() -> manageAccountConnectionStates(action, extras));
- } catch (final RejectedExecutionException e) {
- Log.e(Config.LOGTAG, "can not schedule connection states manager");
- }
+ manageAccountConnectionStates(action, intent == null ? null : intent.getExtras());
if (SystemClock.elapsedRealtime() - mLastExpiryRun.get() >= Config.EXPIRY_INTERVAL) {
expireOldMessages();
}
@@ -950,45 +940,27 @@ public class XmppConnectionService extends Service {
manageAccountConnectionStates(ACTION_INTERNAL_PING, null);
}
- private synchronized void manageAccountConnectionStates(
- final String action, final Bundle extras) {
+ private synchronized void manageAccountConnectionStates(final String action, final Bundle extras) {
final String pushedAccountHash = extras == null ? null : extras.getString("account");
- final boolean interactive = java.util.Objects.equals(ACTION_TRY_AGAIN, action);
+ final boolean interactive = Arrays.asList(ACTION_TRY_AGAIN).contains(action);
WakeLockHelper.acquire(wakeLock);
- boolean pingNow =
- ConnectivityManager.CONNECTIVITY_ACTION.equals(action)
- || (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0
- && ACTION_POST_CONNECTIVITY_CHANGE.equals(action));
+ boolean pingNow = ConnectivityManager.CONNECTIVITY_ACTION.equals(action) || (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0 && ACTION_POST_CONNECTIVITY_CHANGE.equals(action));
final HashSet pingCandidates = new HashSet<>();
- final String androidId = pushedAccountHash == null ? null : PhoneHelper.getAndroidId(this);
+ final String androidId = PhoneHelper.getAndroidId(this);
for (final Account account : accounts) {
- final boolean pushWasMeantForThisAccount =
- androidId != null
- && CryptoHelper.getAccountFingerprint(account, androidId)
- .equals(pushedAccountHash);
- pingNow |=
- processAccountState(
- account,
- interactive,
- "ui".equals(action),
- pushWasMeantForThisAccount,
- pingCandidates);
+ final boolean pushWasMeantForThisAccount = CryptoHelper.getAccountFingerprint(account, androidId).equals(pushedAccountHash);
+ pingNow |= processAccountState(account,
+ interactive,
+ "ui".equals(action),
+ pushWasMeantForThisAccount,
+ pingCandidates);
}
if (pingNow) {
- for (final Account account : pingCandidates) {
+ for (Account account : pingCandidates) {
final boolean lowTimeout = isInLowPingTimeoutMode(account);
account.getXmppConnection().sendPing();
- Log.d(
- Config.LOGTAG,
- account.getJid().asBareJid()
- + " send ping (action="
- + action
- + ",lowTimeout="
- + lowTimeout
- + ")");
- scheduleWakeUpCall(
- lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT,
- account.getUuid().hashCode());
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + " send ping (action=" + action + ",lowTimeout=" + lowTimeout + ")");
+ scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
}
}
WakeLockHelper.release(wakeLock);
@@ -1002,7 +974,7 @@ public class XmppConnectionService extends Service {
}
}
- private boolean processAccountState(final Account account, final boolean interactive, final boolean isUiAction, final boolean isAccountPushed, final HashSet pingCandidates) {
+ private boolean processAccountState(Account account, boolean interactive, boolean isUiAction, boolean isAccountPushed, HashSet pingCandidates) {
if (!account.getStatus().isAttemptReconnect()) {
return false;
}
@@ -1097,10 +1069,15 @@ public class XmppConnectionService extends Service {
}
public boolean isDataSaverDisabled() {
- final ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);
- return !Compatibility.isActiveNetworkMetered(connectivityManager)
- || Compatibility.getRestrictBackgroundStatus(connectivityManager)
- == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ final ConnectivityManager connectivityManager =
+ (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
+ return !connectivityManager.isActiveNetworkMetered()
+ || Compatibility.getRestrictBackgroundStatus(connectivityManager)
+ == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
+ } else {
+ return true;
+ }
}
private void directReply(final Conversation conversation, final String body, final String lastMessageUuid, final boolean dismissAfterReply) {final Message inReplyTo = lastMessageUuid == null ? null : conversation.findMessageWithUuid(lastMessageUuid);
@@ -1181,23 +1158,23 @@ public class XmppConnectionService extends Service {
}
public boolean isScreenLocked() {
- final KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
- final PowerManager powerManager = getSystemService(PowerManager.class);
+ final KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+ final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
final boolean locked = keyguardManager != null && keyguardManager.isKeyguardLocked();
- final boolean interactive;
- try {
- interactive = powerManager != null && powerManager.isInteractive();
- } catch (final Exception e) {
- return false;
- }
+ final boolean interactive = powerManager != null && powerManager.isInteractive();
return locked || !interactive;
}
private boolean isPhoneSilenced() {
- final NotificationManager notificationManager = getSystemService(NotificationManager.class);
- final int filter = notificationManager == null ? NotificationManager.INTERRUPTION_FILTER_UNKNOWN : notificationManager.getCurrentInterruptionFilter();
- final boolean notificationDnd = filter >= NotificationManager.INTERRUPTION_FILTER_PRIORITY;
- final AudioManager audioManager = getSystemService(AudioManager.class);
+ final boolean notificationDnd;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ final NotificationManager notificationManager = getSystemService(NotificationManager.class);
+ final int filter = notificationManager == null ? NotificationManager.INTERRUPTION_FILTER_UNKNOWN : notificationManager.getCurrentInterruptionFilter();
+ notificationDnd = filter >= NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+ } else {
+ notificationDnd = false;
+ }
+ final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
final int ringerMode = audioManager == null ? AudioManager.RINGER_MODE_NORMAL : audioManager.getRingerMode();
try {
if (treatVibrateAsSilent()) {
@@ -1205,7 +1182,7 @@ public class XmppConnectionService extends Service {
} else {
return notificationDnd || ringerMode == AudioManager.RINGER_MODE_SILENT;
}
- } catch (final Throwable throwable) {
+ } catch (Throwable throwable) {
Log.d(Config.LOGTAG, "platform bug in isPhoneSilenced (" + throwable.getMessage() + ")");
return notificationDnd;
}
@@ -1301,7 +1278,7 @@ public class XmppConnectionService extends Service {
Log.e(Config.LOGTAG, "unable to initialize security provider", throwable);
}
Resolver.init(this);
- updateMemorizingTrustManager();
+ updateMemorizingTrustmanager();
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
this.mBitmapCache = new LruCache(cacheSize) {
@@ -1334,21 +1311,19 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, "restoring accounts...");
this.accounts = databaseBackend.getAccounts();
final SharedPreferences.Editor editor = getPreferences().edit();
+ if (this.accounts.size() == 0 && Arrays.asList("Sony", "Sony Ericsson").contains(Build.MANUFACTURER)) {
+ editor.putBoolean(SettingsActivity.KEEP_FOREGROUND_SERVICE, true);
+ Log.d(Config.LOGTAG, Build.MANUFACTURER + " is on blacklist. enabling foreground service");
+ }
final boolean hasEnabledAccounts = hasEnabledAccounts();
- editor.putBoolean(SystemEventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply();
+ editor.putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply();
editor.apply();
toggleSetProfilePictureActivity(hasEnabledAccounts);
reconfigurePushDistributor();
- if (CallIntegration.hasSystemFeature(this)) {
- CallIntegrationConnectionService.togglePhoneAccountsAsync(this, this.accounts);
- }
-
restoreFromDatabase();
- if (QuickConversationsService.isContactListIntegration(this)
- && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
- == PackageManager.PERMISSION_GRANTED) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
startContactObserver();
}
FILE_OBSERVER_EXECUTOR.execute(fileBackend::deleteHistoricAvatarPath);
@@ -1377,18 +1352,20 @@ public class XmppConnectionService extends Service {
this.pgpServiceConnection.bindToService();
}
- final PowerManager powerManager = getSystemService(PowerManager.class);
- this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Conversations:Service");
+ final PowerManager pm = ContextCompat.getSystemService(this, PowerManager.class);
+ this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Conversations:Service");
toggleForegroundService();
updateUnreadCountBadge();
toggleScreenEventReceiver();
final IntentFilter systemBroadcastFilter = new IntentFilter();
- scheduleNextIdlePing();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- systemBroadcastFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ scheduleNextIdlePing();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ systemBroadcastFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ }
+ systemBroadcastFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
}
- systemBroadcastFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
ContextCompat.registerReceiver(
this,
this.mInternalEventReceiver,
@@ -1403,21 +1380,23 @@ public class XmppConnectionService extends Service {
ContextCompat.RECEIVER_EXPORTED);
mForceDuringOnCreate.set(false);
toggleForegroundService();
+ setupPhoneStateListener();
internalPingExecutor.scheduleAtFixedRate(this::manageAccountConnectionStatesInternal,10,10,TimeUnit.SECONDS);
- final SharedPreferences sharedPreferences =
- androidx.preference.PreferenceManager.getDefaultSharedPreferences(this);
- sharedPreferences.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
- Log.d(Config.LOGTAG,"preference '"+key+"' has changed");
- if (AppSettings.KEEP_FOREGROUND_SERVICE.equals(key)) {
- toggleForegroundService();
- }
- }
- });
}
+ private void setupPhoneStateListener() {
+ final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+ if (telephonyManager == null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ return;
+ }
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ }
+
+ public boolean isPhoneInCall() {
+ return isPhoneInCall.get();
+ }
+
private void checkForDeletedFiles() {
if (destroyed) {
Log.d(Config.LOGTAG, "Do not check for deleted files because service has been destroyed");
@@ -1516,63 +1495,45 @@ public class XmppConnectionService extends Service {
toggleForegroundService(false);
}
- private void toggleForegroundService(final boolean force) {
+ private void toggleForegroundService(boolean force) {
final boolean status;
final OngoingCall ongoing = ongoingCall.get();
- final boolean ongoingVideoTranscoding = mOngoingVideoTranscoding.get();
- final int id;
- if (force
- || mForceDuringOnCreate.get()
- || ongoingVideoTranscoding
- || ongoing != null
- || (Compatibility.keepForegroundService(this) && hasEnabledAccounts())) {
+ if (force || mForceDuringOnCreate.get() || mForceForegroundService.get() || ongoing != null || (Compatibility.keepForegroundService(this) && hasEnabledAccounts())) {
final Notification notification;
+ final int id;
if (ongoing != null) {
notification = this.mNotificationService.getOngoingCallNotification(ongoing);
id = NotificationService.ONGOING_CALL_NOTIFICATION_ID;
- startForegroundOrCatch(id, notification, true);
- } else if (ongoingVideoTranscoding) {
- notification = this.mNotificationService.getIndeterminateVideoTranscoding();
- id = NotificationService.ONGOING_VIDEO_TRANSCODING_NOTIFICATION_ID;
- startForegroundOrCatch(id, notification, false);
+ startForegroundOrCatch(id, notification);
+ mNotificationService.cancel(NotificationService.FOREGROUND_NOTIFICATION_ID);
} else {
notification = this.mNotificationService.createForegroundNotification();
id = NotificationService.FOREGROUND_NOTIFICATION_ID;
- startForegroundOrCatch(id, notification, false);
+ startForegroundOrCatch(id, notification);
+ }
+
+ if (!mForceForegroundService.get()) {
+ mNotificationService.notify(id, notification);
}
- mNotificationService.notify(id, notification);
status = true;
} else {
- id = 0;
stopForeground(true);
status = false;
}
-
- for (final int toBeRemoved :
- Collections2.filter(
- Arrays.asList(
- NotificationService.FOREGROUND_NOTIFICATION_ID,
- NotificationService.ONGOING_CALL_NOTIFICATION_ID,
- NotificationService.ONGOING_VIDEO_TRANSCODING_NOTIFICATION_ID),
- i -> i != id)) {
- mNotificationService.cancel(toBeRemoved);
+ if (!mForceForegroundService.get()) {
+ mNotificationService.cancel(NotificationService.FOREGROUND_NOTIFICATION_ID);
}
- Log.d(
- Config.LOGTAG,
- "ForegroundService: " + (status ? "on" : "off") + ", notification: " + id);
+ if (ongoing == null) {
+ mNotificationService.cancel(NotificationService.ONGOING_CALL_NOTIFICATION_ID);
+ }
+ Log.d(Config.LOGTAG, "ForegroundService: " + (status ? "on" : "off"));
}
- private void startForegroundOrCatch(
- final int id, final Notification notification, final boolean requireMicrophone) {
+ private void startForegroundOrCatch(final int id, final Notification notification) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
final int foregroundServiceType;
- if (requireMicrophone
- && ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
- == PackageManager.PERMISSION_GRANTED) {
- foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
- Log.d(Config.LOGTAG, "defaulting to microphone foreground service type");
- } else if (getSystemService(PowerManager.class)
+ if (getSystemService(PowerManager.class)
.isIgnoringBatteryOptimizations(getPackageName())) {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED;
} else if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
@@ -1583,7 +1544,7 @@ public class XmppConnectionService extends Service {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
} else {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE;
- Log.w(Config.LOGTAG, "falling back to special use foreground service type");
+ Log.w(Config.LOGTAG,"falling back to special use foreground service type");
}
startForeground(id, notification, foregroundServiceType);
} else {
@@ -1595,13 +1556,13 @@ public class XmppConnectionService extends Service {
}
public boolean foregroundNotificationNeedsUpdatingWhenErrorStateChanges() {
- return !mOngoingVideoTranscoding.get() && ongoingCall.get() == null && Compatibility.keepForegroundService(this) && hasEnabledAccounts();
+ return !mForceForegroundService.get() && ongoingCall.get() == null && Compatibility.keepForegroundService(this) && hasEnabledAccounts();
}
@Override
public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent);
- if ((Compatibility.keepForegroundService(this) && hasEnabledAccounts()) || mOngoingVideoTranscoding.get() || ongoingCall.get() != null) {
+ if ((Compatibility.keepForegroundService(this) && hasEnabledAccounts()) || mForceForegroundService.get() || ongoingCall.get() != null) {
Log.d(Config.LOGTAG, "ignoring onTaskRemoved because foreground service is activated");
} else {
this.logoutAndSave(false);
@@ -1631,7 +1592,7 @@ public class XmppConnectionService extends Service {
return;
}
final long triggerAtMillis = SystemClock.elapsedRealtime() + (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL * 1000);
- final Intent intent = new Intent(this, SystemEventReceiver.class);
+ final Intent intent = new Intent(this, EventReceiver.class);
intent.setAction(ACTION_POST_CONNECTIVITY_CHANGE);
try {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, s()
@@ -1653,7 +1614,7 @@ public class XmppConnectionService extends Service {
if (alarmManager == null) {
return;
}
- final Intent intent = new Intent(this, SystemEventReceiver.class);
+ final Intent intent = new Intent(this, EventReceiver.class);
intent.setAction(ACTION_PING);
try {
final PendingIntent pendingIntent =
@@ -1672,7 +1633,7 @@ public class XmppConnectionService extends Service {
if (alarmManager == null) {
return;
}
- final Intent intent = new Intent(this, SystemEventReceiver.class);
+ final Intent intent = new Intent(this, EventReceiver.class);
intent.setAction(ACTION_IDLE_PING);
try {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, s()
@@ -1978,95 +1939,26 @@ public class XmppConnectionService extends Service {
public void fetchBookmarks2(final Account account) {
final IqPacket retrieve = mIqGenerator.retrieveBookmarks();
- sendIqPacket(account, retrieve, (a, response) -> {
- if (response.getType() == IqPacket.TYPE.RESULT) {
- final Element pubsub = response.findChild("pubsub", Namespace.PUBSUB);
- final Map bookmarks = Bookmark.parseFromPubsub(pubsub, a);
- processBookmarksInitial(a, bookmarks, true);
+ sendIqPacket(account, retrieve, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(final Account account, final IqPacket response) {
+ if (response.getType() == IqPacket.TYPE.RESULT) {
+ final Element pubsub = response.findChild("pubsub", Namespace.PUBSUB);
+ final Map bookmarks = Bookmark.parseFromPubsub(pubsub, account);
+ processBookmarksInitial(account, bookmarks, true);
+ }
}
});
}
- private void fetchMessageDisplayedSynchronization(final Account account) {
- Log.d(Config.LOGTAG, account.getJid() + ": retrieve mds");
- final var retrieve = mIqGenerator.retrieveMds();
- sendIqPacket(
- account,
- retrieve,
- (a, response) -> {
- if (response.getType() != IqPacket.TYPE.RESULT) {
- return;
- }
- final var pubSub = response.findChild("pubsub", Namespace.PUBSUB);
- final Element items = pubSub == null ? null : pubSub.findChild("items");
- if (items == null
- || !Namespace.MDS_DISPLAYED.equals(items.getAttribute("node"))) {
- return;
- }
- for (final Element child : items.getChildren()) {
- if ("item".equals(child.getName())) {
- processMdsItem(account, child);
- }
- }
- });
- }
-
- public void processMdsItem(final Account account, final Element item) {
- final Jid jid =
- item == null ? null : InvalidJid.getNullForInvalid(item.getAttributeAsJid("id"));
- if (jid == null) {
- return;
- }
- final Element displayed = item.findChild("displayed", Namespace.MDS_DISPLAYED);
- final Element stanzaId =
- displayed == null ? null : displayed.findChild("stanza-id", Namespace.STANZA_IDS);
- final String id = stanzaId == null ? null : stanzaId.getAttribute("id");
- final Conversation conversation = find(account, jid);
- if (id != null && conversation != null) {
- conversation.setDisplayState(id);
- markReadUpToStanzaId(conversation, id);
- }
- }
-
- public void markReadUpToStanzaId(final Conversation conversation, final String stanzaId) {
- final Message message = conversation.findMessageWithServerMsgId(stanzaId);
- if (message == null) { // do we want to check if isRead?
- return;
- }
- markReadUpTo(conversation, message);
- }
-
- public void markReadUpTo(final Conversation conversation, final Message message) {
- final boolean isDismissNotification = isDismissNotification(message);
- final var uuid = message.getUuid();
- Log.d(
- Config.LOGTAG,
- conversation.getAccount().getJid().asBareJid()
- + ": mark "
- + conversation.getJid().asBareJid()
- + " as read up to "
- + uuid);
- markRead(conversation, uuid, isDismissNotification);
- }
-
- private static boolean isDismissNotification(final Message message) {
- Message next = message.next();
- while (next != null) {
- if (message.getStatus() == Message.STATUS_RECEIVED) {
- return false;
- }
- next = next.next();
- }
- return true;
- }
-
- public void processBookmarksInitial(final Account account, final Map bookmarks, final boolean pep) {
+ public void processBookmarksInitial(Account account, Map bookmarks, final boolean pep) {
final Set previousBookmarks = account.getBookmarkedJids();
- for (final Bookmark bookmark : bookmarks.values()) {
+ final boolean synchronizeWithBookmarks = synchronizeWithBookmarks();
+ for (Bookmark bookmark : bookmarks.values()) {
previousBookmarks.remove(bookmark.getJid().asBareJid());
- processModifiedBookmark(bookmark, pep);
+ processModifiedBookmark(bookmark, pep, synchronizeWithBookmarks);
}
- if (pep) {
+ if (pep && synchronizeWithBookmarks) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": " + previousBookmarks.size() + " bookmarks have been removed");
for (Jid jid : previousBookmarks) {
processDeletedBookmark(account, jid);
@@ -2083,7 +1975,7 @@ public class XmppConnectionService extends Service {
}
}
- private void processModifiedBookmark(final Bookmark bookmark, final boolean pep) {
+ private void processModifiedBookmark(Bookmark bookmark, final boolean pep, final boolean synchronizeWithBookmarks) {
final Account account = bookmark.getAccount();
Conversation conversation = find(bookmark.getAccount(), bookmark.getJid(), null);
if (conversation != null) {
@@ -2091,7 +1983,7 @@ public class XmppConnectionService extends Service {
return;
}
bookmark.setConversation(conversation);
- if (pep && !bookmark.autojoin()) {
+ if (pep && synchronizeWithBookmarks && !bookmark.autojoin()) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": archiving conference (" + conversation.getJid() + ") after receiving pep");
archiveConversation(conversation, false);
} else {
@@ -2105,14 +1997,15 @@ public class XmppConnectionService extends Service {
}
}
}
- } else if (bookmark.autojoin()) {
+ } else if (synchronizeWithBookmarks && bookmark.autojoin()) {
conversation = findOrCreateConversation(account, bookmark.getFullJid(), null, true, true, false, null);
bookmark.setConversation(conversation);
}
}
- public void processModifiedBookmark(final Bookmark bookmark) {
- processModifiedBookmark(bookmark, true);
+ public void processModifiedBookmark(Bookmark bookmark) {
+ final boolean synchronizeWithBookmarks = synchronizeWithBookmarks();
+ processModifiedBookmark(bookmark, true, synchronizeWithBookmarks);
}
public void createBookmark(final Account account, final Bookmark bookmark) {
@@ -2194,7 +2087,7 @@ public class XmppConnectionService extends Service {
}
});
} else {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error publishing "+node+" (retry=" + retry + ") " + response);
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error publishing bookmarks (retry=" + retry + ") " + response);
}
});
}
@@ -2774,7 +2667,7 @@ public class XmppConnectionService extends Service {
if (conversation.getNextCounterpart() == null) {
if (conversation.getAccount().getStatus() == Account.State.ONLINE) {
final Bookmark bookmark = conversation.getBookmark();
- if (maySynchronizeWithBookmarks && bookmark != null) {
+ if (maySynchronizeWithBookmarks && bookmark != null && synchronizeWithBookmarks()) {
if (conversation.getMucOptions().getError() == MucOptions.Error.DESTROYED) {
Account account = bookmark.getAccount();
bookmark.setConversation(null);
@@ -2785,8 +2678,8 @@ public class XmppConnectionService extends Service {
}
}
}
+ leaveMuc(conversation);
}
- leaveMuc(conversation);
} else {
if (conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
stopPresenceUpdatesTo(conversation.getContact());
@@ -2807,9 +2700,6 @@ public class XmppConnectionService extends Service {
public void createAccount(final Account account) {
account.initAccountServices(this);
databaseBackend.createAccount(account);
- if (CallIntegration.hasSystemFeature(this)) {
- CallIntegrationConnectionService.togglePhoneAccountAsync(this, account);
- }
this.accounts.add(account);
this.reconnectAccountInBackground(account);
updateAccountUi();
@@ -2819,7 +2709,7 @@ public class XmppConnectionService extends Service {
private void syncEnabledAccountSetting() {
final boolean hasEnabledAccounts = hasEnabledAccounts();
- getPreferences().edit().putBoolean(SystemEventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply();
+ getPreferences().edit().putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply();
toggleSetProfilePictureActivity(hasEnabledAccounts);
}
@@ -2933,9 +2823,6 @@ public class XmppConnectionService extends Service {
toggleForegroundService();
syncEnabledAccountSetting();
mChannelDiscoveryService.cleanCache();
- if (CallIntegration.hasSystemFeature(this)) {
- CallIntegrationConnectionService.togglePhoneAccountAsync(this, account);
- }
return true;
} else {
return false;
@@ -2997,9 +2884,6 @@ public class XmppConnectionService extends Service {
};
mDatabaseWriterExecutor.execute(runnable);
this.accounts.remove(account);
- if (CallIntegration.hasSystemFeature(this)) {
- CallIntegrationConnectionService.unregisterPhoneAccount(this, account);
- }
this.mRosterSyncTaskManager.clear(account);
updateAccountUi();
mNotificationService.updateErrorNotification();
@@ -3536,12 +3420,14 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": fetching members for " + conversation.getName());
}
- public void providePasswordForMuc(final Conversation conversation, final String password) {
+ public void providePasswordForMuc(Conversation conversation, String password) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
conversation.getMucOptions().setPassword(password);
if (conversation.getBookmark() != null) {
final Bookmark bookmark = conversation.getBookmark();
- bookmark.setAutojoin(true);
+ if (synchronizeWithBookmarks()) {
+ bookmark.setAutojoin(true);
+ }
createBookmark(conversation.getAccount(), bookmark);
}
updateConversation(conversation);
@@ -3640,7 +3526,7 @@ public class XmppConnectionService extends Service {
new Thread(() -> onMediaLoaded.onMediaLoaded(fileBackend.convertToAttachments(databaseBackend.getRelativeFilePaths(account, jid, limit)))).start();
}
- public void persistSelfNick(final MucOptions.User self) {
+ public void persistSelfNick(MucOptions.User self) {
final Conversation conversation = self.getConversation();
final boolean tookProposedNickFromBookmark = conversation.getMucOptions().isTookProposedNickFromBookmark();
Jid full = self.getFullJid();
@@ -3652,10 +3538,11 @@ public class XmppConnectionService extends Service {
final Bookmark bookmark = conversation.getBookmark();
final String bookmarkedNick = bookmark == null ? null : bookmark.getNick();
- if (bookmark != null && (tookProposedNickFromBookmark || Strings.isNullOrEmpty(bookmarkedNick)) && !full.getResource().equals(bookmarkedNick)) {
+ if (bookmark != null && (tookProposedNickFromBookmark || TextUtils.isEmpty(bookmarkedNick)) && !full.getResource().equals(bookmarkedNick)) {
final Account account = conversation.getAccount();
final String defaultNick = MucOptions.defaultNick(account);
- if (Strings.isNullOrEmpty(bookmarkedNick) && full.getResource().equals(defaultNick)) {
+ if (TextUtils.isEmpty(bookmarkedNick) && full.getResource().equals(defaultNick)) {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": do not overwrite empty bookmark nick with default nick for " + conversation.getJid().asBareJid());
return;
}
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": persist nick '" + full.getResource() + "' into bookmark for " + conversation.getJid().asBareJid());
@@ -4686,7 +4573,7 @@ public class XmppConnectionService extends Service {
}
public long getAutomaticMessageDeletionDate() {
- final long timeout = getLongPreference(AppSettings.AUTOMATIC_MESSAGE_DELETION, R.integer.automatic_message_deletion);
+ final long timeout = getLongPreference(SettingsActivity.AUTOMATIC_MESSAGE_DELETION, R.integer.automatic_message_deletion);
return timeout == 0 ? timeout : (System.currentTimeMillis() - (timeout * 1000));
}
@@ -4715,16 +4602,20 @@ public class XmppConnectionService extends Service {
return getBooleanPreference("chat_states", R.bool.chat_states);
}
+ private boolean synchronizeWithBookmarks() {
+ return getBooleanPreference("autojoin", R.bool.autojoin);
+ }
+
public boolean useTorToConnect() {
return QuickConversationsService.isConversations() && getBooleanPreference("use_tor", R.bool.use_tor);
}
public boolean showExtendedConnectionOptions() {
- return QuickConversationsService.isConversations() && getBooleanPreference(AppSettings.SHOW_CONNECTION_OPTIONS, R.bool.show_connection_options);
+ return QuickConversationsService.isConversations() && getBooleanPreference("show_connection_options", R.bool.show_connection_options);
}
public boolean broadcastLastActivity() {
- return getBooleanPreference(AppSettings.BROADCAST_LAST_ACTIVITY, R.bool.last_activity);
+ return getBooleanPreference(SettingsActivity.BROADCAST_LAST_ACTIVITY, R.bool.last_activity);
}
public int unreadCount() {
@@ -4738,7 +4629,7 @@ public class XmppConnectionService extends Service {
private List threadSafeList(Set set) {
synchronized (LISTENER_LOCK) {
- return set.isEmpty() ? Collections.emptyList() : new ArrayList<>(set);
+ return set.size() == 0 ? Collections.emptyList() : new ArrayList<>(set);
}
}
@@ -4760,7 +4651,7 @@ public class XmppConnectionService extends Service {
}
}
- public void notifyJingleRtpConnectionUpdate(CallIntegration.AudioDevice selectedAudioDevice, Set availableAudioDevices) {
+ public void notifyJingleRtpConnectionUpdate(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set availableAudioDevices) {
for (OnJingleRtpConnectionUpdate listener : threadSafeList(this.onJingleRtpConnectionUpdate)) {
listener.onAudioDeviceChanged(selectedAudioDevice, availableAudioDevices);
}
@@ -4887,101 +4778,24 @@ public class XmppConnectionService extends Service {
}
}
- public void sendReadMarker(final Conversation conversation, final String upToUuid) {
- final boolean isPrivateAndNonAnonymousMuc =
- conversation.getMode() == Conversation.MODE_MULTI
- && conversation.isPrivateAndNonAnonymous();
+ public void sendReadMarker(final Conversation conversation, String upToUuid) {
+ final boolean isPrivateAndNonAnonymousMuc = conversation.getMode() == Conversation.MODE_MULTI && conversation.isPrivateAndNonAnonymous();
final List readMessages = this.markRead(conversation, upToUuid, true);
- if (readMessages.isEmpty()) {
- return;
+ if (readMessages.size() > 0) {
+ updateConversationUi();
}
- final var account = conversation.getAccount();
- final var connection = account.getXmppConnection();
- updateConversationUi();
- final var last =
- Iterables.getLast(
- Collections2.filter(
- readMessages,
- m ->
- !m.isPrivateMessage()
- && m.getStatus() == Message.STATUS_RECEIVED),
- null);
- if (last == null) {
- return;
- }
-
- final boolean sendDisplayedMarker =
- confirmMessages()
- && (last.trusted() || isPrivateAndNonAnonymousMuc)
- && last.getRemoteMsgId() != null
- && (last.markable || isPrivateAndNonAnonymousMuc);
- final boolean serverAssist =
- connection != null && connection.getFeatures().mdsServerAssist();
-
- final String stanzaId = last.getServerMsgId();
-
- if (sendDisplayedMarker && serverAssist) {
- final var mdsDisplayed = mIqGenerator.mdsDisplayed(stanzaId, conversation);
- final MessagePacket packet = mMessageGenerator.confirm(last);
- packet.addChild(mdsDisplayed);
- if (!last.isPrivateMessage()) {
- packet.setTo(packet.getTo().asBareJid());
- }
- Log.d(Config.LOGTAG,account.getJid().asBareJid()+": server assisted "+packet);
+ final Message markable = Conversation.getLatestMarkableMessage(readMessages, isPrivateAndNonAnonymousMuc);
+ if (confirmMessages()
+ && markable != null
+ && (markable.trusted() || isPrivateAndNonAnonymousMuc)
+ && markable.getRemoteMsgId() != null) {
+ Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": sending read marker to " + markable.getCounterpart().toString());
+ final Account account = conversation.getAccount();
+ final MessagePacket packet = mMessageGenerator.confirm(markable);
this.sendMessagePacket(account, packet);
- } else {
- publishMds(last);
- // read markers will be sent after MDS to flush the CSI stanza queue
- if (sendDisplayedMarker) {
- Log.d(
- Config.LOGTAG,
- conversation.getAccount().getJid().asBareJid()
- + ": sending displayed marker to "
- + last.getCounterpart().toString());
- final MessagePacket packet = mMessageGenerator.confirm(last);
- this.sendMessagePacket(account, packet);
- }
}
}
- private void publishMds(@Nullable final Message message) {
- final String stanzaId = message == null ? null : message.getServerMsgId();
- if (Strings.isNullOrEmpty(stanzaId)) {
- return;
- }
- final Conversation conversation;
- final var conversational = message.getConversation();
- if (conversational instanceof Conversation c) {
- conversation = c;
- } else {
- return;
- }
- final var account = conversation.getAccount();
- final var connection = account.getXmppConnection();
- if (connection == null || !connection.getFeatures().mds()) {
- return;
- }
- final Jid itemId;
- if (message.isPrivateMessage()) {
- itemId = message.getCounterpart();
- } else {
- itemId = conversation.getJid().asBareJid();
- }
- Log.d(Config.LOGTAG,"publishing mds for "+itemId+"/"+stanzaId);
- publishMds(account, itemId, stanzaId, conversation);
- }
-
- private void publishMds(
- final Account account, final Jid itemId, final String stanzaId, final Conversation conversation) {
- final var item = mIqGenerator.mdsDisplayed(stanzaId, conversation);
- pushNodeAndEnforcePublishOptions(
- account,
- Namespace.MDS_DISPLAYED,
- item,
- itemId.toEscapedString(),
- PublishOptions.persistentWhitelistAccessMaxItems());
- }
-
public MemorizingTrustManager getMemorizingTrustManager() {
return this.mMemorizingTrustManager;
}
@@ -4990,15 +4804,15 @@ public class XmppConnectionService extends Service {
this.mMemorizingTrustManager = trustManager;
}
- public void updateMemorizingTrustManager() {
- final MemorizingTrustManager trustManager;
- final var appSettings = new AppSettings(this);
- if (appSettings.isTrustSystemCAStore()) {
- trustManager = new MemorizingTrustManager(getApplicationContext());
+ public void updateMemorizingTrustmanager() {
+ final MemorizingTrustManager tm;
+ final boolean dontTrustSystemCAs = getBooleanPreference("dont_trust_system_cas", R.bool.dont_trust_system_cas);
+ if (dontTrustSystemCAs) {
+ tm = new MemorizingTrustManager(getApplicationContext(), null);
} else {
- trustManager = new MemorizingTrustManager(getApplicationContext(), null);
+ tm = new MemorizingTrustManager(getApplicationContext());
}
- setMemorizingTrustManager(trustManager);
+ setMemorizingTrustManager(tm);
}
public LruCache getBitmapCache() {
@@ -5025,6 +4839,9 @@ public class XmppConnectionService extends Service {
if (Config.QUICKSY_DOMAIN != null) {
hosts.remove(Config.QUICKSY_DOMAIN.toEscapedString()); //we only want to show this when we type a e164 number
}
+ if (Config.DOMAIN_LOCK != null) {
+ hosts.add(Config.DOMAIN_LOCK);
+ }
if (Config.MAGIC_CREATE_DOMAIN != null) {
hosts.add(Config.MAGIC_CREATE_DOMAIN);
}
@@ -5449,7 +5266,7 @@ public class XmppConnectionService extends Service {
return templates;
}
- public void saveConversationAsBookmark(final Conversation conversation, final String name) {
+ public void saveConversationAsBookmark(Conversation conversation, String name) {
final Account account = conversation.getAccount();
final Bookmark bookmark = new Bookmark(account, conversation.getJid().asBareJid());
final String nick = conversation.getJid().getResource();
@@ -5459,7 +5276,7 @@ public class XmppConnectionService extends Service {
if (!TextUtils.isEmpty(name)) {
bookmark.setBookmarkName(name);
}
- bookmark.setAutojoin(true);
+ bookmark.setAutojoin(getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin)));
createBookmark(account, bookmark);
bookmark.setConversation(conversation);
}
@@ -5507,7 +5324,7 @@ public class XmppConnectionService extends Service {
}
public boolean blindTrustBeforeVerification() {
- return getBooleanPreference(AppSettings.BLIND_TRUST_BEFORE_VERIFICATION, R.bool.btbv);
+ return getBooleanPreference(SettingsActivity.BLIND_TRUST_BEFORE_VERIFICATION, R.bool.btbv);
}
public ShortcutService getShortcutService() {
@@ -5574,7 +5391,7 @@ public class XmppConnectionService extends Service {
public interface OnJingleRtpConnectionUpdate {
void onJingleRtpConnectionUpdate(final Account account, final Jid with, final String sessionId, final RtpEndUserState state);
- void onAudioDeviceChanged(CallIntegration.AudioDevice selectedAudioDevice, Set availableAudioDevices);
+ void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set availableAudioDevices);
}
public interface OnAccountUpdate {
diff --git a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java
index 6ea969693..f2cd1e348 100644
--- a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java
+++ b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java
@@ -2,28 +2,26 @@ package eu.siacs.conversations.ui;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.preference.Preference;
import android.util.AttributeSet;
-import com.google.common.base.Strings;
-
import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.utils.PhoneHelper;
public class AboutPreference extends Preference {
- public AboutPreference(final Context context, final AttributeSet attrs, final int defStyle) {
- super(context, attrs, defStyle);
+ public AboutPreference(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
setSummaryAndTitle(context);
- }
+ }
- public AboutPreference(final Context context, final AttributeSet attrs) {
- super(context, attrs);
- setSummaryAndTitle(context);
- }
+ public AboutPreference(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ setSummaryAndTitle(context);
+ }
- private void setSummaryAndTitle(final Context context) {
- setSummary(String.format("%s %s %s (%s)", BuildConfig.APP_NAME, BuildConfig.VERSION_NAME, im.conversations.webrtc.BuildConfig.WEBRTC_VERSION, Strings.nullToEmpty(Build.DEVICE)));
+ private void setSummaryAndTitle(final Context context) {
+ setSummary(String.format("%s %s", BuildConfig.APP_NAME, BuildConfig.VERSION_NAME));
setTitle(context.getString(R.string.title_activity_about_x, BuildConfig.APP_NAME));
}
@@ -34,3 +32,4 @@ public class AboutPreference extends Preference {
getContext().startActivity(intent);
}
}
+
diff --git a/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java
index 0479598f8..21cf7d80f 100644
--- a/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java
@@ -14,7 +14,6 @@ import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
-import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import java.util.ArrayList;
@@ -36,7 +35,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
private final MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
@Override
- public boolean onMenuItemActionExpand(@NonNull final MenuItem item) {
+ public boolean onMenuItemActionExpand(final MenuItem item) {
mSearchEditText.post(() -> {
mSearchEditText.requestFocus();
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -47,7 +46,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
}
@Override
- public boolean onMenuItemActionCollapse(@NonNull final MenuItem item) {
+ public boolean onMenuItemActionCollapse(final MenuItem item) {
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
mSearchEditText.setText("");
@@ -94,7 +93,6 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this,R.layout.activity_choose_contact);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
this.binding.chooseContactList.setFastScrollEnabled(true);
@@ -127,7 +125,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
protected abstract void filterContacts(final String needle);
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
filterContacts();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java b/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java
index 42c5981c2..8564bcfcb 100644
--- a/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java
@@ -1,10 +1,14 @@
package eu.siacs.conversations.ui;
import android.view.MenuItem;
+import android.view.View;
import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
-public abstract class ActionBarActivity extends BaseActivity {
+
+public abstract class ActionBarActivity extends AppCompatActivity {
public static void configureActionBar(ActionBar actionBar) {
configureActionBar(actionBar, true);
}
@@ -16,11 +20,17 @@ public abstract class ActionBarActivity extends BaseActivity {
}
}
+ public void setSupportActionBar(View toolbar) {
+ super.setSupportActionBar((Toolbar) toolbar);
+ }
+
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ break;
}
return super.onOptionsItemSelected(item);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/eu/siacs/conversations/ui/Activities.java b/src/main/java/eu/siacs/conversations/ui/Activities.java
deleted file mode 100644
index d95d6b4ac..000000000
--- a/src/main/java/eu/siacs/conversations/ui/Activities.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.view.View;
-import com.google.android.material.elevation.SurfaceColors;
-
-public final class Activities {
-
- private Activities() {}
-
- public static void setStatusAndNavigationBarColors(final Activity activity, final View view) {
- setStatusAndNavigationBarColors(activity, view, false);
- }
-
- public static void setStatusAndNavigationBarColors(
- final Activity activity, final View view, final boolean raisedStatusBar) {
- final var isLightMode = isLightMode(activity);
- final var window = activity.getWindow();
- final var flags = view.getSystemUiVisibility();
- // an elevation of 4 matches the MaterialToolbar elevation
- if (raisedStatusBar) {
- window.setStatusBarColor(SurfaceColors.SURFACE_5.getColor(activity));
- } else {
- window.setStatusBarColor(SurfaceColors.SURFACE_0.getColor(activity));
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- window.setNavigationBarColor(SurfaceColors.SURFACE_1.getColor(activity));
- if (isLightMode) {
- view.setSystemUiVisibility(
- flags
- | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
- | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
- }
- } else if (isLightMode) {
- view.setSystemUiVisibility(flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
- }
- }
-
- private static boolean isLightMode(final Context context) {
- final int nightModeFlags =
- context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
- return nightModeFlags != Configuration.UI_MODE_NIGHT_YES;
- }
-
- public static boolean isNightMode(final Context context) {
- return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
- == Configuration.UI_MODE_NIGHT_YES;
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/ui/BaseActivity.java b/src/main/java/eu/siacs/conversations/ui/BaseActivity.java
deleted file mode 100644
index cea58c15e..000000000
--- a/src/main/java/eu/siacs/conversations/ui/BaseActivity.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import android.util.Log;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.app.AppCompatDelegate;
-
-import eu.siacs.conversations.Conversations;
-import eu.siacs.conversations.ui.util.SettingsUtils;
-
-public abstract class BaseActivity extends AppCompatActivity {
- private Boolean isDynamicColors;
-
- @Override
- public void onStart() {
- super.onStart();
- final int desiredNightMode = Conversations.getDesiredNightMode(this);
- if (setDesiredNightMode(desiredNightMode)) {
- return;
- }
- final boolean isDynamicColors = Conversations.isDynamicColorsDesired(this);
- setDynamicColors(isDynamicColors);
- }
-
- @Override
- protected void onResume(){
- super.onResume();
- SettingsUtils.applyScreenshotSetting(this);
- }
-
- public void setDynamicColors(final boolean isDynamicColors) {
- if (this.isDynamicColors == null) {
- this.isDynamicColors = isDynamicColors;
- } else {
- if (this.isDynamicColors != isDynamicColors) {
- Log.i(
- "Recreating {} because dynamic color setting has changed",
- getClass().getSimpleName());
- recreate();
- }
- }
- }
-
- public boolean setDesiredNightMode(final int desiredNightMode) {
- if (desiredNightMode == AppCompatDelegate.getDefaultNightMode()) {
- return false;
- }
- AppCompatDelegate.setDefaultNightMode(desiredNightMode);
- Log.i("Recreating {} because desired night mode has changed", getClass().getSimpleName());
- recreate();
- return true;
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java
index 04678c3c7..986aeb563 100644
--- a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java
+++ b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java
@@ -7,8 +7,6 @@ import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.DialogBlockContactBinding;
import eu.siacs.conversations.entities.Blockable;
@@ -21,7 +19,7 @@ public final class BlockContactDialog {
show(xmppActivity, blockable, null);
}
public static void show(final XmppActivity xmppActivity, final Blockable blockable, final String serverMsgId) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(xmppActivity);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(xmppActivity);
final boolean isBlocked = blockable.isBlocked();
builder.setNegativeButton(R.string.cancel, null);
DialogBlockContactBinding binding = DataBindingUtil.inflate(xmppActivity.getLayoutInflater(), R.layout.dialog_block_contact, null, false);
@@ -72,7 +70,7 @@ public final class BlockContactDialog {
} else {
boolean toastShown = false;
if (xmppActivity.xmppConnectionService.sendBlockRequest(blockable, binding.reportSpam.isChecked(), serverMsgId)) {
- Toast.makeText(xmppActivity, R.string.corresponding_chats_closed, Toast.LENGTH_SHORT).show();
+ Toast.makeText(xmppActivity, R.string.corresponding_conversations_closed, Toast.LENGTH_SHORT).show();
toastShown = true;
}
if (xmppActivity instanceof ContactDetailsActivity) {
diff --git a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java
index 20eac8bc3..21a90ffd8 100644
--- a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java
@@ -90,7 +90,7 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem
dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid, x, y) -> {
Blockable blockable = new RawBlockable(account, contactJid);
if (xmppConnectionService.sendBlockRequest(blockable, false, null)) {
- Toast.makeText(BlocklistActivity.this, R.string.corresponding_chats_closed, Toast.LENGTH_SHORT).show();
+ Toast.makeText(BlocklistActivity.this, R.string.corresponding_conversations_closed, Toast.LENGTH_SHORT).show();
}
return true;
});
diff --git a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
index fba273b0a..c2a334821 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
@@ -3,84 +3,86 @@ package eu.siacs.conversations.ui;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
import android.widget.Toast;
-import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.textfield.TextInputLayout;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivityChangePasswordBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.widget.DisabledActionModeCallback;
public class ChangePasswordActivity extends XmppActivity implements XmppConnectionService.OnAccountPasswordChanged {
- private ActivityChangePasswordBinding binding;
-
+ private Button mChangePasswordButton;
private final View.OnClickListener mOnChangePasswordButtonClicked = new View.OnClickListener() {
@Override
- public void onClick(final View view) {
- final var account = mAccount;
- if (account == null) {
- return;
- }
- final String currentPassword = binding.currentPassword.getText().toString();
- final String newPassword = binding.newPassword.getText().toString();
- if (!account.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(account.getPassword())) {
- binding.currentPassword.requestFocus();
- binding.currentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
- removeErrorsOnAllBut(binding.currentPasswordLayout);
+ public void onClick(View view) {
+ if (mAccount != null) {
+ final String currentPassword = mCurrentPassword.getText().toString();
+ final String newPassword = mNewPassword.getText().toString();
+ if (!mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(mAccount.getPassword())) {
+ mCurrentPassword.requestFocus();
+ mCurrentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
+ removeErrorsOnAllBut(mCurrentPasswordLayout);
} else if (newPassword.trim().isEmpty()) {
- binding.newPassword.requestFocus();
- binding.newPasswordLayout.setError(getString(R.string.password_should_not_be_empty));
- removeErrorsOnAllBut(binding.newPasswordLayout);
+ mNewPassword.requestFocus();
+ mNewPasswordLayout.setError(getString(R.string.password_should_not_be_empty));
+ removeErrorsOnAllBut(mNewPasswordLayout);
} else {
- binding.currentPasswordLayout.setError(null);
- binding.newPasswordLayout.setError(null);
- xmppConnectionService.updateAccountPasswordOnServer(account, newPassword, ChangePasswordActivity.this);
- binding.changePasswordButton.setEnabled(false);
- binding.changePasswordButton.setText(R.string.updating);
+ mCurrentPasswordLayout.setError(null);
+ mNewPasswordLayout.setError(null);
+ xmppConnectionService.updateAccountPasswordOnServer(mAccount, newPassword, ChangePasswordActivity.this);
+ mChangePasswordButton.setEnabled(false);
+ mChangePasswordButton.setText(R.string.updating);
}
+ }
}
};
-
-
-
+ private EditText mCurrentPassword;
+ private EditText mNewPassword;
+ private TextInputLayout mNewPasswordLayout;
+ private TextInputLayout mCurrentPasswordLayout;
private Account mAccount;
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
this.mAccount = extractAccount(getIntent());
if (this.mAccount != null && this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
- this.binding.currentPasswordLayout.setVisibility(View.GONE);
+ this.mCurrentPasswordLayout.setVisibility(View.GONE);
} else {
- this.binding.currentPasswordLayout.setVisibility(View.VISIBLE);
+ this.mCurrentPassword.setVisibility(View.VISIBLE);
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- this.binding = DataBindingUtil.setContentView(this, R.layout.activity_change_password);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
- setSupportActionBar(binding.toolbar);
+ setContentView(R.layout.activity_change_password);
+ setSupportActionBar(findViewById(R.id.toolbar));
configureActionBar(getSupportActionBar());
- binding.cancelButton.setOnClickListener(view -> finish());
- binding.changePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
- binding.currentPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
- binding.newPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
+ Button mCancelButton = findViewById(R.id.left_button);
+ mCancelButton.setOnClickListener(view -> finish());
+ this.mChangePasswordButton = findViewById(R.id.right_button);
+ this.mChangePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
+ this.mCurrentPassword = findViewById(R.id.current_password);
+ this.mCurrentPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
+ this.mNewPassword = findViewById(R.id.new_password);
+ this.mNewPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
+ this.mCurrentPasswordLayout = findViewById(R.id.current_password_layout);
+ this.mNewPasswordLayout = findViewById(R.id.new_password_layout);
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
Intent intent = getIntent();
String password = intent != null ? intent.getStringExtra("password") : null;
if (password != null) {
- binding.newPassword.getEditableText().clear();
- binding.newPassword.getEditableText().append(password);
+ this.mNewPassword.getEditableText().clear();
+ this.mNewPassword.getEditableText().append(password);
}
}
@@ -95,21 +97,21 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
@Override
public void onPasswordChangeFailed() {
runOnUiThread(() -> {
- binding.newPasswordLayout.setError(getString(R.string.could_not_change_password));
- binding.changePasswordButton.setEnabled(true);
- binding.changePasswordButton.setText(R.string.change_password);
+ mNewPasswordLayout.setError(getString(R.string.could_not_change_password));
+ mChangePasswordButton.setEnabled(true);
+ mChangePasswordButton.setText(R.string.change_password);
});
}
private void removeErrorsOnAllBut(TextInputLayout exception) {
- if (this.binding.currentPasswordLayout != exception) {
- this.binding.currentPasswordLayout.setErrorEnabled(false);
- this.binding.currentPasswordLayout.setError(null);
+ if (this.mCurrentPasswordLayout != exception) {
+ this.mCurrentPasswordLayout.setErrorEnabled(false);
+ this.mCurrentPasswordLayout.setError(null);
}
- if (this.binding.newPasswordLayout != exception) {
- this.binding.newPasswordLayout.setErrorEnabled(false);
- this.binding.newPasswordLayout.setError(null);
+ if (this.mNewPasswordLayout != exception) {
+ this.mNewPasswordLayout.setErrorEnabled(false);
+ this.mNewPasswordLayout.setError(null);
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java
index f114a83db..4568a5abe 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java
@@ -18,8 +18,6 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import com.google.common.base.Strings;
@@ -64,7 +62,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
if (optedIn || method == ChannelDiscoveryService.Method.LOCAL_SERVER) {
final String query;
if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) {
@@ -132,7 +130,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
}
@Override
- public boolean onMenuItemActionExpand(@NonNull MenuItem item) {
+ public boolean onMenuItemActionExpand(MenuItem item) {
mSearchEditText.post(() -> {
mSearchEditText.requestFocus();
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -142,7 +140,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
}
@Override
- public boolean onMenuItemActionCollapse(@NonNull MenuItem item) {
+ public boolean onMenuItemActionCollapse(MenuItem item) {
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
mSearchEditText.setText("");
@@ -191,7 +189,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
}
@Override
- public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
+ public void onSaveInstanceState(Bundle savedInstanceState) {
if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) {
savedInstanceState.putString("search", mSearchEditText != null ? mSearchEditText.getText().toString() : null);
}
@@ -221,8 +219,8 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
runOnUiThread(() -> {
adapter.submitList(results);
binding.progressBar.setVisibility(View.GONE);
- if (results.isEmpty()) {
- binding.list.setBackground(ContextCompat.getDrawable(this,R.drawable.background_no_results));
+ if (results.size() == 0) {
+ binding.list.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_primary_background_no_results));
} else {
binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
}
@@ -235,7 +233,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
final List accounts = AccountUtils.getEnabledAccounts(xmppConnectionService);
if (accounts.size() == 1) {
joinChannelSearchResult(accounts.get(0), result);
- } else if (accounts.isEmpty()) {
+ } else if (accounts.size() == 0) {
Toast.makeText(this, R.string.please_enable_an_account, Toast.LENGTH_LONG).show();
} else {
final AtomicReference account = new AtomicReference<>(accounts.get(0));
@@ -250,44 +248,40 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
}
@Override
- public boolean onContextItemSelected(@NonNull MenuItem item) {
+ public boolean onContextItemSelected(MenuItem item) {
final Room room = adapter.getCurrent();
- if (room == null) {
- return false;
- }
- final int itemId = item.getItemId();
- if (itemId == R.id.share_with) {
- StartConversationActivity.shareAsChannel(this, room.address);
- return true;
- } else if (itemId == R.id.open_join_dialog) {
- final Intent intent = new Intent(this, StartConversationActivity.class);
- intent.setAction(Intent.ACTION_VIEW);
- intent.putExtra("force_dialog", true);
- intent.setData(Uri.parse(String.format("xmpp:%s?join", room.address)));
- startActivity(intent);
- return true;
- } else {
- return false;
+ if (room != null) {
+ switch (item.getItemId()) {
+ case R.id.share_with:
+ StartConversationActivity.shareAsChannel(this, room.address);
+ return true;
+ case R.id.open_join_dialog:
+ final Intent intent = new Intent(this, StartConversationActivity.class);
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.putExtra("force_dialog", true);
+ intent.setData(Uri.parse(String.format("xmpp:%s?join", room.address)));
+ startActivity(intent);
+ return true;
+ }
}
+ return false;
}
- public void joinChannelSearchResult(final String selectedAccount, final Room result) {
- final Jid jid = Jid.ofEscaped(selectedAccount);
+ public void joinChannelSearchResult(String selectedAccount, Room result) {
+ final Jid jid = Config.DOMAIN_LOCK == null ? Jid.ofEscaped(selectedAccount) : Jid.ofLocalAndDomainEscaped(selectedAccount, Config.DOMAIN_LOCK);
+ final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin);
final Account account = xmppConnectionService.findAccountByJid(jid);
- final Conversation conversation =
- xmppConnectionService.findOrCreateConversation(
- account, result.getRoom(), null, true, true, true, null);
-
- final var existingBookmark = conversation.getBookmark();
- if (existingBookmark == null) {
- final var bookmark = new Bookmark(account, conversation.getJid().asBareJid());
- bookmark.setAutojoin(true);
- xmppConnectionService.createBookmark(account, bookmark);
- } else {
- if (!existingBookmark.autojoin()) {
- existingBookmark.setAutojoin(true);
- xmppConnectionService.createBookmark(account, existingBookmark);
+ final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), null, true, true, true, null);
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark != null) {
+ if (!bookmark.autojoin() && syncAutoJoin) {
+ bookmark.setAutojoin(true);
+ xmppConnectionService.createBookmark(account, bookmark);
}
+ } else {
+ bookmark = new Bookmark(account, conversation.getJid().asBareJid());
+ bookmark.setAutojoin(syncAutoJoin);
+ xmppConnectionService.createBookmark(account, bookmark);
}
switchToConversation(conversation);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java
index 71662589c..af1fb7656 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java
@@ -3,21 +3,20 @@ package eu.siacs.conversations.ui;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.widget.ListView;
import android.widget.Toast;
-import androidx.databinding.DataBindingUtil;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
-import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.ui.adapter.AccountAdapter;
-
import java.util.ArrayList;
import java.util.List;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.ui.adapter.AccountAdapter;
+
public class ChooseAccountForProfilePictureActivity extends XmppActivity {
protected final List accountList = new ArrayList<>();
+ protected ListView accountListView;
protected AccountAdapter mAccountAdapter;
@Override
@@ -29,25 +28,29 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final ActivityManageAccountsBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
- setSupportActionBar(binding.toolbar);
+ setContentView(R.layout.activity_manage_accounts);
+ setSupportActionBar(findViewById(R.id.toolbar));
configureActionBar(getSupportActionBar(), false);
+ accountListView = findViewById(R.id.account_list);
this.mAccountAdapter = new AccountAdapter(this, accountList, false);
- binding.accountList.setAdapter(this.mAccountAdapter);
- binding.accountList.setOnItemClickListener((arg0, view, position, arg3) -> {
+ accountListView.setAdapter(this.mAccountAdapter);
+ accountListView.setOnItemClickListener((arg0, view, position, arg3) -> {
final Account account = accountList.get(position);
goToProfilePictureActivity(account);
});
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
+ final int theme = findTheme();
+ if (this.mTheme != theme) {
+ recreate();
+ }
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
loadEnabledAccounts();
if (accountList.size() == 1) {
goToProfilePictureActivity(accountList.get(0));
diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java
index 41237f392..d6c80b61b 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java
@@ -9,7 +9,6 @@ import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.SoundEffectConstants;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView.MultiChoiceModeListener;
@@ -52,7 +51,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
public static final String EXTRA_SHOW_ENTER_JID = "extra_show_enter_jid";
public static final String EXTRA_CONVERSATION = "extra_conversation";
private static final String EXTRA_FILTERED_CONTACTS = "extra_filtered_contacts";
- private final ArrayList mActivatedAccounts = new ArrayList<>();
+ private final List mActivatedAccounts = new ArrayList<>();
private final Set selected = new HashSet<>();
private Set filterContacts;
@@ -131,7 +130,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
if (this.showEnterJid) {
this.binding.fab.show();
} else {
- binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
+ binding.fab.setImageResource(R.drawable.ic_forward_white_24dp);
}
final SharedPreferences preferences = getPreferences();
@@ -149,7 +148,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
private void onFabClicked(View v) {
- if (selected.isEmpty()) {
+ if (selected.size() == 0) {
showEnterJidDialog(null);
} else {
submitSelection();
@@ -164,8 +163,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle(getTitleFromIntent());
- binding.chooseContactList.setFastScrollEnabled(false);
- binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
+ binding.fab.setImageResource(R.drawable.ic_forward_white_24dp);
binding.fab.show();
final View view = getSearchEditText();
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -177,13 +175,12 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public void onDestroyActionMode(ActionMode mode) {
- this.binding.fab.setImageResource(R.drawable.ic_person_add_24dp);
+ this.binding.fab.setImageResource(R.drawable.ic_person_add_white_24dp);
if (this.showEnterJid) {
this.binding.fab.show();
} else {
this.binding.fab.hide();
}
- binding.chooseContactList.setFastScrollEnabled(true);
selected.clear();
}
@@ -211,9 +208,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
if (selected.size() != 0) {
- getListView().playSoundEffect(SoundEffectConstants.CLICK);
+ getListView().playSoundEffect(0);
}
- getListItemAdapter().notifyDataSetChanged();
Contact item = (Contact) getListItems().get(position);
if (checked) {
selected.add(item.getJid().toString());
@@ -382,12 +378,16 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
filterContacts();
this.mActivatedAccounts.clear();
- for (final Account account : xmppConnectionService.getAccounts()) {
+ for (Account account : xmppConnectionService.getAccounts()) {
if (account.isEnabled()) {
- this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
+ if (Config.DOMAIN_LOCK != null) {
+ this.mActivatedAccounts.add(account.getJid().getEscapedLocal());
+ } else {
+ this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
+ }
}
}
ActivityResult activityResult = this.postponedActivityResult.pop();
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index dd80bf8bd..89c5f9a52 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -244,7 +244,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
@@ -271,6 +271,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
case R.id.action_save_as_bookmark:
saveAsBookmark();
break;
+ case R.id.action_delete_bookmark:
+ deleteBookmark();
+ break;
case R.id.action_destroy_room:
destroyRoom();
break;
@@ -305,7 +308,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
final MucOptions mucOptions = mConversation.getMucOptions();
this.binding.mucEditor.setVisibility(View.VISIBLE);
this.binding.mucDisplay.setVisibility(View.GONE);
- this.binding.editMucNameButton.setImageResource(R.drawable.ic_cancel_24dp);
+ this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
final String name = mucOptions.getName();
this.binding.mucEditTitle.setText("");
final boolean owner = mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER);
@@ -379,7 +382,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
private void hideEditor() {
this.binding.mucEditor.setVisibility(View.GONE);
this.binding.mucDisplay.setVisibility(View.VISIBLE);
- this.binding.editMucNameButton.setImageResource(R.drawable.ic_edit_24dp);
+ this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_edit_body, R.drawable.ic_edit_black_24dp));
}
private void onMucInfoUpdated(String subject, String name) {
@@ -410,21 +413,28 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
- public boolean onPrepareOptionsMenu(final Menu menu) {
- final MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
- final MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
- final MenuItem menuItemDestroyRoom = menu.findItem(R.id.action_destroy_room);
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
+ MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
+ MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
+ MenuItem menuItemDestroyRoom = menu.findItem(R.id.action_destroy_room);
menuItemAdvancedMode.setChecked(mAdvancedMode);
if (mConversation == null) {
return true;
}
- menuItemSaveBookmark.setVisible(mConversation.getBookmark() == null);
+ if (mConversation.getBookmark() != null) {
+ menuItemSaveBookmark.setVisible(false);
+ menuItemDeleteBookmark.setVisible(true);
+ } else {
+ menuItemDeleteBookmark.setVisible(false);
+ menuItemSaveBookmark.setVisible(true);
+ }
menuItemDestroyRoom.setVisible(mConversation.getMucOptions().getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER));
return true;
}
@Override
- public boolean onCreateOptionsMenu(final Menu menu) {
+ public boolean onCreateOptionsMenu(Menu menu) {
final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
getMenuInflater().inflate(R.menu.muc_details, menu);
final MenuItem share = menu.findItem(R.id.action_share);
@@ -450,6 +460,14 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
xmppConnectionService.saveConversationAsBookmark(mConversation, mConversation.getMucOptions().getName());
}
+ protected void deleteBookmark() {
+ final Account account = mConversation.getAccount();
+ final Bookmark bookmark = mConversation.getBookmark();
+ bookmark.setConversation(null);
+ xmppConnectionService.deleteBookmark(account, bookmark);
+ updateView();
+ }
+
protected void destroyRoom() {
final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -465,7 +483,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
if (mPendingConferenceInvite != null) {
mPendingConferenceInvite.execute(this);
mPendingConferenceInvite = null;
@@ -523,7 +541,12 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
final MucOptions mucOptions = mConversation.getMucOptions();
final User self = mucOptions.getSelf();
- final String account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
+ String account;
+ if (Config.DOMAIN_LOCK != null) {
+ account = mConversation.getAccount().getJid().getEscapedLocal();
+ } else {
+ account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
+ }
setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details);
final Bookmark bookmark = mConversation.getBookmark();
this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject() || (bookmark != null && mConversation.getAccount().getXmppConnection().getFeatures().bookmarks2())) ? View.VISIBLE : View.GONE);
@@ -556,7 +579,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
StylingHelper.format(spannable, this.binding.mucSubject.getCurrentTextColor());
MyLinkify.addLinks(spannable, false);
this.binding.mucSubject.setText(spannable);
- this.binding.mucSubject.setTextAppearance( subject.length() > (hasTitle ? 128 : 196) ? com.google.android.material.R.style.TextAppearance_Material3_BodyMedium : com.google.android.material.R.style.TextAppearance_Material3_BodyLarge);
+ this.binding.mucSubject.setTextAppearance(this, subject.length() > (hasTitle ? 128 : 196) ? R.style.TextAppearance_Conversations_Body1_Linkified : R.style.TextAppearance_Conversations_Subhead);
this.binding.mucSubject.setAutoLinkMask(0);
this.binding.mucSubject.setVisibility(View.VISIBLE);
this.binding.mucSubject.setMovementMethod(LinkMovementMethod.getInstance());
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index a932a400b..f184358fe 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -8,7 +8,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.content.res.ColorStateList;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -36,15 +35,8 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.ViewCompat;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.color.MaterialColors;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.google.common.collect.ImmutableList;
-import com.google.common.primitives.Ints;
-
import org.openintents.openpgp.util.OpenPgpUtils;
import java.util.ArrayList;
@@ -55,7 +47,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import eu.siacs.conversations.AppSettings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -66,9 +57,7 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.services.AbstractQuickConversationsService;
-import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.MediaAdapter;
@@ -85,7 +74,6 @@ import eu.siacs.conversations.utils.Emoticons;
import eu.siacs.conversations.utils.IrregularUnicodeDetector;
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.utils.XEP0392Helper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
@@ -147,13 +135,13 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
private void checkContactPermissionAndShowAddDialog() {
if (hasContactsPermission()) {
showAddToPhoneBookDialog();
- } else if (QuickConversationsService.isContactListIntegration(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
}
}
private boolean hasContactsPermission() {
- if (QuickConversationsService.isContactListIntegration(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
} else {
return true;
@@ -213,7 +201,6 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
protected void refreshUiReal() {
- invalidateOptionsMenu();
populateView();
}
@@ -527,7 +514,12 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid()));
- final String account = contact.getAccount().getJid().asBareJid().toEscapedString();
+ String account;
+ if (Config.DOMAIN_LOCK != null) {
+ account = contact.getAccount().getJid().getEscapedLocal();
+ } else {
+ account = contact.getAccount().getJid().asBareJid().toEscapedString();
+ }
binding.detailsAccount.setText(getString(R.string.using_account, account));
AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size);
binding.detailsContactBadge.setOnClickListener(this::onBadgeClick);
@@ -589,7 +581,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
TextView keyType = view.findViewById(R.id.key_type);
keyType.setText(R.string.openpgp_key_id);
if ("pgp".equals(messageFingerprint)) {
- keyType.setTextColor(MaterialColors.getColor(keyType, com.google.android.material.R.attr.colorPrimaryVariant));
+ keyType.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
}
key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
final OnClickListener openKey = v -> launchOpenKeyChain(contact.getPgpKeyId());
@@ -600,77 +592,33 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
binding.keysWrapper.setVisibility(hasKeys ? View.VISIBLE : View.GONE);
- final List tagList = contact.getTags(this);
- final boolean hasMetaTags = contact.isBlocked() || contact.getShownStatus() != Presence.Status.OFFLINE;
- if ((tagList.isEmpty() && !hasMetaTags) || !this.showDynamicTags) {
+ List tagList = contact.getTags(this);
+ if (tagList.size() == 0 || !this.showDynamicTags) {
binding.tags.setVisibility(View.GONE);
} else {
binding.tags.setVisibility(View.VISIBLE);
- binding.tags.removeViews(1, binding.tags.getChildCount() - 1);
- final ImmutableList.Builder viewIdBuilder = new ImmutableList.Builder<>();
+ binding.tags.removeAllViewsInLayout();
for (final ListItem.Tag tag : tagList) {
- final String name = tag.getName();
final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, binding.tags, false);
- tv.setText(name);
- tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(this,XEP0392Helper.rgbFromNick(name))));
- final int id = ViewCompat.generateViewId();
- tv.setId(id);
- viewIdBuilder.add(id);
+ tv.setText(tag.getName());
+ tv.setBackgroundColor(tag.getColor());
binding.tags.addView(tv);
}
- if (contact.isBlocked()) {
- final TextView tv =
- (TextView)
- inflater.inflate(
- R.layout.list_item_tag, binding.tags, false);
- tv.setText(R.string.blocked);
- tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(tv.getContext(), ContextCompat.getColor(tv.getContext(),R.color.gray_800))));
- final int id = ViewCompat.generateViewId();
- tv.setId(id);
- viewIdBuilder.add(id);
- binding.tags.addView(tv);
- } else {
- final Presence.Status status = contact.getShownStatus();
- if (status != Presence.Status.OFFLINE) {
- final TextView tv =
- (TextView)
- inflater.inflate(
- R.layout.list_item_tag, binding.tags, false);
- UIHelper.setStatus(tv, status);
- final int id = ViewCompat.generateViewId();
- tv.setId(id);
- viewIdBuilder.add(id);
- binding.tags.addView(tv);
- }
- }
- binding.flowWidget.setReferencedIds(Ints.toArray(viewIdBuilder.build()));
}
}
- private void onBadgeClick(final View view) {
- if (QuickConversationsService.isContactListIntegration(this)) {
- final Uri systemAccount = contact.getSystemAccount();
- if (systemAccount == null) {
- checkContactPermissionAndShowAddDialog();
- } else {
- final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(systemAccount);
- try {
- startActivity(intent);
- } catch (final ActivityNotFoundException e) {
- Toast.makeText(
- this,
- R.string.no_application_found_to_view_contact,
- Toast.LENGTH_SHORT)
- .show();
- }
- }
+ private void onBadgeClick(View view) {
+ final Uri systemAccount = contact.getSystemAccount();
+ if (systemAccount == null) {
+ checkContactPermissionAndShowAddDialog();
} else {
- Toast.makeText(
- this,
- R.string.contact_list_integration_not_available,
- Toast.LENGTH_SHORT)
- .show();
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(systemAccount);
+ try {
+ startActivity(intent);
+ } catch (final ActivityNotFoundException e) {
+ Toast.makeText(this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show();
+ }
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index da5231357..2d9fe91ae 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -16,4 +16,10 @@ public class ConversationActivity extends AppCompatActivity {
startActivity(new Intent(this, ConversationsActivity.class));
finish();
}
+
+ @Override
+ protected void onResume(){
+ super.onResume();
+ SettingsUtils.applyScreenshotPreventionSetting(this);
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 12fcbfc52..747e2f48c 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -27,7 +27,6 @@ import android.content.IntentSender.SendIntentException;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.content.res.ColorStateList;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -121,7 +120,6 @@ import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.http.HttpDownloadConnection;
import eu.siacs.conversations.medialib.activities.EditActivity;
import eu.siacs.conversations.persistance.FileBackend;
-import eu.siacs.conversations.services.CallIntegrationConnectionService;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -169,19 +167,6 @@ import eu.siacs.conversations.xmpp.jingle.Media;
import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
-import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
public class ConversationFragment extends XmppFragment
implements EditMessage.KeyboardListener,
@@ -1293,7 +1278,7 @@ public class ConversationFragment extends XmppFragment
};
if (conversation == null
|| conversation.getMode() == Conversation.MODE_MULTI
- || Attachment.canBeSendInBand(attachments)
+ || Attachment.canBeSendInband(attachments)
|| (conversation.getAccount().httpUploadAvailable()
&& FileBackend.allFilesUnderSize(
getActivity(), attachments, getMaxHttpUploadSize(conversation)))) {
@@ -2070,27 +2055,21 @@ public class ConversationFragment extends XmppFragment
if (ongoingRtpSession.isPresent()) {
final OngoingRtpSession id = ongoingRtpSession.get();
final Intent intent = new Intent(activity, RtpSessionActivity.class);
- intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(
RtpSessionActivity.EXTRA_ACCOUNT,
id.getAccount().getJid().asBareJid().toEscapedString());
intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.getWith().toEscapedString());
- if (id instanceof AbstractJingleConnection) {
+ if (id instanceof AbstractJingleConnection.Id) {
+ intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.getSessionId());
- startActivity(intent);
- } else if (id instanceof JingleConnectionManager.RtpSessionProposal proposal) {
- if (Media.audioOnly(proposal.media)) {
- intent.putExtra(
- RtpSessionActivity.EXTRA_LAST_ACTION,
- RtpSessionActivity.ACTION_MAKE_VOICE_CALL);
+ } else if (id instanceof JingleConnectionManager.RtpSessionProposal) {
+ if (((JingleConnectionManager.RtpSessionProposal) id).media.contains(Media.VIDEO)) {
+ intent.setAction(RtpSessionActivity.ACTION_MAKE_VIDEO_CALL);
} else {
- intent.putExtra(
- RtpSessionActivity.EXTRA_LAST_ACTION,
- RtpSessionActivity.ACTION_MAKE_VIDEO_CALL);
+ intent.setAction(RtpSessionActivity.ACTION_MAKE_VOICE_CALL);
}
- intent.putExtra(RtpSessionActivity.EXTRA_PROPOSED_SESSION_ID, proposal.sessionId);
- activity.startActivity(intent);
}
+ activity.startActivity(intent);
}
}
@@ -2153,7 +2132,7 @@ public class ConversationFragment extends XmppFragment
activity.xmppConnectionService.updateAccount(account);
}
final Contact contact = conversation.getContact();
- if (Config.USE_JINGLE_MESSAGE_INIT && RtpCapability.jmiSupport(contact)) {
+ if (RtpCapability.jmiSupport(contact)) {
triggerRtpSession(contact.getAccount(), contact.getJid().asBareJid(), action);
} else {
final RtpCapability.Capability capability;
@@ -2173,7 +2152,13 @@ public class ConversationFragment extends XmppFragment
}
private void triggerRtpSession(final Account account, final Jid with, final String action) {
- CallIntegrationConnectionService.placeCall(activity.xmppConnectionService, account,with,RtpSessionActivity.actionToMedia(action));
+ final Intent intent = new Intent(activity, RtpSessionActivity.class);
+ intent.setAction(action);
+ intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, account.getJid().toEscapedString());
+ intent.putExtra(RtpSessionActivity.EXTRA_WITH, with.toEscapedString());
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(intent);
}
private void handleAttachmentSelection(MenuItem item) {
@@ -2501,22 +2486,26 @@ public class ConversationFragment extends XmppFragment
}
private boolean hasPermissions(int requestCode, List permissions) {
- final List missingPermissions = new ArrayList<>();
- for (String permission : permissions) {
- if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU || Config.ONLY_INTERNAL_STORAGE) && permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- continue;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ final List missingPermissions = new ArrayList<>();
+ for (String permission : permissions) {
+ if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU || Config.ONLY_INTERNAL_STORAGE) && permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ continue;
+ }
+ if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ missingPermissions.add(permission);
+ }
}
- if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
- missingPermissions.add(permission);
+ if (missingPermissions.size() == 0) {
+ return true;
+ } else {
+ requestPermissions(
+ missingPermissions.toArray(new String[0]),
+ requestCode);
+ return false;
}
- }
- if (missingPermissions.size() == 0) {
- return true;
} else {
- requestPermissions(
- missingPermissions.toArray(new String[0]),
- requestCode);
- return false;
+ return true;
}
}
@@ -2854,7 +2843,7 @@ public class ConversationFragment extends XmppFragment
}
@Override
- public void onSaveInstanceState(@NonNull Bundle outState) {
+ public void onSaveInstanceState(@NotNull Bundle outState) {
super.onSaveInstanceState(outState);
if (conversation != null) {
outState.putString(STATE_CONVERSATION_UUID, conversation.getUuid());
@@ -3284,10 +3273,10 @@ public class ConversationFragment extends XmppFragment
final Iterator iterator = uris.iterator();
while (iterator.hasNext()) {
final Uri uri = iterator.next();
- if (FileBackend.dangerousFile(uri)) {
+ if (FileBackend.weOwnFile(uri)) {
iterator.remove();
Toast.makeText(
- requireActivity(),
+ getActivity(),
R.string.security_violation_not_attaching_file,
Toast.LENGTH_SHORT)
.show();
@@ -3920,8 +3909,9 @@ public class ConversationFragment extends XmppFragment
});
}
- public void showNoPGPKeyDialog(final boolean plural, final DialogInterface.OnClickListener listener) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
+ public void showNoPGPKeyDialog(boolean plural, DialogInterface.OnClickListener listener) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setIconAttribute(android.R.attr.alertDialogIcon);
if (plural) {
builder.setTitle(getString(R.string.no_pgp_keys));
builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
index 18d9313ca..bb76ea271 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
@@ -61,8 +61,6 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
import org.openintents.openpgp.util.OpenPgpApi;
import java.util.Arrays;
@@ -76,6 +74,7 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OmemoSetting;
import eu.siacs.conversations.databinding.ActivityConversationsBinding;
+import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Conversational;
@@ -85,11 +84,11 @@ import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
import eu.siacs.conversations.ui.interfaces.OnConversationRead;
import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
import eu.siacs.conversations.ui.interfaces.OnConversationsListItemUpdated;
+import eu.siacs.conversations.ui.util.ActionBarUtil;
import eu.siacs.conversations.ui.util.ActivityResult;
import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PendingItem;
-import eu.siacs.conversations.ui.util.ToolbarUtils;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
import eu.siacs.conversations.utils.SignupUtils;
@@ -154,7 +153,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
if (performRedirectIfNecessary(true)) {
return;
}
@@ -237,8 +236,10 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private boolean openBatteryOptimizationDialogIfNeeded() {
- if (isOptimizingBattery() && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ if (isOptimizingBattery()
+ && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M
+ && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.battery_optimizations_enabled);
builder.setMessage(getString(R.string.battery_optimizations_enabled_dialog, getString(R.string.app_name)));
builder.setPositiveButton(R.string.next, (dialog, which) -> {
@@ -484,8 +485,9 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
conversationFragment.reInit(conversation, extras == null ? new Bundle() : extras);
if (mainNeedsRefresh) {
refreshFragment(R.id.main_fragment);
+ } else {
+ invalidateActionBarTitle();
}
- invalidateActionBarTitle();
}
private static void executePendingTransactions(final FragmentManager fragmentManager) {
@@ -600,7 +602,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
@@ -684,8 +686,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
final FragmentManager fragmentManager = getFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
- if (mainFragment instanceof ConversationFragment conversationFragment) {
- final Conversation conversation = conversationFragment.getConversation();
+ if (mainFragment instanceof ConversationFragment) {
+ final Conversation conversation = ((ConversationFragment) mainFragment).getConversation();
if (conversation != null) {
if (conversation.getNextCounterpart() != null) {
actionBar.setTitle(getString(R.string.muc_private_conversation_title, conversation.getNextCounterpart().getResource(), conversation.getName()));
@@ -693,26 +695,16 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
actionBar.setTitle(conversation.getName());
}
actionBar.setDisplayHomeAsUpEnabled(true);
- ToolbarUtils.setActionBarOnClickListener(
+ ActionBarUtil.setActionBarOnClickListener(
binding.toolbar,
(v) -> openConversationDetails(conversation)
);
return;
}
}
- final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
- if (secondaryFragment instanceof ConversationFragment conversationFragment) {
- final Conversation conversation = conversationFragment.getConversation();
- if (conversation != null) {
- actionBar.setTitle(conversation.getName());
- } else {
- actionBar.setTitle(R.string.app_name);
- }
- } else {
- actionBar.setTitle(R.string.app_name);
- }
+ actionBar.setTitle(R.string.app_name);
actionBar.setDisplayHomeAsUpEnabled(false);
- ToolbarUtils.resetActionBarOnClickListeners(binding.toolbar);
+ ActionBarUtil.resetActionBarOnClickListeners(binding.toolbar);
}
private void openConversationDetails(final Conversation conversation) {
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
index 89f121de1..2527167aa 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
@@ -64,7 +64,6 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
-import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.FragmentConversationsOverviewBinding;
@@ -76,7 +75,6 @@ import eu.siacs.conversations.entities.Conversational;
import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.services.XmppConnectionService;
-import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
@@ -170,7 +168,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
title = R.string.title_undo_swipe_out_channel;
}
} else {
- title = R.string.title_undo_swipe_out_chat;
+ title = R.string.title_undo_swipe_out_conversation;
}
final Snackbar snackbar = Snackbar.make(binding.list, title, 5000)
@@ -331,11 +329,6 @@ public class ConversationsOverviewFragment extends XmppFragment {
MenuItem noteToSelf = menu.findItem(R.id.action_note_to_self);
easyOnboardInvite.setVisible(EasyOnboardingInvite.anyHasSupport(activity == null ? null : activity.xmppConnectionService));
- final MenuItem privacyPolicyMenuItem = menu.findItem(R.id.action_privacy_policy);
- privacyPolicyMenuItem.setVisible(
- BuildConfig.PRIVACY_POLICY != null
- && QuickConversationsService.isPlayStoreFlavor());
-
if (activity == null || activity.xmppConnectionService == null || activity.xmppConnectionService.getAccounts().size() != 1) {
noteToSelf.setVisible(false);
}
@@ -467,7 +460,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
private void selectAccountToStartEasyInvite() {
final List accounts = EasyOnboardingInvite.getSupportingAccounts(activity.xmppConnectionService);
- if (accounts.isEmpty()) {
+ if (accounts.size() == 0) {
//This can technically happen if opening the menu item races with accounts reconnecting or something
Toast.makeText(getActivity(),R.string.no_active_accounts_support_this, Toast.LENGTH_LONG).show();
} else if (accounts.size() == 1) {
diff --git a/src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java b/src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java
index ae3406a2d..6e4098264 100644
--- a/src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java
+++ b/src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java
@@ -3,20 +3,18 @@ package eu.siacs.conversations.ui;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
-import android.widget.AutoCompleteTextView;
+import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.DialogCreateConferenceBinding;
+import eu.siacs.conversations.databinding.CreateConferenceDialogBinding;
import eu.siacs.conversations.ui.util.DelayedHintHelper;
public class CreatePrivateGroupChatDialog extends DialogFragment {
@@ -41,9 +39,9 @@ public class CreatePrivateGroupChatDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.create_private_group_chat);
- final DialogCreateConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_conference, null, false);
+ CreateConferenceDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_conference_dialog, null, false);
ArrayList mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY);
StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account);
builder.setView(binding.getRoot());
@@ -59,7 +57,7 @@ public class CreatePrivateGroupChatDialog extends DialogFragment {
public interface CreateConferenceDialogListener {
- void onCreateDialogPositiveClick(AutoCompleteTextView spinner, String subject);
+ void onCreateDialogPositiveClick(Spinner spinner, String subject);
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java b/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java
index b20db451d..8f5e2e6d2 100644
--- a/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java
+++ b/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java
@@ -17,14 +17,13 @@ import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.DialogCreatePublicChannelBinding;
+import eu.siacs.conversations.databinding.CreatePublicChannelDialogBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
@@ -45,7 +44,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
private boolean nameEntered = false;
private boolean skipTetxWatcher = false;
- public static CreatePublicChannelDialog newInstance(final List accounts) {
+ public static CreatePublicChannelDialog newInstance(List accounts) {
CreatePublicChannelDialog dialog = new CreatePublicChannelDialog();
Bundle bundle = new Bundle();
bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList) accounts);
@@ -64,9 +63,9 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
public Dialog onCreateDialog(Bundle savedInstanceState) {
jidWasModified = savedInstanceState != null && savedInstanceState.getBoolean("jid_was_modified_false", false);
nameEntered = savedInstanceState != null && savedInstanceState.getBoolean("name_entered", false);
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.create_public_channel);
- final DialogCreatePublicChannelBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_public_channel, null, false);
+ final CreatePublicChannelDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_public_channel_dialog, null, false);
binding.account.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
@@ -108,7 +107,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
builder.setPositiveButton(nameEntered ? R.string.create : R.string.next, null);
builder.setNegativeButton(nameEntered ? R.string.back : R.string.cancel, null);
DelayedHintHelper.setHint(R.string.channel_bare_jid_example, binding.jid);
- this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
+ this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
binding.jid.setAdapter(knownHostsAdapter);
final AlertDialog dialog = builder.create();
binding.groupChatName.setOnEditorActionListener((v, actionId, event) -> {
@@ -122,7 +121,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
return dialog;
}
- private void updateJidSuggestion(final DialogCreatePublicChannelBinding binding) {
+ private void updateJidSuggestion(CreatePublicChannelDialogBinding binding) {
if (jidWasModified) {
return;
}
@@ -139,7 +138,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
super.onSaveInstanceState(outState);
}
- private static String getJidSuggestion(final DialogCreatePublicChannelBinding binding) {
+ private static String getJidSuggestion(CreatePublicChannelDialogBinding binding) {
final Account account = StartConversationActivity.getSelectedAccount(binding.getRoot().getContext(), binding.account);
final XmppConnection connection = account == null ? null : account.getXmppConnection();
if (connection == null) {
@@ -170,7 +169,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
return name.replaceAll("\\s+","-");
}
- private void goBack(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
+ private void goBack(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
if (nameEntered) {
nameEntered = false;
updateInputs(binding, true);
@@ -180,7 +179,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
}
- private void submit(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
+ private void submit(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
final Context context = binding.getRoot().getContext();
final Editable nameText = binding.groupChatName.getText();
final String name = nameText == null ? "" : nameText.toString().trim();
@@ -228,7 +227,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
- private void updateInputs(final DialogCreatePublicChannelBinding binding, final boolean requestFocus) {
+ private void updateInputs(CreatePublicChannelDialogBinding binding, boolean requestFocus) {
binding.xmppAddressLayout.setVisibility(nameEntered ? View.VISIBLE : View.GONE);
binding.nameLayout.setVisibility(nameEntered ? View.GONE : View.VISIBLE);
if (!requestFocus) {
@@ -266,7 +265,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
@Override
- public void onAttach(@NonNull Context context) {
+ public void onAttach(Context context) {
super.onAttach(context);
try {
mListener = (CreatePublicChannelDialogListener) context;
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 59b902d56..792df76a7 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -33,15 +33,19 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog.Builder;
import androidx.databinding.DataBindingUtil;
-import androidx.lifecycle.Lifecycle;
-import com.google.android.material.color.MaterialColors;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import com.google.common.base.CharMatcher;
-import eu.siacs.conversations.AppSettings;
+import org.openintents.openpgp.util.OpenPgpUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -78,16 +82,8 @@ import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.XmppConnection.Features;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.pep.Avatar;
-
import okhttp3.HttpUrl;
-import org.openintents.openpgp.util.OpenPgpUtils;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
public class EditAccountActivity extends OmemoActivity implements OnAccountUpdate, OnUpdateBlocklist,
OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched {
@@ -102,7 +98,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private Jid jidToEdit;
private boolean mInitMode = false;
private Boolean mForceRegister = null;
- private boolean mUsernameMode = false;
+ private boolean mUsernameMode = Config.DOMAIN_LOCK != null;
private boolean mShowOptions = false;
private Account mAccount;
private final OnClickListener mCancelButtonClickListener = v -> {
@@ -613,7 +609,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.mSavedInstanceInit = savedInstanceState.getBoolean("initMode", false);
}
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_edit_account);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
binding.accountJid.addTextChangedListener(this.mTextWatcher);
binding.accountJid.setOnFocusChangeListener(this.mEditTextFocusListener);
@@ -702,10 +697,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
final Intent intent = getIntent();
- if (intent != null) {
+ final int theme = findTheme();
+ if (this.mTheme != theme) {
+ recreate();
+ } else if (intent != null) {
try {
this.jidToEdit = Jid.ofEscaped(intent.getStringExtra("jid"));
} catch (final IllegalArgumentException | NullPointerException ignored) {
@@ -760,7 +758,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
private void displayVerificationWarningDialog(final XmppUri xmppUri) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.verify_omemo_keys);
View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
final CheckBox isTrustedSource = view.findViewById(R.id.trusted_source);
@@ -775,7 +773,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish());
- final var dialog = builder.create();
+ AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.setOnCancelListener(d -> finish());
dialog.show();
@@ -837,7 +835,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.binding.accountJidLayout.setHint(getString(R.string.username_hint));
} else {
final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
- R.layout.item_autocomplete,
+ R.layout.simple_list_item,
xmppConnectionService.getKnownHosts());
this.binding.accountJid.setAdapter(mKnownHostsAdapter);
}
@@ -855,7 +853,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mAccount != null && mAccount.getJid().getDomain() != null) {
return mAccount.getServer();
} else {
- return null;
+ return Config.DOMAIN_LOCK;
}
}
@@ -941,8 +939,8 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private void changePresence() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- boolean manualStatus = sharedPreferences.getBoolean(AppSettings.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence));
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ boolean manualStatus = sharedPreferences.getBoolean(SettingsActivity.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence));
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
final DialogPresenceBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_presence, null, false);
String current = mAccount.getPresenceStatusMessage();
if (current != null && !current.trim().isEmpty()) {
@@ -951,7 +949,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
setAvailabilityRadioButton(mAccount.getPresenceStatus(), binding);
binding.show.setVisibility(manualStatus ? View.VISIBLE : View.GONE);
List templates = xmppConnectionService.getPresenceTemplates(mAccount);
- PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this, R.layout.item_autocomplete, templates);
+ PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this, R.layout.simple_list_item, templates);
binding.statusMessage.setAdapter(presenceTemplateAdapter);
binding.statusMessage.setOnItemClickListener((parent, view, position, id) -> {
PresenceTemplate template = (PresenceTemplate) parent.getItemAtPosition(position);
@@ -1146,7 +1144,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.binding.pgpFingerprint.setText(OpenPgpUtils.convertKeyIdToHex(pgpKeyId));
this.binding.pgpFingerprint.setOnClickListener(openPgp);
if ("pgp".equals(messageFingerprint)) {
- this.binding.pgpFingerprintDesc.setTextColor(MaterialColors.getColor(binding.pgpFingerprintDesc, com.google.android.material.R.attr.colorPrimaryVariant));
+ this.binding.pgpFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
}
this.binding.pgpFingerprintDesc.setOnClickListener(openPgp);
this.binding.actionDeletePgp.setOnClickListener(delete);
@@ -1157,10 +1155,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
this.binding.axolotlFingerprintBox.setVisibility(View.VISIBLE);
if (ownAxolotlFingerprint.equals(messageFingerprint)) {
- this.binding.ownFingerprintDesc.setTextColor(MaterialColors.getColor(binding.ownFingerprintDesc, com.google.android.material.R.attr.colorPrimaryVariant));
+ this.binding.ownFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
this.binding.ownFingerprintDesc.setText(R.string.omemo_fingerprint_selected_message);
} else {
- this.binding.ownFingerprintDesc.setTextColor(MaterialColors.getColor(binding.ownFingerprintDesc, com.google.android.material.R.attr.colorOnSurface));
+ this.binding.ownFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption);
this.binding.ownFingerprintDesc.setText(R.string.omemo_fingerprint);
}
this.binding.axolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(ownAxolotlFingerprint.substring(2)));
@@ -1224,10 +1222,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private void updateDisplayName(String displayName) {
if (TextUtils.isEmpty(displayName)) {
this.binding.yourName.setText(R.string.no_name_set_instructions);
- this.binding.yourName.setTextColor(MaterialColors.getColor(binding.yourName, com.google.android.material.R.attr.colorOnSurfaceVariant));
+ this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1_Tertiary);
} else {
this.binding.yourName.setText(displayName);
- this.binding.yourName.setTextColor(MaterialColors.getColor(binding.yourName, com.google.android.material.R.attr.colorOnSurfaceVariant));
+ this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1);
}
}
@@ -1251,7 +1249,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
private void showDeletePgpDialog() {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.unpublish_pgp);
builder.setMessage(R.string.unpublish_pgp_message);
builder.setNegativeButton(R.string.cancel, null);
@@ -1281,7 +1279,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
Toast.makeText(EditAccountActivity.this, getString(R.string.device_does_not_support_data_saver, getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
}
});
- } else if (showBatteryWarning) {
+ } else if (showBatteryWarning && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
this.binding.osOptimizationDisable.setText(R.string.disable);
this.binding.osOptimizationHeadline.setText(R.string.battery_optimizations_enabled);
this.binding.osOptimizationBody.setText(getString(R.string.battery_optimizations_enabled_explained, getString(R.string.app_name)));
@@ -1299,7 +1297,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
public void showWipePepDialog() {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ Builder builder = new Builder(this);
builder.setTitle(getString(R.string.clear_other_devices));
builder.setIconAttribute(android.R.attr.alertDialogIcon);
builder.setMessage(getString(R.string.clear_other_devices_desc));
@@ -1326,11 +1324,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mCaptchaDialog != null && mCaptchaDialog.isShowing()) {
mCaptchaDialog.dismiss();
}
- if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
- Log.d(Config.LOGTAG,"activity not running when captcha was requested");
- return;
- }
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(EditAccountActivity.this);
+ final Builder builder = new Builder(EditAccountActivity.this);
final View view = getLayoutInflater().inflate(R.layout.captcha, null);
final ImageView imageView = view.findViewById(R.id.captcha);
final EditText input = view.findViewById(R.id.input);
@@ -1378,7 +1372,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mFetchingMamPrefsToast != null) {
mFetchingMamPrefsToast.cancel();
}
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(EditAccountActivity.this);
+ Builder builder = new Builder(EditAccountActivity.this);
builder.setTitle(R.string.server_side_mam_prefs);
String defaultAttr = prefs.getAttribute("default");
final List defaults = Arrays.asList("never", "roster", "always");
diff --git a/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java b/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java
index f8ecfe9d6..f0793f743 100644
--- a/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java
+++ b/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java
@@ -33,8 +33,9 @@ import java.util.Map;
import io.michaelrocks.libphonenumber.android.NumberParseException;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.DialogEnterJidBinding;
+import eu.siacs.conversations.databinding.EnterJidDialogBinding;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -67,7 +68,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
private KnownHostsAdapter knownHostsAdapter;
private Collection whitelistedDomains = Collections.emptyList();
- private DialogEnterJidBinding binding;
+ private EnterJidDialogBinding binding;
private AlertDialog dialog;
private SanityCheck sanityCheckJid = SanityCheck.NO;
@@ -81,7 +82,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
}
public static EnterJidDialog newInstance(
- final ArrayList activatedAccounts,
+ final List activatedAccounts,
final String title,
final String positiveButton,
final String secondaryButton,
@@ -132,7 +133,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
binding.jid.setAdapter(this.knownHostsAdapter);
binding.jid.addTextChangedListener(this);
- final String prefilledJid = arguments.getString(PREFILLED_JID_KEY);
+ String prefilledJid = getArguments().getString(PREFILLED_JID_KEY);
if (prefilledJid != null) {
binding.jid.append(prefilledJid);
if (!getArguments().getBoolean(ALLOW_EDIT_JID_KEY)) {
diff --git a/src/main/java/eu/siacs/conversations/ui/ExtendedFabSizeChanger.java b/src/main/java/eu/siacs/conversations/ui/ExtendedFabSizeChanger.java
deleted file mode 100644
index 6c21f1a2d..000000000
--- a/src/main/java/eu/siacs/conversations/ui/ExtendedFabSizeChanger.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
-
-public class ExtendedFabSizeChanger extends RecyclerView.OnScrollListener {
-
- private final ExtendedFloatingActionButton extendedFloatingActionButton;
-
- private ExtendedFabSizeChanger(
- final ExtendedFloatingActionButton extendedFloatingActionButton) {
- this.extendedFloatingActionButton = extendedFloatingActionButton;
- }
-
- @Override
- public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
- super.onScrolled(recyclerView, dx, dy);
- if (RecyclerViews.findFirstVisibleItemPosition(recyclerView) > 0) {
- extendedFloatingActionButton.shrink();
- } else {
- extendedFloatingActionButton.extend();
- }
- }
-
- public static RecyclerView.OnScrollListener of(final ExtendedFloatingActionButton fab) {
- return new ExtendedFabSizeChanger(fab);
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java b/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java
index 7ed3fbd9d..e17aab3a4 100644
--- a/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java
+++ b/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java
@@ -13,7 +13,6 @@ import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import java.util.ArrayList;
@@ -51,11 +50,11 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.join_public_channel);
- final DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false);
+ DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false);
DelayedHintHelper.setHint(R.string.channel_full_jid_example, binding.jid);
- this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
+ this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
binding.jid.setAdapter(knownHostsAdapter);
String prefilledJid = getArguments().getString(PREFILLED_JID_KEY);
if (prefilledJid != null) {
@@ -118,6 +117,6 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon
}
public interface JoinConferenceDialogListener {
- void onJoinDialogPositiveClick(Dialog dialog, AutoCompleteTextView spinner, TextInputLayout jidLayout, AutoCompleteTextView jid, boolean isBookmarkChecked);
+ void onJoinDialogPositiveClick(Dialog dialog, Spinner spinner, TextInputLayout jidLayout, AutoCompleteTextView jid, boolean isBookmarkChecked);
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/LocationActivity.java b/src/main/java/eu/siacs/conversations/ui/LocationActivity.java
index 141874b48..49ca027c0 100644
--- a/src/main/java/eu/siacs/conversations/ui/LocationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/LocationActivity.java
@@ -40,6 +40,7 @@ import eu.siacs.conversations.ui.util.LocationHelper;
import eu.siacs.conversations.ui.widget.Marker;
import eu.siacs.conversations.ui.widget.MyLocation;
import eu.siacs.conversations.ui.util.SettingsUtils;
+import eu.siacs.conversations.utils.ThemeHelper;
public abstract class LocationActivity extends ActionBarActivity implements LocationListener {
protected LocationManager locationManager;
@@ -77,6 +78,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context ctx = getApplicationContext();
+ setTheme(ThemeHelper.find(this));
Integer override = ThemeHelper.findThemeOverrideStyle(this);
if (override != null) {
@@ -93,7 +95,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
// Ask for location permissions if location services are enabled and we're
// just starting the activity (we don't want to keep pestering them on every
// screen rotation or if there's no point because it's disabled anyways).
- if (savedInstanceState == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && savedInstanceState == null) {
requestPermissions(REQUEST_CODE_CREATE);
}
@@ -227,6 +229,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
@Override
protected void onResume() {
super.onResume();
+ SettingsUtils.applyScreenshotPreventionSetting(this);
Configuration.getInstance().load(this, getPreferences());
map.onResume();
this.setMyLoc(null);
@@ -241,11 +244,13 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
}
}
+ @TargetApi(Build.VERSION_CODES.M)
protected boolean hasLocationPermissions() {
return (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED);
}
+ @TargetApi(Build.VERSION_CODES.M)
protected void requestPermissions(final int request_code) {
if (!hasLocationPermissions()) {
requestPermissions(
diff --git a/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java b/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java
index ac5b07e77..3793203dd 100644
--- a/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java
@@ -29,7 +29,6 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this,R.layout.activity_media_browser);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
@@ -44,7 +43,7 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
Intent intent = getIntent();
String account = intent == null ? null : intent.getStringExtra("account");
String jid = intent == null ? null : intent.getStringExtra("jid");
diff --git a/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java b/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java
index fa86cbffa..56056f505 100644
--- a/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java
@@ -66,7 +66,7 @@ public class MemorizingActivity extends AppCompatActivity implements OnClickList
@Override
public void onResume() {
super.onResume();
- SettingsUtils.applyScreenshotSetting(this);
+ SettingsUtils.applyScreenshotPreventionSetting(this);
Intent i = getIntent();
decisionId = i.getIntExtra(MemorizingTrustManager.DECISION_INTENT_ID, MTMDecision.DECISION_INVALID);
diff --git a/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java b/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java
index 72cad4cd0..e759ee18e 100644
--- a/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java
@@ -49,7 +49,7 @@ public class MucUsersActivity extends XmppActivity implements XmppConnectionServ
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
final Intent intent = getIntent();
final String uuid = intent == null ? null : intent.getStringExtra("uuid");
if (uuid != null) {
@@ -102,9 +102,8 @@ public class MucUsersActivity extends XmppActivity implements XmppConnectionServ
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
+ ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
setSupportActionBar(binding.toolbar);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
configureActionBar(getSupportActionBar(), true);
this.userAdapter = new UserAdapter(getPreferences().getBoolean("advanced_muc_mode", false));
binding.list.setAdapter(this.userAdapter);
diff --git a/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java b/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java
index ac7559769..44af0d0b2 100644
--- a/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java
@@ -11,9 +11,6 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.color.MaterialColors;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
@@ -36,7 +33,10 @@ public abstract class OmemoActivity extends XmppActivity {
Object account = v.getTag(R.id.TAG_ACCOUNT);
Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT);
Object fingerprintStatus = v.getTag(R.id.TAG_FINGERPRINT_STATUS);
- if (account instanceof Account
+ if (account != null
+ && fingerprint != null
+ && account instanceof Account
+ && fingerprintStatus != null
&& fingerprint instanceof String
&& fingerprintStatus instanceof FingerprintStatus) {
getMenuInflater().inflate(R.menu.omemo_key_context, menu);
@@ -130,8 +130,8 @@ public abstract class OmemoActivity extends XmppActivity {
binding.tglTrust.setChecked(status.isTrusted());
if (status.isActive()) {
- binding.key.setTextColor(MaterialColors.getColor(binding.key, com.google.android.material.R.attr.colorOnSurface));
- binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorOnSurface));
+ binding.key.setTextAppearance(this,R.style.TextAppearance_Conversations_Fingerprint);
+ binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption);
if (status.isVerified()) {
binding.verifiedFingerprint.setVisibility(View.VISIBLE);
binding.verifiedFingerprint.setAlpha(1.0f);
@@ -157,8 +157,8 @@ public abstract class OmemoActivity extends XmppActivity {
toast = v -> hideToast();
}
} else {
- binding.key.setTextColor(MaterialColors.getColor(binding.key, com.google.android.material.R.attr.colorOnSurfaceVariant));
- binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorOnSurfaceVariant));
+ binding.key.setTextAppearance(this,R.style.TextAppearance_Conversations_Fingerprint_Disabled);
+ binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption_Disabled);
toast = v -> replaceToast(getString(R.string.this_device_is_no_longer_in_use), false);
if (status.isVerified()) {
binding.tglTrust.setVisibility(View.GONE);
@@ -181,7 +181,7 @@ public abstract class OmemoActivity extends XmppActivity {
binding.keyType.setVisibility(View.GONE);
}
if (highlight) {
- binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorPrimaryVariant));
+ binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption_Highlight);
binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message));
} else {
binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
@@ -191,7 +191,7 @@ public abstract class OmemoActivity extends XmppActivity {
}
public void showPurgeKeyDialog(final Account account, final String fingerprint) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.distrust_omemo_key);
builder.setMessage(R.string.distrust_omemo_key_text);
builder.setNegativeButton(getString(R.string.cancel), null);
diff --git a/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java
index 8d686c36f..658567aa6 100644
--- a/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java
@@ -63,7 +63,7 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
String uuid = pendingConversationUuid.pop();
if (uuid != null) {
this.conversation = xmppConnectionService.findConversationByUuid(uuid);
@@ -91,7 +91,6 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(this.binding.toolbar);
configureActionBar(getSupportActionBar());
this.binding.cancelButton.setOnClickListener((v) -> this.finish());
@@ -115,7 +114,6 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
final CropImage.ActivityResult result = CropImage.getActivityResult(data);
if (resultCode == RESULT_OK) {
diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
index 2c972734c..b6822b301 100644
--- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
@@ -18,7 +18,6 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
-import androidx.databinding.DataBindingUtil;
import com.canhub.cropper.CropImage;
@@ -26,7 +25,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivityPublishProfilePictureBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
@@ -79,6 +77,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
public void onAvatarPublicationFailed(int res) {
runOnUiThread(() -> {
hintOrWarning.setText(res);
+ hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
hintOrWarning.setVisibility(View.VISIBLE);
publishing = false;
togglePublishButton(true, R.string.publish);
@@ -88,12 +87,8 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- ActivityPublishProfilePictureBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
-
- setSupportActionBar(binding.toolbar);
-
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+ setContentView(R.layout.activity_publish_profile_picture);
+ setSupportActionBar(findViewById(R.id.toolbar));
this.avatar = findViewById(R.id.account_image);
this.cancelButton = findViewById(R.id.cancel_button);
@@ -225,7 +220,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
final Intent intent = getIntent();
this.mInitialAccountSetup = intent != null && intent.getBooleanExtra("setup", false);
@@ -266,6 +261,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
if (bm == null) {
togglePublishButton(false, R.string.publish);
this.hintOrWarning.setVisibility(View.VISIBLE);
+ this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
return;
}
@@ -276,6 +272,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
} else {
togglePublishButton(false, R.string.publish);
this.hintOrWarning.setVisibility(View.VISIBLE);
+ this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
if (account.getStatus() == Account.State.ONLINE) {
this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
} else {
diff --git a/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java b/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java
index e4fdab63a..de2254b4d 100644
--- a/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java
@@ -25,7 +25,6 @@ import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.Set;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -73,8 +72,15 @@ public class RecordingActivity extends Activity implements View.OnClickListener
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
+
@Override
- public void onStart() {
+ protected void onResume() {
+ super.onResume();
+ SettingsUtils.applyScreenshotPreventionSetting(this);
+ }
+
+ @Override
+ protected void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
@@ -95,43 +101,21 @@ public class RecordingActivity extends Activity implements View.OnClickListener
}
}
- private static final Set AAC_SENSITIVE_DEVICES =
- new ImmutableSet.Builder()
- .add("FP4") // Fairphone 4 https://codeberg.org/monocles/monocles_chat/issues/133
- .add("ONEPLUS A6000") // OnePlus 6 https://github.com/iNPUTmice/Conversations/issues/4329
- .add("ONEPLUS A6003") // OnePlus 6 https://github.com/iNPUTmice/Conversations/issues/4329
- .add("ONEPLUS A6010") // OnePlus 6T https://codeberg.org/monocles/monocles_chat/issues/133
- .add("ONEPLUS A6013") // OnePlus 6T https://codeberg.org/monocles/monocles_chat/issues/133
- .add("Pixel 4a") // Pixel 4a https://github.com/iNPUTmice/Conversations/issues/4223
- .add("WP12 Pro") // Oukitel WP 12 Pro https://github.com/iNPUTmice/Conversations/issues/4223
- .add("Volla Phone X") // Volla Phone X https://github.com/iNPUTmice/Conversations/issues/4223
- .build();
-
private boolean startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- mRecorder.setPrivacySensitive(true);
- }
final int outputFormat;
if (Config.USE_OPUS_VOICE_MESSAGES && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
outputFormat = MediaRecorder.OutputFormat.OGG;
mRecorder.setOutputFormat(outputFormat);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.OPUS);
- mRecorder.setAudioEncodingBitRate(32_000);
+ mRecorder.setAudioEncodingBitRate(32000);
} else {
outputFormat = MediaRecorder.OutputFormat.MPEG_4;
mRecorder.setOutputFormat(outputFormat);
- if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL) && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
- // Changing these three settings for AAC sensitive devices for Android<=13 might lead to sporadically truncated (cut-off) voice messages.
- mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
- mRecorder.setAudioSamplingRate(24_000);
- mRecorder.setAudioEncodingBitRate(28_000);
- } else {
- mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
- mRecorder.setAudioSamplingRate(44_100);
- mRecorder.setAudioEncodingBitRate(64_000);
- }
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ mRecorder.setAudioEncodingBitRate(96000);
+ mRecorder.setAudioSamplingRate(22050);
}
setupOutputFile(outputFormat);
mRecorder.setOutputFile(mOutputFile.getAbsolutePath());
diff --git a/src/main/java/eu/siacs/conversations/ui/RecyclerViews.java b/src/main/java/eu/siacs/conversations/ui/RecyclerViews.java
deleted file mode 100644
index cca9c36c0..000000000
--- a/src/main/java/eu/siacs/conversations/ui/RecyclerViews.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-public final class RecyclerViews {
-
- private RecyclerViews() {
- throw new IllegalStateException("Do not instantiate me");
- }
-
- public static boolean scrolledToTop(final RecyclerView recyclerView) {
- final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
- if (layoutManager instanceof LinearLayoutManager linearLayoutManager) {
- return linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0;
- } else {
- return false;
- }
- }
-
- public static int findFirstVisibleItemPosition(final RecyclerView recyclerView) {
- final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
- if (layoutManager instanceof LinearLayoutManager linearLayoutManager) {
- return linearLayoutManager.findFirstVisibleItemPosition();
- } else {
- return RecyclerView.NO_POSITION;
- }
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
index f83d8a0be..9759841df 100644
--- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
@@ -6,16 +6,17 @@ import static java.util.Arrays.asList;
import android.Manifest;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.app.PictureInPictureParams;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.opengl.GLException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import android.util.Rational;
import android.view.KeyEvent;
@@ -56,8 +57,7 @@ import eu.siacs.conversations.databinding.ActivityRtpSessionBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.services.CallIntegration;
-import eu.siacs.conversations.services.CallIntegrationConnectionService;
+import eu.siacs.conversations.services.AppRTCAudioManager;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.widget.DialpadView;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
@@ -71,7 +71,6 @@ import eu.siacs.conversations.xmpp.jingle.ContentAddition;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
import eu.siacs.conversations.xmpp.jingle.Media;
-import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
@@ -91,7 +90,6 @@ public class RtpSessionActivity extends XmppActivity
public static final String EXTRA_WITH = "with";
public static final String EXTRA_SESSION_ID = "session_id";
- public static final String EXTRA_PROPOSED_SESSION_ID = "proposed_session_id";
public static final String EXTRA_LAST_REPORTED_STATE = "last_reported_state";
public static final String EXTRA_LAST_ACTION = "last_action";
public static final String ACTION_ACCEPT_CALL = "action_accept_call";
@@ -105,7 +103,6 @@ public class RtpSessionActivity extends XmppActivity
RtpEndUserState.APPLICATION_ERROR,
RtpEndUserState.SECURITY_ERROR,
RtpEndUserState.DECLINED_OR_BUSY,
- RtpEndUserState.CONTACT_OFFLINE,
RtpEndUserState.CONNECTIVITY_ERROR,
RtpEndUserState.CONNECTIVITY_LOST_ERROR,
RtpEndUserState.RETRACTED);
@@ -127,14 +124,6 @@ public class RtpSessionActivity extends XmppActivity
RtpEndUserState.ACCEPTING_CALL,
RtpEndUserState.CONNECTING,
RtpEndUserState.RECONNECTING);
- private static final List STATES_SHOWING_SPEAKER_CONFIGURATION =
- new ImmutableList.Builder()
- .add(RtpEndUserState.FINDING_DEVICE)
- .add(RtpEndUserState.RINGING)
- .add(RtpEndUserState.ACCEPTING_CALL)
- .add(RtpEndUserState.CONNECTING)
- .addAll(STATES_CONSIDERED_CONNECTED)
- .build();
private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session";
private static final int REQUEST_ACCEPT_CALL = 0x1111;
private static final int REQUEST_ACCEPT_CONTENT = 0x1112;
@@ -154,16 +143,11 @@ public class RtpSessionActivity extends XmppActivity
}
};
- public static Set actionToMedia(final String action) {
+ private static Set actionToMedia(final String action) {
if (ACTION_MAKE_VIDEO_CALL.equals(action)) {
return ImmutableSet.of(Media.AUDIO, Media.VIDEO);
- } else if (ACTION_MAKE_VOICE_CALL.equals(action)) {
- return ImmutableSet.of(Media.AUDIO);
} else {
- Log.w(
- Config.LOGTAG,
- "actionToMedia can not get media set from unknown action " + action);
- return Collections.emptySet();
+ return ImmutableSet.of(Media.AUDIO);
}
}
@@ -329,15 +313,14 @@ public class RtpSessionActivity extends XmppActivity
private void retractSessionProposal() {
final Intent intent = getIntent();
final String action = intent.getAction();
- final String lastAction = intent.getStringExtra(EXTRA_LAST_ACTION);
final Account account = extractAccount(intent);
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
final String state = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE);
if (!Intent.ACTION_VIEW.equals(action)
|| state == null
|| !END_CARD.contains(RtpEndUserState.valueOf(state))) {
- final Set media = actionToMedia(lastAction == null ? action : lastAction);
- resetIntent(account, with, RtpEndUserState.RETRACTED, media);
+ resetIntent(
+ account, with, RtpEndUserState.RETRACTED, actionToMedia(intent.getAction()));
}
xmppConnectionService
.getJingleConnectionManager()
@@ -405,7 +388,7 @@ public class RtpSessionActivity extends XmppActivity
final List permissions = permissions(getMedia());
if (PermissionUtils.hasPermission(this, permissions, REQUEST_ACCEPT_CALL)) {
putScreenInCallMode();
- acceptCall();
+ checkRecorderAndAcceptCall();
}
}
@@ -422,7 +405,8 @@ public class RtpSessionActivity extends XmppActivity
return permissions.build();
}
- private void acceptCall() {
+ private void checkRecorderAndAcceptCall() {
+ checkMicrophoneAvailabilityAsync();
try {
requireRtpConnection().acceptCall();
} catch (final IllegalStateException e) {
@@ -430,32 +414,58 @@ public class RtpSessionActivity extends XmppActivity
}
}
+ private void checkMicrophoneAvailabilityAsync() {
+ new Thread(new MicrophoneAvailabilityCheck(this)).start();
+ }
+
+ private static class MicrophoneAvailabilityCheck implements Runnable {
+
+ private final WeakReference activityReference;
+
+ private MicrophoneAvailabilityCheck(final Activity activity) {
+ this.activityReference = new WeakReference<>(activity);
+ }
+
+ @Override
+ public void run() {
+ final long start = SystemClock.elapsedRealtime();
+ final boolean isMicrophoneAvailable = AppRTCAudioManager.isMicrophoneAvailable();
+ final long stop = SystemClock.elapsedRealtime();
+ Log.d(Config.LOGTAG, "checking microphone availability took " + (stop - start) + "ms");
+ if (isMicrophoneAvailable) {
+ return;
+ }
+ final Activity activity = activityReference.get();
+ if (activity == null) {
+ return;
+ }
+ activity.runOnUiThread(
+ () ->
+ Toast.makeText(
+ activity,
+ R.string.microphone_unavailable,
+ Toast.LENGTH_LONG)
+ .show());
+ }
+ }
+
private void putScreenInCallMode() {
putScreenInCallMode(requireRtpConnection().getMedia());
}
private void putScreenInCallMode(final Set media) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- if (Media.audioOnly(media)) {
+ if (!media.contains(Media.VIDEO)) {
final JingleRtpConnection rtpConnection =
rtpConnectionReference != null ? rtpConnectionReference.get() : null;
- final CallIntegration callIntegration =
- rtpConnection == null ? null : rtpConnection.getCallIntegration();
- if (callIntegration == null
- || callIntegration.getSelectedAudioDevice()
- == CallIntegration.AudioDevice.EARPIECE) {
+ final AppRTCAudioManager audioManager =
+ rtpConnection == null ? null : rtpConnection.getAudioManager();
+ if (audioManager == null
+ || audioManager.getSelectedAudioDevice()
+ == AppRTCAudioManager.AudioDevice.EARPIECE) {
acquireProximityWakeLock();
}
}
- lockOrientation(media);
- }
-
- private void lockOrientation(final Set media) {
- if (Media.audioOnly(media)) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- }
}
@SuppressLint("WakelockTimeout")
@@ -488,8 +498,9 @@ public class RtpSessionActivity extends XmppActivity
}
}
- private void putProximityWakeLockInProperState(final CallIntegration.AudioDevice audioDevice) {
- if (audioDevice == CallIntegration.AudioDevice.EARPIECE) {
+ private void putProximityWakeLockInProperState(
+ final AppRTCAudioManager.AudioDevice audioDevice) {
+ if (audioDevice == AppRTCAudioManager.AudioDevice.EARPIECE) {
acquireProximityWakeLock();
} else {
releaseProximityWakeLock();
@@ -503,9 +514,6 @@ public class RtpSessionActivity extends XmppActivity
public void onNewIntent(final Intent intent) {
Log.d(Config.LOGTAG, this.getClass().getName() + ".onNewIntent()");
super.onNewIntent(intent);
- if (intent == null) {
- return;
- }
setIntent(intent);
if (xmppConnectionService == null) {
Log.d(
@@ -513,21 +521,32 @@ public class RtpSessionActivity extends XmppActivity
"RtpSessionActivity: background service wasn't bound in onNewIntent()");
return;
}
- initializeWithIntent(Event.ON_NEW_INTENT, intent);
+ final Account account = extractAccount(intent);
+ final String action = intent.getAction();
+ final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
+ final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID);
+ if (sessionId != null) {
+ Log.d(Config.LOGTAG, "reinitializing from onNewIntent()");
+ if (initializeActivityWithRunningRtpSession(account, with, sessionId)) {
+ return;
+ }
+ if (ACTION_ACCEPT_CALL.equals(intent.getAction())) {
+ Log.d(Config.LOGTAG, "accepting call from onNewIntent()");
+ requestPermissionsAndAcceptCall();
+ resetIntent(intent.getExtras());
+ }
+ } else if (asList(ACTION_MAKE_VIDEO_CALL, ACTION_MAKE_VOICE_CALL).contains(action)) {
+ proposeJingleRtpSession(account, with, actionToMedia(action));
+ setWith(account.getRoster().getContact(with), null);
+ } else {
+ throw new IllegalStateException("received onNewIntent without sessionId");
+ }
}
@Override
- protected void onBackendConnected() {
- final var intent = getIntent();
- if (intent == null) {
- return;
- }
- initializeWithIntent(Event.ON_BACKEND_CONNECTED, intent);
- }
-
- private void initializeWithIntent(final Event event, @NonNull final Intent intent) {
+ void onBackendConnected() {
+ final Intent intent = getIntent();
final String action = intent.getAction();
- Log.d(Config.LOGTAG, "initializeWithIntent(" + event + "," + action + ")");
final Account account = extractAccount(intent);
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID);
@@ -540,17 +559,10 @@ public class RtpSessionActivity extends XmppActivity
requestPermissionsAndAcceptCall();
resetIntent(intent.getExtras());
}
+ } else if (asList(ACTION_MAKE_VIDEO_CALL, ACTION_MAKE_VOICE_CALL).contains(action)) {
+ proposeJingleRtpSession(account, with, actionToMedia(action));
+ setWith(account.getRoster().getContact(with), null);
} else if (Intent.ACTION_VIEW.equals(action)) {
- final String proposedSessionId = intent.getStringExtra(EXTRA_PROPOSED_SESSION_ID);
- final JingleConnectionManager.TerminatedRtpSession terminatedRtpSession =
- xmppConnectionService
- .getJingleConnectionManager()
- .getTerminalSessionState(with, proposedSessionId);
- if (terminatedRtpSession != null) {
- // termination (due to message error or 'busy' was faster than opening the activity
- initializeWithTerminatedSessionState(account, with, terminatedRtpSession);
- return;
- }
final String extraLastState = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE);
final RtpEndUserState state =
extraLastState == null ? null : RtpEndUserState.valueOf(extraLastState);
@@ -568,15 +580,10 @@ public class RtpSessionActivity extends XmppActivity
.fireJingleRtpConnectionStateUpdates()) {
return;
}
- if (END_CARD.contains(state)) {
- return;
- }
- final String lastAction = intent.getStringExtra(EXTRA_LAST_ACTION);
- final Set media = actionToMedia(lastAction);
- if (xmppConnectionService
+ if (END_CARD.contains(state)
+ || xmppConnectionService
.getJingleConnectionManager()
.hasMatchingProposal(account, with)) {
- putScreenInCallMode(media);
return;
}
Log.d(Config.LOGTAG, "restored state (" + state + ") was not an end card. finishing");
@@ -584,7 +591,7 @@ public class RtpSessionActivity extends XmppActivity
}
}
- private void setWidth(final RtpEndUserState state) {
+ private void setWith(final RtpEndUserState state) {
setWith(getWith(), state);
}
@@ -599,6 +606,24 @@ public class RtpSessionActivity extends XmppActivity
}
}
+ private void proposeJingleRtpSession(
+ final Account account, final Jid with, final Set media) {
+ checkMicrophoneAvailabilityAsync();
+ if (with.isBareJid()) {
+ xmppConnectionService
+ .getJingleConnectionManager()
+ .proposeJingleRtpSession(account, with, media);
+ } else {
+ final String sessionId =
+ xmppConnectionService
+ .getJingleConnectionManager()
+ .initializeRtpSession(account, with, media);
+ initializeActivityWithRunningRtpSession(account, with, sessionId);
+ resetIntent(account, with, sessionId);
+ }
+ putScreenInCallMode(media);
+ }
+
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
@@ -607,7 +632,7 @@ public class RtpSessionActivity extends XmppActivity
PermissionUtils.removeBluetoothConnect(permissions, grantResults);
if (PermissionUtils.allGranted(permissionResult.grantResults)) {
if (requestCode == REQUEST_ACCEPT_CALL) {
- acceptCall();
+ checkRecorderAndAcceptCall();
} else if (requestCode == REQUEST_ACCEPT_CONTENT) {
acceptContentAdd();
} else if (requestCode == REQUEST_ADD_CONTENT) {
@@ -798,7 +823,7 @@ public class RtpSessionActivity extends XmppActivity
requireRtpConnection().getState())) {
putScreenInCallMode();
}
- setWidth(currentState);
+ setWith(currentState);
updateVideoViews(currentState);
updateStateDisplay(currentState, media, contentAddition);
updateVerifiedShield(verified && STATES_SHOWING_SWITCH_TO_CHAT.contains(currentState));
@@ -846,12 +871,8 @@ public class RtpSessionActivity extends XmppActivity
surfaceViewRenderer.setVisibility(View.VISIBLE);
try {
surfaceViewRenderer.init(requireRtpConnection().getEglBaseContext(), null);
- } catch (final IllegalStateException ignored) {
- // SurfaceViewRenderer was already initialized
- } catch (final RuntimeException e) {
- if (Throwables.getRootCause(e) instanceof GLException glException) {
- Log.w(Config.LOGTAG, "could not set up hardware renderer", glException);
- }
+ } catch (final IllegalStateException e) {
+ // Log.d(Config.LOGTAG, "SurfaceViewRenderer was already initialized");
}
surfaceViewRenderer.setEnableHardwareScaler(true);
}
@@ -888,7 +909,6 @@ public class RtpSessionActivity extends XmppActivity
case FINDING_DEVICE -> setTitle(R.string.rtp_state_finding_device);
case RINGING -> setTitle(R.string.rtp_state_ringing);
case DECLINED_OR_BUSY -> setTitle(R.string.rtp_state_declined_or_busy);
- case CONTACT_OFFLINE -> setTitle(R.string.rtp_state_contact_offline);
case CONNECTIVITY_ERROR -> setTitle(R.string.rtp_state_connectivity_error);
case CONNECTIVITY_LOST_ERROR -> setTitle(R.string.rtp_state_connectivity_lost_error);
case RETRACTED -> setTitle(R.string.rtp_state_retracted);
@@ -964,34 +984,33 @@ public class RtpSessionActivity extends XmppActivity
} else if (state == RtpEndUserState.INCOMING_CALL) {
this.binding.rejectCall.setContentDescription(getString(R.string.dismiss_call));
this.binding.rejectCall.setOnClickListener(this::rejectCall);
- this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_24dp);
+ this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.answer_call));
this.binding.acceptCall.setOnClickListener(this::acceptCall);
- this.binding.acceptCall.setImageResource(R.drawable.ic_call_24dp);
+ this.binding.acceptCall.setImageResource(R.drawable.ic_call_white_48dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else if (state == RtpEndUserState.INCOMING_CONTENT_ADD) {
this.binding.rejectCall.setContentDescription(
getString(R.string.reject_switch_to_video));
this.binding.rejectCall.setOnClickListener(this::rejectContentAdd);
- this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
+ this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.accept));
this.binding.acceptCall.setOnClickListener((v -> acceptContentAdd(contentAddition)));
- this.binding.acceptCall.setImageResource(R.drawable.ic_check_24dp);
+ this.binding.acceptCall.setImageResource(R.drawable.ic_baseline_check_24);
this.binding.acceptCall.setVisibility(View.VISIBLE);
- } else if (asList(RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.CONTACT_OFFLINE)
- .contains(state)) {
+ } else if (state == RtpEndUserState.DECLINED_OR_BUSY) {
this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
- this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
+ this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.record_voice_mail));
this.binding.acceptCall.setOnClickListener(this::recordVoiceMail);
- this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_24dp);
+ this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_white_24dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else if (asList(
RtpEndUserState.CONNECTIVITY_ERROR,
@@ -1002,18 +1021,18 @@ public class RtpSessionActivity extends XmppActivity
.contains(state)) {
this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
- this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
+ this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.try_again));
this.binding.acceptCall.setOnClickListener(this::retry);
- this.binding.acceptCall.setImageResource(R.drawable.ic_replay_24dp);
+ this.binding.acceptCall.setImageResource(R.drawable.ic_replay_white_48dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else {
this.binding.rejectCall.setVisibility(View.INVISIBLE);
this.binding.endCall.setContentDescription(getString(R.string.hang_up));
this.binding.endCall.setOnClickListener(this::endCall);
- this.binding.endCall.setImageResource(R.drawable.ic_call_end_24dp);
+ this.binding.endCall.setImageResource(R.drawable.ic_call_end_white_48dp);
this.binding.endCall.setVisibility(View.VISIBLE);
this.binding.acceptCall.setVisibility(View.INVISIBLE);
}
@@ -1037,16 +1056,16 @@ public class RtpSessionActivity extends XmppActivity
private void updateInCallButtonConfiguration(
final RtpEndUserState state, final Set media) {
if (STATES_CONSIDERED_CONNECTED.contains(state) && !isPictureInPicture()) {
- Preconditions.checkArgument(!media.isEmpty(), "Media must not be empty");
+ Preconditions.checkArgument(media.size() > 0, "Media must not be empty");
if (media.contains(Media.VIDEO)) {
final JingleRtpConnection rtpConnection = requireRtpConnection();
updateInCallButtonConfigurationVideo(
rtpConnection.isVideoEnabled(), rtpConnection.isCameraSwitchable());
} else {
- final CallIntegration callIntegration = requireRtpConnection().getCallIntegration();
+ final AppRTCAudioManager audioManager = requireRtpConnection().getAudioManager();
updateInCallButtonConfigurationSpeaker(
- callIntegration.getSelectedAudioDevice(),
- callIntegration.getAudioDevices().size());
+ audioManager.getSelectedAudioDevice(),
+ audioManager.getAudioDevices().size());
this.binding.inCallActionFarRight.setVisibility(View.GONE);
}
if (media.contains(Media.AUDIO)) {
@@ -1055,20 +1074,6 @@ public class RtpSessionActivity extends XmppActivity
} else {
this.binding.inCallActionLeft.setVisibility(View.GONE);
}
- } else if (STATES_SHOWING_SPEAKER_CONFIGURATION.contains(state)
- && !isPictureInPicture()
- && Media.audioOnly(media)) {
- final CallIntegration callIntegration;
- try {
- callIntegration = requireCallIntegration();
- } catch (final IllegalStateException e) {
- Log.e(Config.LOGTAG, "can not update InCallButtonConfiguration in state " + state);
- return;
- }
- updateInCallButtonConfigurationSpeaker(
- callIntegration.getSelectedAudioDevice(),
- callIntegration.getAudioDevices().size());
- this.binding.inCallActionFarRight.setVisibility(View.GONE);
} else {
this.binding.inCallActionLeft.setVisibility(View.GONE);
this.binding.inCallActionRight.setVisibility(View.GONE);
@@ -1078,11 +1083,11 @@ public class RtpSessionActivity extends XmppActivity
@SuppressLint("RestrictedApi")
private void updateInCallButtonConfigurationSpeaker(
- final CallIntegration.AudioDevice selectedAudioDevice, final int numberOfChoices) {
+ final AppRTCAudioManager.AudioDevice selectedAudioDevice, final int numberOfChoices) {
switch (selectedAudioDevice) {
case EARPIECE -> {
this.binding.inCallActionRight.setImageResource(
- R.drawable.ic_volume_off_24dp);
+ R.drawable.ic_volume_off_black_24dp);
if (numberOfChoices >= 2) {
this.binding.inCallActionRight.setOnClickListener(this::switchToSpeaker);
} else {
@@ -1091,12 +1096,12 @@ public class RtpSessionActivity extends XmppActivity
}
}
case WIRED_HEADSET -> {
- this.binding.inCallActionRight.setImageResource(R.drawable.ic_headset_mic_24dp);
+ this.binding.inCallActionRight.setImageResource(R.drawable.ic_headset_black_24dp);
this.binding.inCallActionRight.setOnClickListener(null);
this.binding.inCallActionRight.setClickable(false);
}
case SPEAKER_PHONE -> {
- this.binding.inCallActionRight.setImageResource(R.drawable.ic_volume_up_24dp);
+ this.binding.inCallActionRight.setImageResource(R.drawable.ic_volume_up_black_24dp);
if (numberOfChoices >= 2) {
this.binding.inCallActionRight.setOnClickListener(this::switchToEarpiece);
} else {
@@ -1106,7 +1111,7 @@ public class RtpSessionActivity extends XmppActivity
}
case BLUETOOTH -> {
this.binding.inCallActionRight.setImageResource(
- R.drawable.ic_bluetooth_audio_24dp);
+ R.drawable.ic_bluetooth_audio_black_24dp);
this.binding.inCallActionRight.setOnClickListener(null);
this.binding.inCallActionRight.setClickable(false);
}
@@ -1120,17 +1125,17 @@ public class RtpSessionActivity extends XmppActivity
this.binding.inCallActionRight.setVisibility(View.VISIBLE);
if (isCameraSwitchable) {
this.binding.inCallActionFarRight.setImageResource(
- R.drawable.ic_flip_camera_android_24dp);
+ R.drawable.ic_flip_camera_android_black_24dp);
this.binding.inCallActionFarRight.setVisibility(View.VISIBLE);
this.binding.inCallActionFarRight.setOnClickListener(this::switchCamera);
} else {
this.binding.inCallActionFarRight.setVisibility(View.GONE);
}
if (videoEnabled) {
- this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_24dp);
+ this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_black_24dp);
this.binding.inCallActionRight.setOnClickListener(this::disableVideo);
} else {
- this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_off_24dp);
+ this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_off_black_24dp);
this.binding.inCallActionRight.setOnClickListener(this::enableVideo);
}
}
@@ -1184,10 +1189,10 @@ public class RtpSessionActivity extends XmppActivity
@SuppressLint("RestrictedApi")
private void updateInCallButtonConfigurationMicrophone(final boolean microphoneEnabled) {
if (microphoneEnabled) {
- this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_24dp);
+ this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_black_24dp);
this.binding.inCallActionLeft.setOnClickListener(this::disableMicrophone);
} else {
- this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_off_24dp);
+ this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_off_black_24dp);
this.binding.inCallActionLeft.setOnClickListener(this::enableMicrophone);
}
this.binding.inCallActionLeft.setVisibility(View.VISIBLE);
@@ -1317,17 +1322,21 @@ public class RtpSessionActivity extends XmppActivity
}
}
- private void switchToEarpiece(final View view) {
- requireCallIntegration().setAudioDevice(CallIntegration.AudioDevice.EARPIECE);
+ private void switchToEarpiece(View view) {
+ requireRtpConnection()
+ .getAudioManager()
+ .setDefaultAudioDevice(AppRTCAudioManager.AudioDevice.EARPIECE);
acquireProximityWakeLock();
}
- private void switchToSpeaker(final View view) {
- requireCallIntegration().setAudioDevice(CallIntegration.AudioDevice.SPEAKER_PHONE);
+ private void switchToSpeaker(View view) {
+ requireRtpConnection()
+ .getAudioManager()
+ .setDefaultAudioDevice(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE);
releaseProximityWakeLock();
}
- private void retry(final View view) {
+ private void retry(View view) {
final Intent intent = getIntent();
final Account account = extractAccount(intent);
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
@@ -1336,7 +1345,7 @@ public class RtpSessionActivity extends XmppActivity
final Set media = actionToMedia(lastAction == null ? action : lastAction);
this.rtpConnectionReference = null;
Log.d(Config.LOGTAG, "attempting retry with " + with.toEscapedString());
- CallIntegrationConnectionService.placeCall(xmppConnectionService, account, with, media);
+ proposeJingleRtpSession(account, with, media);
}
private void exit(final View view) {
@@ -1375,33 +1384,6 @@ public class RtpSessionActivity extends XmppActivity
return connection;
}
- private CallIntegration requireCallIntegration() {
- return requireOngoingRtpSession().getCallIntegration();
- }
-
- private OngoingRtpSession requireOngoingRtpSession() {
- final JingleRtpConnection connection =
- this.rtpConnectionReference != null ? this.rtpConnectionReference.get() : null;
- if (connection != null) {
- return connection;
- }
- final Intent currentIntent = getIntent();
- final String withExtra =
- currentIntent == null ? null : currentIntent.getStringExtra(EXTRA_WITH);
- final var account = extractAccount(currentIntent);
- if (withExtra == null) {
- throw new IllegalStateException("Current intent has no EXTRA_WITH");
- }
- final var matching =
- xmppConnectionService
- .getJingleConnectionManager()
- .matchingProposal(account, Jid.of(withExtra));
- if (matching.isPresent()) {
- return matching.get();
- }
- throw new IllegalStateException("No matching session proposal");
- }
-
@Override
public void onJingleRtpConnectionUpdate(
Account account, Jid with, final String sessionId, RtpEndUserState state) {
@@ -1428,7 +1410,6 @@ public class RtpSessionActivity extends XmppActivity
final AbstractJingleConnection.Id id = requireRtpConnection().getId();
final boolean verified = requireRtpConnection().isVerified();
final Set media = getMedia();
- lockOrientation(media);
final ContentAddition contentAddition = getPendingContentAddition();
final Contact contact = getWith();
if (account == id.account && id.with.equals(with) && id.sessionId.equals(sessionId)) {
@@ -1459,8 +1440,8 @@ public class RtpSessionActivity extends XmppActivity
@Override
public void onAudioDeviceChanged(
- final CallIntegration.AudioDevice selectedAudioDevice,
- final Set availableAudioDevices) {
+ final AppRTCAudioManager.AudioDevice selectedAudioDevice,
+ final Set availableAudioDevices) {
Log.d(
Config.LOGTAG,
"onAudioDeviceChanged in activity: selected:"
@@ -1468,26 +1449,19 @@ public class RtpSessionActivity extends XmppActivity
+ ", available:"
+ availableAudioDevices);
try {
- final OngoingRtpSession ongoingRtpSession = requireOngoingRtpSession();
- final RtpEndUserState endUserState;
- if (ongoingRtpSession instanceof JingleRtpConnection jingleRtpConnection) {
- endUserState = jingleRtpConnection.getEndUserState();
- } else {
- // for session proposals all end user states are functionally the same
- endUserState = RtpEndUserState.RINGING;
- }
- final Set media = ongoingRtpSession.getMedia();
+ final RtpEndUserState endUserState = requireRtpConnection().getEndUserState();
+ final Set media = getMedia();
if (END_CARD.contains(endUserState)) {
Log.d(
Config.LOGTAG,
"onAudioDeviceChanged() nothing to do because end card has been reached");
} else {
- if (Media.audioOnly(media)
- && STATES_SHOWING_SPEAKER_CONFIGURATION.contains(endUserState)) {
- final CallIntegration callIntegration = requireCallIntegration();
+ if (Media.audioOnly(media) && endUserState == RtpEndUserState.CONNECTED) {
+ final AppRTCAudioManager audioManager =
+ requireRtpConnection().getAudioManager();
updateInCallButtonConfigurationSpeaker(
- callIntegration.getSelectedAudioDevice(),
- callIntegration.getAudioDevices().size());
+ audioManager.getSelectedAudioDevice(),
+ audioManager.getAudioDevices().size());
}
Log.d(
Config.LOGTAG,
@@ -1513,17 +1487,16 @@ public class RtpSessionActivity extends XmppActivity
if (withExtra == null) {
return;
}
- final Set media = actionToMedia(currentIntent.getStringExtra(EXTRA_LAST_ACTION));
if (Jid.ofEscaped(withExtra).asBareJid().equals(with)) {
runOnUiThread(
() -> {
updateVerifiedShield(false);
updateStateDisplay(state);
- updateButtonConfiguration(state, media, null);
+ updateButtonConfiguration(state);
updateIncomingCallScreen(state);
invalidateOptionsMenu();
});
- resetIntent(account, with, state, media);
+ resetIntent(account, with, state, actionToMedia(currentIntent.getAction()));
}
}
@@ -1552,9 +1525,4 @@ public class RtpSessionActivity extends XmppActivity
private static boolean emptyReference(final WeakReference> weakReference) {
return weakReference == null || weakReference.get() == null;
}
-
- private enum Event {
- ON_BACKEND_CONNECTED,
- ON_NEW_INTENT
- }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ScanActivity.java b/src/main/java/eu/siacs/conversations/ui/ScanActivity.java
index 983f21dc8..dca4daacf 100644
--- a/src/main/java/eu/siacs/conversations/ui/ScanActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ScanActivity.java
@@ -190,6 +190,7 @@ public final class ScanActivity extends AppCompatActivity implements SurfaceText
@Override
protected void onResume() {
super.onResume();
+ SettingsUtils.applyScreenshotPreventionSetting(this);
maybeOpenCamera();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java
index e78ff1534..7967ba284 100644
--- a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java
@@ -44,10 +44,8 @@ import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.Toast;
-import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
import java.lang.ref.WeakReference;
@@ -69,6 +67,7 @@ import eu.siacs.conversations.ui.util.DateSeparator;
import eu.siacs.conversations.ui.util.ListViewUtils;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.ShareUtil;
+import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.FtsUtils;
import eu.siacs.conversations.utils.MessageUtils;
import eu.siacs.conversations.utils.UIHelper;
@@ -100,7 +99,6 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
}
super.onCreate(bundle);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_search);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(this.binding.toolbar);
configureActionBar(getSupportActionBar());
this.messageListAdapter = new MessageAdapter(this, this.messages, uuid == null);
@@ -259,7 +257,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
}
@Override
- protected void onBackendConnected() {
+ void onBackendConnected() {
final List searchTerm = pendingSearch.pop();
if (searchTerm != null && currentSearch.watch(searchTerm)) {
xmppConnectionService.search(searchTerm, uuid,this);
@@ -269,12 +267,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
private void changeBackground(boolean hasSearch, boolean hasResults) {
if (hasSearch) {
if (hasResults) {
- binding.searchResults.setBackgroundColor(MaterialColors.getColor(binding.searchResults, com.google.android.material.R.attr.colorSurface));
+ binding.searchResults.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_secondary));
} else {
- binding.searchResults.setBackgroundResource(R.drawable.background_no_results);
+ binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_no_results));
}
} else {
- binding.searchResults.setBackgroundResource(R.drawable.background_search);
+ binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_search));
}
}
@@ -294,14 +292,14 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
if (!currentSearch.watch(term)) {
return;
}
- if (term.isEmpty()) {
+ if (term.size() > 0) {
+ xmppConnectionService.search(term, uuid,this);
+ } else {
MessageSearchTask.cancelRunningTasks();
this.messages.clear();
messageListAdapter.setHighlightedTerm(null);
messageListAdapter.notifyDataSetChanged();
changeBackground(false, false);
- } else {
- xmppConnectionService.search(term, uuid,this);
}
}
@@ -313,7 +311,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
DateSeparator.addAll(messages);
this.messages.addAll(messages);
messageListAdapter.notifyDataSetChanged();
- changeBackground(true, !messages.isEmpty());
+ changeBackground(true, messages.size() > 0);
ListViewUtils.scrollToBottom(this.binding.searchResults);
});
}
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java
new file mode 100644
index 000000000..9378d82b7
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java
@@ -0,0 +1,77 @@
+package eu.siacs.conversations.ui;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.widget.ListView;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.utils.Compatibility;
+
+public class SettingsFragment extends PreferenceFragment {
+
+ private String page = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.preferences);
+
+ // Remove from standard preferences if the flag ONLY_INTERNAL_STORAGE is false
+ if (!Config.ONLY_INTERNAL_STORAGE) {
+ PreferenceCategory mCategory = (PreferenceCategory) findPreference("security_options");
+ if (mCategory != null) {
+ Preference cleanCache = findPreference("clean_cache");
+ Preference cleanPrivateStorage = findPreference("clean_private_storage");
+ mCategory.removePreference(cleanCache);
+ mCategory.removePreference(cleanPrivateStorage);
+ }
+ }
+ Compatibility.removeUnusedPreferences(this);
+
+ if (!TextUtils.isEmpty(page)) {
+ openPreferenceScreen(page);
+ }
+
+ }
+
+ @Override
+ public void onActivityCreated(Bundle bundle) {
+ super.onActivityCreated(bundle);
+
+ final ListView listView = getActivity().findViewById(android.R.id.list);
+ if (listView != null) {
+ listView.setDivider(null);
+ }
+ }
+
+ public void setActivityIntent(final Intent intent) {
+ boolean wasEmpty = TextUtils.isEmpty(page);
+ if (intent != null) {
+ if (Intent.ACTION_VIEW.equals(intent.getAction())) {
+ if (intent.getExtras() != null) {
+ this.page = intent.getExtras().getString("page");
+ if (wasEmpty) {
+ openPreferenceScreen(page);
+ }
+ }
+ }
+ }
+ }
+
+ private void openPreferenceScreen(final String screenName) {
+ final Preference pref = findPreference(screenName);
+ if (pref instanceof PreferenceScreen) {
+ final PreferenceScreen preferenceScreen = (PreferenceScreen) pref;
+ getActivity().setTitle(preferenceScreen.getTitle());
+ preferenceScreen.setDependency("");
+ setPreferenceScreen((PreferenceScreen) pref);
+ }
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java
index c7ddcc01c..7e53fe897 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java
@@ -5,6 +5,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
+import android.os.Build;
import android.os.Bundle;
import android.view.View;
@@ -14,6 +15,11 @@ import androidx.databinding.DataBindingUtil;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.math.DoubleMath;
+import org.osmdroid.api.IGeoPoint;
+import org.osmdroid.util.GeoPoint;
+
+import java.math.RoundingMode;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityShareLocationBinding;
@@ -21,11 +27,7 @@ import eu.siacs.conversations.ui.util.LocationHelper;
import eu.siacs.conversations.ui.widget.Marker;
import eu.siacs.conversations.ui.widget.MyLocation;
import eu.siacs.conversations.utils.LocationProvider;
-
-import org.osmdroid.api.IGeoPoint;
-import org.osmdroid.util.GeoPoint;
-
-import java.math.RoundingMode;
+import eu.siacs.conversations.utils.ThemeHelper;
public class ShareLocationActivity extends LocationActivity implements LocationListener {
@@ -56,7 +58,6 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_share_location);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
setupMapView(binding.map, LocationProvider.getGeoPoint(this));
@@ -70,12 +71,13 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
this.snackBar.setAction(R.string.enable, view -> {
if (isLocationEnabledAndAllowed()) {
updateUi();
- } else if (!hasLocationPermissions()) {
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasLocationPermissions()) {
requestPermissions(REQUEST_CODE_SNACKBAR_PRESSED);
} else if (!isLocationEnabled()) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
});
+ ThemeHelper.fix(this.snackBar);
this.binding.shareButton.setOnClickListener(this::shareLocation);
@@ -85,7 +87,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
if (!marker_fixed_to_loc) {
if (!isLocationEnabled()) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
- } else {
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(REQUEST_CODE_FAB_PRESSED);
}
}
@@ -115,9 +117,16 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
@NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED && permissions.length > 0 && (
- Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) || Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) || Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
- ) && !shouldShowRequestPermissionRationale(permissions[0])) {
+ if (grantResults.length > 0 &&
+ grantResults[0] != PackageManager.PERMISSION_GRANTED &&
+ Build.VERSION.SDK_INT >= 23 &&
+ permissions.length > 0 &&
+ (
+ Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) ||
+ Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) ||
+ Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
+ ) &&
+ !shouldShowRequestPermissionRationale(permissions[0])) {
noAskAgain = true;
}
@@ -163,7 +172,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
}
@Override
- public void onLocationChanged(@NonNull final Location location) {
+ public void onLocationChanged(final Location location) {
if (this.myLoc == null) {
this.marker_fixed_to_loc = true;
}
@@ -197,7 +206,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
}
private boolean isLocationEnabledAndAllowed() {
- return this.hasLocationFeature && this.hasLocationPermissions() && this.isLocationEnabled();
+ return this.hasLocationFeature && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || this.hasLocationPermissions()) && this.isLocationEnabled();
}
private void toggleFixedLocation() {
@@ -220,8 +229,8 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
if (isLocationEnabledAndAllowed()) {
this.binding.fab.setVisibility(View.VISIBLE);
runOnUiThread(() -> {
- this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_24dp :
- R.drawable.ic_gps_not_fixed_24dp);
+ this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_white_24dp :
+ R.drawable.ic_gps_not_fixed_white_24dp);
this.binding.fab.setContentDescription(getResources().getString(
marker_fixed_to_loc ? R.string.action_unfix_from_location : R.string.action_fix_to_location
));
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index fd7365669..5dfc4e102 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -9,8 +9,6 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-import androidx.annotation.NonNull;
-import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -22,7 +20,6 @@ import java.util.stream.Collectors;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivityShareWithBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
@@ -32,11 +29,7 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.xmpp.Jid;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ShareWithActivity extends XmppActivity
- implements XmppConnectionService.OnConversationUpdate {
+public class ShareWithActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
private static final int REQUEST_STORAGE_PERMISSION = 0x733f32;
private Conversation mPendingConversation = null;
@@ -63,10 +56,11 @@ public class ShareWithActivity extends XmppActivity
private final List tags = new ArrayList<>();
- protected void onActivityResult(
- final int requestCode, final int resultCode, final Intent data) {
+
+ protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == REQUEST_START_NEW_CONVERSATION && resultCode == RESULT_OK) {
+ if (requestCode == REQUEST_START_NEW_CONVERSATION
+ && resultCode == RESULT_OK) {
share.contact = data.getStringExtra("contact");
share.account = data.getStringExtra(EXTRA_ACCOUNT);
}
@@ -79,10 +73,7 @@ public class ShareWithActivity extends XmppActivity
}
@Override
- public void onRequestPermissionsResult(
- final int requestCode,
- @NonNull final String[] permissions,
- @NonNull final int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@@ -94,34 +85,27 @@ public class ShareWithActivity extends XmppActivity
}
}
} else {
- Toast.makeText(
- this,
- getString(
- R.string.no_storage_permission,
- getString(R.string.app_name)),
- Toast.LENGTH_SHORT)
- .show();
+ Toast.makeText(this, getString(R.string.no_storage_permission, getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
}
}
@Override
- protected void onCreate(final Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_share_with);
- final ActivityShareWithBinding binding =
- DataBindingUtil.setContentView(this, R.layout.activity_share_with);
setSupportActionBar(findViewById(R.id.toolbar));
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}
- setTitle(getString(R.string.title_activity_share_with));
+ setTitle(getString(R.string.title_activity_sharewith));
+ RecyclerView mListView = findViewById(R.id.choose_conversation_list);
mAdapter = new ConversationAdapter(this, this.mConversations, this.tags);
- binding.chooseConversationList.setLayoutManager(
- new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
- binding.chooseConversationList.setAdapter(mAdapter);
+ mListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+ mListView.setAdapter(mAdapter);
mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
this.share = new Share();
}
@@ -136,9 +120,8 @@ public class ShareWithActivity extends XmppActivity
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add:
- final Intent intent =
- new Intent(getApplicationContext(), ChooseContactActivity.class);
- intent.putExtra("direct_search", true);
+ final Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
+ intent.putExtra("direct_search",true);
startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
return true;
}
@@ -158,8 +141,7 @@ public class ShareWithActivity extends XmppActivity
if (Intent.ACTION_SEND.equals(action)) {
final String text = intent.getStringExtra(Intent.EXTRA_TEXT);
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
- final boolean asQuote =
- intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
+ final boolean asQuote = intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
if (data != null && "geo".equals(data.getScheme())) {
this.share.uris.clear();
@@ -177,16 +159,14 @@ public class ShareWithActivity extends XmppActivity
this.share.uris = uris == null ? new ArrayList<>() : uris;
}
if (xmppConnectionServiceBound) {
- xmppConnectionService.populateWithOrderedConversations(
- mConversations, this.share.uris.isEmpty(), false);
+ xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0, false);
}
+
}
@Override
- protected void onBackendConnected() {
- if (xmppConnectionServiceBound
- && share != null
- && ((share.contact != null && share.account != null))) {
+ void onBackendConnected() {
+ if (xmppConnectionServiceBound && share != null && ((share.contact != null && share.account != null))) {
share();
return;
}
@@ -195,35 +175,32 @@ public class ShareWithActivity extends XmppActivity
private void share() {
final Conversation conversation;
- Account account;
- try {
- account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
- } catch (final IllegalArgumentException e) {
- account = null;
- }
- if (account == null) {
- return;
- }
+ Account account;
+ try {
+ account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
+ } catch (final IllegalArgumentException e) {
+ account = null;
+ }
+ if (account == null) {
+ return;
+ }
- try {
- conversation =
- xmppConnectionService.findOrCreateConversation(
- account, Jid.of(share.contact), null, false, false, true, null);
-
- } catch (final IllegalArgumentException e) {
- return;
- }
+ try {
+ conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), null, false, false, true, null);
+ } catch (final IllegalArgumentException e) {
+ return;
+ }
share(conversation);
}
private void share(final Conversation conversation) {
- if (!share.uris.isEmpty() && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
+ if (share.uris.size() != 0 && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
mPendingConversation = conversation;
return;
}
- final Intent intent = new Intent(this, ConversationsActivity.class);
+ Intent intent = new Intent(this, ConversationsActivity.class);
intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
- if (!share.uris.isEmpty()) {
+ if (share.uris.size() > 0) {
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, share.uris);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -238,20 +215,15 @@ public class ShareWithActivity extends XmppActivity
try {
startActivity(intent);
} catch (SecurityException e) {
- Toast.makeText(
- this,
- R.string.sharing_application_not_grant_permission,
- Toast.LENGTH_SHORT)
- .show();
+ Toast.makeText(this, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
return;
}
finish();
}
public void refreshUiReal() {
- // TODO inject desired order to not resort on refresh
- xmppConnectionService.populateWithOrderedConversations(
- mConversations, this.share != null && this.share.uris.isEmpty(), false);
+ //TODO inject desired order to not resort on refresh
+ xmppConnectionService.populateWithOrderedConversations(mConversations, this.share != null && this.share.uris.size() == 0, false);
refreshTags();
mAdapter.notifyDataSetChanged();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShortcutActivity.java b/src/main/java/eu/siacs/conversations/ui/ShortcutActivity.java
index 66b3fb886..ff935beae 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShortcutActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShortcutActivity.java
@@ -45,7 +45,7 @@ public class ShortcutActivity extends AbstractSearchableListItemActivity {
}
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
ActionBar bar = getSupportActionBar();
if(bar != null){
diff --git a/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java
index 8ed7e1da6..d4b6a2e30 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java
@@ -9,7 +9,6 @@ import android.location.Location;
import android.location.LocationListener;
import android.net.Uri;
import android.os.Bundle;
-import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -18,8 +17,12 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
-import com.google.common.base.Strings;
-import com.google.common.primitives.Doubles;
+import org.jetbrains.annotations.NotNull;
+import org.osmdroid.util.GeoPoint;
+
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -28,13 +31,8 @@ import eu.siacs.conversations.ui.util.LocationHelper;
import eu.siacs.conversations.ui.util.UriHelper;
import eu.siacs.conversations.ui.widget.Marker;
import eu.siacs.conversations.ui.widget.MyLocation;
-import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.LocationProvider;
-import org.osmdroid.util.GeoPoint;
-
-import java.util.Map;
-
public class ShowLocationActivity extends LocationActivity implements LocationListener {
private GeoPoint loc = LocationProvider.FALLBACK;
@@ -51,49 +49,79 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_show_location);
setSupportActionBar(binding.toolbar);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
-
configureActionBar(getSupportActionBar());
setupMapView(this.binding.map, this.loc);
this.binding.fab.setOnClickListener(view -> startNavigation());
final Intent intent = getIntent();
- if (intent == null) {
- return;
- }
- final String action = intent.getAction();
- switch (Strings.nullToEmpty(action)) {
- case "eu.siacs.conversations.location.show":
- if (intent.hasExtra("longitude") && intent.hasExtra("latitude")) {
- final double longitude = intent.getDoubleExtra("longitude", 0);
- final double latitude = intent.getDoubleExtra("latitude", 0);
- this.loc = new GeoPoint(latitude, longitude);
- }
- break;
- case Intent.ACTION_VIEW:
- final Uri uri = intent.getData();
- if (uri == null) {
+ if (intent != null) {
+ final String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ switch (action) {
+ case "eu.siacs.conversations.location.show":
+ if (intent.hasExtra("longitude") && intent.hasExtra("latitude")) {
+ final double longitude = intent.getDoubleExtra("longitude", 0);
+ final double latitude = intent.getDoubleExtra("latitude", 0);
+ this.loc = new GeoPoint(latitude, longitude);
+ }
break;
- }
- final GeoPoint point;
- try {
- point = GeoHelper.parseGeoPoint(uri);
- } catch (final Exception e) {
+ case Intent.ACTION_VIEW:
+ final Uri geoUri = intent.getData();
+
+ // Attempt to set zoom level if the geo URI specifies it
+ if (geoUri != null) {
+ final HashMap query =
+ UriHelper.parseQueryString(geoUri.getQuery());
+
+ // Check for zoom level.
+ final String z = query.get("z");
+ if (z != null) {
+ try {
+ mapController.setZoom(Double.valueOf(z));
+ } catch (final Exception ignored) {
+ }
+ }
+
+ // Check for the actual geo query.
+ boolean posInQuery = false;
+ final String q = query.get("q");
+ if (q != null) {
+ final Pattern latlng =
+ Pattern.compile(
+ "/^([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)(\\(.*\\))?/");
+ final Matcher m = latlng.matcher(q);
+ if (m.matches()) {
+ try {
+ this.loc =
+ new GeoPoint(
+ Double.valueOf(m.group(1)),
+ Double.valueOf(m.group(3)));
+ posInQuery = true;
+ } catch (final Exception ignored) {
+ }
+ }
+ }
+
+ final String schemeSpecificPart = geoUri.getSchemeSpecificPart();
+ if (schemeSpecificPart != null && !schemeSpecificPart.isEmpty()) {
+ try {
+ final GeoPoint latlong =
+ LocationHelper.parseLatLong(schemeSpecificPart);
+ if (latlong != null && !posInQuery) {
+ this.loc = latlong;
+ }
+ } catch (final NumberFormatException ignored) {
+ }
+ }
+ }
+
break;
- }
- this.loc = point;
- final Map query = UriHelper.parseQueryString(uri.getQuery());
- final String z = query.get("z");
- final Double zoom = Strings.isNullOrEmpty(z) ? null : Doubles.tryParse(z);
- if (zoom != null) {
- Log.d(Config.LOGTAG, "inferring zoom level " + zoom + " from geo uri");
- mapController.setZoom(zoom);
- gotoLoc(false);
- }
- break;
+ }
+ updateLocationMarkers();
}
- updateLocationMarkers();
}
@Override
@@ -121,7 +149,7 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
}
@Override
- public boolean onCreateOptionsMenu(@NonNull final Menu menu) {
+ public boolean onCreateOptionsMenu(@NotNull final Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_show_location, menu);
updateUi();
@@ -144,43 +172,37 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
- final var itemId = item.getItemId();
- if (itemId == R.id.action_copy_location) {
- final ClipboardManager clipboard = getSystemService(ClipboardManager.class);
- final ClipData clip = ClipData.newPlainText("location", createGeoUri().toString());
- clipboard.setPrimaryClip(clip);
- Toast.makeText(this, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show();
- return true;
- } else if (itemId == R.id.action_share_location) {
- final Intent shareIntent = new Intent();
- shareIntent.setAction(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_TEXT, createGeoUri().toString());
- shareIntent.setType("text/plain");
- try {
- startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with)));
- } catch (final ActivityNotFoundException e) {
- // This should happen only on faulty androids because normally chooser is always
- // available
- Toast.makeText(this, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT)
- .show();
- }
- return true;
- } else if (itemId == R.id.action_open_with) {
- final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(createGeoUri());
- try {
- startActivity(Intent.createChooser(intent, getText(R.string.open_with)));
- } catch (final ActivityNotFoundException e) {
- // This should happen only on faulty androids because normally chooser is always
- // available
- Toast.makeText(this, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT)
- .show();
- }
- return true;
-
- } else {
- return super.onOptionsItemSelected(item);
+ switch (item.getItemId()) {
+ case R.id.action_copy_location:
+ final ClipboardManager clipboard =
+ (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
+ if (clipboard != null) {
+ final ClipData clip =
+ ClipData.newPlainText("location", createGeoUri().toString());
+ clipboard.setPrimaryClip(clip);
+ Toast.makeText(this, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT)
+ .show();
+ }
+ return true;
+ case R.id.action_share_location:
+ final Intent shareIntent = new Intent();
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.putExtra(Intent.EXTRA_TEXT, createGeoUri().toString());
+ shareIntent.setType("text/plain");
+ try {
+ startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with)));
+ } catch (final ActivityNotFoundException e) {
+ // This should happen only on faulty androids because normally chooser is always
+ // available
+ Toast.makeText(
+ this,
+ R.string.no_application_found_to_open_file,
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ return true;
}
+ return super.onOptionsItemSelected(item);
}
private void startNavigation() {
@@ -206,7 +228,7 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
}
@Override
- public void onLocationChanged(@NonNull final Location location) {
+ public void onLocationChanged(@NotNull final Location location) {
if (LocationHelper.isBetterLocation(location, this.myLoc)) {
this.myLoc = location;
updateLocationMarkers();
@@ -217,8 +239,8 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
public void onStatusChanged(final String provider, final int status, final Bundle extras) {}
@Override
- public void onProviderEnabled(@NonNull final String provider) {}
+ public void onProviderEnabled(@NotNull final String provider) {}
@Override
- public void onProviderDisabled(@NonNull final String provider) {}
+ public void onProviderDisabled(@NotNull final String provider) {}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
index 29d9b7a9e..82b6d9bb8 100644
--- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -71,7 +71,6 @@ import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.textfield.TextInputLayout;
-import com.google.common.collect.Iterables;
import com.leinardi.android.speeddial.SpeedDialActionItem;
import com.leinardi.android.speeddial.SpeedDialView;
@@ -89,7 +88,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
-import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityStartConversationBinding;
@@ -121,8 +119,6 @@ import eu.siacs.conversations.xmpp.XmppConnection;
public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreatePrivateGroupChatDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener, CreatePublicChannelDialog.CreatePublicChannelDialogListener {
- private static final String PREF_KEY_CONTACT_INTEGRATION_CONSENT = "contact_list_integration_consent";
-
public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri";
private final int REQUEST_SYNC_CONTACTS = 0x28cf;
@@ -252,7 +248,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
};
- public static void populateAccountSpinner(final Context context, final List accounts, final AutoCompleteTextView spinner) {
+ public static void populateAccountSpinner(Context context, List accounts, Spinner spinner) {
if (accounts.size() > 0) {
ArrayAdapter adapter = new ArrayAdapter<>(context, R.layout.simple_list_item, accounts);
adapter.setDropDownViewResource(R.layout.simple_list_item);
@@ -508,7 +504,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, null, true, true, true, null);
bookmark.setConversation(conversation);
- if (!bookmark.autojoin()) {
+ if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin))) {
bookmark.setAutojoin(true);
xmppConnectionService.createBookmark(bookmark.getAccount(), bookmark);
}
@@ -548,27 +544,17 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
protected void deleteConference() {
- final int position = conference_context_id;
+ int position = conference_context_id;
final Bookmark bookmark = (Bookmark) conferences.get(position);
- final var conversation = bookmark.getConversation();
- final boolean hasConversation = conversation != null;
-
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.delete_bookmark);
- if (hasConversation) {
- builder.setMessage(JidDialog.style(this, R.string.remove_bookmark_and_close, bookmark.getJid().toEscapedString()));
- } else {
- builder.setMessage(JidDialog.style(this, R.string.remove_bookmark, bookmark.getJid().toEscapedString()));
- }
- builder.setPositiveButton(hasConversation ? R.string.delete_and_close : R.string.delete, (dialog, which) -> {
+ builder.setMessage(JidDialog.style(this, R.string.remove_bookmark_text, bookmark.getJid().toEscapedString()));
+ builder.setPositiveButton(R.string.delete, (dialog, which) -> {
bookmark.setConversation(null);
final Account account = bookmark.getAccount();
xmppConnectionService.deleteBookmark(account, bookmark);
- if (conversation != null) {
- xmppConnectionService.archiveConversation(conversation);
- }
filter(mSearchEditText.getText().toString());
});
builder.create().show();
@@ -694,14 +680,18 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
dialog.show(ft, FRAGMENT_TAG_DIALOG);
}
- public static Account getSelectedAccount(final Context context, final AutoCompleteTextView spinner) {
+ public static Account getSelectedAccount(Context context, Spinner spinner) {
if (spinner == null || !spinner.isEnabled()) {
return null;
}
if (context instanceof XmppActivity) {
- final Jid jid;
+ Jid jid;
try {
- jid = Jid.ofEscaped(spinner.getText().toString());
+ if (Config.DOMAIN_LOCK != null) {
+ jid = Jid.ofEscaped((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
+ } else {
+ jid = Jid.ofEscaped((String) spinner.getSelectedItem());
+ }
} catch (final IllegalArgumentException e) {
return null;
}
@@ -745,16 +735,12 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
@Override
- public boolean onCreateOptionsMenu(final Menu menu) {
+ public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.start_conversation, menu);
AccountUtils.showHideMenuItems(menu);
- final MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline);
- final MenuItem qrCodeScanMenuItem = menu.findItem(R.id.action_scan_qr_code);
+ MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline);
+ MenuItem qrCodeScanMenuItem = menu.findItem(R.id.action_scan_qr_code);
MenuItem noteToSelf = menu.findItem(R.id.action_note_to_self);
- final MenuItem privacyPolicyMenuItem = menu.findItem(R.id.action_privacy_policy);
- privacyPolicyMenuItem.setVisible(
- BuildConfig.PRIVACY_POLICY != null
- && QuickConversationsService.isPlayStoreFlavor());
qrCodeScanMenuItem.setVisible(isCameraFeatureAvailable());
if (QuickConversationsService.isQuicksy()) {
menuHideOffline.setVisible(false);
@@ -868,95 +854,49 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
private void askForContactsPermissions() {
- if (QuickConversationsService.isContactListIntegration(this)) {
- if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
- != PackageManager.PERMISSION_GRANTED) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
if (mRequestedContactsPermission.compareAndSet(false, true)) {
- final String consent =
- PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
- .getString(PREF_KEY_CONTACT_INTEGRATION_CONSENT, null);
- final boolean requiresConsent =
- (QuickConversationsService.isQuicksy()
- || QuickConversationsService.isPlayStoreFlavor())
- && !"agreed".equals(consent);
- if (requiresConsent && "declined".equals(consent)) {
- Log.d(Config.LOGTAG,"not asking for contacts permission because consent has been declined");
- return;
- }
- if (requiresConsent
- || shouldShowRequestPermissionRationale(
- Manifest.permission.READ_CONTACTS)) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ if (QuickConversationsService.isQuicksy() || shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AtomicBoolean requestPermission = new AtomicBoolean(false);
+ builder.setTitle(R.string.sync_with_contacts);
if (QuickConversationsService.isQuicksy()) {
- builder.setTitle(R.string.quicksy_wants_your_consent);
- builder.setMessage(
- Html.fromHtml(
- getString(R.string.sync_with_contacts_quicksy_static)));
+ builder.setMessage(Html.fromHtml(getString(R.string.sync_with_contacts_quicksy_static)));
} else {
- builder.setTitle(R.string.sync_with_contacts);
- builder.setMessage(
- getString(
- R.string.sync_with_contacts_long,
- getString(R.string.app_name)));
+ builder.setMessage(getString(R.string.sync_with_contacts_long, getString(R.string.app_name)));
}
@StringRes int confirmButtonText;
- if (requiresConsent) {
- confirmButtonText = R.string.agree_and_continue;
- } else {
+ if (QuickConversationsService.isConversations()) {
confirmButtonText = R.string.next;
- }
- builder.setPositiveButton(
- confirmButtonText,
- (dialog, which) -> {
- if (requiresConsent) {
- PreferenceManager.getDefaultSharedPreferences(
- getApplicationContext())
- .edit()
- .putString(
- PREF_KEY_CONTACT_INTEGRATION_CONSENT, "agreed")
- .apply();
- }
- if (requestPermission.compareAndSet(false, true)) {
- requestPermissions(
- new String[] {Manifest.permission.READ_CONTACTS},
- REQUEST_SYNC_CONTACTS);
- }
- });
- if (requiresConsent) {
- builder.setNegativeButton(R.string.decline, (dialog, which) -> PreferenceManager.getDefaultSharedPreferences(
- getApplicationContext())
- .edit()
- .putString(
- PREF_KEY_CONTACT_INTEGRATION_CONSENT, "declined")
- .apply());
} else {
- builder.setOnDismissListener(
- dialog -> {
- if (requestPermission.compareAndSet(false, true)) {
- requestPermissions(
- new String[] {
- Manifest.permission.READ_CONTACTS
- },
- REQUEST_SYNC_CONTACTS);
- }
- });
+ confirmButtonText = R.string.agree_and_continue;
}
- builder.setCancelable(requiresConsent);
+ builder.setPositiveButton(confirmButtonText, (dialog, which) -> {
+ if (requestPermission.compareAndSet(false, true)) {
+ requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
+ }
+ });
+ builder.setOnDismissListener(dialog -> {
+ if (QuickConversationsService.isConversations() && requestPermission.compareAndSet(false, true)) {
+ requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
+ }
+ });
+ if (QuickConversationsService.isQuicksy()) {
+ builder.setNegativeButton(R.string.decline, null);
+ }
+ builder.setCancelable(QuickConversationsService.isQuicksy());
final AlertDialog dialog = builder.create();
- dialog.setCanceledOnTouchOutside(requiresConsent);
- dialog.setOnShowListener(
- dialogInterface -> {
- final TextView tv = dialog.findViewById(android.R.id.message);
- if (tv != null) {
- tv.setMovementMethod(LinkMovementMethod.getInstance());
- }
- });
+ dialog.setCanceledOnTouchOutside(QuickConversationsService.isQuicksy());
+ dialog.setOnShowListener(dialogInterface -> {
+ final TextView tv = dialog.findViewById(android.R.id.message);
+ if (tv != null) {
+ tv.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ });
dialog.show();
} else {
- requestPermissions(
- new String[] {Manifest.permission.READ_CONTACTS},
- REQUEST_SYNC_CONTACTS);
+ requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
}
}
}
@@ -992,10 +932,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
@Override
protected void onBackendConnected() {
- if (QuickConversationsService.isContactListIntegration(this)
- && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
- || checkSelfPermission(Manifest.permission.READ_CONTACTS)
- == PackageManager.PERMISSION_GRANTED)) {
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
xmppConnectionService.getQuickConversationsService().considerSyncBackground(false);
}
if (mPostponedActivityResult != null) {
@@ -1225,7 +1163,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
@Override
- public void onCreateDialogPositiveClick(AutoCompleteTextView spinner, String name) {
+ public void onCreateDialogPositiveClick(Spinner spinner, String name) {
if (!xmppConnectionServiceBound) {
return;
}
@@ -1243,7 +1181,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
@Override
- public void onJoinDialogPositiveClick(Dialog dialog, AutoCompleteTextView spinner, TextInputLayout layout, AutoCompleteTextView jid, boolean isBookmarkChecked) {
+ public void onJoinDialogPositiveClick(Dialog dialog, Spinner spinner, TextInputLayout layout, AutoCompleteTextView jid, boolean isBookmarkChecked) {
if (!xmppConnectionServiceBound) {
return;
}
@@ -1275,7 +1213,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
openConversationsForBookmark(bookmark);
} else {
bookmark = new Bookmark(account, conferenceJid.asBareJid());
- bookmark.setAutojoin(true);
+ bookmark.setAutojoin(getBooleanPreference("autojoin", R.bool.autojoin));
final String nick = conferenceJid.getResource();
if (nick != null && !nick.isEmpty() && !nick.equals(MucOptions.defaultNick(account))) {
bookmark.setNick(nick);
@@ -1394,7 +1332,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
@Override
- public void onCreateContextMenu(@NonNull final ContextMenu menu, @NonNull final View v, final ContextMenuInfo menuInfo) {
+ public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
final StartConversationActivity activity = (StartConversationActivity) getActivity();
if (activity == null) {
@@ -1407,12 +1345,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
final Bookmark bookmark = (Bookmark) activity.conferences.get(acmi.position);
final Conversation conversation = bookmark.getConversation();
final MenuItem share = menu.findItem(R.id.context_share_uri);
- final MenuItem delete = menu.findItem(R.id.context_delete_conference);
- if (conversation != null) {
- delete.setTitle(R.string.delete_and_close);
- } else {
- delete.setTitle(R.string.delete_bookmark);
- }
share.setVisible(conversation == null || !conversation.isPrivateAndNonAnonymous());
} else if (mResContextMenu == R.menu.contact_context) {
activity.contact_context_id = acmi.position;
diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
index ba069b9a5..d5a95b7bf 100644
--- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
@@ -14,7 +14,14 @@ import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import org.whispersystems.libsignal.IdentityKey;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -33,14 +40,6 @@ import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
-import org.whispersystems.libsignal.IdentityKey;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdated {
private final Map ownKeysToTrust = new HashMap<>();
@@ -71,14 +70,12 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_trust_keys);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
this.contactJids = new ArrayList<>();
- final var intent = getIntent();
- final String[] contacts = intent == null ? null : intent.getStringArrayExtra("contacts");
- for (final String jid : (contacts == null ? new String[0] : contacts)) {
+ for (String jid : getIntent().getStringArrayExtra("contacts")) {
try {
this.contactJids.add(Jid.of(jid));
- } catch (final IllegalArgumentException ignored) {
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
}
}
@@ -103,7 +100,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.trust_keys, menu);
MenuItem scanQrCode = menu.findItem(R.id.action_scan_qr_code);
- scanQrCode.setVisible((!ownKeysToTrust.isEmpty() || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
+ scanQrCode.setVisible((ownKeysToTrust.size() > 0 || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
return super.onCreateOptionsMenu(menu);
}
@@ -155,7 +152,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
} else {
reloadFingerprints();
Log.d(Config.LOGTAG, "xmpp uri was: " + uri.getJid() + " has Fingerprints: " + uri.hasFingerprints());
- Toast.makeText(this, R.string.barcode_does_not_contain_fingerprints_for_this_chat, Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, R.string.barcode_does_not_contain_fingerprints_for_this_conversation, Toast.LENGTH_SHORT).show();
}
populateView();
}
@@ -194,7 +191,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
}
);
}
- if (fingerprints.isEmpty()) {
+ if (fingerprints.size() == 0) {
keysCardBinding.noKeysToAccept.setVisibility(View.VISIBLE);
if (hasNoOtherTrustedKeys(jid)) {
if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
@@ -257,8 +254,8 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
}
}
- private void disableEncryptionDialog(final View view) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ private void disableEncryptionDialog(View view) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.disable_encryption);
builder.setMessage(R.string.disable_encryption_message);
builder.setPositiveButton(R.string.disable_now, (dialog, which) -> {
@@ -282,7 +279,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
private boolean foreignActuallyHasKeys() {
synchronized (this.foreignKeysToTrust) {
for (Map.Entry> entry : foreignKeysToTrust.entrySet()) {
- if (!entry.getValue().isEmpty()) {
+ if (entry.getValue().size() > 0) {
return true;
}
}
@@ -308,7 +305,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
foreignKeysToTrust.clear();
for (Jid jid : contactJids) {
Set foreignKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), jid);
- if (hasNoOtherTrustedKeys(jid) && ownKeysSet.isEmpty()) {
+ if (hasNoOtherTrustedKeys(jid) && ownKeysSet.size() == 0) {
foreignKeysSet.addAll(service.getKeysWithTrust(FingerprintStatus.createActive(false), jid));
}
Map foreignFingerprints = new HashMap<>();
@@ -318,7 +315,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
foreignFingerprints.put(fingerprint, false);
}
}
- if (!foreignFingerprints.isEmpty() || !acceptedTargets.contains(jid)) {
+ if (foreignFingerprints.size() > 0 || !acceptedTargets.contains(jid)) {
foreignKeysToTrust.put(jid, foreignFingerprints);
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java
index 199847181..b1b91c99c 100644
--- a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java
@@ -11,8 +11,8 @@ import android.util.Log;
import android.view.View;
import android.widget.Toast;
-import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
+import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
@@ -36,12 +36,14 @@ import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
+import org.jetbrains.annotations.NotNull;
+
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class UriHandlerActivity extends BaseActivity {
+public class UriHandlerActivity extends AppCompatActivity {
public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
private static final String EXTRA_ALLOW_PROVISIONING = "extra_allow_provisioning";
@@ -224,13 +226,13 @@ public class UriHandlerActivity extends BaseActivity {
this.call.enqueue(
new Callback() {
@Override
- public void onFailure(@NonNull Call call, @NonNull IOException e) {
+ public void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.d(Config.LOGTAG, "unable to check HTTP url", e);
showError(R.string.no_xmpp_adddress_found);
}
@Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
+ public void onResponse(@NotNull Call call, @NotNull Response response) {
if (response.isSuccessful()) {
final String linkHeader = response.header("Link");
if (linkHeader != null && processLinkHeader(linkHeader)) {
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 82b2f4e08..e817b760f 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.ui;
import android.Manifest;
import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
@@ -16,9 +17,10 @@ import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -61,8 +63,6 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.RejectedExecutionException;
-import eu.siacs.conversations.AppSettings;
-import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
@@ -161,6 +161,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
};
+ public boolean mSkipBackgroundBinding = false;
public static boolean cancelPotentialWork(Message message, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
@@ -218,10 +219,14 @@ public abstract class XmppActivity extends ActionBarActivity {
abstract protected void refreshUiReal();
@Override
- public void onStart() {
+ protected void onStart() {
super.onStart();
if (!xmppConnectionServiceBound) {
- connectToBackend();
+ if (this.mSkipBackgroundBinding) {
+ Log.d(Config.LOGTAG, "skipping background binding");
+ } else {
+ connectToBackend();
+ }
} else {
this.registerListeners();
this.onBackendConnected();
@@ -361,7 +366,7 @@ public abstract class XmppActivity extends ActionBarActivity {
dialog.show();
}
- protected abstract void onBackendConnected();
+ abstract void onBackendConnected();
protected void registerListeners() {
if (this instanceof XmppConnectionService.OnConversationUpdate) {
@@ -427,10 +432,7 @@ public abstract class XmppActivity extends ActionBarActivity {
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
- startActivity(new Intent(this, eu.siacs.conversations.ui.activity.SettingsActivity.class));
- break;
- case R.id.action_privacy_policy:
- openPrivacyPolicy();
+ startActivity(new Intent(this, SettingsActivity.class));
break;
case R.id.action_accounts:
AccountUtils.launchManageAccounts(this);
@@ -448,20 +450,6 @@ public abstract class XmppActivity extends ActionBarActivity {
return super.onOptionsItemSelected(item);
}
- private void openPrivacyPolicy() {
- if (BuildConfig.PRIVACY_POLICY == null) {
- return;
- }
- final var viewPolicyIntent = new Intent(Intent.ACTION_VIEW);
- viewPolicyIntent.setData(Uri.parse(BuildConfig.PRIVACY_POLICY));
- try {
- startActivity(viewPolicyIntent);
- } catch (final ActivityNotFoundException e) {
- Toast.makeText(this, R.string.no_application_found_to_open_link, Toast.LENGTH_SHORT)
- .show();
- }
- }
-
public void selectPresence(final Conversation conversation, final PresenceSelector.OnPresenceSelected listener) {
final Contact contact = conversation.getContact();
if (contact.showInRoster() || contact.isSelf()) {
@@ -498,6 +486,7 @@ public abstract class XmppActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
metrics = getResources().getDisplayMetrics();
+ ExceptionHelper.init(getApplicationContext());
EmojiInitializationService.execute(this);
this.isCameraFeatureAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
this.mTheme = findTheme();
@@ -752,10 +741,10 @@ public abstract class XmppActivity extends ActionBarActivity {
}
}
- protected void choosePgpSignId(final Account account) {
- xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback<>() {
+ protected void choosePgpSignId(Account account) {
+ xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback() {
@Override
- public void success(final Account a) {
+ public void success(Account account1) {
}
@Override
@@ -872,7 +861,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
protected boolean hasStoragePermission(int requestCode) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
return false;
@@ -910,7 +899,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
protected boolean manuallyChangePresence() {
- return getBooleanPreference(AppSettings.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence);
+ return getBooleanPreference(SettingsActivity.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence);
}
protected String getShareableUri() {
@@ -951,7 +940,7 @@ public abstract class XmppActivity extends ActionBarActivity {
@Override
protected void onResume(){
super.onResume();
- SettingsUtils.applyScreenshotSetting(this);
+ SettingsUtils.applyScreenshotPreventionSetting(this);
}
protected int findTheme() {
@@ -979,7 +968,7 @@ public abstract class XmppActivity extends ActionBarActivity {
if (uri == null || uri.isEmpty()) {
return;
}
- final Point size = new Point();
+ Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
final int width = (size.x < size.y ? size.x : size.y);
Bitmap bitmap = BarcodeProvider.create2dBarcodeBitmap(uri, width);
@@ -1050,15 +1039,14 @@ public abstract class XmppActivity extends ActionBarActivity {
return invite;
}
- public boolean execute(final XmppActivity activity) {
- final XmppConnectionService service = activity.xmppConnectionService;
- final Conversation conversation = service.findConversationByUuid(this.uuid);
+ public boolean execute(XmppActivity activity) {
+ XmppConnectionService service = activity.xmppConnectionService;
+ Conversation conversation = service.findConversationByUuid(this.uuid);
if (conversation == null) {
return false;
}
if (conversation.getMode() == Conversation.MODE_MULTI) {
- for (final Jid jid : jids) {
- // TODO use direct invites for public conferences
+ for (Jid jid : jids) {
service.invite(conversation, jid);
}
return false;
diff --git a/src/main/java/eu/siacs/conversations/ui/activity/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/activity/SettingsActivity.java
deleted file mode 100644
index 7ac855534..000000000
--- a/src/main/java/eu/siacs/conversations/ui/activity/SettingsActivity.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package eu.siacs.conversations.ui.activity;
-
-import android.app.Notification;
-import android.os.Bundle;
-
-import androidx.databinding.DataBindingUtil;
-import androidx.preference.PreferenceFragmentCompat;
-
-import com.google.common.collect.ImmutableSet;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivitySettingsBinding;
-import eu.siacs.conversations.ui.Activities;
-import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.ui.fragment.settings.MainSettingsFragment;
-import eu.siacs.conversations.ui.fragment.settings.NotificationsSettingsFragment;
-import eu.siacs.conversations.ui.fragment.settings.XmppPreferenceFragment;
-
-import java.util.Collections;
-
-public class SettingsActivity extends XmppActivity {
-
- @Override
- protected void refreshUiReal() {}
-
- @Override
- protected void onBackendConnected() {
- final var fragmentManager = getSupportFragmentManager();
- final var currentFragment = fragmentManager.findFragmentById(R.id.fragment_container);
- if (currentFragment instanceof XmppPreferenceFragment xmppPreferenceFragment) {
- xmppPreferenceFragment.onBackendConnected();
- }
- }
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final ActivitySettingsBinding binding =
- DataBindingUtil.setContentView(this, R.layout.activity_settings);
- setSupportActionBar(binding.materialToolbar);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
-
- final var intent = getIntent();
- final var categories = intent == null ? Collections.emptySet() : intent.getCategories();
- final PreferenceFragmentCompat preferenceFragment;
- if (ImmutableSet.of(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
- .equals(categories)) {
- preferenceFragment = new NotificationsSettingsFragment();
- } else {
- preferenceFragment = new MainSettingsFragment();
- }
-
- final var fragmentManager = getSupportFragmentManager();
- final var currentFragment = fragmentManager.findFragmentById(R.id.fragment_container);
- if (currentFragment == null) {
- fragmentManager
- .beginTransaction()
- .replace(R.id.fragment_container, preferenceFragment)
- .commit();
- }
- binding.materialToolbar.setNavigationOnClickListener(
- view -> {
- if (fragmentManager.getBackStackEntryCount() == 0) {
- finish();
- } else {
- fragmentManager.popBackStack();
- }
- });
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java b/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java
deleted file mode 100644
index 975ba9431..000000000
--- a/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package eu.siacs.conversations.ui.activity.result;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.media.RingtoneManager;
-import android.net.Uri;
-
-import androidx.activity.result.contract.ActivityResultContract;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-public class PickRingtone extends ActivityResultContract {
-
- private static final Uri NONE = Uri.parse("about:blank");
-
- private final int ringToneType;
-
- public PickRingtone(final int ringToneType) {
- this.ringToneType = ringToneType;
- }
-
- @NonNull
- @Override
- public Intent createIntent(@NonNull final Context context, final Uri existing) {
- final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringToneType);
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
- if (noneToNull(existing) != null) {
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existing);
- }
- return intent;
- }
-
- @Override
- public Uri parseResult(int resultCode, @Nullable Intent data) {
- if (resultCode != Activity.RESULT_OK || data == null) {
- return null;
- }
- return nullToNone(data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI));
- }
-
- public static Uri noneToNull(final Uri uri) {
- return uri == null || NONE.equals(uri) ? null : uri;
- }
-
- public static @NonNull Uri nullToNone(final Uri uri) {
- return uri == null ? NONE : uri;
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
index 88475c580..038f255ea 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
@@ -8,16 +8,15 @@ import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.color.MaterialColors;
+import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ItemAccountBinding;
+import eu.siacs.conversations.databinding.AccountRowBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
-
-import java.util.List;
+import eu.siacs.conversations.ui.util.StyledAttributes;
public class AccountAdapter extends ArrayAdapter {
@@ -36,33 +35,36 @@ public class AccountAdapter extends ArrayAdapter {
this.showStateButton = true;
}
- @NonNull
@Override
public View getView(int position, View view, @NonNull ViewGroup parent) {
final Account account = getItem(position);
final ViewHolder viewHolder;
if (view == null) {
- ItemAccountBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_account, parent, false);
+ AccountRowBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.account_row, parent, false);
view = binding.getRoot();
viewHolder = new ViewHolder(binding);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
- viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
+ if (Config.DOMAIN_LOCK != null) {
+ viewHolder.binding.accountJid.setText(account.getJid().getLocal());
+ } else {
+ viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
+ }
AvatarWorkerTask.loadAvatar(account, viewHolder.binding.accountImage, R.dimen.avatar);
viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
- viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorPrimary));
+ viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
break;
case DISABLED:
case LOGGED_OUT:
case CONNECTING:
- viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorOnSurfaceVariant));
+ viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
break;
default:
- viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorError));
+ viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError));
break;
}
final boolean isDisabled = (account.getStatus() == Account.State.DISABLED);
@@ -82,9 +84,9 @@ public class AccountAdapter extends ArrayAdapter {
}
private static class ViewHolder {
- private final ItemAccountBinding binding;
+ private final AccountRowBinding binding;
- private ViewHolder(ItemAccountBinding binding) {
+ private ViewHolder(AccountRowBinding binding) {
this.binding = binding;
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java
index aa6fd1b78..ae9a67f6b 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java
@@ -13,18 +13,18 @@ import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
+import java.util.Locale;
+
import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ItemChannelDiscoveryBinding;
+import eu.siacs.conversations.databinding.SearchResultItemBinding;
import eu.siacs.conversations.entities.Room;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.xmpp.Jid;
-import java.util.Locale;
-
public class ChannelSearchResultAdapter extends ListAdapter implements View.OnCreateContextMenuListener {
- private static final DiffUtil.ItemCallback DIFF = new DiffUtil.ItemCallback<>() {
+ private static final DiffUtil.ItemCallback DIFF = new DiffUtil.ItemCallback() {
@Override
public boolean areItemsTheSame(@NonNull Room a, @NonNull Room b) {
return a.address != null && a.address.equals(b.address);
@@ -45,7 +45,7 @@ public class ChannelSearchResultAdapter extends ListAdapter {
@@ -352,40 +347,9 @@ public class ConversationAdapter
StyledAttributes.getColor(activity, R.attr.color_background_primary));
}
- final Message message = conversation.getLatestMessage();
- final int status = message.getStatus();
+ Message message = conversation.getLatestMessage();
final int unreadCount = conversation.unreadCount();
final boolean isRead = conversation.isRead();
- final @DrawableRes Integer messageStatusDrawable =
- MessageAdapter.getMessageStatusAsDrawable(message, status);
- if (message.getType() == Message.TYPE_RTP_SESSION) {
- viewHolder.binding.messageStatus.setVisibility(View.GONE);
- } else if (messageStatusDrawable == null) {
- if (status <= Message.STATUS_RECEIVED) {
- viewHolder.binding.messageStatus.setVisibility(View.GONE);
- } else {
- viewHolder.binding.messageStatus.setVisibility(View.INVISIBLE);
- }
- } else {
- viewHolder.binding.messageStatus.setImageResource(messageStatusDrawable);
- if (status == Message.STATUS_SEND_DISPLAYED) {
- viewHolder.binding.messageStatus.setImageResource(R.drawable.ic_done_all_bold_24dp);
- ImageViewCompat.setImageTintList(
- viewHolder.binding.messageStatus,
- ColorStateList.valueOf(
- MaterialColors.getColor(
- viewHolder.binding.messageStatus,
- com.google.android.material.R.attr.colorPrimary)));
- } else {
- ImageViewCompat.setImageTintList(
- viewHolder.binding.messageStatus,
- ColorStateList.valueOf(
- MaterialColors.getColor(
- viewHolder.binding.messageStatus,
- com.google.android.material.R.attr.colorControlNormal)));
- }
- viewHolder.binding.messageStatus.setVisibility(View.VISIBLE);
- }
final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
if (unreadCount > 0) {
viewHolder.binding.unreadCount.setVisibility(View.VISIBLE);
@@ -421,12 +385,63 @@ public class ConversationAdapter
R.attr.ic_attach_location, R.drawable.ic_attach_location);
showPreviewText = false;
} else {
- final var attachment = Attachment.of(message);
- imageResource = MediaAdapter.getImageDrawable(attachment);
- showPreviewText = false;
- viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
- viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
+ // TODO move this into static MediaPreview method and use same icons as in
+ // MediaAdapter
+ final String mime = message.getMimeType();
+ if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) {
+ final Message.FileParams fileParams = message.getFileParams();
+ if (fileParams.width > 0 && fileParams.height > 0) {
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_videocam,
+ R.drawable.ic_attach_videocam);
+ showPreviewText = false;
+ } else if (fileParams.runtime > 0) {
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_record, R.drawable.ic_attach_record);
+ showPreviewText = false;
+ } else {
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_document,
+ R.drawable.ic_attach_document);
+ showPreviewText = true;
+ }
+ } else {
+ switch (Strings.nullToEmpty(mime).split("/")[0]) {
+ case "image":
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_photo, R.drawable.ic_attach_photo);
+ showPreviewText = false;
+ break;
+ case "video":
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_videocam,
+ R.drawable.ic_attach_videocam);
+ showPreviewText = false;
+ break;
+ case "audio":
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_record,
+ R.drawable.ic_attach_record);
+ showPreviewText = false;
+ break;
+ default:
+ imageResource =
+ activity.getThemeResource(
+ R.attr.ic_attach_document,
+ R.drawable.ic_attach_document);
+ showPreviewText = true;
+ break;
+ }
+ }
}
+ viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
+ viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
} else {
viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
showPreviewText = true;
@@ -460,7 +475,7 @@ public class ConversationAdapter
viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
}
}
- if (status == Message.STATUS_RECEIVED) {
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
viewHolder.binding.senderName.setVisibility(View.VISIBLE);
viewHolder.binding.senderName.setText(
@@ -608,9 +623,9 @@ public class ConversationAdapter
}
static class ConversationViewHolder extends RecyclerView.ViewHolder {
- private final ItemConversationBinding binding;
+ private final ConversationListRowBinding binding;
- private ConversationViewHolder(final ItemConversationBinding binding) {
+ private ConversationViewHolder(ConversationListRowBinding binding) {
super(binding.getRoot());
this.binding = binding;
binding.getRoot().setLongClickable(true);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
index b085cb964..08f8fcd32 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
@@ -6,35 +6,32 @@ import android.widget.Filter;
import androidx.annotation.NonNull;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Ordering;
-
-import eu.siacs.conversations.Config;
-
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
+import java.util.Collections;
import java.util.Locale;
import java.util.regex.Pattern;
+import eu.siacs.conversations.Config;
+
public class KnownHostsAdapter extends ArrayAdapter {
private static final Pattern E164_PATTERN = Pattern.compile("^\\+[1-9]\\d{1,14}$");
- private List domains;
+ private ArrayList domains;
private final Filter domainFilter = new Filter() {
@Override
- protected FilterResults performFiltering(final CharSequence constraint) {
- final ImmutableList.Builder builder = new ImmutableList.Builder<>();
+ protected FilterResults performFiltering(CharSequence constraint) {
+ final ArrayList suggestions = new ArrayList<>();
final String[] split = constraint == null ? new String[0] : constraint.toString().split("@");
if (split.length == 1) {
final String local = split[0].toLowerCase(Locale.ENGLISH);
if (Config.QUICKSY_DOMAIN != null && E164_PATTERN.matcher(local).matches()) {
- builder.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
+ suggestions.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
} else {
for (String domain : domains) {
- builder.add(local + '@' + domain);
+ suggestions.add(local + '@' + domain);
}
}
} else if (split.length == 2) {
@@ -43,49 +40,45 @@ public class KnownHostsAdapter extends ArrayAdapter {
if (domains.contains(domainPart)) {
return new FilterResults();
}
- for (final String domain : domains) {
+ for (String domain : domains) {
if (domain.contains(domainPart)) {
- builder.add(localPart + "@" + domain);
+ suggestions.add(localPart + "@" + domain);
}
}
} else {
return new FilterResults();
}
- final var suggestions = builder.build();
- final FilterResults filterResults = new FilterResults();
+ FilterResults filterResults = new FilterResults();
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
}
@Override
- protected void publishResults(final CharSequence constraint, final FilterResults results) {
- final ImmutableList.Builder suggestions = new ImmutableList.Builder<>();
- if (results.values instanceof Collection> collection) {
- for(final Object item : collection) {
- if (item instanceof String string) {
- suggestions.add(string);
- }
- }
+ protected void publishResults(CharSequence constraint, FilterResults results) {
+ ArrayList filteredList = (ArrayList) results.values;
+ if (results.count > 0) {
+ clear();
+ addAll(filteredList);
+ notifyDataSetChanged();
}
- clear();
- addAll(suggestions.build());
- notifyDataSetChanged();
}
};
- public KnownHostsAdapter(final Context context, final int viewResourceId, final Collection knownHosts) {
+ public KnownHostsAdapter(Context context, int viewResourceId, Collection mKnownHosts) {
super(context, viewResourceId, new ArrayList<>());
- domains = Ordering.natural().sortedCopy(knownHosts);
+ domains = new ArrayList<>(mKnownHosts);
+ Collections.sort(domains);
}
- public KnownHostsAdapter(final Context context, final int viewResourceId) {
+ public KnownHostsAdapter(Context context, int viewResourceId) {
super(context, viewResourceId, new ArrayList<>());
- domains = ImmutableList.of();
+ domains = new ArrayList<>();
}
- public void refresh(final Collection knownHosts) {
- this.domains = Ordering.natural().sortedCopy(knownHosts);
+ public void refresh(Collection knownHosts) {
+ domains = new ArrayList<>(knownHosts);
+ Collections.sort(domains);
notifyDataSetChanged();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
index 4f9311392..5d6d72684 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -1,9 +1,7 @@
package eu.siacs.conversations.ui.adapter;
import android.content.SharedPreferences;
-import android.content.res.ColorStateList;
import android.preference.PreferenceManager;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -11,40 +9,30 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-import androidx.annotation.NonNull;
-import androidx.constraintlayout.helper.widget.Flow;
-import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.ViewCompat;
import androidx.databinding.DataBindingUtil;
-import com.google.android.material.color.MaterialColors;
-import com.google.common.collect.ImmutableList;
-import com.google.common.primitives.Ints;
-
-import eu.siacs.conversations.AppSettings;
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ItemContactBinding;
-import eu.siacs.conversations.entities.Contact;
-import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.entities.Presence;
-import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.ui.util.AvatarWorkerTask;
-import eu.siacs.conversations.utils.IrregularUnicodeDetector;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.utils.XEP0392Helper;
-import eu.siacs.conversations.xmpp.Jid;
+import com.wefika.flowlayout.FlowLayout;
import java.util.List;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ContactBinding;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.ui.SettingsActivity;
+import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.ui.util.AvatarWorkerTask;
+import eu.siacs.conversations.ui.util.StyledAttributes;
+import eu.siacs.conversations.utils.IrregularUnicodeDetector;
+import eu.siacs.conversations.xmpp.Jid;
+
public class ListItemAdapter extends ArrayAdapter {
protected XmppActivity activity;
private boolean showDynamicTags = false;
private OnTagClickedListener mOnTagClickedListener = null;
private final View.OnClickListener onTagTvClick = view -> {
- if (view instanceof TextView tv && mOnTagClickedListener != null) {
+ if (view instanceof TextView && mOnTagClickedListener != null) {
+ TextView tv = (TextView) view;
final String tag = tv.getText().toString();
mOnTagClickedListener.onTagClicked(tag);
}
@@ -58,78 +46,36 @@ public class ListItemAdapter extends ArrayAdapter {
public void refreshSettings() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
- this.showDynamicTags = preferences.getBoolean(AppSettings.SHOW_DYNAMIC_TAGS, false);
+ this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
}
- @NonNull
@Override
- public View getView(int position, View view, @NonNull ViewGroup parent) {
+ public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = activity.getLayoutInflater();
- final ListItem item = getItem(position);
+ ListItem item = getItem(position);
ViewHolder viewHolder;
if (view == null) {
- final ItemContactBinding binding = DataBindingUtil.inflate(inflater,R.layout.item_contact,parent,false);
+ ContactBinding binding = DataBindingUtil.inflate(inflater,R.layout.contact,parent,false);
viewHolder = ViewHolder.get(binding);
view = binding.getRoot();
} else {
viewHolder = (ViewHolder) view.getTag();
}
- if (view.isActivated()) {
- Log.d(Config.LOGTAG,"item "+item.getDisplayName()+" is activated");
- }
- //view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
- final List tags = item.getTags(activity);
- final boolean hasMetaTags;
- if (item instanceof Contact contact) {
- hasMetaTags = contact.isBlocked() || contact.getShownStatus() != Presence.Status.OFFLINE;
- } else {
- hasMetaTags = false;
- }
- if ((tags.isEmpty() && !hasMetaTags) || !this.showDynamicTags) {
+ view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
+
+ List tags = item.getTags(activity);
+ if (tags.size() == 0 || !this.showDynamicTags) {
viewHolder.tags.setVisibility(View.GONE);
} else {
viewHolder.tags.setVisibility(View.VISIBLE);
- viewHolder.tags.removeViews(1, viewHolder.tags.getChildCount() - 1);
- final ImmutableList.Builder viewIdBuilder = new ImmutableList.Builder<>();
- for (final ListItem.Tag tag : tags) {
- final String name = tag.getName();
- final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, viewHolder.tags, false);
- tv.setText(name);
- tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(getContext(),XEP0392Helper.rgbFromNick(name))));
+ viewHolder.tags.removeAllViewsInLayout();
+ for (ListItem.Tag tag : tags) {
+ TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, viewHolder.tags, false);
+ tv.setText(tag.getName());
+ tv.setBackgroundColor(tag.getColor());
tv.setOnClickListener(this.onTagTvClick);
- final int id = ViewCompat.generateViewId();
- tv.setId(id);
- viewIdBuilder.add(id);
viewHolder.tags.addView(tv);
}
- if (item instanceof Contact contact) {
- if (contact.isBlocked()) {
- final TextView tv =
- (TextView)
- inflater.inflate(
- R.layout.list_item_tag, viewHolder.tags, false);
- tv.setText(R.string.blocked);
- tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(tv.getContext(),ContextCompat.getColor(tv.getContext(),R.color.gray_800))));
- final int id = ViewCompat.generateViewId();
- tv.setId(id);
- viewIdBuilder.add(id);
- viewHolder.tags.addView(tv);
- } else {
- final Presence.Status status = contact.getShownStatus();
- if (status != Presence.Status.OFFLINE) {
- final TextView tv =
- (TextView)
- inflater.inflate(
- R.layout.list_item_tag, viewHolder.tags, false);
- UIHelper.setStatus(tv, status);
- final int id = ViewCompat.generateViewId();
- tv.setId(id);
- viewIdBuilder.add(id);
- viewHolder.tags.addView(tv);
- }
- }
- }
- viewHolder.flowWidget.setReferencedIds(Ints.toArray(viewIdBuilder.build()));
}
final Jid jid = item.getJid();
if (jid != null) {
@@ -156,20 +102,18 @@ public class ListItemAdapter extends ArrayAdapter {
private TextView name;
private TextView jid;
private ImageView avatar;
- private ConstraintLayout tags;
- private Flow flowWidget;
+ private FlowLayout tags;
private ViewHolder() {
}
- public static ViewHolder get(final ItemContactBinding binding) {
+ public static ViewHolder get(ContactBinding binding) {
ViewHolder viewHolder = new ViewHolder();
viewHolder.name = binding.contactDisplayName;
viewHolder.jid = binding.contactJid;
viewHolder.avatar = binding.contactPhoto;
viewHolder.tags = binding.tags;
- viewHolder.flowWidget = binding.flowWidget;
binding.getRoot().setTag(viewHolder);
return viewHolder;
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java
index 7b3a35ab3..2683876c7 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java
@@ -1,50 +1,47 @@
package eu.siacs.conversations.ui.adapter;
-import android.content.res.ColorStateList;
+import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
+import androidx.annotation.AttrRes;
import androidx.annotation.DimenRes;
-import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
-import androidx.core.widget.ImageViewCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
-import com.google.android.material.color.MaterialColors;
-import com.google.common.base.Strings;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ItemMediaBinding;
-import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.ui.util.Attachment;
-import eu.siacs.conversations.ui.util.ViewUtil;
-import eu.siacs.conversations.worker.ExportBackupWorker;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.MediaBinding;
+import eu.siacs.conversations.services.ExportBackupService;
+import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.ui.util.Attachment;
+import eu.siacs.conversations.ui.util.StyledAttributes;
+import eu.siacs.conversations.ui.util.ViewUtil;
+
public class MediaAdapter extends RecyclerView.Adapter {
- public static final List DOCUMENT_MIMES =
- Arrays.asList(
- "application/pdf",
- "application/vnd.oasis.opendocument.text",
- "application/msword",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- "text/x-tex",
- "text/plain");
- public static final List CODE_MIMES = Arrays.asList("text/html", "text/xml");
+ public static final List DOCUMENT_MIMES = Arrays.asList(
+ "application/pdf",
+ "application/vnd.oasis.opendocument.text",
+ "application/msword",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "text/x-tex",
+ "text/plain"
+ );
private final ArrayList attachments = new ArrayList<>();
@@ -58,77 +55,58 @@ public class MediaAdapter extends RecyclerView.Adapter ViewUtil.view(activity, attachment));
}
- public void setAttachments(final List attachments) {
+ public void setAttachments(List attachments) {
this.attachments.clear();
this.attachments.addAll(attachments);
notifyDataSetChanged();
@@ -188,21 +167,16 @@ public class MediaAdapter extends RecyclerView.Adapter {
+public class MediaPreviewAdapter extends RecyclerView.Adapter {
private final ArrayList mediaPreviews = new ArrayList<>();
@@ -55,9 +43,8 @@ public class MediaPreviewAdapter
@NonNull
@Override
public MediaPreviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
- ItemMediaPreviewBinding binding =
- DataBindingUtil.inflate(layoutInflater, R.layout.item_media_preview, parent, false);
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ MediaPreviewBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media_preview, parent, false);
return new MediaPreviewViewHolder(binding);
}
@@ -66,19 +53,18 @@ public class MediaPreviewAdapter
final Context context = conversationFragment.getActivity();
final Attachment attachment = mediaPreviews.get(position);
if (attachment.renderThumbnail()) {
- ImageViewCompat.setImageTintList(holder.binding.mediaPreview, null);
+ holder.binding.mediaPreview.setImageAlpha(255);
loadPreview(attachment, holder.binding.mediaPreview);
} else {
cancelPotentialWork(attachment, holder.binding.mediaPreview);
- MediaAdapter.renderPreview(attachment, holder.binding.mediaPreview);
+ MediaAdapter.renderPreview(context, attachment, holder.binding.mediaPreview);
}
- holder.binding.deleteButton.setOnClickListener(
- v -> {
- final int pos = mediaPreviews.indexOf(attachment);
- mediaPreviews.remove(pos);
- notifyItemRemoved(pos);
- conversationFragment.toggleInputMethod();
- });
+ holder.binding.deleteButton.setOnClickListener(v -> {
+ final int pos = mediaPreviews.indexOf(attachment);
+ mediaPreviews.remove(pos);
+ notifyItemRemoved(pos);
+ conversationFragment.toggleInputMethod();
+ });
holder.binding.mediaPreview.setOnClickListener(v -> {
if (attachment.getType() == Attachment.Type.IMAGE) {
conversationFragment.editImage(attachment.getUri());
@@ -88,27 +74,17 @@ public class MediaPreviewAdapter
});
}
- private static void view(final Context context, final Attachment attachment) {
+ private static void view(final Context context, Attachment attachment) {
final Intent view = new Intent(Intent.ACTION_VIEW);
- if (attachment.getType() == Attachment.Type.LOCATION) {
- view.setClass(context, ShowLocationActivity.class);
- view.setData(attachment.getUri());
- } else {
- final Uri uri = FileBackend.getUriForUri(context, attachment.getUri());
- view.setDataAndType(uri, attachment.getMime());
- view.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
+ final Uri uri = FileBackend.getUriForUri(context, attachment.getUri());
+ view.setDataAndType(uri, attachment.getMime());
+ view.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
context.startActivity(view);
} catch (final ActivityNotFoundException e) {
- Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT)
- .show();
+ Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show();
} catch (final SecurityException e) {
- Toast.makeText(
- context,
- R.string.sharing_application_not_grant_permission,
- Toast.LENGTH_SHORT)
- .show();
+ Toast.makeText(context, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
}
}
@@ -137,27 +113,16 @@ public class MediaPreviewAdapter
private void loadPreview(Attachment attachment, ImageView imageView) {
if (cancelPotentialWork(attachment, imageView)) {
XmppActivity activity = (XmppActivity) conversationFragment.getActivity();
- final Bitmap bm =
- activity.xmppConnectionService
- .getFileBackend()
- .getPreviewForUri(
- attachment,
- Math.round(
- activity.getResources()
- .getDimension(R.dimen.media_preview_size)),
- true);
+ final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment,Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)),true);
if (bm != null) {
cancelPotentialWork(attachment, imageView);
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
} else {
- imageView.setBackgroundColor(
- ContextCompat.getColor(imageView.getContext(), R.color.gray_800));
+ imageView.setBackgroundColor(0xff333333);
imageView.setImageDrawable(null);
final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
- final AsyncDrawable asyncDrawable =
- new AsyncDrawable(
- conversationFragment.getActivity().getResources(), null, task);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(conversationFragment.getActivity().getResources(), null, task);
imageView.setImageDrawable(asyncDrawable);
try {
task.execute(attachment);
@@ -184,7 +149,8 @@ public class MediaPreviewAdapter
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
- if (drawable instanceof AsyncDrawable asyncDrawable) {
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
@@ -197,7 +163,7 @@ public class MediaPreviewAdapter
}
public boolean hasAttachments() {
- return !mediaPreviews.isEmpty();
+ return mediaPreviews.size() > 0;
}
public ArrayList getAttachments() {
@@ -210,9 +176,9 @@ public class MediaPreviewAdapter
static class MediaPreviewViewHolder extends RecyclerView.ViewHolder {
- private final ItemMediaPreviewBinding binding;
+ private final MediaPreviewBinding binding;
- MediaPreviewViewHolder(ItemMediaPreviewBinding binding) {
+ MediaPreviewViewHolder(MediaPreviewBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
@@ -246,14 +212,7 @@ public class MediaPreviewAdapter
if (activity == null) {
return null;
}
- return activity.xmppConnectionService
- .getFileBackend()
- .getPreviewForUri(
- this.attachment,
- Math.round(
- activity.getResources()
- .getDimension(R.dimen.media_preview_size)),
- false);
+ return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)), false);
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java
index 6463412dd..de3216908 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java
@@ -17,7 +17,7 @@ import org.openintents.openpgp.util.OpenPgpUtils;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
-import eu.siacs.conversations.databinding.ItemContactBinding;
+import eu.siacs.conversations.databinding.ContactBinding;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -62,7 +62,7 @@ public class UserAdapter extends ListAdapter
- implements View.OnCreateContextMenuListener {
+public class UserPreviewAdapter extends ListAdapter implements View.OnCreateContextMenuListener {
private MucOptions.User selectedUser = null;
@@ -29,43 +28,29 @@ public class UserPreviewAdapter extends ListAdapter {
- final XmppActivity activity = XmppActivity.find(v);
- if (activity != null) {
- activity.highlightInMuc(user.getConversation(), user.getName());
- }
- });
+ viewHolder.binding.getRoot().setOnClickListener(v -> {
+ final XmppActivity activity = XmppActivity.find(v);
+ if (activity != null) {
+ activity.highlightInMuc(user.getConversation(), user.getName());
+ }
+ });
viewHolder.binding.getRoot().setOnCreateContextMenuListener(this);
viewHolder.binding.getRoot().setTag(user);
- viewHolder
- .binding
- .getRoot()
- .setOnLongClickListener(
- v -> {
- selectedUser = user;
- return false;
- });
+ viewHolder.binding.getRoot().setOnLongClickListener(v -> {
+ selectedUser = user;
+ return false;
+ });
}
@Override
- public void onCreateContextMenu(
- ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MucDetailsContextMenuHelper.onCreateContextMenu(menu, v);
}
@@ -75,9 +60,9 @@ public class UserPreviewAdapter extends ListAdapter getValues() {
+ List