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