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