aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2017-05-31 21:49:40 +0200
committerChristian Schneppe <christian@pix-art.de>2017-05-31 21:49:40 +0200
commitc741b33bc22fc87eb75dbc448898ebeba88dbe0c (patch)
treecb7935fba0e0b7c19550e1ceb93b02ea26442f95 /src
parent21bf06c064554c406a6b769160c36a471da45e07 (diff)
add the 4 most frequently contacted contacts as app shortcuts
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/pixart/messenger/parser/IqParser.java1
-rw-r--r--src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java18
-rw-r--r--src/main/java/de/pixart/messenger/services/AvatarService.java21
-rw-r--r--src/main/java/de/pixart/messenger/services/ShortcutService.java131
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java16
-rw-r--r--src/main/java/de/pixart/messenger/ui/StartConversationActivity.java11
6 files changed, 192 insertions, 6 deletions
diff --git a/src/main/java/de/pixart/messenger/parser/IqParser.java b/src/main/java/de/pixart/messenger/parser/IqParser.java
index bfb2fa71e..1783fed07 100644
--- a/src/main/java/de/pixart/messenger/parser/IqParser.java
+++ b/src/main/java/de/pixart/messenger/parser/IqParser.java
@@ -83,6 +83,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
}
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateRosterUi();
+ mXmppConnectionService.getShortcutService().refresh();
}
public String avatarData(final IqPacket packet) {
diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
index ddf516f93..7b49eb376 100644
--- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
@@ -48,6 +48,7 @@ import de.pixart.messenger.entities.Message;
import de.pixart.messenger.entities.PresenceTemplate;
import de.pixart.messenger.entities.Roster;
import de.pixart.messenger.entities.ServiceDiscoveryResult;
+import de.pixart.messenger.services.ShortcutService;
import de.pixart.messenger.xmpp.jid.InvalidJidException;
import de.pixart.messenger.xmpp.jid.Jid;
import de.pixart.messenger.xmpp.mam.MamReference;
@@ -1432,4 +1433,21 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("delete from " + START_TIMES_TABLE);
}
}
+
+ public List<ShortcutService.FrequentContact> getFrequentContacts(int days) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ final String SQL = "select " + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + " from " + Conversation.TABLENAME + " join " + Message.TABLENAME + " on conversations.uuid=messages.conversationUuid where messages.status!=0 and carbon==0 and conversations.mode=0 and messages.timeSent>=? group by conversations.uuid order by count(body) desc limit 4;";
+ String[] whereArgs = new String[]{String.valueOf(System.currentTimeMillis() - (Config.MILLISECONDS_IN_DAY * days))};
+ Cursor cursor = db.rawQuery(SQL, whereArgs);
+ ArrayList<ShortcutService.FrequentContact> contacts = new ArrayList<>();
+ while (cursor.moveToNext()) {
+ try {
+ contacts.add(new ShortcutService.FrequentContact(cursor.getString(0), Jid.fromString(cursor.getString(1))));
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, e.getMessage());
+ }
+ }
+ cursor.close();
+ return contacts;
+ }
}
diff --git a/src/main/java/de/pixart/messenger/services/AvatarService.java b/src/main/java/de/pixart/messenger/services/AvatarService.java
index 15c49940f..3d3af8d26 100644
--- a/src/main/java/de/pixart/messenger/services/AvatarService.java
+++ b/src/main/java/de/pixart/messenger/services/AvatarService.java
@@ -3,9 +3,12 @@ package de.pixart.messenger.services;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.net.Uri;
+import android.util.DisplayMetrics;
import android.util.Log;
import java.util.ArrayList;
@@ -69,6 +72,24 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
return avatar;
}
+ public Bitmap getRoundedShortcut(final Contact contact) {
+ DisplayMetrics metrics = mXmppConnectionService.getResources().getDisplayMetrics();
+ int size = Math.round(metrics.density * 48);
+ Bitmap bitmap = get(contact, size);
+ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+
+ final Paint paint = new Paint();
+ final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+ paint.setAntiAlias(true);
+ canvas.drawARGB(0, 0, 0, 0);
+ canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(bitmap, rect, rect, paint);
+ return output;
+ }
+
public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) {
Contact c = user.getContact();
if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null || user.getAvatar() == null)) {
diff --git a/src/main/java/de/pixart/messenger/services/ShortcutService.java b/src/main/java/de/pixart/messenger/services/ShortcutService.java
new file mode 100644
index 000000000..56345c663
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/services/ShortcutService.java
@@ -0,0 +1,131 @@
+package de.pixart.messenger.services;
+
+import android.annotation.TargetApi;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Build;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import de.pixart.messenger.Config;
+import de.pixart.messenger.entities.Account;
+import de.pixart.messenger.entities.Contact;
+import de.pixart.messenger.ui.StartConversationActivity;
+import de.pixart.messenger.utils.ReplacingSerialSingleThreadExecutor;
+import de.pixart.messenger.xmpp.jid.Jid;
+
+public class ShortcutService {
+ private final XmppConnectionService xmppConnectionService;
+ private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor = new ReplacingSerialSingleThreadExecutor(false);
+
+ public ShortcutService(XmppConnectionService xmppConnectionService) {
+ this.xmppConnectionService = xmppConnectionService;
+ }
+
+ public void refresh() {
+ refresh(false);
+ }
+
+ public void refresh(final boolean forceUpdate) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
+ final Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ refreshImpl(forceUpdate);
+ }
+ };
+ replacingSerialSingleThreadExecutor.execute(r);
+ }
+ }
+
+ @TargetApi(25)
+ public void report(Contact contact) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
+ ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
+ shortcutManager.reportShortcutUsed(getShortcutId(contact));
+ }
+ }
+
+ @TargetApi(25)
+ private void refreshImpl(boolean forceUpdate) {
+ List<FrequentContact> frequentContacts = xmppConnectionService.databaseBackend.getFrequentContacts(30);
+ HashMap<String, Account> accounts = new HashMap<>();
+ for (Account account : xmppConnectionService.getAccounts()) {
+ accounts.put(account.getUuid(), account);
+ }
+ List<Contact> contacts = new ArrayList<>();
+ for (FrequentContact frequentContact : frequentContacts) {
+ Account account = accounts.get(frequentContact.account);
+ if (account != null) {
+ contacts.add(account.getRoster().getContact(frequentContact.contact));
+ }
+ }
+ ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
+ boolean needsUpdate = forceUpdate || contactsChanged(contacts, shortcutManager.getDynamicShortcuts());
+ if (!needsUpdate) {
+ Log.d(Config.LOGTAG, "skipping shortcut update");
+ return;
+ }
+ List<ShortcutInfo> newDynamicShortCuts = new ArrayList<>();
+ for (Contact contact : contacts) {
+ ShortcutInfo shortcut = new ShortcutInfo.Builder(xmppConnectionService, getShortcutId(contact))
+ .setShortLabel(contact.getDisplayName())
+ .setIntent(getShortcutIntent(contact))
+ .setIcon(Icon.createWithBitmap(xmppConnectionService.getAvatarService().getRoundedShortcut(contact)))
+ .build();
+ newDynamicShortCuts.add(shortcut);
+ }
+ if (shortcutManager.setDynamicShortcuts(newDynamicShortCuts)) {
+ Log.d(Config.LOGTAG, "updated dynamic shortcuts");
+ } else {
+ Log.d(Config.LOGTAG, "unable to update dynamic shortcuts");
+ }
+ }
+
+ private static boolean contactsChanged(List<Contact> needles, List<ShortcutInfo> haystack) {
+ for (Contact needle : needles) {
+ if (!contactExists(needle, haystack)) {
+ return true;
+ }
+ }
+ return needles.size() != haystack.size();
+ }
+
+ @TargetApi(25)
+ private static boolean contactExists(Contact needle, List<ShortcutInfo> haystack) {
+ for (ShortcutInfo shortcutInfo : haystack) {
+ if (getShortcutId(needle).equals(shortcutInfo.getId()) && needle.getDisplayName().equals(shortcutInfo.getShortLabel())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String getShortcutId(Contact contact) {
+ return contact.getAccount().getJid().toBareJid().toPreppedString() + "#" + contact.getJid().toBareJid().toPreppedString();
+ }
+
+ private Intent getShortcutIntent(Contact contact) {
+ Intent intent = new Intent(xmppConnectionService, StartConversationActivity.class);
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("xmpp:" + contact.getJid().toBareJid().toString()));
+ intent.putExtra("account", contact.getAccount().getJid().toBareJid().toString());
+ return intent;
+ }
+
+ public static class FrequentContact {
+ private final String account;
+ private final Jid contact;
+
+ public FrequentContact(String account, Jid contact) {
+ this.account = account;
+ this.contact = contact;
+ }
+ }
+}
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index 61a9d2318..27412e1ea 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -70,6 +70,7 @@ import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import de.duenndns.ssl.MemorizingTrustManager;
@@ -189,8 +190,9 @@ public class XmppConnectionService extends Service {
};
private FileBackend fileBackend = new FileBackend(this);
private MemorizingTrustManager mMemorizingTrustManager;
- private NotificationService mNotificationService = new NotificationService(
- this);
+ private NotificationService mNotificationService = new NotificationService(this);
+ private ShortcutService mShortcutService = new ShortcutService(this);
+ private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false);
private OnMessagePacketReceived mMessageParser = new MessageParser(this);
private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
private IqParser mIqParser = new IqParser(this);
@@ -1663,6 +1665,7 @@ public class XmppConnectionService extends Service {
}
}
Log.d(Config.LOGTAG, "finished merging phone contacts");
+ mShortcutService.refresh(mInitialAddressbookSyncCompleted.compareAndSet(false, true));
updateAccountUi();
}
});
@@ -3788,10 +3791,11 @@ public class XmppConnectionService extends Service {
return this.mMessageArchiveService;
}
- public List<Contact> findContacts(Jid jid) {
+ public List<Contact> findContacts(Jid jid, String accountJid) {
ArrayList<Contact> contacts = new ArrayList<>();
for (Account account : getAccounts()) {
- if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ if (!account.isOptionSet(Account.OPTION_DISABLED)
+ && (accountJid == null || accountJid.equals(account.getJid().toBareJid().toString()))) {
Contact contact = account.getRoster().getContactFromRoster(jid);
if (contact != null) {
contacts.add(contact);
@@ -4176,6 +4180,10 @@ public class XmppConnectionService extends Service {
}
}
+ public ShortcutService getShortcutService() {
+ return mShortcutService;
+ }
+
public interface OnMamPreferencesFetched {
void onPreferencesFetched(Element prefs);
diff --git a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java
index f3cbf7be9..73400dde3 100644
--- a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java
@@ -831,7 +831,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
case Intent.ACTION_VIEW:
Uri uri = intent.getData();
if (uri != null) {
- return new Invite(intent.getData(), false).invite();
+ Invite invite = new Invite(intent.getData(), false);
+ invite.account = intent.getStringExtra("account");
+ return invite.invite();
} else {
return false;
}
@@ -870,7 +872,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
finish();
return true;
}
- List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
+ List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid(), invite.account);
if (invite.isMuc()) {
Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid());
if (muc != null) {
@@ -893,6 +895,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
Toast.makeText(this,R.string.verified_fingerprints,Toast.LENGTH_SHORT).show();
}
}
+ if (invite.account != null) {
+ xmppConnectionService.getShortcutService().report(contact);
+ }
switchToConversation(contact, invite.getBody());
}
return true;
@@ -1182,6 +1187,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
super(uri, safeSource);
}
+ public String account;
+
boolean invite() {
if (getJid() != null) {
return handleJid(this);