1package eu.siacs.conversations.services;
  2
  3import android.annotation.SuppressLint;
  4import android.annotation.TargetApi;
  5import android.content.ComponentName;
  6import android.content.Context;
  7import android.content.Intent;
  8import android.content.IntentFilter;
  9import android.content.ServiceConnection;
 10import android.graphics.drawable.Icon;
 11import android.os.Build;
 12import android.os.Bundle;
 13import android.os.IBinder;
 14import android.service.chooser.ChooserTarget;
 15import android.service.chooser.ChooserTargetService;
 16import android.util.Log;
 17
 18import java.util.ArrayList;
 19import java.util.Collections;
 20import java.util.List;
 21
 22import eu.siacs.conversations.Config;
 23import eu.siacs.conversations.entities.Conversation;
 24import eu.siacs.conversations.persistance.FileBackend;
 25import eu.siacs.conversations.receiver.SystemEventReceiver;
 26import eu.siacs.conversations.ui.ConversationsActivity;
 27import eu.siacs.conversations.utils.Compatibility;
 28
 29@SuppressLint("Deprecated")
 30@TargetApi(Build.VERSION_CODES.M)
 31public class ContactChooserTargetService extends ChooserTargetService implements ServiceConnection {
 32
 33    private final Object lock = new Object();
 34    private static final int MAX_TARGETS = 5;
 35    private XmppConnectionService mXmppConnectionService;
 36
 37    private static boolean textOnly(IntentFilter filter) {
 38        for (int i = 0; i < filter.countDataTypes(); ++i) {
 39            if (!"text/plain".equals(filter.getDataType(i))) {
 40                return false;
 41            }
 42        }
 43        return true;
 44    }
 45
 46    @Override
 47    public List<ChooserTarget> onGetChooserTargets(
 48            final ComponentName targetActivityName, final IntentFilter matchedFilter) {
 49        if (!SystemEventReceiver.hasEnabledAccounts(this)) {
 50            return Collections.emptyList();
 51        }
 52        final Intent intent = new Intent(this, XmppConnectionService.class);
 53        intent.setAction("contact_chooser");
 54        Compatibility.startService(this, intent);
 55        bindService(intent, this, Context.BIND_AUTO_CREATE);
 56        try {
 57            waitForService();
 58            if (!mXmppConnectionService.areMessagesInitialized()) {
 59                return Collections.emptyList();
 60            }
 61            final ArrayList<Conversation> conversations = new ArrayList<>();
 62            mXmppConnectionService.populateWithOrderedConversations(
 63                    conversations, textOnly(matchedFilter));
 64            final ComponentName componentName =
 65                    new ComponentName(this, ConversationsActivity.class);
 66            final int pixel = AvatarService.getSystemUiAvatarSize(this);
 67            final ArrayList<ChooserTarget> chooserTargets = new ArrayList<>();
 68            for (final Conversation conversation : conversations) {
 69                if (conversation.sentMessagesCount() == 0) {
 70                    continue;
 71                }
 72                final String name = conversation.getName().toString();
 73                final Icon icon =
 74                        Icon.createWithBitmap(FileBackend.drawDrawable(
 75                                mXmppConnectionService.getAvatarService().get(conversation, pixel)));
 76                final float score = 1 - (1.0f / MAX_TARGETS) * chooserTargets.size();
 77                final Bundle extras = new Bundle();
 78                extras.putString(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
 79                chooserTargets.add(new ChooserTarget(name, icon, score, componentName, extras));
 80                if (chooserTargets.size() >= MAX_TARGETS) {
 81                    return chooserTargets;
 82                }
 83            }
 84            return chooserTargets;
 85        } catch (final InterruptedException e) {
 86            Log.d(
 87                    Config.LOGTAG,
 88                    "Thread got interrupted before binding to XmppConnectionService",
 89                    e);
 90        } finally {
 91            unbindService(this);
 92        }
 93        return Collections.emptyList();
 94    }
 95
 96    @Override
 97    public void onServiceConnected(final ComponentName name, final IBinder service) {
 98        XmppConnectionService.XmppConnectionBinder binder =
 99                (XmppConnectionService.XmppConnectionBinder) service;
100        mXmppConnectionService = binder.getService();
101        synchronized (this.lock) {
102            lock.notifyAll();
103        }
104    }
105
106    @Override
107    public void onServiceDisconnected(ComponentName name) {
108        mXmppConnectionService = null;
109    }
110
111    private void waitForService() throws InterruptedException {
112        if (mXmppConnectionService == null) {
113            synchronized (this.lock) {
114                lock.wait();
115            }
116        }
117    }
118}