Implement ShortcutInfo for API 30.

This commit is contained in:
Alex Hart
2020-11-17 09:58:28 -04:00
parent 75062ada8a
commit 930370783e
18 changed files with 464 additions and 50 deletions

View File

@@ -4,51 +4,78 @@ package org.thoughtcrime.securesms.service;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.database.Cursor;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.content.ContextCompat;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.sharing.ShareActivity;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sharing.ShareActivity;
import org.thoughtcrime.securesms.util.AvatarUtil;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.ConversationUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ServiceUtil;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@RequiresApi(api = Build.VERSION_CODES.M)
public class DirectShareService extends ChooserTargetService {
private static final String TAG = DirectShareService.class.getSimpleName();
private static final String TAG = DirectShareService.class.getSimpleName();
private static final int MAX_TARGETS = 10;
@Override
public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName,
IntentFilter matchedFilter)
{
List<ChooserTarget> results = new LinkedList<>();
ComponentName componentName = new ComponentName(this, ShareActivity.class);
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(this);
Cursor cursor = threadDatabase.getRecentConversationList(10, false, FeatureFlags.groupsV1ForcedMigration());
Map<RecipientId, ChooserTarget> results = new LinkedHashMap<>();
try {
ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor);
if (Build.VERSION.SDK_INT >= ConversationUtil.CONVERSATION_SUPPORT_VERSION) {
ShortcutManager shortcutManager = ServiceUtil.getShortcutManager(this);
if (shortcutManager != null && !shortcutManager.getDynamicShortcuts().isEmpty()) {
addChooserTargetsFromDynamicShortcuts(results, shortcutManager.getDynamicShortcuts());
}
if (results.size() >= MAX_TARGETS) {
return new ArrayList<>(results.values());
}
}
ComponentName componentName = new ComponentName(this, ShareActivity.class);
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(this);
try (ThreadDatabase.Reader reader = threadDatabase.readerFor(threadDatabase.getRecentConversationList(MAX_TARGETS, false, FeatureFlags.groupsV1ForcedMigration()))) {
ThreadRecord record;
while ((record = reader.getNext()) != null) {
if (results.containsKey(record.getRecipient().getId())) {
continue;
}
Recipient recipient = Recipient.resolved(record.getRecipient().getId());
String name = recipient.getDisplayName(this);
@@ -71,25 +98,53 @@ public class DirectShareService extends ChooserTargetService {
avatar = getFallbackDrawable(recipient);
}
Bundle bundle = new Bundle();
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId());
bundle.putString(ShareActivity.EXTRA_RECIPIENT_ID, recipient.getId().serialize());
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType());
bundle.setClassLoader(getClassLoader());
Bundle bundle = buildExtras(record);
results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle));
results.put(recipient.getId(), new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle));
}
return results;
} finally {
if (cursor != null) cursor.close();
return new ArrayList<>(results.values());
}
}
private @NonNull Bundle buildExtras(@NonNull ThreadRecord threadRecord) {
Bundle bundle = new Bundle();
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, threadRecord.getThreadId());
bundle.putString(ShareActivity.EXTRA_RECIPIENT_ID, threadRecord.getRecipient().getId().serialize());
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, threadRecord.getDistributionType());
return bundle;
}
private Bitmap getFallbackDrawable(@NonNull Recipient recipient) {
Context themedContext = new ContextThemeWrapper(this, R.style.TextSecure_LightTheme);
return BitmapUtil.createFromDrawable(recipient.getFallbackContactPhotoDrawable(themedContext, false),
getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height));
}
@RequiresApi(ConversationUtil.CONVERSATION_SUPPORT_VERSION)
private void addChooserTargetsFromDynamicShortcuts(@NonNull Map<RecipientId, ChooserTarget> targetMap, @NonNull List<ShortcutInfo> shortcutInfos) {
Stream.of(shortcutInfos)
.sorted((lhs, rhs) -> Integer.compare(lhs.getRank(), rhs.getRank()))
.takeWhileIndexed((idx, info) -> idx < MAX_TARGETS)
.forEach(info -> {
Recipient recipient = Recipient.resolved(RecipientId.from(info.getId()));
ChooserTarget target = buildChooserTargetFromShortcutInfo(info, recipient);
targetMap.put(RecipientId.from(info.getId()), target);
});
}
@RequiresApi(ConversationUtil.CONVERSATION_SUPPORT_VERSION)
private @NonNull ChooserTarget buildChooserTargetFromShortcutInfo(@NonNull ShortcutInfo info, @NonNull Recipient recipient) {
ThreadRecord threadRecord = DatabaseFactory.getThreadDatabase(this).getThreadRecordFor(recipient);
return new ChooserTarget(info.getShortLabel(),
AvatarUtil.getIconForShortcut(this, recipient),
info.getRank() / ((float) MAX_TARGETS),
new ComponentName(this, ShareActivity.class),
buildExtras(threadRecord));
}
}