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