mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
174 lines
6.7 KiB
Java
174 lines
6.7 KiB
Java
package org.thoughtcrime.securesms.connect;
|
|
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.ShortcutManager;
|
|
import android.graphics.Bitmap;
|
|
import android.os.Build;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.RequiresApi;
|
|
import androidx.core.content.pm.ShortcutInfoCompat;
|
|
import androidx.core.content.pm.ShortcutManagerCompat;
|
|
import androidx.core.graphics.drawable.IconCompat;
|
|
|
|
import com.b44t.messenger.DcChat;
|
|
import com.b44t.messenger.DcChatlist;
|
|
import com.b44t.messenger.DcContext;
|
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|
|
|
import org.thoughtcrime.securesms.ShareActivity;
|
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
|
import org.thoughtcrime.securesms.mms.GlideRequest;
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
|
import org.thoughtcrime.securesms.util.DrawableUtil;
|
|
import org.thoughtcrime.securesms.util.Util;
|
|
|
|
import java.util.Collections;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.concurrent.ExecutionException;
|
|
|
|
/**
|
|
* The Signal code has a similar class called ConversationUtil.
|
|
*
|
|
* This class uses the Sharing Shortcuts API to publish dynamic launcher shortcuts (the ones that
|
|
* appear when you long-press on an app) and direct-sharing-shortcuts.
|
|
*
|
|
* It replaces the class DirectShareService, because DirectShareService used the
|
|
* ChooserTargetService API, which was replaced by the Sharing Shortcuts API.
|
|
*/
|
|
public class DirectShareUtil {
|
|
|
|
private static final String TAG = DirectShareUtil.class.getSimpleName();
|
|
private static final String SHORTCUT_CATEGORY = "android.shortcut.conversation";
|
|
|
|
public static void clearShortcut(@NonNull Context context, int chatId) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
Util.runOnAnyBackgroundThread(() -> {
|
|
try {
|
|
ShortcutManagerCompat.removeDynamicShortcuts(context, Collections.singletonList(Integer.toString(chatId)));
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Clearing shortcut failed: " + e);
|
|
e.printStackTrace();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public static void resetAllShortcuts(@NonNull Context context) {
|
|
Util.runOnBackground(() -> {
|
|
try {
|
|
ShortcutManagerCompat.removeAllDynamicShortcuts(context);
|
|
triggerRefreshDirectShare(context);
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Resetting shortcuts failed: " + e);
|
|
e.printStackTrace();
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void triggerRefreshDirectShare(Context context) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
Util.runOnBackgroundDelayed(() -> {
|
|
try {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1
|
|
&& context.getSystemService(ShortcutManager.class).isRateLimitingActive()) {
|
|
return;
|
|
}
|
|
|
|
int maxShortcuts = ShortcutManagerCompat.getMaxShortcutCountPerActivity(context);
|
|
List<ShortcutInfoCompat> currentShortcuts = ShortcutManagerCompat.getDynamicShortcuts(context);
|
|
List<ShortcutInfoCompat> newShortcuts = getChooserTargets(context);
|
|
|
|
if (maxShortcuts > 0
|
|
&& currentShortcuts.size() + newShortcuts.size() > maxShortcuts) {
|
|
ShortcutManagerCompat.removeAllDynamicShortcuts(context);
|
|
}
|
|
|
|
boolean success = ShortcutManagerCompat.addDynamicShortcuts(context, newShortcuts);
|
|
Log.i(TAG, "Updated dynamic shortcuts, success: " + success);
|
|
} catch(Exception e) {
|
|
Log.e(TAG, "Updating dynamic shortcuts failed: " + e);
|
|
}
|
|
|
|
// Wait 1500ms, this is called by onResume(), and we want to make sure that refreshing
|
|
// shortcuts does not delay loading of the chatlist
|
|
}, 1500);
|
|
}
|
|
}
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
|
private static List<ShortcutInfoCompat> getChooserTargets(Context context) {
|
|
List<ShortcutInfoCompat> results = new LinkedList<>();
|
|
DcContext dcContext = DcHelper.getContext(context);
|
|
|
|
DcChatlist chatlist = dcContext.getChatlist(
|
|
DcContext.DC_GCL_FOR_FORWARDING | DcContext.DC_GCL_NO_SPECIALS,
|
|
null,
|
|
0
|
|
);
|
|
int max = 5;
|
|
if (chatlist.getCnt() < max) {
|
|
max = chatlist.getCnt();
|
|
}
|
|
for (int i = 0; i < max; i++) {
|
|
DcChat chat = chatlist.getChat(i);
|
|
if (!chat.canSend()) {
|
|
continue;
|
|
}
|
|
|
|
Intent intent = new Intent(context, ShareActivity.class);
|
|
intent.setAction(Intent.ACTION_SEND);
|
|
intent.putExtra(ShareActivity.EXTRA_ACC_ID, dcContext.getAccountId());
|
|
intent.putExtra(ShareActivity.EXTRA_CHAT_ID, chat.getId());
|
|
|
|
Recipient recipient = new Recipient(context, chat);
|
|
Bitmap avatar = getIconForShortcut(context, recipient);
|
|
results.add(new ShortcutInfoCompat.Builder(context, Integer.toString(chat.getId()))
|
|
.setShortLabel(chat.getName())
|
|
.setLongLived(true)
|
|
.setRank(i+1)
|
|
.setIcon(IconCompat.createWithAdaptiveBitmap(avatar))
|
|
.setCategories(Collections.singleton(SHORTCUT_CATEGORY))
|
|
.setIntent(intent)
|
|
.setActivity(new ComponentName(context, "org.thoughtcrime.securesms.RoutingActivity"))
|
|
.build());
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
private static Bitmap getIconForShortcut(@NonNull Context context, @NonNull Recipient recipient) {
|
|
try {
|
|
return getShortcutInfoBitmap(context, recipient);
|
|
} catch (ExecutionException | InterruptedException | NullPointerException e) {
|
|
return getFallbackDrawable(context, recipient);
|
|
}
|
|
}
|
|
|
|
private static @NonNull Bitmap getShortcutInfoBitmap(@NonNull Context context, @NonNull Recipient recipient) throws ExecutionException, InterruptedException {
|
|
return DrawableUtil.wrapBitmapForShortcutInfo(request(GlideApp.with(context).asBitmap(), context, recipient, false).circleCrop().submit().get());
|
|
}
|
|
|
|
private static Bitmap getFallbackDrawable(Context context, @NonNull Recipient recipient) {
|
|
return BitmapUtil.createFromDrawable(recipient.getFallbackAvatarDrawable(context),
|
|
context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
|
|
context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height));
|
|
}
|
|
|
|
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, boolean loadSelf) {
|
|
final ContactPhoto photo;
|
|
photo = recipient.getContactPhoto(context);
|
|
|
|
return glideRequest.load(photo)
|
|
.error(getFallbackDrawable(context, recipient))
|
|
.diskCacheStrategy(DiskCacheStrategy.ALL);
|
|
}
|
|
}
|