diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cdeca242e1..73fddfea2f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -269,6 +269,13 @@
+
+
+
+
+
+
+
diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java
index 9de2d7029b..66969cf4af 100644
--- a/src/org/thoughtcrime/securesms/ConversationListActivity.java
+++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java
@@ -24,6 +24,7 @@ import com.actionbarsherlock.view.MenuItem;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
+import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
@@ -66,6 +67,8 @@ public class ConversationListActivity extends PassphraseRequiredSherlockFragment
initializeSenderReceiverService();
initializeResources();
initializeContactUpdatesReceiver();
+
+ DirectoryRefreshListener.schedule(this);
}
@Override
diff --git a/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java b/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java
new file mode 100644
index 0000000000..b617f7e5c1
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java
@@ -0,0 +1,60 @@
+package org.thoughtcrime.securesms.service;
+
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
+
+public class DirectoryRefreshListener extends BroadcastReceiver {
+
+ private static final String REFRESH_EVENT = "org.whispersystems.whisperpush.DIRECTORY_REFRESH";
+ private static final String BOOT_EVENT = "android.intent.action.BOOT_COMPLETED";
+
+ private static final long INTERVAL = 24 * 60 * 60 * 1000; // 24 hours.
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (REFRESH_EVENT.equals(intent.getAction())) handleRefreshAction(context);
+ else if (BOOT_EVENT.equals(intent.getAction())) handleBootEvent(context);
+ }
+
+ private void handleBootEvent(Context context) {
+ schedule(context);
+ }
+
+ private void handleRefreshAction(Context context) {
+ schedule(context);
+ }
+
+ public static void schedule(Context context) {
+ if (!TextSecurePreferences.isPushRegistered(context)) return;
+
+ AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(DirectoryRefreshListener.REFRESH_EVENT);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+ long time = TextSecurePreferences.getDirectoryRefreshTime(context);
+
+ if (time <= System.currentTimeMillis()) {
+ if (time != 0) {
+ Intent serviceIntent = new Intent(context, DirectoryRefreshService.class);
+ serviceIntent.setAction(DirectoryRefreshService.REFRESH_ACTION);
+ context.startService(serviceIntent);
+ }
+
+ time = System.currentTimeMillis() + INTERVAL;
+ }
+
+ Log.w("DirectoryRefreshListener", "Scheduling for: " + time);
+
+ alarmManager.cancel(pendingIntent);
+ alarmManager.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+
+ TextSecurePreferences.setDirectoryRefreshTime(context, time);
+ }
+
+}
diff --git a/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java b/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java
new file mode 100644
index 0000000000..72dd9cff36
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java
@@ -0,0 +1,79 @@
+package org.thoughtcrime.securesms.service;
+
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.util.Log;
+
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
+import org.whispersystems.textsecure.directory.Directory;
+import org.whispersystems.textsecure.push.PushServiceSocket;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class DirectoryRefreshService extends Service {
+
+ public static final String REFRESH_ACTION = "org.whispersystems.whisperpush.REFRESH_ACTION";
+
+ private static final Executor executor = Executors.newSingleThreadExecutor();
+
+ @Override
+ public int onStartCommand (Intent intent, int flags, int startId) {
+ if (REFRESH_ACTION.equals(intent.getAction())) {
+ handleRefreshAction();
+ }
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private void handleRefreshAction() {
+ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Directory Refresh");
+ wakeLock.acquire();
+
+ executor.execute(new RefreshRunnable(wakeLock));
+ }
+
+ private class RefreshRunnable implements Runnable {
+ private final PowerManager.WakeLock wakeLock;
+ private final Context context;
+
+ public RefreshRunnable(PowerManager.WakeLock wakeLock) {
+ this.wakeLock = wakeLock;
+ this.context = DirectoryRefreshService.this.getApplicationContext();
+ }
+
+ public void run() {
+ try {
+ Log.w("DirectoryRefreshService", "Refreshing directory...");
+ Directory directory = Directory.getInstance(context);
+ String localNumber = TextSecurePreferences.getLocalNumber(context);
+ String password = TextSecurePreferences.getPushServerPassword(context);
+ PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
+
+ Set eligibleContactTokens = directory.getPushEligibleContactTokens(localNumber);
+ List activeTokens = socket.retrieveDirectory(eligibleContactTokens);
+
+ if (activeTokens != null) {
+ eligibleContactTokens.removeAll(activeTokens);
+ directory.setTokens(activeTokens, eligibleContactTokens);
+ }
+
+ Log.w("DirectoryRefreshService", "Directory refresh complete...");
+ } finally {
+ if (wakeLock != null && wakeLock.isHeld())
+ wakeLock.release();
+ }
+ }
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/service/RegistrationService.java b/src/org/thoughtcrime/securesms/service/RegistrationService.java
index 8f5e138dd7..53fa4051ad 100644
--- a/src/org/thoughtcrime/securesms/service/RegistrationService.java
+++ b/src/org/thoughtcrime/securesms/service/RegistrationService.java
@@ -289,6 +289,8 @@ public class RegistrationService extends Service {
contactTokens.removeAll(activeTokens);
Directory.getInstance(this).setTokens(activeTokens, contactTokens);
}
+
+ DirectoryRefreshListener.schedule(this);
}
private synchronized String waitForChallenge() throws AccountVerificationTimeoutException {
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index 009d36f1e1..2e54f6af2c 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -38,6 +38,15 @@ public class TextSecurePreferences {
private static final String GCM_PASSWORD_PREF = "pref_gcm_password";
private static final String PROMPTED_PUSH_REGISTRATION_PREF = "pref_prompted_push_registration";
private static final String SIGNALING_KEY_PREF = "pref_signaling_key";
+ private static final String DIRECTORY_FRESH_TIME_PREF = "pref_directory_refresh_time";
+
+ public static long getDirectoryRefreshTime(Context context) {
+ return getLongPreference(context, DIRECTORY_FRESH_TIME_PREF, 0L);
+ }
+
+ public static void setDirectoryRefreshTime(Context context, long value) {
+ setLongPreference(context, DIRECTORY_FRESH_TIME_PREF, value);
+ }
public static String getLocalNumber(Context context) {
return getStringPreference(context, LOCAL_NUMBER_PREF, "No Stored Number");
@@ -224,4 +233,13 @@ public class TextSecurePreferences {
PreferenceManager.getDefaultSharedPreferences(context).edit().putInt(key, value).commit();
}
+ private static long getLongPreference(Context context, String key, long defaultValue) {
+ return PreferenceManager.getDefaultSharedPreferences(context).getLong(key, defaultValue);
+ }
+
+ private static void setLongPreference(Context context, String key, long value) {
+ PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(key, value).commit();
+ }
+
+
}