/* This file is part of ZAX. ZAX 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, either version 3 of the License, or (at your option) any later version. ZAX 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 ZAX. If not, see <http://www.gnu.org/licenses/>. */ package com.inovex.zabbixmobile.push.pubnub; import android.app.AlarmManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Handler; import android.os.IBinder; import android.os.SystemClock; import android.support.v7.app.NotificationCompat; import android.util.Log; import com.inovex.zabbixmobile.R; import com.inovex.zabbixmobile.model.ZaxPreferences; import com.inovex.zabbixmobile.push.NotificationService; import com.pubnub.api.Callback; import com.pubnub.api.Pubnub; import com.pubnub.api.PubnubError; import org.json.JSONException; import org.json.JSONObject; /** * Push service maintaining the connection to Pubnub and showing notifications * when Pubnub sends data. * */ public class PubnubPushService extends Service { public static final String RINGTONE = "RINGTONE"; public static final String PUBNUB_SUBSCRIBE_KEY = "PUBNUB_SUBSCRIBE_KEY"; public static final String OLD_NOTIFICATION_ICONS = "OLD_NOTIFICATION_ICONS"; String PUSHCHANNEL = "zabbixmobile"; private static final String TAG = PubnubPushService.class.getSimpleName(); private static AlarmManager am; Pubnub pubnub; PushListener mPushListener; private Handler handler; boolean initialConnect = true; private String subscribeKey; class PushListener extends AsyncTask<String, Void, Boolean> { @Override protected Boolean doInBackground(String... params) { try { pubnub.subscribe(params[0], new Callback() { @Override public void successCallback(String channel, Object input) { Log.i("PushService", "execute"); try { if (input instanceof JSONObject) { JSONObject jsonObj = (JSONObject) input; String status = null, message = null; Long triggerid = null; try { status = jsonObj.getString("status"); } catch (JSONException e) { e.printStackTrace(); } try { message = jsonObj.getString("message"); } catch (JSONException e) { e.printStackTrace(); } try { triggerid = jsonObj.getLong("triggerid"); } catch (JSONException e) { e.printStackTrace(); } createNotification(status, message, triggerid); } } catch (Exception e) { e.printStackTrace(); } } @Override public void connectCallback(String channel, Object message) { Log.i(TAG, "connect to " + channel + ": " + message.toString()); if (initialConnect) { handler.post(new Runnable() { @Override public void run() { initialConnect = false; } }); } } @Override public void disconnectCallback(String channel, Object message) { Log.i(TAG, "disconnect to " + channel + ": " + message.toString()); } @Override public void errorCallback(String channel, final PubnubError error) { Log.i(TAG, "error (" + channel + "): " + error.getErrorString()); if (initialConnect) { handler.post(new Runnable() { @Override public void run() { NotificationCompat.Builder builder = new NotificationCompat.Builder(PubnubPushService.this); builder.setSmallIcon(R.drawable.problem) .setContentTitle(getResources().getString(R.string.push_connection_error)) .setContentText(error.toString()); NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.notify(1, builder.build()); initialConnect = false; } }); } } @Override public void reconnectCallback(String channel, Object message) { Log.i(TAG, "reconnect to " + channel + ": " + message.toString()); } }); Log.i(TAG, "subscribe"); } catch (Exception e) { e.printStackTrace(); } return Boolean.TRUE; // Return your real result here } private void createNotification(String status, String message, Long triggerid) { Intent intent = new Intent(getApplicationContext(),NotificationService.class); intent.putExtra("status",status); intent.putExtra("message",message); intent.putExtra("triggerid",triggerid); intent.putExtra("source","pubnub"); startService(intent); } } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); this.handler = new Handler(); if (mPushListener == null) mPushListener = new PushListener(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); Log.d(TAG, "onStartCommand"); subscribeKey = intent.getStringExtra(PUBNUB_SUBSCRIBE_KEY); if (subscribeKey == null) subscribeKey = ""; pubnub = new Pubnub("", // PUBLISH_KEY subscribeKey, // SUBSCRIBE_KEY "", // SECRET_KEY "", // CIPHER_KEY false // SSL_ON? ); if (mPushListener.getStatus() != AsyncTask.Status.RUNNING && mPushListener.getStatus() != AsyncTask.Status.FINISHED) { mPushListener.execute(PUSHCHANNEL); Log.i("PushListener", "start"); } return START_REDELIVER_INTENT; } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); mPushListener.cancel(true); pubnub.unsubscribe(PUSHCHANNEL); } /** * This starts or stops the push service depending on the user's settings. * * @param context */ public static void startOrStopPushService(Context context) { // start the push receiver, if it is enabled ZaxPreferences preferences = ZaxPreferences.getInstance(context); boolean push = preferences.isPushEnabled(); Intent intent = new Intent(context, PubnubPushService.class); intent.putExtra(PUBNUB_SUBSCRIBE_KEY, preferences.getPushSubscribeKey()); // alarm manager if (am == null) am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); if (push) { Log.d(TAG, "starting service"); setRepeatingAlarm(pendingIntent); context.startService(intent); } else { Log.d(TAG, "stopping service"); stopRepeatingAlarm(pendingIntent); context.stopService(intent); } } public static void killPushService(Context context) { Log.d(TAG, "stopping push service"); Intent intent = new Intent(context, PubnubPushService.class); context.stopService(intent); } private static void setRepeatingAlarm(PendingIntent pendingIntent) { Log.d("PushServiceAlarm", "setRepeatingAlarm"); // cancel old alarm am.cancel(pendingIntent); // wake up every 60 minutes to ensure service stays alive int alarmFrequency = 60 * 60 * 1000; // start service after one minute to avoid wasting precious CPU time // after device boot am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1 * 60 * 1000, alarmFrequency, pendingIntent); } private static void stopRepeatingAlarm(PendingIntent pendingIntent) { Log.d("PushServiceAlarm", "stopRepeatingAlarm"); am.cancel(pendingIntent); } }