ShortcutService.java

  1package eu.siacs.conversations.services;
  2
  3import android.annotation.TargetApi;
  4import android.content.Intent;
  5import android.content.pm.ShortcutInfo;
  6import android.content.pm.ShortcutManager;
  7import android.graphics.Bitmap;
  8import android.graphics.drawable.Icon;
  9import android.net.Uri;
 10import android.os.Build;
 11import android.util.Log;
 12
 13import androidx.annotation.NonNull;
 14import androidx.core.content.pm.ShortcutInfoCompat;
 15import androidx.core.graphics.drawable.IconCompat;
 16
 17import java.util.ArrayList;
 18import java.util.HashMap;
 19import java.util.List;
 20
 21import eu.siacs.conversations.Config;
 22import eu.siacs.conversations.entities.Account;
 23import eu.siacs.conversations.entities.Contact;
 24import eu.siacs.conversations.ui.StartConversationActivity;
 25import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
 26import eu.siacs.conversations.xmpp.Jid;
 27
 28public class ShortcutService {
 29
 30    private final XmppConnectionService xmppConnectionService;
 31    private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor = new ReplacingSerialSingleThreadExecutor(ShortcutService.class.getSimpleName());
 32
 33    public ShortcutService(XmppConnectionService xmppConnectionService) {
 34        this.xmppConnectionService = xmppConnectionService;
 35    }
 36
 37    public void refresh() {
 38        refresh(false);
 39    }
 40
 41    public void refresh(final boolean forceUpdate) {
 42        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
 43            final Runnable r = new Runnable() {
 44                @Override
 45                public void run() {
 46                    refreshImpl(forceUpdate);
 47                }
 48            };
 49            replacingSerialSingleThreadExecutor.execute(r);
 50        }
 51    }
 52
 53    @TargetApi(25)
 54    public void report(Contact contact) {
 55        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
 56            ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
 57            shortcutManager.reportShortcutUsed(getShortcutId(contact));
 58        }
 59    }
 60
 61    @TargetApi(25)
 62    private void refreshImpl(boolean forceUpdate) {
 63        List<FrequentContact> frequentContacts = xmppConnectionService.databaseBackend.getFrequentContacts(30);
 64        HashMap<String,Account> accounts = new HashMap<>();
 65        for(Account account : xmppConnectionService.getAccounts()) {
 66            accounts.put(account.getUuid(),account);
 67        }
 68        List<Contact> contacts = new ArrayList<>();
 69        for(FrequentContact frequentContact : frequentContacts) {
 70            Account account = accounts.get(frequentContact.account);
 71            if (account != null) {
 72                contacts.add(account.getRoster().getContact(frequentContact.contact));
 73            }
 74        }
 75        ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
 76        boolean needsUpdate = forceUpdate || contactsChanged(contacts,shortcutManager.getDynamicShortcuts());
 77        if (!needsUpdate) {
 78            Log.d(Config.LOGTAG,"skipping shortcut update");
 79            return;
 80        }
 81        List<ShortcutInfo> newDynamicShortCuts = new ArrayList<>();
 82        for (Contact contact : contacts) {
 83            ShortcutInfo shortcut = getShortcutInfo(contact);
 84            newDynamicShortCuts.add(shortcut);
 85        }
 86        if (shortcutManager.setDynamicShortcuts(newDynamicShortCuts)) {
 87            Log.d(Config.LOGTAG,"updated dynamic shortcuts");
 88        } else {
 89            Log.d(Config.LOGTAG, "unable to update dynamic shortcuts");
 90        }
 91    }
 92
 93    public ShortcutInfoCompat getShortcutInfoCompat(Contact contact) {
 94        return new ShortcutInfoCompat.Builder(xmppConnectionService, getShortcutId(contact))
 95                        .setShortLabel(contact.getDisplayName())
 96                        .setIntent(getShortcutIntent(contact))
 97                        .setIcon(IconCompat.createFromIcon(Icon.createWithBitmap(xmppConnectionService.getAvatarService().getRoundedShortcut(contact))))
 98                        .setIsConversation()
 99                        .build();
100    }
101
102    @TargetApi(Build.VERSION_CODES.N_MR1)
103    private ShortcutInfo getShortcutInfo(Contact contact) {
104        return getShortcutInfoCompat(contact).toShortcutInfo();
105    }
106
107    private static boolean contactsChanged(List<Contact> needles, List<ShortcutInfo> haystack) {
108        for(Contact needle : needles) {
109            if(!contactExists(needle,haystack)) {
110                return true;
111            }
112        }
113        return needles.size() != haystack.size();
114    }
115
116    @TargetApi(25)
117    private static boolean contactExists(Contact needle, List<ShortcutInfo> haystack) {
118        for(ShortcutInfo shortcutInfo : haystack) {
119            if (getShortcutId(needle).equals(shortcutInfo.getId()) && needle.getDisplayName().equals(shortcutInfo.getShortLabel())) {
120                return true;
121            }
122        }
123        return false;
124    }
125
126    private static String getShortcutId(Contact contact) {
127        return contact.getAccount().getJid().asBareJid().toEscapedString()+"#"+contact.getJid().asBareJid().toEscapedString();
128    }
129
130    private Intent getShortcutIntent(Contact contact) {
131        Intent intent = new Intent(xmppConnectionService, StartConversationActivity.class);
132        intent.setAction(Intent.ACTION_VIEW);
133        intent.setData(Uri.parse("xmpp:"+contact.getJid().asBareJid().toEscapedString()));
134        intent.putExtra("account",contact.getAccount().getJid().asBareJid().toString());
135        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
136        return intent;
137    }
138
139    @NonNull
140    public Intent createShortcut(Contact contact, boolean legacy) {
141        Intent intent;
142        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !legacy) {
143            ShortcutInfo shortcut = getShortcutInfo(contact);
144            ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
145            intent = shortcutManager.createShortcutResultIntent(shortcut);
146        } else {
147            intent = createShortcutResultIntent(contact);
148        }
149        return intent;
150    }
151
152    @NonNull
153    private Intent createShortcutResultIntent(Contact contact) {
154        AvatarService avatarService = xmppConnectionService.getAvatarService();
155        Bitmap icon = avatarService.getRoundedShortcutWithIcon(contact);
156        Intent intent = new Intent();
157        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, contact.getDisplayName());
158        intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
159        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, getShortcutIntent(contact));
160        return intent;
161    }
162
163    public static class FrequentContact {
164        private final String account;
165        private final Jid contact;
166
167        public FrequentContact(String account, Jid contact) {
168            this.account = account;
169            this.contact = contact;
170        }
171    }
172
173}