Monthly Archives: March 2013

Dynamic Dates with Java

I made a new change for build 48 of Fusion to show the date portion based on time. The difficulty is making it all work with all the different time zones and locales. 24 hours isn’t always a day because of daylight savings time. So I have to use Calendar. Here’s the static code:

public static String stripFieldFromPattern(SimpleDateFormat sdf, Date d,
        DateFormat.Field field) {
    StringBuilder b = new StringBuilder();
    boolean isLastCharValid = true;
    boolean isNextCharValid = false;
    AttributedCharacterIterator i = sdf.formatToCharacterIterator(d);
    for (char c = i.first(); c != AttributedCharacterIterator.DONE; c = i
            .next()) {

        Map<Attribute, Object> attributes = i.getAttributes();

        if (attributes.containsKey(field)) {
            isLastCharValid = false;
            continue;
        }

        char nextChar = i.next();
        isNextCharValid = (nextChar != AttributedCharacterIterator.DONE && i
                .getAttribute(field) == null);
        i.previous();

        if (!attributes.isEmpty() || c == ' ') {
            b.append(c);
        } else {
            if (isLastCharValid && isNextCharValid)
                b.append(c);
        }
        isLastCharValid = true;
    }
    return b.toString();
}

This will strip any field from a date pattern. I’d strip the Year field if an event occurred in the last year. Here’s the implementation as written in Fusion:

Calendar eventDateTime = Calendar.getInstance();
Calendar yesterday = Calendar.getInstance();
Calendar lastYear = Calendar.getInstance();

eventDateTime.setTimeInMillis(msgItem.getCompletionDateTime());
yesterday.add(Calendar.DATE, -1);
lastYear.add(Calendar.YEAR, -1);

String timeString;
String providerName;
if (eventDateTime.after(yesterday)) {
    timeString = DateFormat.getTimeInstance(DateFormat.SHORT,
            Locale.getDefault()).format(eventDateTime.getTime());
    providerName = IMProvider.IMServiceNames[msgItem
            .getIMProviderType().ordinal()];
} else if (eventDateTime.after(lastYear)) {
    SimpleDateFormat sdfOriginal = (SimpleDateFormat) SimpleDateFormat
            .getDateTimeInstance(DateFormat.SHORT,
                    DateFormat.SHORT, Locale.getDefault());
    timeString = Utils.stripFieldFromPattern(sdfOriginal,
            eventDateTime.getTime(), DateFormat.Field.YEAR);
    providerName = IMProvider.IMServiceNames[msgItem
            .getIMProviderType().ordinal()];

} else {
    timeString = DateFormat.getDateTimeInstance(DateFormat.SHORT,
            DateFormat.SHORT, Locale.getDefault()).format(
            eventDateTime.getTime());
    providerName = IMProvider.IMServiceShortNames[msgItem
            .getIMProviderType().ordinal()];
}

String format = "%1$s";
if (!this.useColoredStatus && !this.useIMServiceIcon
        && !this.useIMServiceIndicator)
    format += " via %2$s";
subText = String.format(format, timeString, providerName);

I just realized the providerName is repeated unnecessarily. Oops! Regardless, it has nothing to with the topic here.

Build 36! SMS fully sync now! READ ME!

http://www.mediafire.com/?9fr9lc5po5blc6h[1]

Okay, so now SMS messages sync. If you have a bunch of old messages you don’t care about. Uninstall Fusion and reinstall it. You shouldn’t have to worry about reinstalling the GV app. I’ll submit a warning next build if Fusion couldn’t get the necessary push permissions.

So, of course if SMS is syncing this is when we need to worry about duplicates. I do a synchronize lock for outgoing messages you probably won’t ever see duplicates there. Let me know if you ever do.

Incoming is a whole other issue. So, Fusion and your stock app will both receive the message and both will write to the android stock database. The “workaround” is make Fusion wait to see if maybe another app will input the same message into the stock database. This is kinda silly. There’s no clean way to do this automatically without making the app slower. That’s NOT an option for me.

So, you can disable Fusion from receiving incoming messages. The second your stock app writes the incoming message, Fusion will INSTANTLY resync the database and the message will popup. Of course, if you ever choose to disable/uninstall your default messenger, then turn that option back.

The option is enabled by default.

I made some crash fixes so it looks like we’re in business now. It’s just MMS and notifications from here on out. After that we’re at feature-complete and I can start reworking code around for better stability and speed (yeah, I said it).

I need somebody to make sure you don’t auto crash and then I’ll publish it on the Play Store.

Google Voice can’t delete individual messages…

Seriously, this is crazy. Apparently Google only knows how to work with “conversations”. There is literally no way to delete an individual message.

