├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── README
├── default.properties
├── res
├── drawable
│ ├── icon.png
│ └── logo.png
├── layout
│ └── main.xml
└── values
│ ├── colors.xml
│ └── strings.xml
├── src
└── com
│ └── tokudu
│ └── demo
│ ├── ConnectionLog.java
│ ├── PushActivity.java
│ └── PushService.java
└── wmqtt.jar
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/*
2 | gen/*
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidPushNotificationsDemo
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Push Notifications Demo for Android
2 | More details at http://tokudu.com/2010/how-to-implement-push-notifications-for-android
3 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Indicates whether an apk should be generated for each density.
11 | split.density=false
12 | # Project target.
13 | target=android-3
14 |
--------------------------------------------------------------------------------
/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tokudu/AndroidPushNotificationsDemo/ea18b09073a5fed9aaf22b0733a83286464fe636/res/drawable/icon.png
--------------------------------------------------------------------------------
/res/drawable/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tokudu/AndroidPushNotificationsDemo/ea18b09073a5fed9aaf22b0733a83286464fe636/res/drawable/logo.png
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
36 |
37 |
44 |
45 |
52 |
53 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #a2d03b
4 | #FFFFFF
5 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, PushActivity!
4 | Push Demo
5 | Your Device Target:
6 | Stop Push Service
7 | Start Push service
8 | www.tokudu.com
9 |
10 |
--------------------------------------------------------------------------------
/src/com/tokudu/demo/ConnectionLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | */
4 |
5 | package com.tokudu.demo;
6 |
7 | import java.io.BufferedWriter;
8 | import java.io.File;
9 | import java.io.FileWriter;
10 | import java.io.IOException;
11 | import java.io.Writer;
12 | import java.text.SimpleDateFormat;
13 | import java.util.Date;
14 |
15 | import android.os.Environment;
16 |
17 | public class ConnectionLog
18 | {
19 | private String mPath;
20 | private Writer mWriter;
21 |
22 | private static final SimpleDateFormat TIMESTAMP_FMT =
23 | new SimpleDateFormat("[HH:mm:ss] ");
24 |
25 | public ConnectionLog()
26 | throws IOException
27 | {
28 | File sdcard = Environment.getExternalStorageDirectory();
29 | File logDir = new File(sdcard, "tokudu/log/");
30 | if (!logDir.exists()) {
31 | logDir.mkdirs();
32 | // do not allow media scan
33 | new File(logDir, ".nomedia").createNewFile();
34 | }
35 |
36 | open(logDir.getAbsolutePath() + "/push.log");
37 | }
38 |
39 | public ConnectionLog(String basePath)
40 | throws IOException
41 | {
42 | open(basePath);
43 | }
44 |
45 | protected void open(String basePath)
46 | throws IOException
47 | {
48 | File f = new File(basePath + "-" + getTodayString());
49 | mPath = f.getAbsolutePath();
50 | mWriter = new BufferedWriter(new FileWriter(mPath), 2048);
51 |
52 | println("Opened log.");
53 | }
54 |
55 | private static String getTodayString()
56 | {
57 | SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-hhmmss");
58 | return df.format(new Date());
59 | }
60 |
61 | public String getPath()
62 | {
63 | return mPath;
64 | }
65 |
66 | public void println(String message)
67 | throws IOException
68 | {
69 | mWriter.write(TIMESTAMP_FMT.format(new Date()));
70 | mWriter.write(message);
71 | mWriter.write('\n');
72 | mWriter.flush();
73 | }
74 |
75 | public void close()
76 | throws IOException
77 | {
78 | mWriter.close();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/com/tokudu/demo/PushActivity.java:
--------------------------------------------------------------------------------
1 | package com.tokudu.demo;
2 |
3 | import android.app.Activity;
4 | import android.content.SharedPreferences;
5 | import android.content.SharedPreferences.Editor;
6 | import android.os.Bundle;
7 | import android.provider.Settings.Secure;
8 | import android.view.View;
9 | import android.view.View.OnClickListener;
10 | import android.widget.Button;
11 | import android.widget.TextView;
12 |
13 | public class PushActivity extends Activity {
14 | private String mDeviceID;
15 | /** Called when the activity is first created. */
16 | @Override
17 | public void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.main);
20 |
21 | mDeviceID = Secure.getString(this.getContentResolver(), Secure.ANDROID_ID);
22 | ((TextView) findViewById(R.id.target_text)).setText(mDeviceID);
23 |
24 | final Button startButton = ((Button) findViewById(R.id.start_button));
25 | final Button stopButton = ((Button) findViewById(R.id.stop_button));
26 | startButton.setOnClickListener(new OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | Editor editor = getSharedPreferences(PushService.TAG, MODE_PRIVATE).edit();
30 | editor.putString(PushService.PREF_DEVICE_ID, mDeviceID);
31 | editor.commit();
32 | PushService.actionStart(getApplicationContext());
33 | startButton.setEnabled(false);
34 | stopButton.setEnabled(true);
35 | }
36 | });
37 | stopButton.setOnClickListener(new OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | PushService.actionStop(getApplicationContext());
41 | startButton.setEnabled(true);
42 | stopButton.setEnabled(false);
43 | }
44 | });
45 | }
46 |
47 | @Override
48 | protected void onResume() {
49 | super.onResume();
50 |
51 | SharedPreferences p = getSharedPreferences(PushService.TAG, MODE_PRIVATE);
52 | boolean started = p.getBoolean(PushService.PREF_STARTED, false);
53 |
54 | ((Button) findViewById(R.id.start_button)).setEnabled(!started);
55 | ((Button) findViewById(R.id.stop_button)).setEnabled(started);
56 | }
57 | }
--------------------------------------------------------------------------------
/src/com/tokudu/demo/PushService.java:
--------------------------------------------------------------------------------
1 | package com.tokudu.demo;
2 |
3 | import java.io.IOException;
4 |
5 | import com.ibm.mqtt.IMqttClient;
6 | import com.ibm.mqtt.MqttClient;
7 | import com.ibm.mqtt.MqttException;
8 | import com.ibm.mqtt.MqttPersistence;
9 | import com.ibm.mqtt.MqttPersistenceException;
10 | import com.ibm.mqtt.MqttSimpleCallback;
11 |
12 | import android.app.AlarmManager;
13 | import android.app.Notification;
14 | import android.app.NotificationManager;
15 | import android.app.PendingIntent;
16 | import android.app.Service;
17 | import android.content.BroadcastReceiver;
18 | import android.content.Context;
19 | import android.content.Intent;
20 | import android.content.IntentFilter;
21 | import android.content.SharedPreferences;
22 | import android.net.ConnectivityManager;
23 | import android.net.NetworkInfo;
24 | import android.os.IBinder;
25 | import android.util.Log;
26 |
27 | /*
28 | * PushService that does all of the work.
29 | * Most of the logic is borrowed from KeepAliveService.
30 | * http://code.google.com/p/android-random/source/browse/trunk/TestKeepAlive/src/org/devtcg/demo/keepalive/KeepAliveService.java?r=219
31 | */
32 | public class PushService extends Service
33 | {
34 | // this is the log tag
35 | public static final String TAG = "DemoPushService";
36 |
37 | // the IP address, where your MQTT broker is running.
38 | private static final String MQTT_HOST = "209.124.50.174";
39 | // the port at which the broker is running.
40 | private static int MQTT_BROKER_PORT_NUM = 1883;
41 | // Let's not use the MQTT persistence.
42 | private static MqttPersistence MQTT_PERSISTENCE = null;
43 | // We don't need to remember any state between the connections, so we use a clean start.
44 | private static boolean MQTT_CLEAN_START = true;
45 | // Let's set the internal keep alive for MQTT to 15 mins. I haven't tested this value much. It could probably be increased.
46 | private static short MQTT_KEEP_ALIVE = 60 * 15;
47 | // Set quality of services to 0 (at most once delivery), since we don't want push notifications
48 | // arrive more than once. However, this means that some messages might get lost (delivery is not guaranteed)
49 | private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ;
50 | private static int MQTT_QUALITY_OF_SERVICE = 0;
51 | // The broker should not retain any messages.
52 | private static boolean MQTT_RETAINED_PUBLISH = false;
53 |
54 | // MQTT client ID, which is given the broker. In this example, I also use this for the topic header.
55 | // You can use this to run push notifications for multiple apps with one MQTT broker.
56 | public static String MQTT_CLIENT_ID = "tokudu";
57 |
58 | // These are the actions for the service (name are descriptive enough)
59 | private static final String ACTION_START = MQTT_CLIENT_ID + ".START";
60 | private static final String ACTION_STOP = MQTT_CLIENT_ID + ".STOP";
61 | private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID + ".KEEP_ALIVE";
62 | private static final String ACTION_RECONNECT = MQTT_CLIENT_ID + ".RECONNECT";
63 |
64 | // Connection log for the push service. Good for debugging.
65 | private ConnectionLog mLog;
66 |
67 | // Connectivity manager to determining, when the phone loses connection
68 | private ConnectivityManager mConnMan;
69 | // Notification manager to displaying arrived push notifications
70 | private NotificationManager mNotifMan;
71 |
72 | // Whether or not the service has been started.
73 | private boolean mStarted;
74 |
75 | // This the application level keep-alive interval, that is used by the AlarmManager
76 | // to keep the connection active, even when the device goes to sleep.
77 | private static final long KEEP_ALIVE_INTERVAL = 1000 * 60 * 28;
78 |
79 | // Retry intervals, when the connection is lost.
80 | private static final long INITIAL_RETRY_INTERVAL = 1000 * 10;
81 | private static final long MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30;
82 |
83 | // Preferences instance
84 | private SharedPreferences mPrefs;
85 | // We store in the preferences, whether or not the service has been started
86 | public static final String PREF_STARTED = "isStarted";
87 | // We also store the deviceID (target)
88 | public static final String PREF_DEVICE_ID = "deviceID";
89 | // We store the last retry interval
90 | public static final String PREF_RETRY = "retryInterval";
91 |
92 | // Notification title
93 | public static String NOTIF_TITLE = "Tokudu";
94 | // Notification id
95 | private static final int NOTIF_CONNECTED = 0;
96 |
97 | // This is the instance of an MQTT connection.
98 | private MQTTConnection mConnection;
99 | private long mStartTime;
100 |
101 |
102 | // Static method to start the service
103 | public static void actionStart(Context ctx) {
104 | Intent i = new Intent(ctx, PushService.class);
105 | i.setAction(ACTION_START);
106 | ctx.startService(i);
107 | }
108 |
109 | // Static method to stop the service
110 | public static void actionStop(Context ctx) {
111 | Intent i = new Intent(ctx, PushService.class);
112 | i.setAction(ACTION_STOP);
113 | ctx.startService(i);
114 | }
115 |
116 | // Static method to send a keep alive message
117 | public static void actionPing(Context ctx) {
118 | Intent i = new Intent(ctx, PushService.class);
119 | i.setAction(ACTION_KEEPALIVE);
120 | ctx.startService(i);
121 | }
122 |
123 | @Override
124 | public void onCreate() {
125 | super.onCreate();
126 |
127 | log("Creating service");
128 | mStartTime = System.currentTimeMillis();
129 |
130 | try {
131 | mLog = new ConnectionLog();
132 | Log.i(TAG, "Opened log at " + mLog.getPath());
133 | } catch (IOException e) {
134 | Log.e(TAG, "Failed to open log", e);
135 | }
136 |
137 | // Get instances of preferences, connectivity manager and notification manager
138 | mPrefs = getSharedPreferences(TAG, MODE_PRIVATE);
139 | mConnMan = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
140 | mNotifMan = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
141 |
142 | /* If our process was reaped by the system for any reason we need
143 | * to restore our state with merely a call to onCreate. We record
144 | * the last "started" value and restore it here if necessary. */
145 | handleCrashedService();
146 | }
147 |
148 | // This method does any necessary clean-up need in case the server has been destroyed by the system
149 | // and then restarted
150 | private void handleCrashedService() {
151 | if (wasStarted() == true) {
152 | log("Handling crashed service...");
153 | // stop the keep alives
154 | stopKeepAlives();
155 |
156 | // Do a clean start
157 | start();
158 | }
159 | }
160 |
161 | @Override
162 | public void onDestroy() {
163 | log("Service destroyed (started=" + mStarted + ")");
164 |
165 | // Stop the services, if it has been started
166 | if (mStarted == true) {
167 | stop();
168 | }
169 |
170 | try {
171 | if (mLog != null)
172 | mLog.close();
173 | } catch (IOException e) {}
174 | }
175 |
176 | @Override
177 | public void onStart(Intent intent, int startId) {
178 | super.onStart(intent, startId);
179 | log("Service started with intent=" + intent);
180 |
181 | // Do an appropriate action based on the intent.
182 | if (intent.getAction().equals(ACTION_STOP) == true) {
183 | stop();
184 | stopSelf();
185 | } else if (intent.getAction().equals(ACTION_START) == true) {
186 | start();
187 | } else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) {
188 | keepAlive();
189 | } else if (intent.getAction().equals(ACTION_RECONNECT) == true) {
190 | if (isNetworkAvailable()) {
191 | reconnectIfNecessary();
192 | }
193 | }
194 | }
195 |
196 | @Override
197 | public IBinder onBind(Intent intent) {
198 | return null;
199 | }
200 |
201 | // log helper function
202 | private void log(String message) {
203 | log(message, null);
204 | }
205 | private void log(String message, Throwable e) {
206 | if (e != null) {
207 | Log.e(TAG, message, e);
208 |
209 | } else {
210 | Log.i(TAG, message);
211 | }
212 |
213 | if (mLog != null)
214 | {
215 | try {
216 | mLog.println(message);
217 | } catch (IOException ex) {}
218 | }
219 | }
220 |
221 | // Reads whether or not the service has been started from the preferences
222 | private boolean wasStarted() {
223 | return mPrefs.getBoolean(PREF_STARTED, false);
224 | }
225 |
226 | // Sets whether or not the services has been started in the preferences.
227 | private void setStarted(boolean started) {
228 | mPrefs.edit().putBoolean(PREF_STARTED, started).commit();
229 | mStarted = started;
230 | }
231 |
232 | private synchronized void start() {
233 | log("Starting service...");
234 |
235 | // Do nothing, if the service is already running.
236 | if (mStarted == true) {
237 | Log.w(TAG, "Attempt to start connection that is already active");
238 | return;
239 | }
240 |
241 | // Establish an MQTT connection
242 | connect();
243 |
244 | // Register a connectivity listener
245 | registerReceiver(mConnectivityChanged, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
246 | }
247 |
248 | private synchronized void stop() {
249 | // Do nothing, if the service is not running.
250 | if (mStarted == false) {
251 | Log.w(TAG, "Attempt to stop connection not active.");
252 | return;
253 | }
254 |
255 | // Save stopped state in the preferences
256 | setStarted(false);
257 |
258 | // Remove the connectivity receiver
259 | unregisterReceiver(mConnectivityChanged);
260 | // Any existing reconnect timers should be removed, since we explicitly stopping the service.
261 | cancelReconnect();
262 |
263 | // Destroy the MQTT connection if there is one
264 | if (mConnection != null) {
265 | mConnection.disconnect();
266 | mConnection = null;
267 | }
268 | }
269 |
270 | //
271 | private synchronized void connect() {
272 | log("Connecting...");
273 | // fetch the device ID from the preferences.
274 | String deviceID = mPrefs.getString(PREF_DEVICE_ID, null);
275 | // Create a new connection only if the device id is not NULL
276 | if (deviceID == null) {
277 | log("Device ID not found.");
278 | } else {
279 | try {
280 | mConnection = new MQTTConnection(MQTT_HOST, deviceID);
281 | } catch (MqttException e) {
282 | // Schedule a reconnect, if we failed to connect
283 | log("MqttException: " + (e.getMessage() != null ? e.getMessage() : "NULL"));
284 | if (isNetworkAvailable()) {
285 | scheduleReconnect(mStartTime);
286 | }
287 | }
288 | setStarted(true);
289 | }
290 | }
291 |
292 | private synchronized void keepAlive() {
293 | try {
294 | // Send a keep alive, if there is a connection.
295 | if (mStarted == true && mConnection != null) {
296 | mConnection.sendKeepAlive();
297 | }
298 | } catch (MqttException e) {
299 | log("MqttException: " + (e.getMessage() != null? e.getMessage(): "NULL"), e);
300 |
301 | mConnection.disconnect();
302 | mConnection = null;
303 | cancelReconnect();
304 | }
305 | }
306 |
307 | // Schedule application level keep-alives using the AlarmManager
308 | private void startKeepAlives() {
309 | Intent i = new Intent();
310 | i.setClass(this, PushService.class);
311 | i.setAction(ACTION_KEEPALIVE);
312 | PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
313 | AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
314 | alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
315 | System.currentTimeMillis() + KEEP_ALIVE_INTERVAL,
316 | KEEP_ALIVE_INTERVAL, pi);
317 | }
318 |
319 | // Remove all scheduled keep alives
320 | private void stopKeepAlives() {
321 | Intent i = new Intent();
322 | i.setClass(this, PushService.class);
323 | i.setAction(ACTION_KEEPALIVE);
324 | PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
325 | AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
326 | alarmMgr.cancel(pi);
327 | }
328 |
329 | // We schedule a reconnect based on the starttime of the service
330 | public void scheduleReconnect(long startTime) {
331 | // the last keep-alive interval
332 | long interval = mPrefs.getLong(PREF_RETRY, INITIAL_RETRY_INTERVAL);
333 |
334 | // Calculate the elapsed time since the start
335 | long now = System.currentTimeMillis();
336 | long elapsed = now - startTime;
337 |
338 |
339 | // Set an appropriate interval based on the elapsed time since start
340 | if (elapsed < interval) {
341 | interval = Math.min(interval * 4, MAXIMUM_RETRY_INTERVAL);
342 | } else {
343 | interval = INITIAL_RETRY_INTERVAL;
344 | }
345 |
346 | log("Rescheduling connection in " + interval + "ms.");
347 |
348 | // Save the new internval
349 | mPrefs.edit().putLong(PREF_RETRY, interval).commit();
350 |
351 | // Schedule a reconnect using the alarm manager.
352 | Intent i = new Intent();
353 | i.setClass(this, PushService.class);
354 | i.setAction(ACTION_RECONNECT);
355 | PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
356 | AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
357 | alarmMgr.set(AlarmManager.RTC_WAKEUP, now + interval, pi);
358 | }
359 |
360 | // Remove the scheduled reconnect
361 | public void cancelReconnect() {
362 | Intent i = new Intent();
363 | i.setClass(this, PushService.class);
364 | i.setAction(ACTION_RECONNECT);
365 | PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
366 | AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
367 | alarmMgr.cancel(pi);
368 | }
369 |
370 | private synchronized void reconnectIfNecessary() {
371 | if (mStarted == true && mConnection == null) {
372 | log("Reconnecting...");
373 | connect();
374 | }
375 | }
376 |
377 | // This receiver listeners for network changes and updates the MQTT connection
378 | // accordingly
379 | private BroadcastReceiver mConnectivityChanged = new BroadcastReceiver() {
380 | @Override
381 | public void onReceive(Context context, Intent intent) {
382 | // Get network info
383 | NetworkInfo info = (NetworkInfo)intent.getParcelableExtra (ConnectivityManager.EXTRA_NETWORK_INFO);
384 |
385 | // Is there connectivity?
386 | boolean hasConnectivity = (info != null && info.isConnected()) ? true : false;
387 |
388 | log("Connectivity changed: connected=" + hasConnectivity);
389 |
390 | if (hasConnectivity) {
391 | reconnectIfNecessary();
392 | } else if (mConnection != null) {
393 | // if there no connectivity, make sure MQTT connection is destroyed
394 | mConnection.disconnect();
395 | cancelReconnect();
396 | mConnection = null;
397 | }
398 | }
399 | };
400 |
401 | // Display the topbar notification
402 | private void showNotification(String text) {
403 | Notification n = new Notification();
404 |
405 | n.flags |= Notification.FLAG_SHOW_LIGHTS;
406 | n.flags |= Notification.FLAG_AUTO_CANCEL;
407 |
408 | n.defaults = Notification.DEFAULT_ALL;
409 |
410 | n.icon = com.tokudu.demo.R.drawable.icon;
411 | n.when = System.currentTimeMillis();
412 |
413 | // Simply open the parent activity
414 | PendingIntent pi = PendingIntent.getActivity(this, 0,
415 | new Intent(this, PushActivity.class), 0);
416 |
417 | // Change the name of the notification here
418 | n.setLatestEventInfo(this, NOTIF_TITLE, text, pi);
419 |
420 | mNotifMan.notify(NOTIF_CONNECTED, n);
421 | }
422 |
423 | // Check if we are online
424 | private boolean isNetworkAvailable() {
425 | NetworkInfo info = mConnMan.getActiveNetworkInfo();
426 | if (info == null) {
427 | return false;
428 | }
429 | return info.isConnected();
430 | }
431 |
432 | // This inner class is a wrapper on top of MQTT client.
433 | private class MQTTConnection implements MqttSimpleCallback {
434 | IMqttClient mqttClient = null;
435 |
436 | // Creates a new connection given the broker address and initial topic
437 | public MQTTConnection(String brokerHostName, String initTopic) throws MqttException {
438 | // Create connection spec
439 | String mqttConnSpec = "tcp://" + brokerHostName + "@" + MQTT_BROKER_PORT_NUM;
440 | // Create the client and connect
441 | mqttClient = MqttClient.createMqttClient(mqttConnSpec, MQTT_PERSISTENCE);
442 | String clientID = MQTT_CLIENT_ID + "/" + mPrefs.getString(PREF_DEVICE_ID, "");
443 | mqttClient.connect(clientID, MQTT_CLEAN_START, MQTT_KEEP_ALIVE);
444 |
445 | // register this client app has being able to receive messages
446 | mqttClient.registerSimpleHandler(this);
447 |
448 | // Subscribe to an initial topic, which is combination of client ID and device ID.
449 | initTopic = MQTT_CLIENT_ID + "/" + initTopic;
450 | subscribeToTopic(initTopic);
451 |
452 | log("Connection established to " + brokerHostName + " on topic " + initTopic);
453 |
454 | // Save start time
455 | mStartTime = System.currentTimeMillis();
456 | // Star the keep-alives
457 | startKeepAlives();
458 | }
459 |
460 | // Disconnect
461 | public void disconnect() {
462 | try {
463 | stopKeepAlives();
464 | mqttClient.disconnect();
465 | } catch (MqttPersistenceException e) {
466 | log("MqttException" + (e.getMessage() != null? e.getMessage():" NULL"), e);
467 | }
468 | }
469 | /*
470 | * Send a request to the message broker to be sent messages published with
471 | * the specified topic name. Wildcards are allowed.
472 | */
473 | private void subscribeToTopic(String topicName) throws MqttException {
474 |
475 | if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
476 | // quick sanity check - don't try and subscribe if we don't have
477 | // a connection
478 | log("Connection error" + "No connection");
479 | } else {
480 | String[] topics = { topicName };
481 | mqttClient.subscribe(topics, MQTT_QUALITIES_OF_SERVICE);
482 | }
483 | }
484 | /*
485 | * Sends a message to the message broker, requesting that it be published
486 | * to the specified topic.
487 | */
488 | private void publishToTopic(String topicName, String message) throws MqttException {
489 | if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
490 | // quick sanity check - don't try and publish if we don't have
491 | // a connection
492 | log("No connection to public to");
493 | } else {
494 | mqttClient.publish(topicName,
495 | message.getBytes(),
496 | MQTT_QUALITY_OF_SERVICE,
497 | MQTT_RETAINED_PUBLISH);
498 | }
499 | }
500 |
501 | /*
502 | * Called if the application loses it's connection to the message broker.
503 | */
504 | public void connectionLost() throws Exception {
505 | log("Loss of connection" + "connection downed");
506 | stopKeepAlives();
507 | // null itself
508 | mConnection = null;
509 | if (isNetworkAvailable() == true) {
510 | reconnectIfNecessary();
511 | }
512 | }
513 |
514 | /*
515 | * Called when we receive a message from the message broker.
516 | */
517 | public void publishArrived(String topicName, byte[] payload, int qos, boolean retained) {
518 | // Show a notification
519 | String s = new String(payload);
520 | showNotification(s);
521 | log("Got message: " + s);
522 | }
523 |
524 | public void sendKeepAlive() throws MqttException {
525 | log("Sending keep alive");
526 | // publish to a keep-alive topic
527 | publishToTopic(MQTT_CLIENT_ID + "/keepalive", mPrefs.getString(PREF_DEVICE_ID, ""));
528 | }
529 | }
530 | }
--------------------------------------------------------------------------------
/wmqtt.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tokudu/AndroidPushNotificationsDemo/ea18b09073a5fed9aaf22b0733a83286464fe636/wmqtt.jar
--------------------------------------------------------------------------------