glideRequest = GlideApp.with(context).asBitmap().load(new ConversationShortcutPhoto(recipient));
- if (recipient.shouldBlurAvatar()) {
- glideRequest = glideRequest.transform(new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS));
- }
- return Icon.createWithAdaptiveBitmap(glideRequest.submit().get());
- } catch (ExecutionException | InterruptedException e) {
- throw new AssertionError("This call should not fail.", e);
- }
- }
-
@WorkerThread
public static @NonNull IconCompat getIconCompatForShortcut(@NonNull Context context, @NonNull Recipient recipient) {
try {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java
index c145e8f8df..fa37473671 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java
@@ -1,16 +1,15 @@
package org.thoughtcrime.securesms.util;
-import android.app.Person;
import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
-import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.WorkerThread;
+import androidx.core.app.Person;
+import androidx.core.content.pm.ShortcutInfoCompat;
+import androidx.core.content.pm.ShortcutManagerCompat;
import com.annimon.stream.Stream;
@@ -37,7 +36,7 @@ import java.util.Set;
*/
public final class ConversationUtil {
- public static final int CONVERSATION_SUPPORT_VERSION = 30;
+ public static final int CONVERSATION_SUPPORT_VERSION = 30;
private static final String TAG = Log.tag(ConversationUtil.class);
@@ -49,7 +48,7 @@ public final class ConversationUtil {
*/
@WorkerThread
public static @NonNull String getChannelId(@NonNull Context context, @NonNull Recipient recipient) {
- Recipient resolved = recipient.resolve();
+ Recipient resolved = recipient.resolve();
return resolved.getNotificationChannel() != null ? resolved.getNotificationChannel() : NotificationChannels.getMessagesChannel(context);
}
@@ -63,24 +62,21 @@ public final class ConversationUtil {
/**
* Synchronously pushes a new dynamic shortcut for the given recipient if one does not already exist.
- *
+ *
* If added, this recipient is given a high ranking with the intention of not appearing immediately in results.
*/
@WorkerThread
public static void pushShortcutForRecipientIfNeededSync(@NonNull Context context, @NonNull Recipient recipient) {
- if (Build.VERSION.SDK_INT >= CONVERSATION_SUPPORT_VERSION) {
- ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(context);
- String shortcutId = getShortcutId(recipient);
- List shortcuts = shortcutManager.getDynamicShortcuts();
+ String shortcutId = getShortcutId(recipient);
+ List shortcuts = ShortcutManagerCompat.getDynamicShortcuts(context);
- boolean hasPushedRecipientShortcut = Stream.of(shortcuts)
- .filter(info -> Objects.equals(shortcutId, info.getId()))
- .findFirst()
- .isPresent();
+ boolean hasPushedRecipientShortcut = Stream.of(shortcuts)
+ .filter(info -> Objects.equals(shortcutId, info.getId()))
+ .findFirst()
+ .isPresent();
- if (!hasPushedRecipientShortcut) {
- pushShortcutForRecipientInternal(context, recipient, shortcuts.size());
- }
+ if (!hasPushedRecipientShortcut) {
+ pushShortcutForRecipientInternal(context, recipient, shortcuts.size());
}
}
@@ -88,33 +84,26 @@ public final class ConversationUtil {
* Clears all currently set dynamic shortcuts
*/
public static void clearAllShortcuts(@NonNull Context context) {
- if (Build.VERSION.SDK_INT >= CONVERSATION_SUPPORT_VERSION) {
- ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(context);
- List shortcutInfos = shortcutManager.getDynamicShortcuts();
+ List shortcutInfos = ShortcutManagerCompat.getDynamicShortcuts(context);
- shortcutManager.removeLongLivedShortcuts(Stream.of(shortcutInfos).map(ShortcutInfo::getId).toList());
- }
+ ShortcutManagerCompat.removeLongLivedShortcuts(context, Stream.of(shortcutInfos).map(ShortcutInfoCompat::getId).toList());
}
/**
* Clears the shortcuts tied to a given thread.
*/
public static void clearShortcuts(@NonNull Context context, @NonNull Set threadIds) {
- if (Build.VERSION.SDK_INT >= CONVERSATION_SUPPORT_VERSION) {
- SignalExecutors.BOUNDED.execute(() -> {
- List recipientIds = DatabaseFactory.getThreadDatabase(context).getRecipientIdsForThreadIds(threadIds);
- ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(context);
+ SignalExecutors.BOUNDED.execute(() -> {
+ List recipientIds = DatabaseFactory.getThreadDatabase(context).getRecipientIdsForThreadIds(threadIds);
- shortcutManager.removeLongLivedShortcuts(Stream.of(recipientIds).map(ConversationUtil::getShortcutId).toList());
- });
- }
+ ShortcutManagerCompat.removeLongLivedShortcuts(context, Stream.of(recipientIds).map(ConversationUtil::getShortcutId).toList());
+ });
}
/**
* Returns an ID that is unique between all recipients.
*
* @param recipientId The recipient ID to get a shortcut ID for
- *
* @return A unique identifier that is stable for a given recipient id
*/
public static @NonNull String getShortcutId(@NonNull RecipientId recipientId) {
@@ -125,7 +114,6 @@ public final class ConversationUtil {
* Returns an ID that is unique between all recipients.
*
* @param recipient The recipient to get a shortcut for.
- *
* @return A unique identifier that is stable for a given recipient id
*/
public static @NonNull String getShortcutId(@NonNull Recipient recipient) {
@@ -148,10 +136,8 @@ public final class ConversationUtil {
}
}
- @RequiresApi(CONVERSATION_SUPPORT_VERSION)
public static int getMaxShortcuts(@NonNull Context context) {
- ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(context);
- return Math.min(shortcutManager.getMaxShortcutCountPerActivity(), 150);
+ return Math.min(ShortcutManagerCompat.getMaxShortcutCountPerActivity(context), 150);
}
/**
@@ -162,42 +148,37 @@ public final class ConversationUtil {
* recipient should be first in the list.
* @return True if the update was successful, false if we were rate-limited.
*/
- @RequiresApi(CONVERSATION_SUPPORT_VERSION)
@WorkerThread
public static boolean setActiveShortcuts(@NonNull Context context, @NonNull List rankedRecipients) {
- ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(context);
-
- if (shortcutManager.isRateLimitingActive()) {
+ if (ShortcutManagerCompat.isRateLimitingActive(context)) {
return false;
}
- int maxShortcuts = shortcutManager.getMaxShortcutCountPerActivity();
+ int maxShortcuts = ShortcutManagerCompat.getMaxShortcutCountPerActivity(context);
if (rankedRecipients.size() > maxShortcuts) {
Log.w(TAG, "Too many recipients provided! Provided: " + rankedRecipients.size() + ", Max: " + maxShortcuts);
rankedRecipients = rankedRecipients.subList(0, maxShortcuts);
}
- List shortcuts = new ArrayList<>(rankedRecipients.size());
+ List shortcuts = new ArrayList<>(rankedRecipients.size());
for (int i = 0; i < rankedRecipients.size(); i++) {
- ShortcutInfo info = buildShortcutInfo(context, rankedRecipients.get(i), i);
+ ShortcutInfoCompat info = buildShortcutInfo(context, rankedRecipients.get(i), i);
shortcuts.add(info);
}
- return shortcutManager.setDynamicShortcuts(shortcuts);
+ return ShortcutManagerCompat.setDynamicShortcuts(context, shortcuts);
}
/**
* Pushes a dynamic shortcut for a given recipient to the shortcut manager
*/
- @RequiresApi(CONVERSATION_SUPPORT_VERSION)
@WorkerThread
private static void pushShortcutForRecipientInternal(@NonNull Context context, @NonNull Recipient recipient, int rank) {
- ShortcutInfo shortcutInfo = buildShortcutInfo(context, recipient, rank);
- ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(context);
+ ShortcutInfoCompat shortcutInfo = buildShortcutInfo(context, recipient, rank);
- shortcutManager.pushDynamicShortcut(shortcutInfo);
+ ShortcutManagerCompat.pushDynamicShortcut(context, shortcutInfo);
}
/**
@@ -206,13 +187,12 @@ public final class ConversationUtil {
* @param context The Context under which we are operating
* @param recipient The Recipient to generate a ShortcutInfo for
* @param rank The rank that should be assigned to this recipient
- * @return The new ShortcutInfo
+ * @return The new ShortcutInfo
*/
- @RequiresApi(CONVERSATION_SUPPORT_VERSION)
@WorkerThread
- private static @NonNull ShortcutInfo buildShortcutInfo(@NonNull Context context,
- @NonNull Recipient recipient,
- int rank)
+ private static @NonNull ShortcutInfoCompat buildShortcutInfo(@NonNull Context context,
+ @NonNull Recipient recipient,
+ int rank)
{
Recipient resolved = recipient.resolve();
Person[] persons = buildPersons(context, resolved);
@@ -220,49 +200,46 @@ public final class ConversationUtil {
String shortName = resolved.isSelf() ? context.getString(R.string.note_to_self) : resolved.getShortDisplayName(context);
String longName = resolved.isSelf() ? context.getString(R.string.note_to_self) : resolved.getDisplayName(context);
- return new ShortcutInfo.Builder(context, getShortcutId(resolved))
- .setLongLived(true)
- .setIntent(ConversationIntents.createBuilder(context, resolved.getId(), threadId).build())
- .setShortLabel(shortName)
- .setLongLabel(longName)
- .setIcon(AvatarUtil.getIconForShortcut(context, resolved))
- .setPersons(persons)
- .setCategories(Collections.singleton(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION))
- .setActivity(new ComponentName(context, "org.thoughtcrime.securesms.RoutingActivity"))
- .setRank(rank)
- .build();
+ return new ShortcutInfoCompat.Builder(context, getShortcutId(resolved))
+ .setLongLived(true)
+ .setIntent(ConversationIntents.createBuilder(context, resolved.getId(), threadId).build())
+ .setShortLabel(shortName)
+ .setLongLabel(longName)
+ .setIcon(AvatarUtil.getIconCompatForShortcut(context, resolved))
+ .setPersons(persons)
+ .setCategories(Collections.singleton("android.shortcut.conversation"))
+ .setActivity(new ComponentName(context, "org.thoughtcrime.securesms.RoutingActivity"))
+ .setRank(rank)
+ .build();
}
/**
* @return an array of Person objects correlating to members of a conversation (other than self)
*/
- @RequiresApi(CONVERSATION_SUPPORT_VERSION)
@WorkerThread
private static @NonNull Person[] buildPersons(@NonNull Context context, @NonNull Recipient recipient) {
if (recipient.isGroup()) {
return buildPersonsForGroup(context, recipient.getGroupId().get());
} else {
- return new Person[]{buildPerson(context, recipient)};
+ return new Person[] { buildPerson(context, recipient) };
}
}
/**
* @return an array of Person objects correlating to members of a group (other than self)
*/
- @RequiresApi(CONVERSATION_SUPPORT_VERSION)
@WorkerThread
private static @NonNull Person[] buildPersonsForGroup(@NonNull Context context, @NonNull GroupId groupId) {
List members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
- return Stream.of(members).map(member -> buildPerson(context, member.resolve())).toArray(Person[]::new);
+ return Stream.of(members).map(member -> buildPersonWithoutIcon(context, member.resolve())).toArray(Person[]::new);
}
/**
* @return A Person object representing the given Recipient
*/
- @RequiresApi(28)
@WorkerThread
- public static @NonNull Person buildPerson(@NonNull Context context, @NonNull Recipient recipient) {
+ public static @NonNull Person buildPersonWithoutIcon(@NonNull Context context, @NonNull Recipient recipient) {
return new Person.Builder()
.setKey(getShortcutId(recipient.getId()))
.setName(recipient.getDisplayName(context))
@@ -274,12 +251,12 @@ public final class ConversationUtil {
* @return A Compat Library Person object representing the given Recipient
*/
@WorkerThread
- public static @NonNull androidx.core.app.Person buildPersonCompat(@NonNull Context context, @NonNull Recipient recipient) {
- return new androidx.core.app.Person.Builder()
- .setKey(getShortcutId(recipient.getId()))
- .setName(recipient.getDisplayName(context))
- .setIcon(AvatarUtil.getIconForNotification(context, recipient))
- .setUri(recipient.isSystemContact() ? recipient.getContactUri().toString() : null)
- .build();
+ public static @NonNull Person buildPerson(@NonNull Context context, @NonNull Recipient recipient) {
+ return new Person.Builder()
+ .setKey(getShortcutId(recipient.getId()))
+ .setName(recipient.getDisplayName(context))
+ .setIcon(AvatarUtil.getIconForNotification(context, recipient))
+ .setUri(recipient.isSystemContact() ? recipient.getContactUri().toString() : null)
+ .build();
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java
index 86b2158a1c..e5294a025f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/ServiceUtil.java
@@ -8,7 +8,6 @@ import android.app.NotificationManager;
import android.app.job.JobScheduler;
import android.content.ClipboardManager;
import android.content.Context;
-import android.content.pm.ShortcutManager;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManager;
import android.location.LocationManager;
@@ -35,11 +34,6 @@ public class ServiceUtil {
return (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
}
- @RequiresApi(25)
- public static @Nullable ShortcutManager getShortcutManager(@NonNull Context context) {
- return ContextCompat.getSystemService(context, ShortcutManager.class);
- }
-
public static WindowManager getWindowManager(Context context) {
return (WindowManager) context.getSystemService(Activity.WINDOW_SERVICE);
}
diff --git a/app/witness-verifications.gradle b/app/witness-verifications.gradle
index a1ee83fbdc..f00b164160 100644
--- a/app/witness-verifications.gradle
+++ b/app/witness-verifications.gradle
@@ -69,11 +69,11 @@ dependencyVerification {
['androidx.coordinatorlayout:coordinatorlayout:1.1.0',
'44a9e30abf56af1025c52a0af506fee9c4131aa55efda52f9fd9451211c5e8cb'],
- ['androidx.core:core-ktx:1.1.0',
- '070cc5f8864f449128a2f4b25ca5b67aa3adca3ee1bd611e2eaf1a18fad83178'],
+ ['androidx.core:core-ktx:1.5.0',
+ '5964cfe7a4882da2a00fb6ca3d3a072d04139208186f7bc4b3cb66022764fc42'],
- ['androidx.core:core:1.3.2',
- '94de196cd67950cff6ef3e1ac59015f8eaaf61840bdc238f2cf54ddef8dd0be9'],
+ ['androidx.core:core:1.5.0',
+ '2b279712795689069cfb63e48b3ab63c32a5649bdda44c482eb8f81ca1a72161'],
['androidx.cursoradapter:cursoradapter:1.0.0',
'a81c8fe78815fa47df5b749deb52727ad11f9397da58b16017f4eb2c11e28564'],
@@ -195,6 +195,9 @@ dependencyVerification {
['androidx.savedstate:savedstate:1.0.0',
'2510a5619c37579c9ce1a04574faaf323cd0ffe2fc4e20fa8f8f01e5bb402e83'],
+ ['androidx.sharetarget:sharetarget:1.1.0',
+ '618574dca0dcfc644282c1ec65c159fc349e6c500dc77444ada39b42638a3824'],
+
['androidx.slidingpanelayout:slidingpanelayout:1.0.0',
'76bffb7cefbf780794d8817002dad1562f3e27c0a9f746d62401c8edb30aeede'],
@@ -213,8 +216,8 @@ dependencyVerification {
['androidx.vectordrawable:vectordrawable:1.1.0',
'46fd633ac01b49b7fcabc263bf098c5a8b9e9a69774d234edcca04fb02df8e26'],
- ['androidx.versionedparcelable:versionedparcelable:1.1.0',
- '9a1d77140ac222b7866b5054ee7d159bc1800987ed2d46dd6afdd145abb710c1'],
+ ['androidx.versionedparcelable:versionedparcelable:1.1.1',
+ '57e8d93260d18d5b9007c9eed3c64ad159de90c8609ebfc74a347cbd514535a4'],
['androidx.viewpager2:viewpager2:1.0.0',
'e95c0031d4cc247cd48196c6287e58d2cee54d9c79b85afea7c90920330275af'],