mobile/android/base/background/announcements/AnnouncementsBroadcastService.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/background/announcements/AnnouncementsBroadcastService.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,179 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +package org.mozilla.gecko.background.announcements;
     1.9 +
    1.10 +import org.mozilla.gecko.background.BackgroundService;
    1.11 +import org.mozilla.gecko.background.common.GlobalConstants;
    1.12 +import org.mozilla.gecko.background.common.log.Logger;
    1.13 +
    1.14 +import android.app.AlarmManager;
    1.15 +import android.app.PendingIntent;
    1.16 +import android.content.Context;
    1.17 +import android.content.Intent;
    1.18 +import android.content.SharedPreferences;
    1.19 +import android.content.SharedPreferences.Editor;
    1.20 +
    1.21 +/**
    1.22 + * A service which listens to broadcast intents from the system and from the
    1.23 + * browser, registering or unregistering the main
    1.24 + * {@link AnnouncementsService} with the {@link AlarmManager}.
    1.25 + */
    1.26 +public class AnnouncementsBroadcastService extends BackgroundService {
    1.27 +  private static final String WORKER_THREAD_NAME = "AnnouncementsBroadcastServiceWorker";
    1.28 +  private static final String LOG_TAG = "AnnounceBrSvc";
    1.29 +
    1.30 +  public AnnouncementsBroadcastService() {
    1.31 +    super(WORKER_THREAD_NAME);
    1.32 +  }
    1.33 +
    1.34 +  protected static SharedPreferences getSharedPreferences(Context context) {
    1.35 +    return context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH,
    1.36 +        GlobalConstants.SHARED_PREFERENCES_MODE);
    1.37 +  }
    1.38 +
    1.39 +  protected SharedPreferences getSharedPreferences() {
    1.40 +    return this.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH,
    1.41 +        GlobalConstants.SHARED_PREFERENCES_MODE);
    1.42 +  }
    1.43 +
    1.44 +  private void toggleAlarm(final Context context, boolean enabled) {
    1.45 +    final Class<?> serviceClass = AnnouncementsService.class;
    1.46 +    Logger.info(LOG_TAG, (enabled ? "R" : "Unr") + "egistering " + serviceClass.getSimpleName() +
    1.47 +        ".");
    1.48 +
    1.49 +    final Intent service = new Intent(context, serviceClass);
    1.50 +    final PendingIntent pending =  PendingIntent.getService(context, 0, service,
    1.51 +        PendingIntent.FLAG_CANCEL_CURRENT);
    1.52 +
    1.53 +    if (!enabled) {
    1.54 +      cancelAlarm(pending);
    1.55 +      return;
    1.56 +    }
    1.57 +
    1.58 +    final long pollInterval = getPollInterval(context);
    1.59 +    scheduleAlarm(pollInterval, pending);
    1.60 +  }
    1.61 +
    1.62 +  /**
    1.63 +   * Record the last launch time of our version of Fennec.
    1.64 +   *
    1.65 +   * @param context
    1.66 +   *          the <code>Context</code> to use to gain access to
    1.67 +   *          <code>SharedPreferences</code>.
    1.68 +   */
    1.69 +  public static void recordLastLaunch(final Context context) {
    1.70 +    final long now = System.currentTimeMillis();
    1.71 +    final SharedPreferences preferences = getSharedPreferences(context);
    1.72 +
    1.73 +    // One of several things might be true, according to our logs:
    1.74 +    //
    1.75 +    // * The new current time is older than the last
    1.76 +    // * … or way in the future
    1.77 +    // * … or way in the distant past
    1.78 +    // * … or it's reasonable.
    1.79 +    //
    1.80 +    // Furthermore, when we come to calculate idle we might find that the clock
    1.81 +    // is dramatically different — that the current time is thirteen years older
    1.82 +    // than our saved timestamp (system clock resets to 2000 on battery change),
    1.83 +    // or it's thirty years in the future (previous timestamp was saved as 0).
    1.84 +    //
    1.85 +    // We should try to do something vaguely sane in these situations.
    1.86 +    long previous = preferences.getLong(AnnouncementsConstants.PREF_LAST_LAUNCH, -1);
    1.87 +    if (previous == -1) {
    1.88 +      Logger.debug(LOG_TAG, "No previous launch recorded.");
    1.89 +    }
    1.90 +
    1.91 +    if (now < GlobalConstants.BUILD_TIMESTAMP_MSEC) {
    1.92 +      Logger.warn(LOG_TAG, "Current time " + now + " is older than build date " +
    1.93 +                           GlobalConstants.BUILD_TIMESTAMP_MSEC + ". Ignoring until clock is corrected.");
    1.94 +      return;
    1.95 +    }
    1.96 +
    1.97 +    if (now > AnnouncementsConstants.LATEST_ACCEPTED_LAUNCH_TIMESTAMP_MSEC) {
    1.98 +      Logger.warn(LOG_TAG, "Launch time " + now + " is later than max sane launch timestamp " +
    1.99 +                           AnnouncementsConstants.LATEST_ACCEPTED_LAUNCH_TIMESTAMP_MSEC +
   1.100 +                           ". Ignoring until clock is corrected.");
   1.101 +      return;
   1.102 +    }
   1.103 +
   1.104 +    if (previous > now) {
   1.105 +      Logger.debug(LOG_TAG, "Previous launch " + previous + " later than current time " +
   1.106 +                            now + ", but new time is sane. Accepting new time.");
   1.107 +    }
   1.108 +
   1.109 +    preferences.edit().putLong(AnnouncementsConstants.PREF_LAST_LAUNCH, now).commit();
   1.110 +  }
   1.111 +
   1.112 +  public static long getPollInterval(final Context context) {
   1.113 +    final SharedPreferences preferences = getSharedPreferences(context);
   1.114 +    return preferences.getLong(AnnouncementsConstants.PREF_ANNOUNCE_FETCH_INTERVAL_MSEC, AnnouncementsConstants.DEFAULT_ANNOUNCE_FETCH_INTERVAL_MSEC);
   1.115 +  }
   1.116 +
   1.117 +  public static void setPollInterval(final Context context, long interval) {
   1.118 +    final SharedPreferences preferences = getSharedPreferences(context);
   1.119 +    preferences.edit().putLong(AnnouncementsConstants.PREF_ANNOUNCE_FETCH_INTERVAL_MSEC, interval).commit();
   1.120 +  }
   1.121 +
   1.122 +  @Override
   1.123 +  protected void onHandleIntent(Intent intent) {
   1.124 +    Logger.setThreadLogTag(AnnouncementsConstants.GLOBAL_LOG_TAG);
   1.125 +
   1.126 +    // Intent can be null. Bug 1025937.
   1.127 +    if (intent == null) {
   1.128 +      Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
   1.129 +      return;
   1.130 +    }
   1.131 +
   1.132 +    final String action = intent.getAction();
   1.133 +    Logger.debug(LOG_TAG, "Broadcast onReceive. Intent is " + action);
   1.134 +
   1.135 +    if (AnnouncementsConstants.ACTION_ANNOUNCEMENTS_PREF.equals(action)) {
   1.136 +      handlePrefIntent(intent);
   1.137 +      return;
   1.138 +    }
   1.139 +
   1.140 +    if (Intent.ACTION_BOOT_COMPLETED.equals(action) ||
   1.141 +        Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
   1.142 +      BackgroundService.reflectContextToFennec(this,
   1.143 +          GlobalConstants.GECKO_PREFERENCES_CLASS,
   1.144 +          GlobalConstants.GECKO_BROADCAST_ANNOUNCEMENTS_PREF_METHOD);
   1.145 +      return;
   1.146 +    }
   1.147 +
   1.148 +    // Failure case.
   1.149 +    Logger.warn(LOG_TAG, "Unknown intent " + action);
   1.150 +  }
   1.151 +
   1.152 +  /**
   1.153 +   * Handle the intent sent by the browser when it wishes to notify us
   1.154 +   * of the value of the user preference. Look at the value and toggle the
   1.155 +   * alarm service accordingly.
   1.156 +   *
   1.157 +   * @param intent must be non-null.
   1.158 +   */
   1.159 +  private void handlePrefIntent(Intent intent) {
   1.160 +    if (!intent.hasExtra("enabled")) {
   1.161 +      Logger.warn(LOG_TAG, "Got ANNOUNCEMENTS_PREF intent without enabled. Ignoring.");
   1.162 +      return;
   1.163 +    }
   1.164 +
   1.165 +    final boolean enabled = intent.getBooleanExtra("enabled", true);
   1.166 +    Logger.debug(LOG_TAG, intent.getStringExtra("branch") + "/" +
   1.167 +                          intent.getStringExtra("pref")   + " = " +
   1.168 +                          (intent.hasExtra("enabled") ? enabled : ""));
   1.169 +
   1.170 +    toggleAlarm(this, enabled);
   1.171 +
   1.172 +    // Primarily intended for debugging and testing, but this doesn't do any harm.
   1.173 +    if (!enabled) {
   1.174 +      Logger.info(LOG_TAG, "!enabled: clearing last fetch.");
   1.175 +      final SharedPreferences sharedPreferences = getSharedPreferences();
   1.176 +      final Editor editor = sharedPreferences.edit();
   1.177 +      editor.remove(AnnouncementsConstants.PREF_LAST_FETCH_LOCAL_TIME);
   1.178 +      editor.remove(AnnouncementsConstants.PREF_EARLIEST_NEXT_ANNOUNCE_FETCH);
   1.179 +      editor.commit();
   1.180 +    }
   1.181 +  }
   1.182 +}

mercurial