├── app
├── src
│ └── main
│ │ ├── assets
│ │ └── file
│ │ ├── ic_launcher-playstore.png
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ └── arrow.png
│ │ ├── drawable-ldpi
│ │ │ └── arrow.png
│ │ ├── drawable-mdpi
│ │ │ └── arrow.png
│ │ ├── drawable-xhdpi
│ │ │ └── arrow.png
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── attrs_arrow.xml
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── menu
│ │ │ ├── activity_client_connections_contextual.xml
│ │ │ ├── activity_connection_details.xml
│ │ │ ├── activity_last_will.xml
│ │ │ ├── activity_connection_details_disconnected.xml
│ │ │ ├── activity_publish.xml
│ │ │ ├── activity_subscribe.xml
│ │ │ ├── activity_publish_disconnected.xml
│ │ │ ├── activity_subscribe_disconnected.xml
│ │ │ ├── activity_connections_logging.xml
│ │ │ ├── activity_new_connection.xml
│ │ │ ├── activity_advanced.xml
│ │ │ └── activity_connections.xml
│ │ ├── drawable
│ │ │ ├── ic_add.xml
│ │ │ ├── ic_cloud_circle.xml
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout
│ │ │ ├── list_view_text_view.xml
│ │ │ ├── activity_connection_details.xml
│ │ │ ├── connection_text_view.xml
│ │ │ ├── client_connections.xml
│ │ │ ├── filedialogitem.xml
│ │ │ ├── activity_subscribe.xml
│ │ │ ├── activity_new_connection.xml
│ │ │ ├── activity_last_will.xml
│ │ │ ├── activity_publish.xml
│ │ │ └── activity_advanced.xml
│ │ └── raw
│ │ │ └── jsr47android.properties
│ │ ├── resources
│ │ └── io
│ │ │ └── bytehala
│ │ │ └── eclipsemqtt
│ │ │ └── sample
│ │ │ └── package.html
│ │ ├── java
│ │ └── io
│ │ │ └── bytehala
│ │ │ └── eclipsemqtt
│ │ │ └── sample
│ │ │ ├── CallbackBundle.java
│ │ │ ├── MqttTraceCallback.java
│ │ │ ├── SubscribeFragment.java
│ │ │ ├── PublishFragment.java
│ │ │ ├── PersistenceException.java
│ │ │ ├── HistoryFragment.java
│ │ │ ├── LastWillActivity.java
│ │ │ ├── Notify.java
│ │ │ ├── ActivityConstants.java
│ │ │ ├── Connections.java
│ │ │ ├── MqttCallbackHandler.java
│ │ │ ├── OpenFileDialog.java
│ │ │ ├── ActionListener.java
│ │ │ ├── AdvancedActivity.java
│ │ │ ├── NewConnectionActivity.java
│ │ │ ├── Listener.java
│ │ │ ├── Persistence.java
│ │ │ ├── Connection.java
│ │ │ └── ConnectionDetailsActivity.java
│ │ └── AndroidManifest.xml
├── libs
│ └── org.eclipse.paho.android.service-1.0.2.jar
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── jarRepositories.xml
├── markdown-navigator.xml
└── markdown-navigator-enh.xml
├── .travis.yml
├── gradle.properties
├── import-summary.txt
├── gradlew.bat
├── README.md
├── .gitignore
└── gradlew
/app/src/main/assets/file:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/drawable-hdpi/arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/drawable-ldpi/arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/drawable-mdpi/arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/drawable-xhdpi/arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/libs/org.eclipse.paho.android.service-1.0.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/libs/org.eclipse.paho.android.service-1.0.2.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytehala/android-mqtt-quickstart/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Apr 06 17:16:30 MDT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_client_connections_contextual.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs_arrow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/resources/io/bytehala/eclipsemqtt/sample/package.html:
--------------------------------------------------------------------------------
1 |
2 | Contains classes for a basic graphical user interface to drive multiple MQTT clients.
3 | Since the Android environment does not allow object references to be passed between activities, the classes Connection and Connections
4 | enable a basic Model to pass connections around using unique client handles.
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cloud_circle.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_view_text_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_connection_details.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_last_will.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_connection_details_disconnected.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_connection_details.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/connection_text_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | android:
3 | components:
4 | # Uncomment the lines below if you want to
5 | # use the latest revision of Android SDK Tools
6 | # - platform-tools
7 | - tools
8 |
9 | # The BuildTools version used by your project
10 | - build-tools-28.0.3
11 |
12 | # The SDK version used to compile your project
13 | - android-28
14 |
15 | # Additional components
16 | #- extra-google-m2repository
17 | #- extra-android-m2repository
18 | #- addon-google_apis-google-19
19 |
20 | # Specify at least one system image,
21 | # if you need to run emulator(s) during your tests
22 | #- sys-img-armeabi-v7a-android-19
23 | #- sys-img-x86-android-17
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_publish.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
16 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_subscribe.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
16 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_publish_disconnected.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
16 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_subscribe_disconnected.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
16 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_connections_logging.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_new_connection.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_advanced.xml:
--------------------------------------------------------------------------------
1 |
12 |
15 |
16 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/CallbackBundle.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 |
16 | import android.os.Bundle;
17 |
18 | /**
19 | * For File selector to share data
20 | *
21 | */
22 | public interface CallbackBundle {
23 | abstract void callback(Bundle bundle);
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_connections.xml:
--------------------------------------------------------------------------------
1 |
12 |
14 |
15 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/MqttTraceCallback.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import org.eclipse.paho.android.service.MqttTraceHandler;
16 |
17 | import android.util.Log;
18 |
19 | public class MqttTraceCallback implements MqttTraceHandler {
20 |
21 | public void traceDebug(java.lang.String arg0, java.lang.String arg1) {
22 | Log.i(arg0, arg1);
23 | };
24 |
25 | public void traceError(java.lang.String arg0, java.lang.String arg1) {
26 | Log.e(arg0, arg1);
27 | };
28 |
29 | public void traceException(java.lang.String arg0, java.lang.String arg1,
30 | java.lang.Exception arg2) {
31 | Log.e(arg0, arg1, arg2);
32 | };
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/client_connections.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
17 |
18 |
25 |
26 |
27 |
28 |
37 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/SubscribeFragment.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import android.os.Bundle;
16 | import android.view.LayoutInflater;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 |
20 | import androidx.fragment.app.Fragment;
21 |
22 | /**
23 | * Fragment for the subscribe pane for the client
24 | *
25 | */
26 | public class SubscribeFragment extends Fragment {
27 |
28 | /**
29 | * @see Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)
30 | */
31 | @Override
32 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
33 | Bundle savedInstanceState) {
34 |
35 | return LayoutInflater.from(getActivity()).inflate(R.layout.activity_subscribe, null);
36 |
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/PublishFragment.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import android.os.Bundle;
16 | import android.view.LayoutInflater;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 |
20 | import androidx.fragment.app.Fragment;
21 |
22 | /**
23 | * Fragment for the publish message pane.
24 | *
25 | */
26 | public class PublishFragment extends Fragment {
27 |
28 | /**
29 | * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
30 | */
31 | @Override
32 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
33 | Bundle savedInstanceState) {
34 |
35 | return LayoutInflater.from(getActivity()).inflate(R.layout.activity_publish, null);
36 |
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | buildToolsVersion '28.0.3'
6 |
7 | defaultConfig {
8 | applicationId "io.bytehala.eclipsemqtt.sample"
9 | minSdkVersion 18
10 | targetSdkVersion 28
11 | multiDexEnabled true
12 | versionCode 3
13 | versionName "1.1-SNAPSHOT"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
20 | }
21 | }
22 |
23 | lintOptions {
24 | abortOnError false
25 | }
26 |
27 | compileOptions {
28 | sourceCompatibility '1.8'
29 | targetCompatibility '1.8'
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation "androidx.core:core:1.2.0"
35 | implementation "com.google.android.material:material:1.1.0"
36 | implementation 'com.android.support:design:28.0.0'
37 |
38 | // Do not remove, even if using AndroidX. Used by :org.eclipse.paho.android.service
39 | implementation 'com.android.support:support-v4:28.0.0'
40 | // Eclipse MQTT libraries
41 | implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
42 | implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.2'
43 |
44 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/filedialogitem.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
35 |
36 |
37 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/PersistenceException.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | /**
16 | * Persistence Exception, defines an error with persisting a {@link Connection}
17 | * fails. Example operations are {@link Persistence#persistConnection(Connection)} and {@link Persistence#restoreConnections(android.content.Context)};
18 | * these operations throw this exception to indicate unexpected results occurred when performing actions on the database.
19 | *
20 | */
21 | public class PersistenceException extends Exception {
22 |
23 | /**
24 | * Creates a persistence exception with the given error message
25 | * @param message The error message to display
26 | */
27 | public PersistenceException(String message) {
28 | super(message);
29 | }
30 |
31 | /** Serialisation ID**/
32 | private static final long serialVersionUID = 5326458803268855071L;
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/import-summary.txt:
--------------------------------------------------------------------------------
1 | ECLIPSE ANDROID PROJECT IMPORT SUMMARY
2 | ======================================
3 |
4 | Ignored Files:
5 | --------------
6 | The following files were *not* copied into the new Gradle project; you
7 | should evaluate whether these are still needed in your project and if
8 | so manually move them:
9 |
10 | * build.xml
11 | * ic_launcher-web.png
12 | * proguard-project.txt
13 |
14 | Replaced Jars with Dependencies:
15 | --------------------------------
16 | The importer recognized the following .jar files as third party
17 | libraries and replaced them with Gradle dependencies instead. This has
18 | the advantage that more explicit version information is known, and the
19 | libraries can be updated automatically. However, it is possible that
20 | the .jar file in your project was of an older version than the
21 | dependency we picked, which could render the project not compileable.
22 | You can disable the jar replacement in the import wizard and try again:
23 |
24 | android-support-v4.jar => com.android.support:support-v4:19.1.0
25 |
26 | Moved Files:
27 | ------------
28 | Android Gradle projects use a different directory structure than ADT
29 | Eclipse projects. Here's how the projects were restructured:
30 |
31 | * AndroidManifest.xml => app/src/main/AndroidManifest.xml
32 | * assets/ => app/src/main/assets/
33 | * libs/org.eclipse.paho.android.service-1.0.2.jar => app/libs/org.eclipse.paho.android.service-1.0.2.jar
34 | * libs/org.eclipse.paho.client.mqttv3-1.0.2.jar => app/libs/org.eclipse.paho.client.mqttv3-1.0.2.jar
35 | * res/ => app/src/main/res/
36 | * src/ => app/src/main/java/
37 | * src/org/eclipse/paho/android/service/sample/package.html => app/src/main/resources/org/eclipse/paho/android/service/sample/package.html
38 |
39 | Next Steps:
40 | -----------
41 | You can now build the project. The Gradle project needs network
42 | connectivity to download dependencies.
43 |
44 | Bugs:
45 | -----
46 | If for some reason your project does not build, and you determine that
47 | it is due to a bug or limitation of the Eclipse to Gradle importer,
48 | please file a bug at http://b.android.com with category
49 | Component-Tools.
50 |
51 | (This import summary is for your information only, and can be deleted
52 | after import once you are satisfied with the results.)
53 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/HistoryFragment.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import android.os.Bundle;
16 | import android.text.Spanned;
17 | import android.widget.ArrayAdapter;
18 |
19 | import androidx.fragment.app.ListFragment;
20 | import io.bytehala.eclipsemqtt.sample.R;
21 |
22 | /**
23 | * This fragment displays the history information for a client
24 | *
25 | */
26 | public class HistoryFragment extends ListFragment {
27 |
28 | /** Client handle to a {@link Connection} object **/
29 | String clientHandle = null;
30 | /** {@link ArrayAdapter} to display the formatted text **/
31 | ArrayAdapter arrayAdapter = null;
32 |
33 | /**
34 | * @see ListFragment#onCreate(Bundle)
35 | */
36 | @Override
37 | public void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 |
40 | //Pull history information out of bundle
41 |
42 | clientHandle = getArguments().getString("handle");
43 | Connection connection = Connections.getInstance(getActivity()).getConnection(clientHandle);
44 |
45 | Spanned[] history = connection.history();
46 |
47 | //Initialise the arrayAdapter, view and add data
48 | arrayAdapter = new ArrayAdapter(getActivity(), R.layout.list_view_text_view);
49 |
50 | arrayAdapter.addAll(history);
51 | setListAdapter(arrayAdapter);
52 |
53 | }
54 |
55 | /**
56 | * Updates the data displayed to match the current history
57 | */
58 | public void refresh() {
59 | if (arrayAdapter != null) {
60 | arrayAdapter.clear();
61 | arrayAdapter.addAll(Connections.getInstance(getActivity()).getConnection(clientHandle).history());
62 | arrayAdapter.notifyDataSetChanged();
63 | }
64 |
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
56 |
57 |
58 |
59 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/LastWillActivity.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import android.app.Activity;
16 | import android.content.Intent;
17 | import android.os.Bundle;
18 | import android.view.Menu;
19 | import android.view.MenuItem;
20 | import android.view.MenuItem.OnMenuItemClickListener;
21 | import android.widget.CheckBox;
22 | import android.widget.EditText;
23 | import android.widget.RadioGroup;
24 |
25 | import androidx.appcompat.app.AppCompatActivity;
26 |
27 | /**
28 | * Activity for setting the last will message for the client
29 | *
30 | */
31 | public class LastWillActivity extends AppCompatActivity {
32 |
33 | /**
34 | * Reference to the current instance of LastWillActivity for use with anonymous listener
35 | */
36 | private LastWillActivity last = this;
37 |
38 | /**
39 | * @see Activity#onCreate(Bundle)
40 | */
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_last_will);
45 |
46 | }
47 |
48 | /**
49 | * @see Activity#onCreateOptionsMenu(Menu)
50 | */
51 | @Override
52 | public boolean onCreateOptionsMenu(Menu menu) {
53 | getMenuInflater().inflate(R.menu.activity_last_will, menu);
54 |
55 | menu.findItem(R.id.publish).setOnMenuItemClickListener(new OnMenuItemClickListener() {
56 |
57 | @Override
58 | public boolean onMenuItemClick(MenuItem item) {
59 |
60 | Intent result = new Intent();
61 |
62 | String message = ((EditText) findViewById(R.id.lastWill)).getText().toString();
63 | String topic = ((EditText) findViewById(R.id.lastWillTopic)).getText().toString();
64 |
65 | RadioGroup radio = (RadioGroup) findViewById(R.id.qosRadio);
66 | int checked = radio.getCheckedRadioButtonId();
67 | int qos = ActivityConstants.defaultQos;
68 |
69 | //determine which qos value has been selected
70 | switch (checked)
71 | {
72 | case R.id.qos0 :
73 | qos = 0;
74 | break;
75 | case R.id.qos1 :
76 | qos = 1;
77 | break;
78 | case R.id.qos2 :
79 | qos = 2;
80 | break;
81 | }
82 |
83 | boolean retained = ((CheckBox) findViewById(R.id.retained)).isChecked();
84 |
85 | //package the data collected into the intent
86 | result.putExtra(ActivityConstants.message, message);
87 | result.putExtra(ActivityConstants.topic, topic);
88 | result.putExtra(ActivityConstants.qos, qos);
89 | result.putExtra(ActivityConstants.retained, retained);
90 |
91 | //set the result and finish activity
92 | last.setResult(RESULT_OK, result);
93 | last.finish();
94 |
95 | return false;
96 | }
97 |
98 | });
99 | return true;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/Notify.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.util.Calendar;
16 | import io.bytehala.eclipsemqtt.sample.R;
17 | import android.app.Notification;
18 | import android.app.NotificationManager;
19 | import android.app.PendingIntent;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.widget.Toast;
23 |
24 | import androidx.core.app.NotificationCompat;
25 |
26 | /**
27 | * Provides static methods for creating and showing notifications to the user.
28 | *
29 | */
30 | public class Notify {
31 |
32 | /** Message ID Counter **/
33 | private static int MessageID = 0;
34 |
35 | /**
36 | * Displays a notification in the notification area of the UI
37 | * @param context Context from which to create the notification
38 | * @param messageString The string to display to the user as a message
39 | * @param intent The intent which will start the activity when the user clicks the notification
40 | * @param notificationTitle The resource reference to the notification title
41 | */
42 | static void notifcation(Context context, String messageString, Intent intent, int notificationTitle) {
43 |
44 | //Get the notification manage which we will use to display the notification
45 | String ns = Context.NOTIFICATION_SERVICE;
46 | NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
47 |
48 | Calendar.getInstance().getTime().toString();
49 |
50 | long when = System.currentTimeMillis();
51 |
52 | //get the notification title from the application's strings.xml file
53 | CharSequence contentTitle = context.getString(notificationTitle);
54 |
55 | //the message that will be displayed as the ticker
56 | String ticker = contentTitle + " " + messageString;
57 |
58 | //build the pending intent that will start the appropriate activity
59 | PendingIntent pendingIntent = PendingIntent.getActivity(context,
60 | ActivityConstants.showHistory, intent, 0);
61 |
62 | //build the notification
63 | NotificationCompat.Builder notificationCompat = new NotificationCompat.Builder(context);
64 | notificationCompat.setAutoCancel(true)
65 | .setContentTitle(contentTitle)
66 | .setContentIntent(pendingIntent)
67 | .setContentText(messageString)
68 | .setTicker(ticker)
69 | .setWhen(when)
70 | .setSmallIcon(R.mipmap.ic_launcher);
71 |
72 | Notification notification = notificationCompat.build();
73 | //display the notification
74 | mNotificationManager.notify(MessageID, notification);
75 | MessageID++;
76 |
77 | }
78 |
79 | /**
80 | * Display a toast notification to the user
81 | * @param context Context from which to create a notification
82 | * @param text The text the toast should display
83 | * @param duration The amount of time for the toast to appear to the user
84 | */
85 | static void toast(Context context, CharSequence text, int duration) {
86 | Toast toast = Toast.makeText(context, text, duration);
87 | toast.show();
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_subscribe.xml:
--------------------------------------------------------------------------------
1 |
12 |
17 |
18 |
22 |
23 |
29 |
30 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
51 |
52 |
57 |
58 |
65 |
66 |
67 |
73 |
74 |
79 |
80 |
85 |
86 |
87 |
88 |
89 |
90 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/jsr47android.properties:
--------------------------------------------------------------------------------
1 | # Properties file which configures the operation of the JDK logging facility.
2 | #
3 | # The configuration in this file is the suggesgted configuration
4 | # for collecting trace for helping debug problems related to the
5 | # Paho MQTT client. It configures trace to be continuosly collected
6 | # in memory with minimal impact on performance.
7 | #
8 | # When the push trigger (by default a Severe level message) or a
9 | # specific request is made to "push" the in memory trace then it
10 | # is "pushed" to the configured target handler. By default
11 | # this is the standard java.util.logging.FileHandler. The Paho Debug
12 | # class can be used to push the memory trace to its target
13 | #
14 | # To enable trace either:
15 | # - use this properties file as is and set the logging facility up
16 | # to use it by configuring the util logging system property e.g.
17 | #
18 | # >java -Djava.util.logging.config.file=\jsr47android.properties
19 | #
20 | # - explicitly load this file as the configuration file for a LogManager
21 | #
22 | # - This contents of this file can also be merged with another
23 | # java.util.logging config file to ensure provide wider logging
24 | # and trace including Paho trace
25 |
26 | # Global logging properties.
27 | # ------------------------------------------
28 | # The set of handlers to be loaded upon startup.
29 | # Comma-separated list of class names.
30 | handlers=java.util.logging.FileHandler
31 |
32 | # Default global logging level.
33 | # Loggers and Handlers may override this level
34 | #.level=INFO
35 |
36 | # Loggers
37 | # ------------------------------------------
38 | # A FileHandler is attached to the paho packages
39 | # and the level specified to collected all trace related
40 | # to paho packages. This will override any root/global
41 | # level handlers if set.
42 | org.eclipse.paho.client.mqttv3.handlers=java.util.logging.FileHandler
43 |
44 | org.eclipse.paho.client.mqttv3.level=ALL
45 | # It is possible to set more granular trace on a per class basis e.g.
46 | #org.eclipse.paho.client.mqttv3.internal.ClientComms.level=ALL
47 |
48 | # Handlers
49 | # -----------------------------------------
50 | # Note: the target handler that is associated with the MemoryHandler is not a root handler
51 | # and hence not returned when getting the handlers from root. It appears accessing
52 | # target handler programatically is not possible as target is a private variable in
53 | # class MemoryHandler
54 | java.util.logging.MemoryHandler.level=FINEST
55 | java.util.logging.MemoryHandler.size=10000
56 | java.util.logging.MemoryHandler.push=SEVERE
57 | java.util.logging.MemoryHandler.target=java.util.logging.FileHandler
58 | #java.util.logging.MemoryHandler.target=java.util.logging.ConsoleHandler
59 |
60 |
61 | # --- FileHandler ---
62 | # Override of global logging level
63 | java.util.logging.FileHandler.level=ALL
64 |
65 | # Naming style for the output file:
66 | # (The output file is placed in the directory
67 | # defined by the "java.io.tmpdir" System property.)
68 | # See java.util.logging for more options
69 | java.util.logging.FileHandler.pattern=%t/paho%u.log
70 |
71 | # Limiting size of output file in bytes:
72 | java.util.logging.FileHandler.limit=200000
73 |
74 | # Number of output files to cycle through, by appending an
75 | # integer to the base file name:
76 | java.util.logging.FileHandler.count=3
77 |
78 | # Style of output (Simple or XML):
79 | java.util.logging.FileHandler.formatter=org.eclipse.paho.client.mqttv3.logging.SimpleLogFormatter
80 |
81 | # --- ConsoleHandler ---
82 | # Override of global logging level
83 | #java.util.logging.ConsoleHandler.level=INFO
84 | #java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
85 | #java.util.logging.ConsoleHandler.formatter=org.eclipse.paho.client.mqttv3.internal.logging.SimpleLogFormatter
86 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/ActivityConstants.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import org.eclipse.paho.client.mqttv3.MqttMessage;
16 |
17 | /**
18 | * This Class provides constants used for returning results from an activity
19 | *
20 | */
21 | public class ActivityConstants {
22 |
23 | /** Application TAG for logs where class name is not used*/
24 | static final String TAG = "MQTT Android";
25 |
26 | /*Default values **/
27 |
28 | /** Default QOS value*/
29 | static final int defaultQos = 0;
30 | /** Default timeout*/
31 | static final int defaultTimeOut = 1000;
32 | /** Default keep alive value*/
33 | static final int defaultKeepAlive = 10;
34 | /** Default SSL enabled flag*/
35 | static final boolean defaultSsl = false;
36 | /** Default message retained flag */
37 | static final boolean defaultRetained = false;
38 | /** Default last will message*/
39 | static final MqttMessage defaultLastWill = null;
40 | /** Default port*/
41 | static final int defaultPort = 1883;
42 |
43 | /** Connect Request Code */
44 | static final int connect = 0;
45 | /** AdvancedActivity Connect Request Code **/
46 | static final int advancedConnect = 1;
47 | /** Last will Request Code **/
48 | static final int lastWill = 2;
49 | /** Show History Request Code **/
50 | static final int showHistory = 3;
51 |
52 | /* Bundle Keys */
53 |
54 | /** Server Bundle Key **/
55 | static final String server = "server";
56 | /** Port Bundle Key **/
57 | static final String port = "port";
58 | /** ClientID Bundle Key **/
59 | static final String clientId = "clientId";
60 | /** Topic Bundle Key **/
61 | static final String topic = "topic";
62 | /** History Bundle Key **/
63 | static final String history = "history";
64 | /** Message Bundle Key **/
65 | static final String message = "message";
66 | /** Retained Flag Bundle Key **/
67 | static final String retained = "retained";
68 | /** QOS Value Bundle Key **/
69 | static final String qos = "qos";
70 | /** User name Bundle Key **/
71 | static final String username = "username";
72 | /** Password Bundle Key **/
73 | static final String password = "password";
74 | /** Keep Alive value Bundle Key **/
75 | static final String keepalive = "keepalive";
76 | /** Timeout Bundle Key **/
77 | static final String timeout = "timeout";
78 | /** SSL Enabled Flag Bundle Key **/
79 | static final String ssl = "ssl";
80 | /** SSL Key File Bundle Key **/
81 | static final String ssl_key = "ssl_key";
82 | /** Connections Bundle Key **/
83 | static final String connections = "connections";
84 | /** Clean Session Flag Bundle Key **/
85 | static final String cleanSession = "cleanSession";
86 | /** Action Bundle Key **/
87 | static final String action = "action";
88 |
89 | /* Property names */
90 |
91 | /** Property name for the history field in {@link Connection} object for use with {@link java.beans.PropertyChangeEvent} **/
92 | static final String historyProperty = "history";
93 |
94 | /** Property name for the connection status field in {@link Connection} object for use with {@link java.beans.PropertyChangeEvent} **/
95 | static final String ConnectionStatusProperty = "connectionStatus";
96 |
97 | /* Useful constants*/
98 |
99 | /** Space String Literal **/
100 | static final String space = " ";
101 | /** Empty String for comparisons **/
102 | static final String empty = new String();
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | xmlns:android
17 |
18 | ^$
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | xmlns:.*
28 |
29 | ^$
30 |
31 |
32 | BY_NAME
33 |
34 |
35 |
36 |
37 |
38 |
39 | .*:id
40 |
41 | http://schemas.android.com/apk/res/android
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | .*:name
51 |
52 | http://schemas.android.com/apk/res/android
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | name
62 |
63 | ^$
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | style
73 |
74 | ^$
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | .*
84 |
85 | ^$
86 |
87 |
88 | BY_NAME
89 |
90 |
91 |
92 |
93 |
94 |
95 | .*
96 |
97 | http://schemas.android.com/apk/res/android
98 |
99 |
100 | ANDROID_ATTRIBUTE_ORDER
101 |
102 |
103 |
104 |
105 |
106 |
107 | .*
108 |
109 | .*
110 |
111 |
112 | BY_NAME
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > :warning: **Please feel free to create issues if it does not run for you.
2 | # android-mqtt-quickstart [](https://travis-ci.org/bytehala/android-mqtt-quickstart)
3 | Android Studio port of the Eclipse paho MQTT sample project.
4 | Beside that you can use subscribe/pulish to a MQTT server, sms functionality is added to this project.
5 |
6 |
7 | ## How sms functionality is working ?
8 | If you want to send sms, you have to first subscribe to sms topic in application
9 | To set your phone number in messages received via sms topic, The thirteen first characters of your message will be the phone number you want to send
10 | example:
11 | ```
12 | message topic: sms
13 | payload: +989375915077 Hello
14 | ```
15 |
16 |
17 | It is highly recommended to change the default phone number in ```src\main\java\io\bytehala\eclipsemqtt\sample\MqttCallbackHandler.java``` line 141
18 |
19 | ## Environment Tested On
20 | 1. OpenJDK Java 11 by Amazon (sdkman 11.0.6-amzn)
21 | 2. Samsung galaxy mini s5570 SDK version 18 ( OS android, Cyanogen mod )
22 | 3. Android Studio 4.1.1
23 |
24 | #### This information are from the forked repo
25 |
26 | I am maintaining this on my own, and as such am unable to test on multiple devices and environments.
27 |
28 | You can support me buy contributing code, filing bugs, asking/answering questions, or buying me a coffee.
29 |
30 |
31 |
32 |
33 |
34 | ## Getting Started
35 | 1. Download the code `git clone http://www.github.com/bytehala/android-mqtt-quickstart`
36 | 2. Open the project in Android Studio
37 | 3. Build and run it.
38 |
39 | ## Using the Sample App
40 | To test the app, you need an MQTT broker. Luckily, HiveMQ provides a free one which we can use for testing.
41 | 
42 |
43 | After successfully connecting, you can start subscribing and publishing to topics using the app.
44 | 
45 |
46 | 
47 |
48 | ## More About MQTT
49 | MQTT is a messaging protocol which has applications in the Internet of Things (IoT).
50 | This sample project uses Eclipse's open-source implementation called the Paho Project.
51 | If you go to the [original source](https://github.com/eclipse/paho.mqtt.java) where I lifted this project from, there are non-Android sample projects that use the Paho library.
52 |
53 | This youtube video explains the MQTT for IoT at a very basic level.
54 |
55 | [](http://www.youtube.com/watch?v=1XzC3WqmiBs "Basics of MQTT IoT")
56 |
57 | Learn more about the other MQTT options such as QOS, Last Will, etc from this really helpful 12 part series by HiveMQ
58 | http://www.hivemq.com/blog/mqtt-essentials/
59 |
60 | ## Create Your Own App
61 | All you need is an MQTT broker.
62 | This app is just piggybacking on HiveMQ's free broker.
63 |
64 | Take note of the dependencies in this project.
65 | `org.eclipse.paho.android.service` and `org.eclipse.paho.client.mqttv3` depend on the old android-support-v4, specifically the LocalBroadcastManager class.
66 |
67 | Maybe we can migrate to mqttv5 using the plain Java library at https://github.com/eclipse/paho.mqtt.java
68 |
69 | The eclipse sources can be found at:
70 | https://github.com/eclipse/paho.mqtt.android
71 |
72 | Honestly, when I made an MQTT app for a client, I just built on top of this sample project.
73 |
74 | # Word of Warning
75 | This app was made in 2015-2016, and is a demo of how to use the Eclipse MQTT Libraries, not how to code in Android.
76 |
77 | Architecture components are a thing now, and I strongly advise the use of ViewModel and LifecycleHook.
78 |
79 | # Work In Progress
80 | Definitely look at the "jetpacknav" branch which aims to transform everything into a Single-Activity application, which has been the Android recommendation since 2018. It's currently a work in progress but a clear example of how to transform legacy apps from the old Android paradigm (multiple-Activity) to the newer ones (single-Activity Jetpack).
81 |
82 | # MQTT V3 vs V5
83 | This project uses MQTT v3 and I will be looking into using v3 and v5 in the near future.
--------------------------------------------------------------------------------
/.idea/markdown-navigator-enh.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_new_connection.xml:
--------------------------------------------------------------------------------
1 |
12 |
17 |
18 |
22 |
23 |
29 |
30 |
37 |
38 |
39 |
45 |
46 |
52 |
53 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
85 |
86 |
87 |
93 |
94 |
100 |
101 |
107 |
108 |
109 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/Connections.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.util.HashMap;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | import android.content.Context;
20 |
21 | import org.eclipse.paho.android.service.MqttAndroidClient;
22 |
23 | /**
24 | * Connections is a singleton class which stores all the connection objects
25 | * in one central place so they can be passed between activities using a client
26 | * handle
27 | *
28 | */
29 | public class Connections {
30 |
31 | /** Singleton instance of Connections**/
32 | private static Connections instance = null;
33 |
34 | /** List of {@link Connection} objects**/
35 | private HashMap connections = null;
36 |
37 | /** {@link Persistence} object used to save, delete and restore connections**/
38 | private Persistence persistence = null;
39 |
40 | /**
41 | * Create a Connections object
42 | * @param context Applications context
43 | */
44 | private Connections(Context context)
45 | {
46 | connections = new HashMap();
47 |
48 | //attempt to restore state
49 | persistence = new Persistence(context);
50 | try {
51 | List l = persistence.restoreConnections(context);
52 | for (Connection c : l) {
53 | connections.put(c.handle(), c);
54 | }
55 | }
56 | catch (PersistenceException e) {
57 | e.printStackTrace();
58 | }
59 |
60 | }
61 |
62 | /**
63 | * Returns an already initialised instance of Connections, if Connections has yet to be created, it will
64 | * create and return that instance
65 | * @param context The applications context used to create the Connections object if it is not already initialised
66 | * @return Connections instance
67 | */
68 | public synchronized static Connections getInstance(Context context)
69 | {
70 | if (instance == null) {
71 | instance = new Connections(context);
72 | }
73 |
74 | return instance;
75 | }
76 |
77 | /**
78 | * Finds and returns a connection object that the given client handle points to
79 | * @param handle The handle to the Connection to return
80 | * @return a connection associated with the client handle, null if one is not found
81 | */
82 | public Connection getConnection(String handle)
83 | {
84 |
85 | return connections.get(handle);
86 | }
87 |
88 | /**
89 | * Adds a Connection object to the collection of connections associated with this object
90 | * @param connection connection to add
91 | */
92 | public void addConnection(Connection connection)
93 | {
94 | connections.put(connection.handle(), connection);
95 | try {
96 | persistence.persistConnection(connection);
97 | }
98 | catch (PersistenceException e)
99 | {
100 | //error persisting well lets just swallow this
101 | e.printStackTrace();
102 | }
103 | }
104 |
105 | /**
106 | * Create a fully initialised MqttAndroidClient for the parameters given
107 | * @param context The Applications context
108 | * @param serverURI The ServerURI to connect to
109 | * @param clientId The clientId for this client
110 | * @return new instance of MqttAndroidClient
111 | */
112 | public MqttAndroidClient createClient(Context context, String serverURI, String clientId)
113 | {
114 | MqttAndroidClient client = new MqttAndroidClient(context, serverURI, clientId);
115 | return client;
116 | }
117 |
118 | /**
119 | * Get all the connections associated with this Connections object.
120 | * @return Map of connections
121 | */
122 | public Map getConnections()
123 | {
124 | return connections;
125 | }
126 |
127 | /**
128 | * Removes a connection from the map of connections
129 | * @param connection connection to be removed
130 | */
131 | public void removeConnection(Connection connection) {
132 | connections.remove(connection.handle());
133 | persistence.deleteConnection(connection);
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_last_will.xml:
--------------------------------------------------------------------------------
1 |
12 |
18 |
19 |
23 |
24 |
30 |
31 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
57 |
58 |
66 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
85 |
86 |
92 |
93 |
100 |
101 |
106 |
107 |
112 |
113 |
114 |
115 |
116 |
122 |
128 |
129 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_publish.xml:
--------------------------------------------------------------------------------
1 |
12 |
18 |
19 |
23 |
24 |
30 |
31 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
57 |
58 |
66 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
84 |
85 |
91 |
92 |
99 |
100 |
105 |
106 |
111 |
112 |
113 |
120 |
121 |
126 |
127 |
128 |
129 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/java,gradle,kotlin,android,androidstudio
3 | # Edit at https://www.gitignore.io/?templates=java,gradle,kotlin,android,androidstudio
4 |
5 | ### Android ###
6 | # Built application files
7 | *.apk
8 | *.ap_
9 | *.aab
10 |
11 | # Files for the ART/Dalvik VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # Generated files
18 | bin/
19 | gen/
20 | out/
21 | release/
22 |
23 | # Gradle files
24 | .gradle/
25 | build/
26 |
27 | # Local configuration file (sdk path, etc)
28 | local.properties
29 |
30 | # Proguard folder generated by Eclipse
31 | proguard/
32 |
33 | # Log Files
34 | *.log
35 |
36 | # Android Studio Navigation editor temp files
37 | .navigation/
38 |
39 | # Android Studio captures folder
40 | captures/
41 |
42 | # IntelliJ
43 | *.iml
44 | .idea/workspace.xml
45 | .idea/tasks.xml
46 | .idea/gradle.xml
47 | .idea/assetWizardSettings.xml
48 | .idea/dictionaries
49 | .idea/libraries
50 | # Android Studio 3 in .gitignore file.
51 | .idea/caches
52 | .idea/modules.xml
53 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
54 | .idea/navEditor.xml
55 |
56 | # Keystore files
57 | # Uncomment the following lines if you do not want to check your keystore files in.
58 | #*.jks
59 | #*.keystore
60 |
61 | # External native build folder generated in Android Studio 2.2 and later
62 | .externalNativeBuild
63 |
64 | # Google Services (e.g. APIs or Firebase)
65 | # google-services.json
66 |
67 | # Freeline
68 | freeline.py
69 | freeline/
70 | freeline_project_description.json
71 |
72 | # fastlane
73 | fastlane/report.xml
74 | fastlane/Preview.html
75 | fastlane/screenshots
76 | fastlane/test_output
77 | fastlane/readme.md
78 |
79 | # Version control
80 | vcs.xml
81 |
82 | # lint
83 | lint/intermediates/
84 | lint/generated/
85 | lint/outputs/
86 | lint/tmp/
87 | # lint/reports/
88 |
89 | ### Android Patch ###
90 | gen-external-apklibs
91 | output.json
92 |
93 | # Replacement of .externalNativeBuild directories introduced
94 | # with Android Studio 3.5.
95 | .cxx/
96 |
97 | ### Java ###
98 | # Compiled class file
99 |
100 | # Log file
101 |
102 | # BlueJ files
103 | *.ctxt
104 |
105 | # Mobile Tools for Java (J2ME)
106 | .mtj.tmp/
107 |
108 | # Package Files #
109 | *.jar
110 | *.war
111 | *.nar
112 | *.ear
113 | *.zip
114 | *.tar.gz
115 | *.rar
116 |
117 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
118 | hs_err_pid*
119 |
120 | ### Kotlin ###
121 | # Compiled class file
122 |
123 | # Log file
124 |
125 | # BlueJ files
126 |
127 | # Mobile Tools for Java (J2ME)
128 |
129 | # Package Files #
130 |
131 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
132 |
133 | ### Gradle ###
134 | .gradle
135 |
136 | # Ignore Gradle GUI config
137 | gradle-app.setting
138 |
139 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
140 | !gradle-wrapper.jar
141 |
142 | # Cache of project
143 | .gradletasknamecache
144 |
145 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
146 | # gradle/wrapper/gradle-wrapper.properties
147 |
148 | ### Gradle Patch ###
149 | **/build/
150 |
151 | ### AndroidStudio ###
152 | # Covers files to be ignored for android development using Android Studio.
153 |
154 | # Built application files
155 |
156 | # Files for the ART/Dalvik VM
157 |
158 | # Java class files
159 |
160 | # Generated files
161 |
162 | # Gradle files
163 |
164 | # Signing files
165 | .signing/
166 |
167 | # Local configuration file (sdk path, etc)
168 |
169 | # Proguard folder generated by Eclipse
170 |
171 | # Log Files
172 |
173 | # Android Studio
174 | /*/build/
175 | /*/local.properties
176 | /*/out
177 | /*/*/build
178 | /*/*/production
179 | *.ipr
180 | *~
181 | *.swp
182 |
183 | # Android Patch
184 |
185 | # External native build folder generated in Android Studio 2.2 and later
186 |
187 | # NDK
188 | obj/
189 |
190 | # IntelliJ IDEA
191 | *.iws
192 | /out/
193 |
194 | # User-specific configurations
195 | .idea/caches/
196 | .idea/libraries/
197 | .idea/shelf/
198 | .idea/.name
199 | .idea/compiler.xml
200 | .idea/copyright/profiles_settings.xml
201 | .idea/encodings.xml
202 | .idea/misc.xml
203 | .idea/scopes/scope_settings.xml
204 | .idea/vcs.xml
205 | .idea/jsLibraryMappings.xml
206 | .idea/datasources.xml
207 | .idea/dataSources.ids
208 | .idea/sqlDataSources.xml
209 | .idea/dynamic.xml
210 | .idea/uiDesigner.xml
211 |
212 | # OS-specific files
213 | .DS_Store
214 | .DS_Store?
215 | ._*
216 | .Spotlight-V100
217 | .Trashes
218 | ehthumbs.db
219 | Thumbs.db
220 |
221 | # Legacy Eclipse project files
222 | .classpath
223 | .project
224 | .cproject
225 | .settings/
226 |
227 | # Mobile Tools for Java (J2ME)
228 |
229 | # Package Files #
230 |
231 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
232 |
233 | ## Plugin-specific files:
234 |
235 | # mpeltonen/sbt-idea plugin
236 | .idea_modules/
237 |
238 | # JIRA plugin
239 | atlassian-ide-plugin.xml
240 |
241 | # Mongo Explorer plugin
242 | .idea/mongoSettings.xml
243 |
244 | # Crashlytics plugin (for Android Studio and IntelliJ)
245 | com_crashlytics_export_strings.xml
246 | crashlytics.properties
247 | crashlytics-build.properties
248 | fabric.properties
249 |
250 | ### AndroidStudio Patch ###
251 |
252 | !/gradle/wrapper/gradle-wrapper.jar
253 |
254 | # End of https://www.gitignore.io/api/java,gradle,kotlin,android,androidstudio
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | Bytehala MQTT
15 | Settings
16 | Server
17 | Port
18 | Connect
19 |
20 | New Connection
21 | +
22 |
23 | New Connection
24 | Client ID
25 | Connected to
26 |
27 | Disconnect
28 | Subscribe
29 | Publish
30 | Subscribe
31 | Disconnected from
32 | Topic
33 | History
34 | History
35 | Subscribed to
36 | org.eclipse.paho.android.service.sample.ClientConnections
37 | Unknown connection status to
38 | Connecting to
39 | Disconnecting from
40 | An error occurred connecting to
41 |
42 | Publish
43 | Message
44 | 0
45 | 1
46 | 2
47 |
48 | QOS
49 | Retained
50 | Clean Session
51 | Advanced Options
52 | Advanced
53 | Advanced
54 | User Name
55 | Password
56 | SSL
57 | Time Out
58 | Keep Alive \nTimeout
59 |
60 | Last Will Message
61 | Set Last Will Message
62 | Set Last Will Message
63 | Last Will
64 | MQTT Message Received
65 | MQTT Client Has Lost Connection
66 |
67 | Save
68 | Connection Details
69 | Enable Logging
70 | Disable Logging
71 | ClientID, server address or Port number is missing. Please correct or press back arrow cancel.
72 |
73 | dd/MM/yy \'at\' HH:mm:ss
74 | Unknown Error
75 | Delete Connection
76 | Disconnect Client?
77 | The selected client is currently connected or connecting, deleting this connection will cause it to be disconnected.
78 | Continue
79 | Cancel
80 |
81 |
82 | Received message %1$s <br/> <small>Topic: %2$s </small>
83 | <br/> <small> %1$s </small>
84 | %1$s has received %2$s on topic %3$s
85 | Published message: %1$s to topic: %2$s
86 | Subscribed to %1$s
87 | Disconnected
88 | Failed to publish message: %1$s to topic: %2$s
89 | Failed to subscribe to %1$s
90 | %1$s has lost connection to %2$s
91 | Disconnect failed.<br/> <small>Reason: %s</small>
92 | Client failed to connect.<br/> <small>Reason: %s</small>
93 | Client connected successfully
94 |
95 |
96 | broker.hivemq.com
97 | 1883
98 | Enable SSL
99 | Clean Session
100 | hello
101 | Hello World
102 | user
103 | password
104 | 60
105 | 200
106 | file://
107 | select
108 | Send Message
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_advanced.xml:
--------------------------------------------------------------------------------
1 |
12 |
17 |
18 |
22 |
23 |
29 |
30 |
39 |
40 |
41 |
42 |
48 |
49 |
55 |
56 |
64 |
65 |
66 |
72 |
73 |
79 |
80 |
85 |
86 |
95 |
96 |
97 |
98 |
105 |
106 |
107 |
108 |
114 |
115 |
121 |
122 |
130 |
131 |
132 |
138 |
139 |
146 |
147 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/MqttCallbackHandler.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import io.bytehala.eclipsemqtt.sample.R;
16 | import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
17 | import org.eclipse.paho.client.mqttv3.MqttCallback;
18 | import org.eclipse.paho.client.mqttv3.MqttMessage;
19 |
20 | import android.annotation.SuppressLint;
21 | import android.app.ListActivity;
22 | import android.app.PendingIntent;
23 | import android.content.Context;
24 | import android.content.Intent;
25 | import android.telephony.SmsManager;
26 | import android.util.Log;
27 |
28 | import io.bytehala.eclipsemqtt.sample.Connection.ConnectionStatus;
29 |
30 | /**
31 | * Handles call backs from the MQTT Client
32 | *
33 | */
34 | public class MqttCallbackHandler implements MqttCallback {
35 | private String TAG = "MQTT Message";
36 |
37 | /** {@link Context} for the application used to format and import external strings**/
38 | private Context context;
39 | /** Client handle to reference the connection that this handler is attached to**/
40 | private String clientHandle;
41 |
42 | /**
43 | * Creates an MqttCallbackHandler object
44 | * @param context The application's context
45 | * @param clientHandle The handle to a {@link Connection} object
46 | */
47 | public MqttCallbackHandler(Context context, String clientHandle)
48 | {
49 | this.context = context;
50 | this.clientHandle = clientHandle;
51 | }
52 |
53 | /**
54 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang.Throwable)
55 | */
56 | @Override
57 | public void connectionLost(Throwable cause) {
58 | // cause.printStackTrace();
59 | if (cause != null) {
60 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
61 | c.addAction("Connection Lost");
62 | c.changeConnectionStatus(ConnectionStatus.DISCONNECTED);
63 |
64 | //format string to use a notification text
65 | Object[] args = new Object[2];
66 | args[0] = c.getId();
67 | args[1] = c.getHostName();
68 |
69 | String message = context.getString(R.string.connection_lost, args);
70 |
71 | //build intent
72 | Intent intent = new Intent();
73 | intent.setClassName(context, "io.bytehala.eclipsemqtt.sample.ConnectionDetailsActivity");
74 | intent.putExtra("handle", clientHandle);
75 |
76 | //notify the user
77 | Notify.notifcation(context, message, intent, R.string.notifyTitle_connectionLost);
78 | }
79 | }
80 |
81 | /**
82 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String, org.eclipse.paho.client.mqttv3.MqttMessage)
83 | */
84 | @Override
85 | public void messageArrived(String topic, MqttMessage message) throws Exception {
86 |
87 | //Get connection object associated with this object
88 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
89 |
90 | //create arguments to format message arrived notifcation string
91 | String[] args = new String[2];
92 | args[0] = new String(message.getPayload());
93 | args[1] = topic+";qos:"+message.getQos()+";retained:"+message.isRetained();
94 |
95 | //get the string from strings.xml and format
96 | @SuppressLint("StringFormatMatches") String messageString = context.getString(R.string.messageRecieved, (Object[]) args);
97 |
98 | //create intent to start activity
99 | Intent intent = new Intent();
100 | intent.setClassName(context, "io.bytehala.eclipsemqtt.sample.ConnectionDetailsActivity");
101 | intent.putExtra("handle", clientHandle);
102 |
103 | //format string args
104 | Object[] notifyArgs = new String[3];
105 | notifyArgs[0] = c.getId();
106 | notifyArgs[1] = new String(message.getPayload());
107 | notifyArgs[2] = topic;
108 |
109 |
110 | String phone_number = ((String) notifyArgs[1]). substring(0,13);
111 |
112 | // if topic was sms send message to other number
113 | if (topic.equals("sms")){
114 | sendMessage((String) notifyArgs[1], phone_number);
115 | Log.d(TAG, "messageArrived: "+ topic + "\t" + notifyArgs[1] );
116 | }
117 | //notify the user
118 | Notify.notifcation(context, context.getString(R.string.notification, notifyArgs), intent, R.string.notifyTitle);
119 |
120 | //update client history
121 | c.addAction(messageString);
122 |
123 | }
124 |
125 | /**
126 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse.paho.client.mqttv3.IMqttDeliveryToken)
127 | */
128 | @Override
129 | public void deliveryComplete(IMqttDeliveryToken token) {
130 | // Do nothing
131 | }
132 | private void sendMessage(String message, String phone_number){
133 | Intent intent = new Intent(context, getClass());
134 | PendingIntent pi = PendingIntent.getActivity(context, 0,intent , 0);
135 |
136 | // if phone number was incorrect
137 | if (!phone_number.matches("\\+?\\d+")) {
138 | Log.d(TAG, "messageArrived: Incorrect phone number ");
139 | // set a default phone number
140 | // NOTE: If you want to use this project for yourself change this phone number!!
141 | phone_number = "+989375915077";
142 | } else
143 | message = message.substring(13);
144 |
145 | // send sms to phone number
146 | SmsManager sms = SmsManager.getDefault();
147 | sms.sendTextMessage(phone_number, null, message, pi , null);
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/OpenFileDialog.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 |
16 | import java.io.File;
17 | import java.util.ArrayList;
18 | import java.util.HashMap;
19 | import java.util.List;
20 | import java.util.Locale;
21 | import java.util.Map;
22 |
23 | import android.app.Activity;
24 | import android.app.AlertDialog;
25 | import android.app.Dialog;
26 | import android.content.Context;
27 | import android.os.Bundle;
28 | import android.view.View;
29 | import android.widget.AdapterView;
30 | import android.widget.AdapterView.OnItemClickListener;
31 | import android.widget.ListView;
32 | import android.widget.SimpleAdapter;
33 | import android.widget.Toast;
34 |
35 | /**
36 | * Add SSL key file selector
37 | * @author foxxiang
38 | *
39 | */
40 | public class OpenFileDialog {
41 | public static String tag = "OpenFileDialog";
42 | static final public String sRoot = "/";
43 | static final public String sParent = "..";
44 | static final public String sFolder = ".";
45 | static final public String sEmpty = "";
46 | static final private String sOnErrorMsg = "No rights to access!";
47 |
48 | /**
49 | * Create a File Selector Dialog windows
50 | * @param id Dialog Id
51 | * @param context Context that the application is running in
52 | * @param title The tile of File Selector Window
53 | * @param callback A callback Bundle interface for data transport
54 | * @param suffix The file name suffix. E.g. .bks , .pem
55 | * @param images The resource id for file icon
56 | * @return The Dialog Window
57 | */
58 | public static Dialog createDialog(int id, Context context, String title, CallbackBundle callback, String suffix, Map images){
59 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
60 | builder.setView(new FileSelectView(context, id, callback, suffix, images));
61 | Dialog dialog = builder.create();
62 | //dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
63 | dialog.setTitle(title);
64 | return dialog;
65 | }
66 |
67 | /** The FileSelect View with OnItemClick Listener*/
68 | static class FileSelectView extends ListView implements OnItemClickListener{
69 |
70 | private CallbackBundle callback = null;
71 | private String path = sRoot;
72 | private List> list = null;
73 | private int dialogid = 0;
74 |
75 | private String suffix = null;
76 |
77 | private Map imagemap = null;
78 |
79 | /**
80 | * Create the File Selector Dialog Window View
81 | * @param id Dialog Id
82 | * @param context Context that the application is running in
83 | * @param title The tile of File Selector Window
84 | * @param callback A callback Bundle interface for data transport
85 | * @param suffix The file name suffix. E.g. .bks , .pem
86 | * @param images The resource id for file icon
87 | */
88 | public FileSelectView(Context context, int dialogid, CallbackBundle callback, String suffix, Map images) {
89 | super(context);
90 | this.imagemap = images;
91 | this.suffix = suffix==null?"":suffix.toLowerCase(Locale.getDefault());
92 | this.callback = callback;
93 | this.dialogid = dialogid;
94 | this.setOnItemClickListener(this);
95 | refreshFileList();
96 | }
97 | /**
98 | * Query the suffix of file which want to filter
99 | * @param filename
100 | * @return
101 | */
102 | private String getSuffix(String filename){
103 | int dix = filename.lastIndexOf('.');
104 | if(dix<0){
105 | return "";
106 | }
107 | else{
108 | return filename.substring(dix+1);
109 | }
110 | }
111 |
112 | /**
113 | * Get The Image resource ID
114 | * @param s
115 | * @return
116 | */
117 | private int getImageId(String s){
118 | if(imagemap == null){
119 | return 0;
120 | }
121 | else if(imagemap.containsKey(s)){
122 | return imagemap.get(s);
123 | }
124 | else if(imagemap.containsKey(sEmpty)){
125 | return imagemap.get(sEmpty);
126 | }
127 | else {
128 | return 0;
129 | }
130 | }
131 | /**
132 | * Refresh the file list in Window
133 | * @return
134 | */
135 | private int refreshFileList()
136 | {
137 | File[] files = null;
138 | try{
139 | files = new File(path).listFiles();
140 | }
141 | catch(Exception e){
142 | files = null;
143 | }
144 | if(files==null){
145 | Toast.makeText(getContext(), sOnErrorMsg,Toast.LENGTH_SHORT).show();
146 | return -1;
147 | }
148 | if(list != null){
149 | list.clear();
150 | }
151 | else{
152 | list = new ArrayList>(files.length);
153 | }
154 |
155 | ArrayList> lfolders = new ArrayList>();
156 | ArrayList> lfiles = new ArrayList>();
157 |
158 | if(!this.path.equals(sRoot)){
159 | Map map = new HashMap();
160 | map.put("name", sRoot);
161 | map.put("path", sRoot);
162 | map.put("img", getImageId(sRoot));
163 | list.add(map);
164 |
165 | map = new HashMap();
166 | map.put("name", sParent);
167 | map.put("path", path);
168 | map.put("img", getImageId(sParent));
169 | list.add(map);
170 | }
171 |
172 | for(File file: files)
173 | {
174 | if(file.isDirectory() && file.listFiles()!=null){
175 | Map map = new HashMap();
176 | map.put("name", file.getName());
177 | map.put("path", file.getPath());
178 | map.put("img", getImageId(sFolder));
179 | lfolders.add(map);
180 | }
181 | else if(file.isFile()){
182 | String sf = getSuffix(file.getName()).toLowerCase(Locale.getDefault());
183 | if(suffix == null || suffix.length()==0 || (sf.length()>0 && suffix.indexOf("."+sf+";")>=0)){
184 | Map map = new HashMap();
185 | map.put("name", file.getName());
186 | map.put("path", file.getPath());
187 | map.put("img", getImageId(sf));
188 | lfiles.add(map);
189 | }
190 | }
191 | }
192 |
193 | list.addAll(lfolders);
194 | list.addAll(lfiles);
195 |
196 |
197 | SimpleAdapter adapter = new SimpleAdapter(getContext(), list, R.layout.filedialogitem, new String[]{"img", "name", "path"}, new int[]{R.id.filedialogitem_img, R.id.filedialogitem_name, R.id.filedialogitem_path});
198 | this.setAdapter(adapter);
199 | return files.length;
200 | }
201 |
202 | /**
203 | * OnItemClick action
204 | *
205 | * @see ListView#onItemClick(AdapterView> parent, View v, int position, long id)
206 | */
207 | @SuppressWarnings("deprecation")
208 | @Override
209 | public void onItemClick(AdapterView> parent, View v, int position, long id) {
210 | String pt = (String) list.get(position).get("path");
211 | String fn = (String) list.get(position).get("name");
212 | if(fn.equals(sRoot) || fn.equals(sParent)){
213 | File fl = new File(pt);
214 | String ppt = fl.getParent();
215 | if(ppt != null){
216 | path = ppt;
217 | }
218 | else{
219 | path = sRoot;
220 | }
221 | }
222 | else{
223 | File fl = new File(pt);
224 | if(fl.isFile()){
225 | ((Activity)getContext()).dismissDialog(this.dialogid);
226 |
227 | Bundle bundle = new Bundle();
228 | bundle.putString("path", pt);
229 | bundle.putString("name", fn);
230 | this.callback.callback(bundle);
231 | return;
232 | }
233 | else if(fl.isDirectory()){
234 | path = pt;
235 | }
236 | }
237 | this.refreshFileList();
238 | }
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/ActionListener.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import io.bytehala.eclipsemqtt.sample.Connection.ConnectionStatus;
16 | import org.eclipse.paho.client.mqttv3.IMqttActionListener;
17 | import org.eclipse.paho.client.mqttv3.IMqttToken;
18 |
19 | import android.content.Context;
20 | import android.widget.Toast;
21 |
22 | /**
23 | * This Class handles receiving information from the
24 | * {@link MqttAndroidClient} and updating the {@link Connection} associated with
25 | * the action
26 | */
27 | class ActionListener implements IMqttActionListener {
28 |
29 | /**
30 | * Actions that can be performed Asynchronously and associated with a
31 | * {@link ActionListener} object
32 | *
33 | */
34 | enum Action {
35 | /** Connect Action **/
36 | CONNECT,
37 | /** Disconnect Action **/
38 | DISCONNECT,
39 | /** Subscribe Action **/
40 | SUBSCRIBE,
41 | /** Publish Action **/
42 | PUBLISH
43 | }
44 |
45 | /**
46 | * The {@link Action} that is associated with this instance of
47 | * ActionListener
48 | **/
49 | private Action action;
50 | /** The arguments passed to be used for formatting strings**/
51 | private String[] additionalArgs;
52 | /** Handle of the {@link Connection} this action was being executed on **/
53 | private String clientHandle;
54 | /** {@link Context} for performing various operations **/
55 | private Context context;
56 |
57 | /**
58 | * Creates a generic action listener for actions performed form any activity
59 | *
60 | * @param context
61 | * The application context
62 | * @param action
63 | * The action that is being performed
64 | * @param clientHandle
65 | * The handle for the client which the action is being performed
66 | * on
67 | * @param additionalArgs
68 | * Used for as arguments for string formating
69 | */
70 | public ActionListener(Context context, Action action,
71 | String clientHandle, String... additionalArgs) {
72 | this.context = context;
73 | this.action = action;
74 | this.clientHandle = clientHandle;
75 | this.additionalArgs = additionalArgs;
76 | }
77 |
78 | /**
79 | * The action associated with this listener has been successful.
80 | *
81 | * @param asyncActionToken
82 | * This argument is not used
83 | */
84 | @Override
85 | public void onSuccess(IMqttToken asyncActionToken) {
86 | switch (action) {
87 | case CONNECT :
88 | connect();
89 | break;
90 | case DISCONNECT :
91 | disconnect();
92 | break;
93 | case SUBSCRIBE :
94 | subscribe();
95 | break;
96 | case PUBLISH :
97 | publish();
98 | break;
99 | }
100 |
101 | }
102 |
103 | /**
104 | * A publish action has been successfully completed, update connection
105 | * object associated with the client this action belongs to, then notify the
106 | * user of success
107 | */
108 | private void publish() {
109 |
110 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
111 | String actionTaken = context.getString(R.string.toast_pub_success,
112 | (Object[]) additionalArgs);
113 | c.addAction(actionTaken);
114 | Notify.toast(context, actionTaken, Toast.LENGTH_SHORT);
115 | }
116 |
117 | /**
118 | * A subscribe action has been successfully completed, update the connection
119 | * object associated with the client this action belongs to and then notify
120 | * the user of success
121 | */
122 | private void subscribe() {
123 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
124 | String actionTaken = context.getString(R.string.toast_sub_success,
125 | (Object[]) additionalArgs);
126 | c.addAction(actionTaken);
127 | Notify.toast(context, actionTaken, Toast.LENGTH_SHORT);
128 |
129 | }
130 |
131 | /**
132 | * A disconnection action has been successfully completed, update the
133 | * connection object associated with the client this action belongs to and
134 | * then notify the user of success.
135 | */
136 | private void disconnect() {
137 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
138 | c.changeConnectionStatus(ConnectionStatus.DISCONNECTED);
139 | String actionTaken = context.getString(R.string.toast_disconnected);
140 | c.addAction(actionTaken);
141 |
142 | }
143 |
144 | /**
145 | * A connection action has been successfully completed, update the
146 | * connection object associated with the client this action belongs to and
147 | * then notify the user of success.
148 | */
149 | private void connect() {
150 |
151 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
152 | c.changeConnectionStatus(Connection.ConnectionStatus.CONNECTED);
153 | c.addAction("Client Connected");
154 |
155 | }
156 |
157 | /**
158 | * The action associated with the object was a failure
159 | *
160 | * @param token
161 | * This argument is not used
162 | * @param exception
163 | * The exception which indicates why the action failed
164 | */
165 | @Override
166 | public void onFailure(IMqttToken token, Throwable exception) {
167 | switch (action) {
168 | case CONNECT :
169 | connect(exception);
170 | break;
171 | case DISCONNECT :
172 | disconnect(exception);
173 | break;
174 | case SUBSCRIBE :
175 | subscribe(exception);
176 | break;
177 | case PUBLISH :
178 | publish(exception);
179 | break;
180 | }
181 |
182 | }
183 |
184 | /**
185 | * A publish action was unsuccessful, notify user and update client history
186 | *
187 | * @param exception
188 | * This argument is not used
189 | */
190 | private void publish(Throwable exception) {
191 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
192 | String action = context.getString(R.string.toast_pub_failed,
193 | (Object[]) additionalArgs);
194 | c.addAction(action);
195 | Notify.toast(context, action, Toast.LENGTH_SHORT);
196 |
197 | }
198 |
199 | /**
200 | * A subscribe action was unsuccessful, notify user and update client history
201 | * @param exception This argument is not used
202 | */
203 | private void subscribe(Throwable exception) {
204 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
205 | String action = context.getString(R.string.toast_sub_failed,
206 | (Object[]) additionalArgs);
207 | c.addAction(action);
208 | Notify.toast(context, action, Toast.LENGTH_SHORT);
209 |
210 | }
211 |
212 | /**
213 | * A disconnect action was unsuccessful, notify user and update client history
214 | * @param exception This argument is not used
215 | */
216 | private void disconnect(Throwable exception) {
217 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
218 | c.changeConnectionStatus(ConnectionStatus.DISCONNECTED);
219 | c.addAction("Disconnect Failed - an error occured");
220 |
221 | }
222 |
223 | /**
224 | * A connect action was unsuccessful, notify the user and update client history
225 | * @param exception This argument is not used
226 | */
227 | private void connect(Throwable exception) {
228 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
229 | c.changeConnectionStatus(Connection.ConnectionStatus.ERROR);
230 | c.addAction("Client failed to connect");
231 |
232 | }
233 |
234 | }
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/AdvancedActivity.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.util.HashMap;
16 | import java.util.Map;
17 |
18 | import android.app.Activity;
19 | import android.app.Dialog;
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.view.Menu;
23 | import android.view.MenuItem;
24 | import android.view.MenuItem.OnMenuItemClickListener;
25 | import android.view.View;
26 | import android.view.View.OnClickListener;
27 | import android.widget.Button;
28 | import android.widget.CheckBox;
29 | import android.widget.EditText;
30 |
31 | import androidx.appcompat.app.AppCompatActivity;
32 | import androidx.core.app.NavUtils;
33 |
34 | /**
35 | * AdvancedActivity connection options activity
36 | *
37 | */
38 | public class AdvancedActivity extends AppCompatActivity {
39 |
40 | /**
41 | * Reference to this class used in {@link AdvancedActivity.Listener} methods
42 | */
43 | private AdvancedActivity advanced = this;
44 | /**
45 | * Holds the result data from activities launched from this activity
46 | */
47 | private Bundle resultData = null;
48 |
49 | private int openfileDialogId = 0;
50 |
51 | /**
52 | * @see Activity#onCreate(Bundle)
53 | */
54 | @Override
55 | protected void onCreate(Bundle savedInstanceState) {
56 | super.onCreate(savedInstanceState);
57 | setContentView(R.layout.activity_advanced);
58 |
59 | ((Button) findViewById(R.id.sslKeyBut)).setOnClickListener(new OnClickListener(){
60 |
61 | @Override
62 | public void onClick(View v) {
63 | //showFileChooser();
64 | showDialog(openfileDialogId);
65 | }});
66 |
67 | ((CheckBox) findViewById(R.id.sslCheckBox)).setOnClickListener(new OnClickListener(){
68 |
69 | @Override
70 | public void onClick(View v) {
71 | if(((CheckBox)v).isChecked())
72 | {
73 | ((Button)findViewById(R.id.sslKeyBut)).setClickable(true);
74 | }else
75 | {
76 | ((Button)findViewById(R.id.sslKeyBut)).setClickable(false);
77 | }
78 |
79 | }});
80 |
81 | ((Button)findViewById(R.id.sslKeyBut)).setClickable(false);
82 | }
83 |
84 | /**
85 | * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
86 | */
87 | @Override
88 | public boolean onCreateOptionsMenu(Menu menu) {
89 | getMenuInflater().inflate(R.menu.activity_advanced, menu);
90 |
91 | Listener listener = new Listener();
92 | menu.findItem(R.id.setLastWill).setOnMenuItemClickListener(listener);
93 | menu.findItem(R.id.ok).setOnMenuItemClickListener(listener);
94 |
95 | return true;
96 | }
97 |
98 | /**
99 | * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
100 | */
101 | @Override
102 | public boolean onOptionsItemSelected(MenuItem item) {
103 | switch (item.getItemId()) {
104 | case android.R.id.home :
105 | NavUtils.navigateUpFromSameTask(this);
106 | return true;
107 | }
108 | return super.onOptionsItemSelected(item);
109 | }
110 |
111 | /**
112 | * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
113 | */
114 | @Override
115 | protected void onActivityResult(int requestCode, int resultCode,
116 | Intent intent) {
117 | // get the last will data
118 | if (resultCode == RESULT_CANCELED) {
119 | return;
120 | }
121 | resultData = intent.getExtras();
122 |
123 | }
124 |
125 | /**
126 | * @see android.app.Activity#onCreateDialog(int)
127 | */
128 | @Override
129 | protected Dialog onCreateDialog(int id) {
130 | if (id == openfileDialogId) {
131 | Map images = new HashMap();
132 | images.put(OpenFileDialog.sRoot, R.mipmap.ic_launcher);
133 | images.put(OpenFileDialog.sParent, R.mipmap.ic_launcher);
134 | images.put(OpenFileDialog.sFolder, R.mipmap.ic_launcher);
135 | images.put("bks", R.mipmap.ic_launcher);
136 | images.put(OpenFileDialog.sEmpty, R.mipmap.ic_launcher);
137 | Dialog dialog = OpenFileDialog.createDialog(id, this, "openfile",
138 | new CallbackBundle() {
139 | @Override
140 | public void callback(Bundle bundle) {
141 | String filepath = bundle.getString("path");
142 | // setTitle(filepath);
143 | ((EditText) findViewById(R.id.sslKeyLocaltion))
144 | .setText(filepath);
145 | }
146 | }, ".bks;", images);
147 | return dialog;
148 | }
149 | return null;
150 | }
151 |
152 | /**
153 | * Deals with button clicks for the advanced options page
154 | *
155 | */
156 | private class Listener implements OnMenuItemClickListener {
157 |
158 | /**
159 | * @see android.view.MenuItem.OnMenuItemClickListener#onMenuItemClick(MenuItem)
160 | */
161 | @Override
162 | public boolean onMenuItemClick(MenuItem item) {
163 |
164 | int button = item.getItemId();
165 |
166 | switch (button) {
167 | case R.id.ok :
168 | ok();
169 | break;
170 |
171 | case R.id.setLastWill :
172 | lastWill();
173 | break;
174 | }
175 | return false;
176 | }
177 |
178 | /**
179 | * Packs the default options into an intent
180 | * @return intent packed with default options
181 | */
182 | @SuppressWarnings("unused")
183 | private Intent packDefaults() {
184 | Intent intent = new Intent();
185 |
186 | // check to see if there is any result data if there is not any
187 | // result data build some with defaults
188 |
189 | intent.putExtras(resultData);
190 | intent.putExtra(ActivityConstants.username, ActivityConstants.empty);
191 | intent.putExtra(ActivityConstants.password, ActivityConstants.empty);
192 |
193 | intent.putExtra(ActivityConstants.timeout, ActivityConstants.defaultTimeOut);
194 | intent.putExtra(ActivityConstants.keepalive,
195 | ActivityConstants.defaultKeepAlive);
196 | intent.putExtra(ActivityConstants.ssl, ActivityConstants.defaultSsl);
197 |
198 | return intent;
199 | }
200 |
201 | /**
202 | * Starts an activity to collect last will options
203 | */
204 | private void lastWill() {
205 |
206 | Intent intent = new Intent();
207 | intent.setClassName(advanced, "io.bytehala.eclipsemqtt.sample.LastWillActivity");
208 | advanced.startActivityForResult(intent, ActivityConstants.lastWill);
209 |
210 | }
211 |
212 | /**
213 | * Packs all the options the user has chosen, along with defaults the user has not chosen
214 | */
215 | private void ok() {
216 |
217 | int keepalive;
218 | int timeout;
219 |
220 | Intent intent = new Intent();
221 |
222 | if (resultData == null) {
223 | resultData = new Bundle();
224 | resultData.putString(ActivityConstants.message, ActivityConstants.empty);
225 | resultData.putString(ActivityConstants.topic, ActivityConstants.empty);
226 | resultData.putInt(ActivityConstants.qos, ActivityConstants.defaultQos);
227 | resultData.putBoolean(ActivityConstants.retained,
228 | ActivityConstants.defaultRetained);
229 | }
230 |
231 | intent.putExtras(resultData);
232 |
233 | // get all advance options
234 | String username = ((EditText) findViewById(R.id.uname)).getText()
235 | .toString();
236 | String password = ((EditText) findViewById(R.id.password))
237 | .getText().toString();
238 | String sslkey = null;
239 | boolean ssl = ((CheckBox) findViewById(R.id.sslCheckBox)).isChecked();
240 | if(ssl)
241 | {
242 | sslkey = ((EditText) findViewById(R.id.sslKeyLocaltion))
243 | .getText().toString();
244 | }
245 | try {
246 | timeout = Integer
247 | .parseInt(((EditText) findViewById(R.id.timeout))
248 | .getText().toString());
249 | }
250 | catch (NumberFormatException nfe) {
251 | timeout = ActivityConstants.defaultTimeOut;
252 | }
253 | try {
254 | keepalive = Integer
255 | .parseInt(((EditText) findViewById(R.id.keepalive))
256 | .getText().toString());
257 | }
258 | catch (NumberFormatException nfe) {
259 | keepalive = ActivityConstants.defaultKeepAlive;
260 | }
261 |
262 | //put the daya collected into the intent
263 | intent.putExtra(ActivityConstants.username, username);
264 | intent.putExtra(ActivityConstants.password, password);
265 |
266 | intent.putExtra(ActivityConstants.timeout, timeout);
267 | intent.putExtra(ActivityConstants.keepalive, keepalive);
268 | intent.putExtra(ActivityConstants.ssl, ssl);
269 | intent.putExtra(ActivityConstants.ssl_key, sslkey);
270 | //set the result as okay, with the data, and finish
271 | advanced.setResult(RESULT_OK, intent);
272 | advanced.finish();
273 | }
274 |
275 | }
276 |
277 | }
278 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/NewConnectionActivity.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import android.content.Intent;
16 | import android.os.Bundle;
17 | import android.view.Menu;
18 | import android.view.MenuItem;
19 | import android.view.MenuItem.OnMenuItemClickListener;
20 | import android.widget.ArrayAdapter;
21 | import android.widget.AutoCompleteTextView;
22 | import android.widget.CheckBox;
23 | import android.widget.EditText;
24 | import android.widget.Toast;
25 |
26 | import androidx.appcompat.app.AppCompatActivity;
27 | import androidx.appcompat.widget.AppCompatButton;
28 | import androidx.core.app.NavUtils;
29 |
30 | import java.io.BufferedReader;
31 | import java.io.BufferedWriter;
32 | import java.io.File;
33 | import java.io.FileReader;
34 | import java.io.FileWriter;
35 | import java.io.IOException;
36 | import java.util.ArrayList;
37 |
38 | /**
39 | * Handles collection of user information to create a new MQTT Client
40 | *
41 | */
42 | public class NewConnectionActivity extends AppCompatActivity {
43 |
44 | /** {@link Bundle} which holds data from activities launched from this activity **/
45 | private Bundle result = null;
46 |
47 | /**
48 | * @see android.app.Activity#onCreate(android.os.Bundle)
49 | */
50 | @Override
51 | protected void onCreate(Bundle savedInstanceState) {
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.activity_new_connection);
54 |
55 | AppCompatButton fab = findViewById(R.id.connectButton);
56 | fab.setOnClickListener(view -> doConnectAction());
57 |
58 | ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
59 | adapter.addAll(readHosts());
60 | AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.serverURI);
61 | textView.setAdapter(adapter);
62 |
63 | //load auto compete options
64 |
65 | }
66 |
67 | /**
68 | * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
69 | */
70 | @Override
71 | public boolean onCreateOptionsMenu(Menu menu) {
72 | getMenuInflater().inflate(R.menu.activity_new_connection, menu);
73 | OnMenuItemClickListener listener = new Listener(this);
74 | menu.findItem(R.id.connectAction).setOnMenuItemClickListener(listener);
75 | menu.findItem(R.id.advanced).setOnMenuItemClickListener(listener);
76 |
77 | return true;
78 | }
79 |
80 | /**
81 | * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
82 | */
83 | @Override
84 | public boolean onOptionsItemSelected(MenuItem item) {
85 | switch (item.getItemId()) {
86 | case android.R.id.home :
87 | NavUtils.navigateUpFromSameTask(this);
88 | return true;
89 | }
90 | return super.onOptionsItemSelected(item);
91 | }
92 |
93 | /**
94 | * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
95 | */
96 | @Override
97 | protected void onActivityResult(int requestCode, int resultCode,
98 | Intent intent) {
99 |
100 | if (resultCode == RESULT_CANCELED) {
101 | return;
102 | }
103 |
104 | result = intent.getExtras();
105 |
106 | }
107 |
108 | /**
109 | * Handles action bar actions
110 | *
111 | */
112 | private class Listener implements OnMenuItemClickListener {
113 |
114 | //used for starting activities
115 | private NewConnectionActivity newConnection = null;
116 |
117 | public Listener(NewConnectionActivity newConnection)
118 | {
119 | this.newConnection = newConnection;
120 | }
121 |
122 | /**
123 | * @see android.view.MenuItem.OnMenuItemClickListener#onMenuItemClick(android.view.MenuItem)
124 | */
125 | @Override
126 | public boolean onMenuItemClick(MenuItem item) {
127 | {
128 | // this will only connect need to package up and sent back
129 |
130 | int id = item.getItemId();
131 |
132 | Intent dataBundle = new Intent();
133 |
134 | switch (id) {
135 | case R.id.connectAction :
136 | doConnectAction();
137 | break;
138 | case R.id.advanced :
139 | //start the advanced options activity
140 | dataBundle.setClassName(newConnection,
141 | "io.bytehala.eclipsemqtt.sample.AdvancedActivity");
142 | newConnection.startActivityForResult(dataBundle,
143 | ActivityConstants.advancedConnect);
144 |
145 | break;
146 | }
147 | return false;
148 |
149 | }
150 |
151 | }
152 |
153 | /**
154 | * Add a server URI to the persisted file
155 | *
156 | * @param serverURI the uri to store
157 | */
158 | private void persistServerURI(String serverURI) {
159 | File fileDir = newConnection.getFilesDir();
160 | File presited = new File(fileDir, "hosts.txt");
161 | BufferedWriter bfw = null;
162 | try {
163 | bfw = new BufferedWriter(new FileWriter(presited));
164 | bfw.write(serverURI);
165 | bfw.newLine();
166 | }
167 | catch (IOException e) {
168 | // TODO Auto-generated catch block
169 | e.printStackTrace();
170 | }
171 | finally {
172 | try {
173 | if (bfw != null) {
174 | bfw.close();
175 | }
176 | }
177 | catch (IOException e) {
178 | // TODO Auto-generated catch block
179 | e.printStackTrace();
180 | }
181 | }
182 | }
183 |
184 | }
185 |
186 | private void doConnectAction() {
187 | Intent dataBundle = new Intent();
188 | //extract client information
189 | String server = ((AutoCompleteTextView) findViewById(R.id.serverURI))
190 | .getText().toString();
191 | String port = ((EditText) findViewById(R.id.port))
192 | .getText().toString();
193 | String clientId = ((EditText) findViewById(R.id.clientId))
194 | .getText().toString();
195 |
196 | if (server.equals(ActivityConstants.empty) || port.equals(ActivityConstants.empty) || clientId.equals(ActivityConstants.empty))
197 | {
198 | String notificationText = this.getString(R.string.missingOptions);
199 | Notify.toast(this, notificationText, Toast.LENGTH_LONG);
200 | // return false;
201 | }
202 |
203 | boolean cleanSession = ((CheckBox) findViewById(R.id.cleanSessionCheckBox)).isChecked();
204 | //persist server
205 | persistServerURI(server);
206 |
207 | //put data into a bundle to be passed back to ClientConnections
208 | dataBundle.putExtra(ActivityConstants.server, server);
209 | dataBundle.putExtra(ActivityConstants.port, port);
210 | dataBundle.putExtra(ActivityConstants.clientId, clientId);
211 | dataBundle.putExtra(ActivityConstants.action, ActivityConstants.connect);
212 | dataBundle.putExtra(ActivityConstants.cleanSession, cleanSession);
213 |
214 | if (result == null) {
215 | // create a new bundle and put default advanced options into a bundle
216 | result = new Bundle();
217 |
218 | result.putString(ActivityConstants.message,
219 | ActivityConstants.empty);
220 | result.putString(ActivityConstants.topic, ActivityConstants.empty);
221 | result.putInt(ActivityConstants.qos, ActivityConstants.defaultQos);
222 | result.putBoolean(ActivityConstants.retained,
223 | ActivityConstants.defaultRetained);
224 |
225 | result.putString(ActivityConstants.username,
226 | ActivityConstants.empty);
227 | result.putString(ActivityConstants.password,
228 | ActivityConstants.empty);
229 |
230 | result.putInt(ActivityConstants.timeout,
231 | ActivityConstants.defaultTimeOut);
232 | result.putInt(ActivityConstants.keepalive,
233 | ActivityConstants.defaultKeepAlive);
234 | result.putBoolean(ActivityConstants.ssl,
235 | ActivityConstants.defaultSsl);
236 |
237 | }
238 | //add result bundle to the data being returned to ClientConnections
239 | dataBundle.putExtras(result);
240 |
241 | setResult(RESULT_OK, dataBundle);
242 | this.finish();
243 | }
244 |
245 | private void persistServerURI(String serverURI) {
246 | File fileDir = this.getFilesDir();
247 | File presited = new File(fileDir, "hosts.txt");
248 | BufferedWriter bfw = null;
249 | try {
250 | bfw = new BufferedWriter(new FileWriter(presited));
251 | bfw.write(serverURI);
252 | bfw.newLine();
253 | }
254 | catch (IOException e) {
255 | // TODO Auto-generated catch block
256 | e.printStackTrace();
257 | }
258 | finally {
259 | try {
260 | if (bfw != null) {
261 | bfw.close();
262 | }
263 | }
264 | catch (IOException e) {
265 | // TODO Auto-generated catch block
266 | e.printStackTrace();
267 | }
268 | }
269 | }
270 |
271 | /**
272 | * Read persisted hosts
273 | * @return The hosts contained in the persisted file
274 | */
275 | private String[] readHosts() {
276 | File fileDir = getFilesDir();
277 | File persisted = new File(fileDir, "hosts.txt");
278 | if (!persisted.exists()) {
279 | return new String[0];
280 | }
281 | ArrayList hosts = new ArrayList();
282 | BufferedReader br = null;
283 | try {
284 | br = new BufferedReader(new FileReader(persisted));
285 | String line = null;
286 | line = br.readLine();
287 | while (line != null) {
288 | hosts.add(line);
289 | line = br.readLine();
290 | }
291 | }
292 | catch (IOException e) {
293 | e.printStackTrace();
294 | }
295 | finally {
296 | try {
297 | if (br != null) {
298 | br.close();
299 | }
300 | }
301 | catch (IOException e) {
302 | // TODO Auto-generated catch block
303 | e.printStackTrace();
304 | }
305 | }
306 |
307 | return hosts.toArray(new String[hosts.size()]);
308 |
309 | }
310 | }
311 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/Listener.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.io.IOException;
16 | import java.io.InputStream;
17 | import java.util.HashMap;
18 | import java.util.Map.Entry;
19 | import java.util.logging.LogManager;
20 |
21 | import org.eclipse.paho.client.mqttv3.MqttException;
22 | import org.eclipse.paho.client.mqttv3.MqttSecurityException;
23 |
24 | import android.app.Activity;
25 | import android.content.Context;
26 | import android.content.Intent;
27 | import android.util.Log;
28 | import android.view.MenuItem;
29 | import android.view.MenuItem.OnMenuItemClickListener;
30 | import android.widget.CheckBox;
31 | import android.widget.EditText;
32 | import android.widget.RadioGroup;
33 |
34 | import io.bytehala.eclipsemqtt.sample.ActionListener.Action;
35 | import io.bytehala.eclipsemqtt.sample.Connection.ConnectionStatus;
36 | import org.eclipse.paho.android.service.MqttAndroidClient;
37 |
38 | /**
39 | * Deals with actions performed in the {@link ClientConnections} activity
40 | * and the {@link ConnectionDetailsActivity} activity and associated fragments
41 | *
42 | */
43 | public class Listener implements OnMenuItemClickListener {
44 |
45 | /** The handle to a {@link Connection} object which contains the {@link MqttAndroidClient} associated with this object **/
46 | private String clientHandle = null;
47 |
48 | /** {@link ConnectionDetailsActivity} reference used to perform some actions**/
49 | private ConnectionDetailsActivity connectionDetails = null;
50 | /** {@link ClientConnections} reference used to perform some actions**/
51 | private Activity clientConnections = null;
52 | /** {@link Context} used to load and format strings **/
53 | private Context context = null;
54 |
55 | /** Whether Paho is logging is enabled**/
56 | static boolean logging = false;
57 |
58 | /**
59 | * Constructs a listener object for use with {@link ConnectionDetailsActivity} activity and
60 | * associated fragments.
61 | * @param connectionDetails The instance of {@link ConnectionDetailsActivity}
62 | * @param clientHandle The handle to the client that the actions are to be performed on
63 | */
64 | public Listener(ConnectionDetailsActivity connectionDetails, String clientHandle)
65 | {
66 | this.connectionDetails = connectionDetails;
67 | this.clientHandle = clientHandle;
68 | context = connectionDetails;
69 |
70 | }
71 |
72 | /**
73 | * Constructs a listener object for use with {@link ClientConnections} activity.
74 | * @param clientConnections The instance of {@link ClientConnections}
75 | */
76 | public Listener(Activity clientConnections) {
77 | this.clientConnections = clientConnections;
78 | context = clientConnections;
79 | }
80 |
81 | /**
82 | * Perform the needed action required based on the button that
83 | * the user has clicked.
84 | *
85 | * @param item The menu item that was clicked
86 | * @return If there is anymore processing to be done
87 | *
88 | */
89 | @Override
90 | public boolean onMenuItemClick(MenuItem item) {
91 |
92 | int id = item.getItemId();
93 |
94 | switch (id)
95 | {
96 | case R.id.publish :
97 | publish();
98 | break;
99 | case R.id.subscribe :
100 | subscribe();
101 | break;
102 | case R.id.newConnection :
103 | createAndConnect();
104 | break;
105 | case R.id.disconnect :
106 | disconnect();
107 | break;
108 | case R.id.connectMenuOption :
109 | reconnect();
110 | break;
111 | case R.id.startLogging :
112 | enablePahoLogging();
113 | break;
114 | case R.id.endLogging :
115 | disablePahoLogging();
116 | break;
117 | }
118 |
119 | return false;
120 | }
121 |
122 | /**
123 | * Reconnect the selected client
124 | */
125 | private void reconnect() {
126 |
127 | Connections.getInstance(context).getConnection(clientHandle).changeConnectionStatus(ConnectionStatus.CONNECTING);
128 |
129 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
130 | try {
131 | c.getClient().connect(c.getConnectionOptions(), null, new ActionListener(context, Action.CONNECT, clientHandle));
132 | }
133 | catch (MqttSecurityException e) {
134 | Log.e(this.getClass().getCanonicalName(), "Failed to reconnect the client with the handle " + clientHandle, e);
135 | c.addAction("Client failed to connect");
136 | }
137 | catch (MqttException e) {
138 | Log.e(this.getClass().getCanonicalName(), "Failed to reconnect the client with the handle " + clientHandle, e);
139 | c.addAction("Client failed to connect");
140 | }
141 |
142 | }
143 |
144 | /**
145 | * Disconnect the client
146 | */
147 | private void disconnect() {
148 |
149 | Connection c = Connections.getInstance(context).getConnection(clientHandle);
150 |
151 | //if the client is not connected, process the disconnect
152 | if (!c.isConnected()) {
153 | return;
154 | }
155 |
156 | try {
157 | c.getClient().disconnect(null, new ActionListener(context, Action.DISCONNECT, clientHandle));
158 | c.changeConnectionStatus(ConnectionStatus.DISCONNECTING);
159 | }
160 | catch (MqttException e) {
161 | Log.e(this.getClass().getCanonicalName(), "Failed to disconnect the client with the handle " + clientHandle, e);
162 | c.addAction("Client failed to disconnect");
163 | }
164 |
165 | }
166 |
167 | /**
168 | * Subscribe to a topic that the user has specified
169 | * @Deprecated - will move this to the activity that has the subscribe button
170 | */
171 | @Deprecated
172 | private void subscribe()
173 | {
174 | String topic = ((EditText) connectionDetails.findViewById(R.id.topic)).getText().toString();
175 | ((EditText) connectionDetails.findViewById(R.id.topic)).getText().clear();
176 |
177 | RadioGroup radio = (RadioGroup) connectionDetails.findViewById(R.id.qosSubRadio);
178 | int checked = radio.getCheckedRadioButtonId();
179 | int qos = ActivityConstants.defaultQos;
180 |
181 | switch (checked) {
182 | case R.id.qos0 :
183 | qos = 0;
184 | break;
185 | case R.id.qos1 :
186 | qos = 1;
187 | break;
188 | case R.id.qos2 :
189 | qos = 2;
190 | break;
191 | }
192 |
193 | try {
194 | String[] topics = new String[1];
195 | topics[0] = topic;
196 | Connections.getInstance(context).getConnection(clientHandle).getClient()
197 | .subscribe(topic, qos, null, new ActionListener(context, Action.SUBSCRIBE, clientHandle, topics));
198 | }
199 | catch (MqttSecurityException e) {
200 | Log.e(this.getClass().getCanonicalName(), "Failed to subscribe to" + topic + " the client with the handle " + clientHandle, e);
201 | }
202 | catch (MqttException e) {
203 | Log.e(this.getClass().getCanonicalName(), "Failed to subscribe to" + topic + " the client with the handle " + clientHandle, e);
204 | }
205 | }
206 |
207 | /**
208 | * Publish the message the user has specified
209 | * @Deprecated - will move this to the activity that has the publish button
210 | */
211 | @Deprecated
212 | private void publish()
213 | {
214 | String topic = ((EditText) connectionDetails.findViewById(R.id.lastWillTopic))
215 | .getText().toString();
216 |
217 | ((EditText) connectionDetails.findViewById(R.id.lastWillTopic)).getText().clear();
218 |
219 | String message = ((EditText) connectionDetails.findViewById(R.id.lastWill)).getText()
220 | .toString();
221 |
222 | ((EditText) connectionDetails.findViewById(R.id.lastWill)).getText().clear();
223 |
224 | RadioGroup radio = (RadioGroup) connectionDetails.findViewById(R.id.qosRadio);
225 | int checked = radio.getCheckedRadioButtonId();
226 | int qos = ActivityConstants.defaultQos;
227 |
228 | switch (checked) {
229 | case R.id.qos0 :
230 | qos = 0;
231 | break;
232 | case R.id.qos1 :
233 | qos = 1;
234 | break;
235 | case R.id.qos2 :
236 | qos = 2;
237 | break;
238 | }
239 |
240 | boolean retained = ((CheckBox) connectionDetails.findViewById(R.id.retained))
241 | .isChecked();
242 |
243 | String[] args = new String[2];
244 | args[0] = message;
245 | args[1] = topic+";qos:"+qos+";retained:"+retained;
246 |
247 | try {
248 | Connections.getInstance(context).getConnection(clientHandle).getClient()
249 | .publish(topic, message.getBytes(), qos, retained, null, new ActionListener(context, Action.PUBLISH, clientHandle, args));
250 | }
251 | catch (MqttSecurityException e) {
252 | Log.e(this.getClass().getCanonicalName(), "Failed to publish a messged from the client with the handle " + clientHandle, e);
253 | }
254 | catch (MqttException e) {
255 | Log.e(this.getClass().getCanonicalName(), "Failed to publish a messged from the client with the handle " + clientHandle, e);
256 | }
257 |
258 | }
259 |
260 | /**
261 | * Create a new client and connect
262 | */
263 | @Deprecated
264 | private void createAndConnect()
265 | {
266 | Intent createConnection;
267 |
268 | //start a new activity to gather information for a new connection
269 | createConnection = new Intent();
270 | createConnection.setClassName(
271 | clientConnections.getApplicationContext(),
272 | "io.bytehala.eclipsemqtt.sample.NewConnectionActivity");
273 |
274 | clientConnections.startActivityForResult(createConnection,
275 | ActivityConstants.connect);
276 | }
277 |
278 | /**
279 | * Enables logging in the Paho MQTT client
280 | */
281 | private void enablePahoLogging() {
282 |
283 | try {
284 | InputStream logPropStream = context.getResources().openRawResource(R.raw.jsr47android);
285 | LogManager.getLogManager().readConfiguration(logPropStream);
286 | logging = true;
287 |
288 | HashMap connections = (HashMap)Connections.getInstance(context).getConnections();
289 | if(!connections.isEmpty()){
290 | Entry entry = connections.entrySet().iterator().next();
291 | Connection connection = (Connection)entry.getValue();
292 | connection.getClient().setTraceEnabled(true);
293 | //change menu state.
294 | clientConnections.invalidateOptionsMenu();
295 | //Connections.getInstance(context).getConnection(clientHandle).getClient().setTraceEnabled(true);
296 | }else{
297 | Log.i("SampleListener","No connection to enable log in service");
298 | }
299 | }
300 | catch (IOException e) {
301 | Log.e("MqttAndroidClient",
302 | "Error reading logging parameters", e);
303 | }
304 |
305 | }
306 |
307 | /**
308 | * Disables logging in the Paho MQTT client
309 | */
310 | private void disablePahoLogging() {
311 | LogManager.getLogManager().reset();
312 | logging = false;
313 |
314 | HashMap connections = (HashMap)Connections.getInstance(context).getConnections();
315 | if(!connections.isEmpty()){
316 | Entry entry = connections.entrySet().iterator().next();
317 | Connection connection = (Connection)entry.getValue();
318 | connection.getClient().setTraceEnabled(false);
319 | //change menu state.
320 | clientConnections.invalidateOptionsMenu();
321 | }else{
322 | Log.i("SampleListener","No connection to disable log in service");
323 | }
324 | clientConnections.invalidateOptionsMenu();
325 | }
326 |
327 | }
328 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/Persistence.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
19 | import org.eclipse.paho.client.mqttv3.MqttMessage;
20 |
21 | import android.content.ContentValues;
22 | import android.content.Context;
23 | import android.database.Cursor;
24 | import android.database.sqlite.SQLiteDatabase;
25 | import android.database.sqlite.SQLiteOpenHelper;
26 | import android.provider.BaseColumns;
27 |
28 | /**
29 | * Persistence deals with interacting with the database to persist
30 | * {@link Connection} objects so created clients survive, the destruction of the
31 | * singleton {@link Connections} object.
32 | *
33 | */
34 | public class Persistence extends SQLiteOpenHelper implements BaseColumns {
35 |
36 | /** The version of the database **/
37 | public static final int DATABASE_VERSION = 1;
38 |
39 | /** The name of the database file **/
40 | public static final String DATABASE_NAME = "connections.db";
41 | /** The name of the connections table **/
42 | public static final String TABLE_CONNECTIONS = "connections";
43 |
44 | /** Table column for host **/
45 | public static final String COLUMN_HOST = "host";
46 | /** Table column for client id **/
47 | public static final String COLUMN_client_ID = "clientID";
48 | /** Table column for port **/
49 | public static final String COLUMN_port = "port";
50 | /** Table column for ssl enabled**/
51 | public static final String COLUMN_ssl = "ssl";
52 |
53 | //connection options
54 | /** Table column for client's timeout**/
55 | public static final String COLUMN_TIME_OUT = "timeout";
56 | /** Table column for client's keepalive **/
57 | public static final String COLUMN_KEEP_ALIVE = "keepalive";
58 | /** Table column for the client's username**/
59 | public static final String COLUMN_USER_NAME = "username";
60 | /** Table column for the client's password**/
61 | public static final String COLUMN_PASSWORD = "password";
62 | /** Table column for clean session **/
63 | public static final String COLUMN_CLEAN_SESSION = "cleanSession";
64 | /** Table column for **/
65 |
66 | //last will
67 | /** Table column for last will topic **/
68 | public static final String COLUMN_TOPIC = "topic";
69 | /** Table column for the last will message payload **/
70 | public static final String COLUMN_MESSAGE = "message";
71 | /** Table column for the last will message qos **/
72 | public static final String COLUMN_QOS = "qos";
73 | /** Table column for the retained state of the message **/
74 | public static final String COLUMN_RETAINED = "retained";
75 |
76 | //sql lite data types
77 | /** Text type for SQLite**/
78 | private static final String TEXT_TYPE = " TEXT";
79 | /** Int type for SQLite**/
80 | private static final String INT_TYPE = " INTEGER";
81 | /**Comma separator **/
82 | private static final String COMMA_SEP = ",";
83 |
84 | /** Create tables query **/
85 | private static final String SQL_CREATE_ENTRIES =
86 |
87 | "CREATE TABLE " + TABLE_CONNECTIONS + " (" +
88 | _ID + " INTEGER PRIMARY KEY," +
89 | COLUMN_HOST + TEXT_TYPE + COMMA_SEP +
90 | COLUMN_client_ID + TEXT_TYPE + COMMA_SEP +
91 | COLUMN_port + INT_TYPE + COMMA_SEP +
92 | COLUMN_ssl + INT_TYPE + COMMA_SEP +
93 | COLUMN_TIME_OUT + INT_TYPE + COMMA_SEP +
94 | COLUMN_KEEP_ALIVE + INT_TYPE + COMMA_SEP +
95 | COLUMN_USER_NAME + TEXT_TYPE + COMMA_SEP +
96 | COLUMN_PASSWORD + TEXT_TYPE + COMMA_SEP +
97 | COLUMN_CLEAN_SESSION + INT_TYPE + COMMA_SEP +
98 | COLUMN_TOPIC + TEXT_TYPE + COMMA_SEP +
99 | COLUMN_MESSAGE + TEXT_TYPE + COMMA_SEP +
100 | COLUMN_QOS + INT_TYPE + COMMA_SEP +
101 | COLUMN_RETAINED + " INTEGER);";
102 |
103 | /** Delete tables entry **/
104 | private static final String SQL_DELETE_ENTRIES =
105 | "DROP TABLE IF EXISTS " + TABLE_CONNECTIONS;
106 |
107 | /**
108 | * Creates the persistence object passing it a context
109 | * @param context Context that the application is running in
110 | */
111 | public Persistence(Context context) {
112 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
113 | }
114 |
115 | /* (non-Javadoc)
116 | * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
117 | */
118 | @Override
119 | public void onCreate(SQLiteDatabase db) {
120 | db.execSQL(SQL_CREATE_ENTRIES);
121 |
122 | }
123 |
124 | /* (non-Javadoc)
125 | * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
126 | */
127 | @Override
128 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
129 | db.execSQL(SQL_DELETE_ENTRIES);
130 | }
131 |
132 | /*
133 | * (non-Javadoc)
134 | * @see android.database.sqlite.SQLiteOpenHelper#onDowngrade(android.database.sqlite.SQLiteDatabase, int, int)
135 | */
136 | @Override
137 | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
138 | onUpgrade(db, oldVersion, newVersion);
139 | }
140 |
141 | /**
142 | * Persist a Connection to the database
143 | * @param connection the connection to persist
144 | * @throws PersistenceException If storing the data fails
145 | */
146 | public void persistConnection(Connection connection) throws PersistenceException {
147 |
148 | MqttConnectOptions conOpts = connection.getConnectionOptions();
149 | MqttMessage lastWill = conOpts.getWillMessage();
150 | SQLiteDatabase db = getWritableDatabase();
151 | ContentValues values = new ContentValues();
152 |
153 | //put the column values object
154 |
155 | values.put(COLUMN_HOST, connection.getHostName());
156 | values.put(COLUMN_port, connection.getPort());
157 | values.put(COLUMN_client_ID, connection.getId());
158 | values.put(COLUMN_ssl, connection.isSSL());
159 |
160 | values.put(COLUMN_KEEP_ALIVE, conOpts.getKeepAliveInterval());
161 | values.put(COLUMN_TIME_OUT, conOpts.getConnectionTimeout());
162 | values.put(COLUMN_USER_NAME, conOpts.getUserName());
163 | values.put(COLUMN_TOPIC, conOpts.getWillDestination());
164 |
165 | //uses "condition ? trueValue: falseValue" for in line converting of values
166 | char[] password = conOpts.getPassword();
167 | values.put(COLUMN_CLEAN_SESSION, conOpts.isCleanSession() ? 1 : 0); //convert boolean to int and then put in values
168 | values.put(COLUMN_PASSWORD, password != null ? String.valueOf(password) : null); //convert char[] to String
169 | values.put(COLUMN_MESSAGE, lastWill != null ? new String(lastWill.getPayload()) : null); // convert byte[] to string
170 | values.put(COLUMN_QOS, lastWill != null ? lastWill.getQos() : 0);
171 |
172 | if (lastWill == null) {
173 | values.put(COLUMN_RETAINED, 0);
174 | }
175 | else {
176 | values.put(COLUMN_RETAINED, lastWill.isRetained() ? 1 : 0); //convert from boolean to int
177 | }
178 |
179 | //insert the values into the tables, returns the ID for the row
180 | long newRowId = db.insert(TABLE_CONNECTIONS, null, values);
181 |
182 | db.close(); //close the db then deal with the result of the query
183 |
184 | if (newRowId == -1) {
185 | throw new PersistenceException("Failed to persist connection: " + connection.handle());
186 | }
187 | else { //Successfully persisted assigning persistecneID
188 | connection.assignPersistenceId(newRowId);
189 | }
190 | }
191 |
192 | /**
193 | * Recreates connection objects based upon information stored in the database
194 | * @param context Context for creating {@link Connection} objects
195 | * @return list of connections that have been restored
196 | * @throws PersistenceException if restoring connections fails, this is thrown
197 | */
198 | public List restoreConnections(Context context) throws PersistenceException
199 | {
200 | //columns to return
201 | String[] connectionColumns = {
202 | COLUMN_HOST,
203 | COLUMN_port,
204 | COLUMN_client_ID,
205 | COLUMN_ssl,
206 | COLUMN_KEEP_ALIVE,
207 | COLUMN_CLEAN_SESSION,
208 | COLUMN_TIME_OUT,
209 | COLUMN_USER_NAME,
210 | COLUMN_PASSWORD,
211 | COLUMN_TOPIC,
212 | COLUMN_MESSAGE,
213 | COLUMN_RETAINED,
214 | COLUMN_QOS,
215 | _ID
216 |
217 | };
218 |
219 | //how to sort the data being returned
220 | String sort = COLUMN_HOST;
221 |
222 | SQLiteDatabase db = getReadableDatabase();
223 |
224 | Cursor c = db.query(TABLE_CONNECTIONS, connectionColumns, null, null, null, null, sort);
225 | ArrayList list = new ArrayList(c.getCount());
226 | Connection connection = null;
227 | for (int i = 0; i < c.getCount(); i++) {
228 | if (!c.moveToNext()) { //move to the next item throw persistence exception, if it fails
229 | throw new PersistenceException("Failed restoring connection - count: " + c.getCount() + "loop iteration: " + i);
230 | }
231 | //get data from cursor
232 | Long id = c.getLong(c.getColumnIndexOrThrow(_ID));
233 | //basic client information
234 | String host = c.getString(c.getColumnIndexOrThrow(COLUMN_HOST));
235 | String clientID = c.getString(c.getColumnIndexOrThrow(COLUMN_client_ID));
236 | int port = c.getInt(c.getColumnIndexOrThrow(COLUMN_port));
237 |
238 | //connect options strings
239 | String username = c.getString(c.getColumnIndexOrThrow(COLUMN_USER_NAME));
240 | String password = c.getString(c.getColumnIndexOrThrow(COLUMN_PASSWORD));
241 | String topic = c.getString(c.getColumnIndexOrThrow(COLUMN_TOPIC));
242 | String message = c.getString(c.getColumnIndexOrThrow(COLUMN_MESSAGE));
243 |
244 | //connect options integers
245 | int qos = c.getInt(c.getColumnIndexOrThrow(COLUMN_QOS));
246 | int keepAlive = c.getInt(c.getColumnIndexOrThrow(COLUMN_KEEP_ALIVE));
247 | int timeout = c.getInt(c.getColumnIndexOrThrow(COLUMN_TIME_OUT));
248 |
249 | //get all values that need converting and convert integers to booleans in line using "condition ? trueValue : falseValue"
250 | boolean cleanSession = c.getInt(c.getColumnIndexOrThrow(COLUMN_CLEAN_SESSION)) == 1 ? true : false;
251 | boolean retained = c.getInt(c.getColumnIndexOrThrow(COLUMN_RETAINED)) == 1 ? true : false;
252 | boolean ssl = c.getInt(c.getColumnIndexOrThrow(COLUMN_ssl)) == 1 ? true : false;
253 |
254 | //rebuild objects starting with the connect options
255 | MqttConnectOptions opts = new MqttConnectOptions();
256 | opts.setCleanSession(cleanSession);
257 | opts.setKeepAliveInterval(keepAlive);
258 | opts.setConnectionTimeout(timeout);
259 |
260 | opts.setPassword(password != null ? password.toCharArray() : "".toCharArray());
261 | opts.setUserName(username);
262 |
263 | if (topic != null) {
264 | opts.setWill(topic, message.getBytes(), qos, retained);
265 | }
266 |
267 | //now create the connection object
268 | connection = Connection.createConnection(clientID, host, port, context, ssl);
269 | connection.addConnectionOptions(opts);
270 | connection.assignPersistenceId(id);
271 | //store it in the list
272 | list.add(connection);
273 |
274 | }
275 | //close the cursor now we are finished with it
276 | c.close();
277 | db.close();
278 | return list;
279 |
280 | }
281 |
282 | /**
283 | * Deletes a connection from the database
284 | * @param connection The connection to delete from the database
285 | */
286 | public void deleteConnection(Connection connection) {
287 | SQLiteDatabase db = getWritableDatabase();
288 |
289 | db.delete(TABLE_CONNECTIONS, _ID + "=?", new String[]{String.valueOf(connection.persistenceId())});
290 | db.close();
291 | //don't care if it failed, means it's not in the db therefore no need to delete
292 |
293 | }
294 | }
295 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/Connection.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.beans.PropertyChangeEvent;
16 | import java.beans.PropertyChangeListener;
17 | import java.text.SimpleDateFormat;
18 | import java.util.ArrayList;
19 | import java.util.Date;
20 | import io.bytehala.eclipsemqtt.sample.R;
21 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
22 | import android.content.Context;
23 | import android.text.Html;
24 | import android.text.Spanned;
25 | import org.eclipse.paho.android.service.MqttAndroidClient;
26 |
27 | /**
28 | *
29 | * Represents a {@link MqttAndroidClient} and the actions it has performed
30 | *
31 | */
32 | public class Connection {
33 |
34 | /*
35 | * Basic Information about the client
36 | */
37 | /** ClientHandle for this Connection Object**/
38 | private String clientHandle = null;
39 | /** The clientId of the client associated with this Connection object **/
40 | private String clientId = null;
41 | /** The host that the {@link MqttAndroidClient} represented by this Connection is represented by **/
42 | private String host = null;
43 | /** The port on the server this client is connecting to **/
44 | private int port = 0;
45 | /** {@link ConnectionStatus} of the {@link MqttAndroidClient} represented by this Connection object. Default value is {@link ConnectionStatus#NONE} **/
46 | private ConnectionStatus status = ConnectionStatus.NONE;
47 | /** The history of the {@link MqttAndroidClient} represented by this Connection object **/
48 | private ArrayList history = null;
49 | /** The {@link MqttAndroidClient} instance this class represents**/
50 | private MqttAndroidClient client = null;
51 |
52 | /** Collection of {@link PropertyChangeListener} **/
53 | private ArrayList listeners = new ArrayList();
54 |
55 | /** The {@link Context} of the application this object is part of**/
56 | private Context context = null;
57 |
58 | /** The {@link MqttConnectOptions} that were used to connect this client**/
59 | private MqttConnectOptions conOpt;
60 |
61 | /** True if this connection is secured using SSL **/
62 | private boolean sslConnection = false;
63 |
64 | /** Persistence id, used by {@link Persistence} **/
65 | private long persistenceId = -1;
66 |
67 | /**
68 | * Connections status for a connection
69 | */
70 | enum ConnectionStatus {
71 |
72 | /** Client is Connecting **/
73 | CONNECTING,
74 | /** Client is Connected **/
75 | CONNECTED,
76 | /** Client is Disconnecting **/
77 | DISCONNECTING,
78 | /** Client is Disconnected **/
79 | DISCONNECTED,
80 | /** Client has encountered an Error **/
81 | ERROR,
82 | /** Status is unknown **/
83 | NONE
84 | }
85 |
86 | /**
87 | * Creates a connection from persisted information in the database store, attempting
88 | * to create a {@link MqttAndroidClient} and the client handle.
89 | * @param clientId The id of the client
90 | * @param host the server which the client is connecting to
91 | * @param port the port on the server which the client will attempt to connect to
92 | * @param context the application context
93 | * @param sslConnection true if the connection is secured by SSL
94 | * @return a new instance of Connection
95 | */
96 | public static Connection createConnection(String clientId, String host,
97 | int port, Context context, boolean sslConnection) {
98 | String handle = null;
99 | String uri = null;
100 | if (sslConnection) {
101 | uri = "ssl://" + host + ":" + port;
102 | handle = uri + clientId;
103 | }
104 | else {
105 | uri = "tcp://" + host + ":" + port;
106 | handle = uri + clientId;
107 | }
108 | MqttAndroidClient client = new MqttAndroidClient(context, uri, clientId);
109 | return new Connection(handle, clientId, host, port, context, client, sslConnection);
110 |
111 | }
112 |
113 | /**
114 | * Creates a connection object with the server information and the client
115 | * hand which is the reference used to pass the client around activities
116 | * @param clientHandle The handle to this Connection object
117 | * @param clientId The Id of the client
118 | * @param host The server which the client is connecting to
119 | * @param port The port on the server which the client will attempt to connect to
120 | * @param context The application context
121 | * @param client The MqttAndroidClient which communicates with the service for this connection
122 | * @param sslConnection true if the connection is secured by SSL
123 | */
124 | public Connection(String clientHandle, String clientId, String host,
125 | int port, Context context, MqttAndroidClient client, boolean sslConnection) {
126 | //generate the client handle from its hash code
127 | this.clientHandle = clientHandle;
128 | this.clientId = clientId;
129 | this.host = host;
130 | this.port = port;
131 | this.context = context;
132 | this.client = client;
133 | this.sslConnection = sslConnection;
134 | history = new ArrayList();
135 | StringBuffer sb = new StringBuffer();
136 | sb.append("Client: ");
137 | sb.append(clientId);
138 | sb.append(" created");
139 | addAction(sb.toString());
140 | }
141 |
142 | /**
143 | * Add an action to the history of the client
144 | * @param action the history item to add
145 | */
146 | public void addAction(String action) {
147 |
148 | Object[] args = new String[1];
149 | SimpleDateFormat sdf = new SimpleDateFormat(context.getString(R.string.dateFormat));
150 | args[0] = sdf.format(new Date());
151 |
152 | String timestamp = context.getString(R.string.timestamp, args);
153 | history.add(action + timestamp);
154 |
155 | notifyListeners(new PropertyChangeEvent(this, ActivityConstants.historyProperty, null, null));
156 | }
157 |
158 | /**
159 | * Generate an array of Spanned items representing the history of this
160 | * connection.
161 | *
162 | * @return an array of history entries
163 | */
164 | public Spanned[] history() {
165 |
166 | int i = 0;
167 | Spanned[] array = new Spanned[history.size()];
168 |
169 | for (String s : history) {
170 | if (s != null) {
171 | array[i] = Html.fromHtml(s);
172 | i++;
173 | }
174 | }
175 |
176 | return array;
177 |
178 | }
179 |
180 | /**
181 | * Gets the client handle for this connection
182 | * @return client Handle for this connection
183 | */
184 | public String handle() {
185 | return clientHandle;
186 | }
187 |
188 | /**
189 | * Determines if the client is connected
190 | * @return is the client connected
191 | */
192 | public boolean isConnected() {
193 | return status == ConnectionStatus.CONNECTED;
194 | }
195 |
196 | /**
197 | * Changes the connection status of the client
198 | * @param connectionStatus The connection status of this connection
199 | */
200 | public void changeConnectionStatus(ConnectionStatus connectionStatus) {
201 | status = connectionStatus;
202 | notifyListeners((new PropertyChangeEvent(this, ActivityConstants.ConnectionStatusProperty, null, null)));
203 | }
204 |
205 | /**
206 | * A string representing the state of the client this connection
207 | * object represents
208 | *
209 | *
210 | * @return A string representing the state of the client
211 | */
212 | @Override
213 | public String toString() {
214 | StringBuffer sb = new StringBuffer();
215 | sb.append(clientId);
216 | sb.append("\n ");
217 |
218 | switch (status) {
219 |
220 | case CONNECTED :
221 | sb.append(context.getString(R.string.connectedto));
222 | break;
223 | case DISCONNECTED :
224 | sb.append(context.getString(R.string.disconnected));
225 | break;
226 | case NONE :
227 | sb.append(context.getString(R.string.no_status));
228 | break;
229 | case CONNECTING :
230 | sb.append(context.getString(R.string.connecting));
231 | break;
232 | case DISCONNECTING :
233 | sb.append(context.getString(R.string.disconnecting));
234 | break;
235 | case ERROR :
236 | sb.append(context.getString(R.string.connectionError));
237 | }
238 | sb.append(" ");
239 | sb.append(host);
240 |
241 | return sb.toString();
242 | }
243 |
244 | /**
245 | * Determines if a given handle refers to this client
246 | * @param handle The handle to compare with this clients handle
247 | * @return true if the handles match
248 | */
249 | public boolean isHandle(String handle) {
250 | return clientHandle.equals(handle);
251 | }
252 |
253 | /**
254 | * Compares two connection objects for equality
255 | * this only takes account of the client handle
256 | * @param o The object to compare to
257 | * @return true if the client handles match
258 | */
259 | @Override
260 | public boolean equals(Object o) {
261 | if (!(o instanceof Connection)) {
262 | return false;
263 | }
264 |
265 | Connection c = (Connection) o;
266 |
267 | return clientHandle.equals(c.clientHandle);
268 |
269 | }
270 |
271 | /**
272 | * Get the client Id for the client this object represents
273 | * @return the client id for the client this object represents
274 | */
275 | public String getId() {
276 | return clientId;
277 | }
278 |
279 | /**
280 | * Get the host name of the server that this connection object is associated with
281 | * @return the host name of the server this connection object is associated with
282 | */
283 | public String getHostName() {
284 |
285 | return host;
286 | }
287 |
288 | /**
289 | * Determines if the client is in a state of connecting or connected.
290 | * @return if the client is connecting or connected
291 | */
292 | public boolean isConnectedOrConnecting() {
293 | return (status == ConnectionStatus.CONNECTED) || (status == ConnectionStatus.CONNECTING);
294 | }
295 |
296 | /**
297 | * Client is currently not in an error state
298 | * @return true if the client is in not an error state
299 | */
300 | public boolean noError() {
301 | return status != ConnectionStatus.ERROR;
302 | }
303 |
304 | /**
305 | * Gets the client which communicates with the android service.
306 | * @return the client which communicates with the android service
307 | */
308 | public MqttAndroidClient getClient() {
309 | return client;
310 | }
311 |
312 | /**
313 | * Add the connectOptions used to connect the client to the server
314 | * @param connectOptions the connectOptions used to connect to the server
315 | */
316 | public void addConnectionOptions(MqttConnectOptions connectOptions) {
317 | conOpt = connectOptions;
318 |
319 | }
320 |
321 | /**
322 | * Get the connectOptions used to connect this client to the server
323 | * @return The connectOptions used to connect the client to the server
324 | */
325 | public MqttConnectOptions getConnectionOptions()
326 | {
327 | return conOpt;
328 | }
329 |
330 | /**
331 | * Register a {@link PropertyChangeListener} to this object
332 | * @param listener the listener to register
333 | */
334 | public void registerChangeListener(PropertyChangeListener listener)
335 | {
336 | listeners.add(listener);
337 | }
338 |
339 | /**
340 | * Remove a registered {@link PropertyChangeListener}
341 | * @param listener A reference to the listener to remove
342 | */
343 | public void removeChangeListener(PropertyChangeListener listener)
344 | {
345 | if (listener != null) {
346 | listeners.remove(listener);
347 | }
348 | }
349 |
350 | /**
351 | * Notify {@link PropertyChangeListener} objects that the object has been updated
352 | * @param propertyChangeEvent
353 | */
354 | private void notifyListeners(PropertyChangeEvent propertyChangeEvent)
355 | {
356 | for (PropertyChangeListener listener : listeners)
357 | {
358 | listener.propertyChange(propertyChangeEvent);
359 | }
360 | }
361 |
362 | /**
363 | * Gets the port that this connection connects to.
364 | * @return port that this connection connects to
365 | */
366 | public int getPort() {
367 | return port;
368 | }
369 |
370 | /**
371 | * Determines if the connection is secured using SSL, returning a C style integer value
372 | * @return 1 if SSL secured 0 if plain text
373 | */
374 | public int isSSL() {
375 | return sslConnection ? 1 : 0;
376 | }
377 |
378 | /**
379 | * Assign a persistence ID to this object
380 | * @param id the persistence id to assign
381 | */
382 | public void assignPersistenceId(long id) {
383 | persistenceId = id;
384 | }
385 |
386 | /**
387 | * Returns the persistence ID assigned to this object
388 | * @return the persistence ID assigned to this object
389 | */
390 | public long persistenceId() {
391 | return persistenceId;
392 | }
393 | }
394 |
--------------------------------------------------------------------------------
/app/src/main/java/io/bytehala/eclipsemqtt/sample/ConnectionDetailsActivity.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 1999, 2014 IBM Corp.
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | */
13 | package io.bytehala.eclipsemqtt.sample;
14 |
15 | import java.beans.PropertyChangeEvent;
16 | import java.beans.PropertyChangeListener;
17 | import java.util.ArrayList;
18 |
19 |
20 | import android.app.PendingIntent;
21 | import android.content.Intent;
22 | import android.os.Bundle;
23 | import android.telephony.SmsManager;
24 | import android.util.Log;
25 | import android.view.Menu;
26 | import android.widget.CheckBox;
27 | import android.widget.EditText;
28 | import android.widget.RadioGroup;
29 |
30 | import androidx.appcompat.app.ActionBar;
31 | import androidx.appcompat.app.AppCompatActivity;
32 | import androidx.fragment.app.Fragment;
33 | import androidx.fragment.app.FragmentManager;
34 | import androidx.fragment.app.FragmentPagerAdapter;
35 | import androidx.fragment.app.FragmentTransaction;
36 | import androidx.viewpager.widget.ViewPager;
37 |
38 | import org.eclipse.paho.client.mqttv3.MqttException;
39 | import org.eclipse.paho.client.mqttv3.MqttSecurityException;
40 |
41 | /**
42 | * The connection details activity operates the fragments that make up the
43 | * connection details screen.
44 | *
45 | * The fragments which this FragmentActivity uses are
46 | *
47 | * {@link HistoryFragment}
48 | * {@link PublishFragment}
49 | * {@link SubscribeFragment}
50 | *
51 | *
52 | */
53 | public class ConnectionDetailsActivity extends AppCompatActivity implements
54 | ActionBar.TabListener {
55 |
56 | /**
57 | * {@link SectionsPagerAdapter} that is used to get pages to display
58 | */
59 | SectionsPagerAdapter sectionsPagerAdapter;
60 | /**
61 | * {@link ViewPager} object allows pages to be flipped left and right
62 | */
63 | ViewPager viewPager;
64 |
65 | /** The currently selected tab **/
66 | private int selected = 0;
67 |
68 | /**
69 | * The handle to the {@link Connection} which holds the data for the client
70 | * selected
71 | **/
72 | private String clientHandle = null;
73 |
74 | /** This instance of ConnectionDetailsActivity **/
75 | private final ConnectionDetailsActivity connectionDetails = this;
76 |
77 | /**
78 | * The instance of {@link Connection} that the clientHandle
79 | * represents
80 | **/
81 | private Connection connection = null;
82 |
83 | /**
84 | * The {@link ChangeListener} this object is using for the connection
85 | * updates
86 | **/
87 | private ChangeListener changeListener = null;
88 |
89 | /**
90 | * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
91 | */
92 | @Override
93 | protected void onCreate(Bundle savedInstanceState) {
94 | super.onCreate(savedInstanceState);
95 |
96 | clientHandle = getIntent().getStringExtra("handle");
97 |
98 | setContentView(R.layout.activity_connection_details);
99 | // Create the adapter that will return a fragment for each of the pages
100 | sectionsPagerAdapter = new SectionsPagerAdapter(
101 | getSupportFragmentManager());
102 |
103 | // Set up the action bar for tab navigation
104 | final ActionBar actionBar = getSupportActionBar();
105 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
106 |
107 | // add the sectionsPagerAdapter
108 | viewPager = (ViewPager) findViewById(R.id.pager);
109 | viewPager.setAdapter(sectionsPagerAdapter);
110 |
111 | viewPager
112 | .setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
113 |
114 | @Override
115 | public void onPageSelected(int position) {
116 | // select the tab that represents the current page
117 | actionBar.setSelectedNavigationItem(position);
118 |
119 | }
120 | });
121 |
122 | // Create the tabs for the screen
123 | for (int i = 0; i < sectionsPagerAdapter.getCount(); i++) {
124 | ActionBar.Tab tab = actionBar.newTab();
125 | tab.setText(sectionsPagerAdapter.getPageTitle(i));
126 | tab.setTabListener(this);
127 | actionBar.addTab(tab);
128 | }
129 |
130 | connection = Connections.getInstance(this).getConnection(clientHandle);
131 | changeListener = new ChangeListener();
132 | connection.registerChangeListener(changeListener);
133 | }
134 |
135 | @Override
136 | protected void onDestroy() {
137 | connection.removeChangeListener(null);
138 | super.onDestroy();
139 | }
140 |
141 | /**
142 | * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
143 | */
144 | @Override
145 | public boolean onCreateOptionsMenu(Menu menu) {
146 | int menuID;
147 | Integer button = null;
148 | boolean connected = Connections.getInstance(this)
149 | .getConnection(clientHandle).isConnected();
150 |
151 | // Select the correct action bar menu to display based on the
152 | // connectionStatus and which tab is selected
153 | if (connected) {
154 |
155 | switch (selected) {
156 | case 0 : // history view
157 | menuID = R.menu.activity_connection_details;
158 | break;
159 | case 1 : // subscribe view
160 | menuID = R.menu.activity_subscribe;
161 | button = R.id.subscribe;
162 | break;
163 | case 2 : // publish view
164 | menuID = R.menu.activity_publish;
165 | button = R.id.publish;
166 | break;
167 | default :
168 | menuID = R.menu.activity_connection_details;
169 | break;
170 | }
171 | }
172 | else {
173 | switch (selected) {
174 | case 0 : // history view
175 | menuID = R.menu.activity_connection_details_disconnected;
176 | break;
177 | case 1 : // subscribe view
178 | menuID = R.menu.activity_subscribe_disconnected;
179 | button = R.id.subscribe;
180 | break;
181 | case 2 : // publish view
182 | menuID = R.menu.activity_publish_disconnected;
183 | button = R.id.publish;
184 | break;
185 | default :
186 | menuID = R.menu.activity_connection_details_disconnected;
187 | break;
188 | }
189 | }
190 | // inflate the menu selected
191 | getMenuInflater().inflate(menuID, menu);
192 | Listener listener = new Listener(this, clientHandle);
193 | // add listeners
194 | if (button != null) {
195 | // add listeners
196 | menu.findItem(button).setOnMenuItemClickListener(listener);
197 | if (!Connections.getInstance(this).getConnection(clientHandle)
198 | .isConnected()) {
199 | menu.findItem(button).setEnabled(false);
200 | }
201 | }
202 | // add the listener to the disconnect or connect menu option
203 | if (connected) {
204 | menu.findItem(R.id.disconnect).setOnMenuItemClickListener(listener);
205 | }
206 | else {
207 | menu.findItem(R.id.connectMenuOption).setOnMenuItemClickListener(
208 | listener);
209 | }
210 |
211 | return true;
212 | }
213 |
214 | /**
215 | * @see android.app.ActionBar.TabListener#onTabUnselected(android.app.ActionBar.Tab,
216 | * android.app.FragmentTransaction)
217 | */
218 | @Override
219 | public void onTabUnselected(ActionBar.Tab tab,
220 | FragmentTransaction fragmentTransaction) {
221 | // Don't need to do anything when a tab is unselected
222 | }
223 |
224 | /**
225 | * @see android.app.ActionBar.TabListener#onTabSelected(android.app.ActionBar.Tab,
226 | * android.app.FragmentTransaction)
227 | */
228 | @Override
229 | public void onTabSelected(ActionBar.Tab tab,
230 | FragmentTransaction fragmentTransaction) {
231 | // When the given tab is selected, switch to the corresponding page in
232 | // the ViewPager.
233 | viewPager.setCurrentItem(tab.getPosition());
234 | selected = tab.getPosition();
235 | // invalidate the options menu so it can be updated
236 | invalidateOptionsMenu();
237 |
238 | updateButtons();
239 |
240 |
241 | // history fragment is at position zero so get this then refresh its
242 | // view
243 | ((HistoryFragment) sectionsPagerAdapter.getItem(0)).refresh();
244 | }
245 |
246 | /**
247 | * @see android.app.ActionBar.TabListener#onTabReselected(android.app.ActionBar.Tab,
248 | * android.app.FragmentTransaction)
249 | */
250 | @Override
251 | public void onTabReselected(ActionBar.Tab tab,
252 | FragmentTransaction fragmentTransaction) {
253 | // Don't need to do anything when the tab is reselected
254 | }
255 |
256 | /**
257 | * Provides the Activity with the pages to display for each tab
258 | *
259 | */
260 | public class SectionsPagerAdapter extends FragmentPagerAdapter {
261 |
262 | // Stores the instances of the pages
263 | private ArrayList fragments = null;
264 |
265 | /**
266 | * Only Constructor, requires a the activity's fragment managers
267 | *
268 | * @param fragmentManager
269 | */
270 | public SectionsPagerAdapter(FragmentManager fragmentManager) {
271 | super(fragmentManager);
272 | fragments = new ArrayList();
273 | // create the history view, passes the client handle as an argument
274 | // through a bundle
275 | Fragment fragment = new HistoryFragment();
276 | Bundle args = new Bundle();
277 | args.putString("handle", getIntent().getStringExtra("handle"));
278 | fragment.setArguments(args);
279 | // add all the fragments for the display to the fragments list
280 | fragments.add(fragment);
281 | fragments.add(new SubscribeFragment());
282 | fragments.add(new PublishFragment());
283 |
284 | }
285 |
286 | /**
287 | * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
288 | */
289 | @Override
290 | public Fragment getItem(int position) {
291 | return fragments.get(position);
292 | }
293 |
294 | /**
295 | * @see android.support.v4.view.PagerAdapter#getCount()
296 | */
297 | @Override
298 | public int getCount() {
299 | return fragments.size();
300 | }
301 |
302 | /**
303 | *
304 | * @see FragmentPagerAdapter#getPageTitle(int)
305 | */
306 | @Override
307 | public CharSequence getPageTitle(int position) {
308 | switch (position) {
309 | case 0 :
310 | return getString(R.string.history).toUpperCase();
311 | case 1 :
312 | return getString(R.string.subscribe).toUpperCase();
313 | case 2 :
314 | return getString(R.string.publish).toUpperCase();
315 | }
316 | // return null if there is no title matching the position
317 | return null;
318 | }
319 |
320 | }
321 |
322 | /**
323 | * ChangeListener updates the UI when the {@link Connection}
324 | * object it is associated with updates
325 | *
326 | */
327 | private class ChangeListener implements PropertyChangeListener {
328 |
329 | /**
330 | * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
331 | */
332 | @Override
333 | public void propertyChange(PropertyChangeEvent event) {
334 | // connection object has change refresh the UI
335 |
336 | connectionDetails.runOnUiThread(new Runnable() {
337 |
338 | @Override
339 | public void run() {
340 | connectionDetails.invalidateOptionsMenu();
341 | ((HistoryFragment) connectionDetails.sectionsPagerAdapter
342 | .getItem(0)).refresh();
343 |
344 | updateButtons();
345 |
346 | }
347 | });
348 |
349 | }
350 | }
351 |
352 | private void updateButtons() {
353 | /*
354 | After sending SMS we would crash here , @param clientHandle is null
355 | */
356 |
357 | boolean connected = Connections.getInstance(connectionDetails)
358 | .getConnection(clientHandle).isConnected();
359 |
360 | if(selected == 2) {
361 | connectionDetails.findViewById(R.id.publishButton).setEnabled(connected);
362 | connectionDetails.findViewById(R.id.publishButton).setOnClickListener(
363 | view -> publish()
364 | );
365 | }
366 | if(selected == 1) {
367 | connectionDetails.findViewById(R.id.subscribeButton).setEnabled(connected);
368 | connectionDetails.findViewById(R.id.subscribeButton).setOnClickListener(
369 | view -> subscribe()
370 | );
371 | }
372 | }
373 |
374 | /**
375 | * Subscribe to a topic that the user has specified
376 | */
377 | private void subscribe()
378 | {
379 | String topic = ((EditText) connectionDetails.findViewById(R.id.topic)).getText().toString();
380 | ((EditText) connectionDetails.findViewById(R.id.topic)).getText().clear();
381 |
382 | RadioGroup radio = (RadioGroup) connectionDetails.findViewById(R.id.qosSubRadio);
383 | int checked = radio.getCheckedRadioButtonId();
384 | int qos = ActivityConstants.defaultQos;
385 |
386 | switch (checked) {
387 | case R.id.qos0 :
388 | qos = 0;
389 | break;
390 | case R.id.qos1 :
391 | qos = 1;
392 | break;
393 | case R.id.qos2 :
394 | qos = 2;
395 | break;
396 | }
397 |
398 | try {
399 | String[] topics = new String[1];
400 | topics[0] = topic;
401 | Connections.getInstance(this).getConnection(clientHandle).getClient()
402 | .subscribe(topic, qos, null, new ActionListener(this, ActionListener.Action.SUBSCRIBE, clientHandle, topics));
403 | }
404 | catch (MqttSecurityException e) {
405 | Log.e(this.getClass().getCanonicalName(), "Failed to subscribe to" + topic + " the client with the handle " + clientHandle, e);
406 | }
407 | catch (MqttException e) {
408 | Log.e(this.getClass().getCanonicalName(), "Failed to subscribe to" + topic + " the client with the handle " + clientHandle, e);
409 | }
410 | }
411 |
412 | /**
413 | * Publish the message the user has specified
414 | */
415 | private void publish()
416 | {
417 | String topic = ((EditText) connectionDetails.findViewById(R.id.lastWillTopic))
418 | .getText().toString();
419 |
420 | ((EditText) connectionDetails.findViewById(R.id.lastWillTopic)).getText().clear();
421 |
422 | String message = ((EditText) connectionDetails.findViewById(R.id.lastWill)).getText()
423 | .toString();
424 |
425 | ((EditText) connectionDetails.findViewById(R.id.lastWill)).getText().clear();
426 |
427 | RadioGroup radio = (RadioGroup) connectionDetails.findViewById(R.id.qosRadio);
428 | int checked = radio.getCheckedRadioButtonId();
429 | int qos = ActivityConstants.defaultQos;
430 |
431 | switch (checked) {
432 | case R.id.qos0 :
433 | qos = 0;
434 | break;
435 | case R.id.qos1 :
436 | qos = 1;
437 | break;
438 | case R.id.qos2 :
439 | qos = 2;
440 | break;
441 | }
442 |
443 | boolean retained = ((CheckBox) connectionDetails.findViewById(R.id.retained))
444 | .isChecked();
445 |
446 | String[] args = new String[2];
447 | args[0] = message;
448 | args[1] = topic+";qos:"+qos+";retained:"+retained;
449 |
450 | try {
451 | Connections.getInstance(this).getConnection(clientHandle).getClient()
452 | .publish(topic, message.getBytes(), qos, retained, null, new ActionListener(this, ActionListener.Action.PUBLISH, clientHandle, args));
453 | } catch (MqttException e) {
454 | Log.e(this.getClass().getCanonicalName(), "Failed to publish a messged from the client with the handle " + clientHandle, e);
455 | }
456 |
457 | }
458 |
459 | }
460 |
--------------------------------------------------------------------------------