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