/* * Copyright 2014 Bevbot LLC <info@bevbot.com> * * This file is part of the Kegtab package from the Kegbot project. For * more information on Kegtab or Kegbot, see <http://kegbot.org/>. * * Kegtab is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, version 2. * * Kegtab is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with Kegtab. If not, see <http://www.gnu.org/licenses/>. */ package org.kegbot.app.service; import android.app.AlarmManager; import android.app.IntentService; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; import android.util.Log; import org.kegbot.app.KegbotApplication; import org.kegbot.app.R; import org.kegbot.app.config.AppConfiguration; import org.kegbot.app.util.CheckinClient; import org.kegbot.app.util.Utils; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; /** * Checkin service: pings kegbot servers for version/support information. * * @author mike wakerly (opensource@hoho.com) */ public class CheckinService extends IntentService { private static final String TAG = CheckinService.class.getSimpleName(); static final String CHECKIN_NOW_ACTION = "org.kegbot.app.CHECKIN"; private static final long CHECKIN_INTERVAL_MILLIS = AlarmManager.INTERVAL_HALF_DAY; private static final int CHECKIN_NOTIFICATION_ID = 100; private AppConfiguration mConfig; private PendingIntent mPendingIntent; private WakeLock mWakeLock; public CheckinService() { super("CheckinService"); } @Override public void onCreate() { super.onCreate(); mConfig = ((KegbotApplication) getApplication()).getConfig(); final PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "kbcheckin"); registerAlarm(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { acquireWakeLock(); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { // If action was unset, it means the service was started // only to schedule the next checkin. try { if (CHECKIN_NOW_ACTION.equals(intent.getAction())) { doCheckin(); } } finally { releaseWakeLock(); } } @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { super.dump(fd, writer, args); writer.println( String.format("Last checkin attempt: %s", new Date(mConfig.getLastCheckinAttempt()))); writer.println( String.format("Last checkin success: %s", new Date(mConfig.getLastCheckinSuccess()))); } private void registerAlarm() { unregisterAlarm(); Log.d(TAG, "Registering alarm."); final Intent intent = getCheckinNowIntent(this); mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); final AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); final long nextCheckin = SystemClock.elapsedRealtime() + CHECKIN_INTERVAL_MILLIS; alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextCheckin, CHECKIN_INTERVAL_MILLIS, mPendingIntent); } private void unregisterAlarm() { if (mPendingIntent != null) { Log.d(TAG, "Unregistering alarm."); final AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.cancel(mPendingIntent); mPendingIntent = null; } } private void acquireWakeLock() { synchronized (mWakeLock) { if (!mWakeLock.isHeld()) { Log.d(TAG, "Acquiring wake lock."); mWakeLock.acquire(); } } } private void releaseWakeLock() { synchronized (mWakeLock) { if (mWakeLock.isHeld()) { Log.d(TAG, "Releasing wake lock."); mWakeLock.release(); } } } private void doCheckin() { final CheckinClient client = CheckinClient.fromContext(getApplicationContext()); try { client.checkin(); } catch (IOException e) { Log.w(TAG, "Checkin failed.", e); return; } NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (mConfig.getUpdateAvailable()) { Log.d(TAG, "Update is available, notifying.."); final boolean updateRequired = mConfig.getUpdateRequired(); Intent notificationIntent = new Intent(Intent.ACTION_VIEW); notificationIntent.setData(Uri.parse("market://details?id=org.kegbot.app")); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); int titleRes = updateRequired ? R.string.checkin_update_required_title : R.string.checkin_update_available_title; final Notification.Builder builder = new Notification.Builder(this) .setSmallIcon(updateRequired ? R.drawable.icon_warning : R.drawable.icon_download) .setContentTitle(getString(titleRes)) .setContentText(getString(R.string.checkin_update_description)) .setContentIntent(contentIntent) .setOnlyAlertOnce(true) .setAutoCancel(true); final Notification notification = Utils.buildNotification(builder); Log.d(TAG, "Posting notification."); nm.notify(CHECKIN_NOTIFICATION_ID, notification); } else { nm.cancel(CHECKIN_NOTIFICATION_ID); } } private static Intent getCheckinNowIntent(Context context) { final Intent intent = new Intent(CHECKIN_NOW_ACTION); return intent; } public static void requestImmediateCheckin(Context context) { Log.d(TAG, "Requesting immediate checkin."); final Intent intent = getCheckinNowIntent(context); context.sendBroadcast(intent); } public static void startCheckinService(Context context, boolean checkinNow) { final Intent intent = new Intent(context, CheckinService.class); if (checkinNow) { intent.setAction(CHECKIN_NOW_ACTION); } context.startService(intent); } }