Now I’m not so sure how to implement this. There are two ways.

  1. Delete the entire conversation from Google Voice’s servers and keep every other message on your Fusion database. The problem is, if you lose your database (like uninstalling the app), the entire conversation is lost.
  2. Leave the conversation on Google Voice’s servers, but flag the MessageID as deleted. This pretty much means that Fusion will ignore the message on every sync, but it’ll still be on Google’s server.

Really dumb implementation.

Build 31! Feedback needed!

http://www.mediafire.com/?d5i7bwx347rckq5

I haven’t uploaded it to the Play Store. I need somebody to run it and let me know if it works (aka doesn’t crash on boot).

I moved everything to E164 by using libphonenumber. It’s bloated and slow (200kb) but I’ll trim that down later.

The database is upgraded on boot (which is why it needs testing).

The search function is working as expected now. Clicking the search button will list all your contacts immediately.

Loading the first instance of contacts takes a little bit more time, but remember that it’s all cached after the first run though.

Dark Action Bar is properly fixed, so no more odd coloring in Android 2.x

Permission Breakdown

Permissions Breakdown:
android.permission.ACCESS_NETWORK_STATE: Google Voice Connectivity
android.permission.INTERNET: Google Voice Connectivity
android.permission.GET_ACCOUNTS: Get Google Account Names
android.permission.MANAGE_ACCOUNTS: Create Google Account Prompt
android.permission.READ_CONTACTS: Build Contacts List
android.permission.READ_PROFILE: Get your profile icon
android.permission.RECEIVE_BOOT_COMPLETED: Start on Boot
android.permission.RECEIVE_SMS: Receive Text Messages
android.permission.SEND_SMS: Send Text Messages
android.permission.USE_CREDENTIALS: Get Google Voice OAuth2 credentials (never your password)
android.permission.VIBRATE: Vibrate on New Message
com.android.vending.BILLING: Future Donations
com.google.android.apps.googlevoice.INBOX_NOTIFICATION.permission.C2D_MESSAGE: GV Push Notification
com.google.android.apps.googlevoice.permission.RECEIVE_SMS: GV Push Workaround
com.google.android.c2dm.permission.RECEIVE: Push Notifications
com.google.android.providers.gsf.permission.READ_GSERVICES: Register GV Push Notifications

Changelogs

v0.77: Download MMS

v0.76: Vibration, Ringtone and Text Entry options

v0.74: QuickReply revamped and customizable. Close-able conversations.

v0.71: QuickReply for Android 3.0+

v0.70: Multiview support + theme fixes

v0.69: Open and share MMS

v0.68: Shows MMS, Navigation Modes and Collapsable Contact Banner

v0.65: Crash fixes

v0.64: Quick Reply system is complete

v0.63: Google Voice stability

v0.61: Mark as read is finished. Bug fixes

v0.60: New Icon, Quick Reply, Speed fixes

v0.55: Rich notifications + CDMA fix for splitting messages.

v0.54: Outgoing status fix

v0.53: 160 character limit fixed, photos not showing fixed, crash fixes

v0.52: Message new contacts, faster loading, fixed crashes and notifications

v0.51: Speed improvements

v0.49: Number parsing is complete

v0.47: Fixed crash if you don’t have a profile icon.

v0.46: Hi-res contact icons

v0.45: All known bugs fixes. On to UI phase

v0.44: Shortcode messaging has been fixed. Only warns about Google Voice if you’re not going to get messages.

v0.43: Fixed issue where Fusion would grab the wrong account (usually Dropbox). Fixed crashes on clicking notification.

v0.42: Fixed crash on syncing database with blank messages

v0.41: Fixed crash on swipe

v0.40: Fixed contacts spinner not working properly

v0.39: Race conditions, notifications, UI duplication fixes. Warnings added.

v0.38: Massive lag fix

v0.37: Minor bugfix

v0.36: Incoming messages now sync. Lots of bug fixes.

v0.35: Fixed search on Android 2.x. Outgoing messages now write to the internal db.

v0.34: Search works in conversations. SQL should work multithreaded now. Crash fixes. Search bug fixes. International support improved

v0.33: Copy, Delete, & Info options when long pressing messages. Links now open on click. Fixed crash on notification or reopening app. Notifications now take you directly to the conversation. Profile photo is now shown. Search bugfix.

v0.31: Clicking search lists everyone. Better phone number parsing and int’l support

v0.30: Search auto hides after picking a contact or selecting someone. Fixed Android 2.x crashes and contacts not auto sorting on new message

v0.29: Contact search and bug fixes

v0.28: Fixed huge bug where messages wouldn’t send.

v0.27: Contact icons and small crash fix.

v0.26: SQLite database lock crashes. Nearly all reported crashes fixed

v0.25: Fixed possible wrong sender and few more crashes (reports actually do help!). Added disable SMS option.

v0.24: Removed AsyncTasks. More crash fixes. Added disable notifications option

v0.23: Fixed the Play Store’s automatic tablet blocking. Should support any and all devices now.