Skip to content
Snippets Groups Projects
Commit d374a7cd authored by maniac103's avatar maniac103 Committed by mueller-ma
Browse files

General code cleanup (#1029)


* Use lambdas where appropriate.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Use diamond operator where appropriate.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Use foreach.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Remove unused imports.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Remove a few redundant casts.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Code cleanup

- Name variables consistently
- Cleanup some whitespace
- Remove unneeded throws statements
- Remove some unused stuff

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Drop redundant 'OpenHAB' prefix from class names.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Update checkstyle config to better match our style.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Fix coding style issues.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Don't generate IDs in android package.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Improve some comments.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>

* Fix checkstyle issues in tests.

Signed-off-by: default avatarDanny Baumann <dannybaumann@web.de>
parent 59d119d3
Branches
No related tags found
No related merge requests found
Showing
with 341 additions and 338 deletions
......@@ -95,7 +95,7 @@ public class MemorizingTrustManager implements X509TrustManager {
Activity foregroundAct;
NotificationManager notificationManager;
private static int decisionId = 0;
private static SparseArray<MTMDecision> openDecisions = new SparseArray<MTMDecision>();
private static SparseArray<MTMDecision> openDecisions = new SparseArray<>();
Handler masterHandler;
private File keyStoreFile;
......
......@@ -4,7 +4,7 @@ import android.support.multidex.MultiDexApplication;
import org.openhab.habdroid.core.connection.ConnectionFactory;
public class OpenHABApplication extends MultiDexApplication {
public class HabDroidApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
......
......@@ -19,6 +19,8 @@ import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.widget.Toast;
import es.dmoral.toasty.Toasty;
import org.openhab.habdroid.R;
import org.openhab.habdroid.core.connection.Connection;
import org.openhab.habdroid.core.connection.ConnectionFactory;
......@@ -29,17 +31,15 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import es.dmoral.toasty.Toasty;
/**
* This service handles voice commands and sends them to openHAB.
*/
public class OpenHABVoiceService extends IntentService {
private static final String TAG = OpenHABVoiceService.class.getSimpleName();
public class VoiceService extends IntentService {
private static final String TAG = VoiceService.class.getSimpleName();
private Handler mHandler = new Handler(Looper.getMainLooper());
public OpenHABVoiceService() {
super("OpenHABVoiceService");
public VoiceService() {
super("VoiceService");
}
@Override
......
package org.openhab.habdroid.core.connection;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.util.Log;
import okhttp3.OkHttpClient;
import org.openhab.habdroid.util.AsyncHttpClient;
import org.openhab.habdroid.util.HttpClient;
import org.openhab.habdroid.util.SyncHttpClient;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import okhttp3.OkHttpClient;
public abstract class AbstractConnection implements Connection {
private static final String TAG = AbstractConnection.class.getSimpleName();
private int connectionType;
private String username;
private String password;
private String baseUrl;
private final int mConnectionType;
private final String mUserName;
private final String mPassword;
private final String mBaseUrl;
private final AsyncHttpClient asyncHttpClient;
private final SyncHttpClient syncHttpClient;
private final AsyncHttpClient mAsyncHttpClient;
private final SyncHttpClient mSyncHttpClient;
AbstractConnection(OkHttpClient httpClient, int connectionType,
String baseUrl, String username, String password) {
this.username = username;
this.password = password;
this.baseUrl = baseUrl;
this.connectionType = connectionType;
mUserName = username;
mPassword = password;
mBaseUrl = baseUrl;
mConnectionType = connectionType;
asyncHttpClient = new AsyncHttpClient(httpClient, baseUrl, username, password);
syncHttpClient = new SyncHttpClient(httpClient, baseUrl, username, password);
mAsyncHttpClient = new AsyncHttpClient(httpClient, baseUrl, username, password);
mSyncHttpClient = new SyncHttpClient(httpClient, baseUrl, username, password);
}
AbstractConnection(@NonNull AbstractConnection base, int connectionType) {
this.username = base.username;
this.password = base.password;
this.baseUrl = base.baseUrl;
this.connectionType = connectionType;
mUserName = base.mUserName;
mPassword = base.mPassword;
mBaseUrl = base.mBaseUrl;
mConnectionType = connectionType;
asyncHttpClient = base.getAsyncHttpClient();
syncHttpClient = base.getSyncHttpClient();
mAsyncHttpClient = base.getAsyncHttpClient();
mSyncHttpClient = base.getSyncHttpClient();
}
private boolean hasUsernameAndPassword() {
return getUsername() != null && !getUsername().isEmpty() && getPassword() != null &&
!getPassword().isEmpty();
return getUsername() != null && !getUsername().isEmpty()
&& getPassword() != null && !getPassword().isEmpty();
}
@Override
public AsyncHttpClient getAsyncHttpClient() {
return asyncHttpClient;
return mAsyncHttpClient;
}
@Override
public SyncHttpClient getSyncHttpClient() {
return syncHttpClient;
return mSyncHttpClient;
}
@Override
public String getUsername() {
return username;
return mUserName;
}
@Override
public String getPassword() {
return password;
return mPassword;
}
@Override
public int getConnectionType() {
return connectionType;
return mConnectionType;
}
@Override
public boolean checkReachabilityInBackground() {
Log.d(TAG, "Checking reachability of " + baseUrl);
Log.d(TAG, "Checking reachability of " + mBaseUrl);
try {
URL url = new URL(baseUrl);
URL url = new URL(mBaseUrl);
int checkPort = url.getPort();
if (url.getProtocol().equals("http") && checkPort == -1)
if (url.getProtocol().equals("http") && checkPort == -1) {
checkPort = 80;
if (url.getProtocol().equals("https") && checkPort == -1)
} else if (url.getProtocol().equals("https") && checkPort == -1) {
checkPort = 443;
}
Socket s = new Socket();
s.connect(new InetSocketAddress(url.getHost(), checkPort), 1000);
Log.d(TAG, "Socket connected");
......@@ -101,10 +99,10 @@ public abstract class AbstractConnection implements Connection {
@Override
public int hashCode() {
int result = 17;
result = 31 * result + connectionType;
result = 31 * result + baseUrl.hashCode();
result = 31 * result + (username != null ? username.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
result = 31 * result + mConnectionType;
result = 31 * result + mBaseUrl.hashCode();
result = 31 * result + (mUserName != null ? mUserName.hashCode() : 0);
result = 31 * result + (mPassword != null ? mPassword.hashCode() : 0);
return result;
}
}
package org.openhab.habdroid.core.connection;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.openhab.habdroid.util.AsyncHttpClient;
......@@ -42,6 +41,7 @@ public interface Connection {
* @return The username used for this connection.
*/
@Nullable String getUsername();
@Nullable String getPassword();
/**
......
......@@ -19,6 +19,10 @@ import android.support.annotation.VisibleForTesting;
import android.support.v4.util.Pair;
import android.util.Log;
import de.duenndns.ssl.MemorizingTrustManager;
import okhttp3.OkHttpClient;
import okhttp3.internal.tls.OkHostnameVerifier;
import org.openhab.habdroid.core.CloudMessagingHelper;
import org.openhab.habdroid.core.connection.exception.ConnectionException;
import org.openhab.habdroid.core.connection.exception.NetworkNotAvailableException;
......@@ -41,16 +45,13 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import de.duenndns.ssl.MemorizingTrustManager;
import okhttp3.OkHttpClient;
import okhttp3.internal.tls.OkHostnameVerifier;
/**
* A factory class, which is the main entry point to get a Connection to a specific openHAB
* server. Use this factory class whenever you need to obtain a connection to load additional
* data from the openHAB server or another supported source (see the constants in {@link Connection}).
* data from the openHAB server or another supported source
* (see the constants in {@link Connection}).
*/
final public class ConnectionFactory extends BroadcastReceiver implements
public final class ConnectionFactory extends BroadcastReceiver implements
SharedPreferences.OnSharedPreferenceChangeListener, Handler.Callback {
private static final String TAG = ConnectionFactory.class.getSimpleName();
private static final List<Integer> LOCAL_CONNECTION_TYPES = Arrays.asList(
......@@ -75,9 +76,9 @@ final public class ConnectionFactory extends BroadcastReceiver implements
private static final int MSG_AVAILABLE_DONE = 2;
private static final int MSG_CLOUD_DONE = 3;
private Context ctx;
private SharedPreferences settings;
private MemorizingTrustManager mTrustManager;
private final Context mContext;
private final SharedPreferences mPrefs;
private final MemorizingTrustManager mTrustManager;
private OkHttpClient mHttpClient;
private String mLastClientCertAlias;
......@@ -86,12 +87,12 @@ final public class ConnectionFactory extends BroadcastReceiver implements
private CloudConnection mCloudConnection;
private Connection mAvailableConnection;
private ConnectionException mConnectionFailureReason;
private HashSet<UpdateListener> mListeners = new HashSet<>();
private final HashSet<UpdateListener> mListeners = new HashSet<>();
private boolean mNeedsUpdate;
private boolean mIgnoreNextConnectivityChange;
private boolean mAvailableInitialized;
private boolean mCloudInitialized;
private Object mInitializationLock = new Object();
private final Object mInitializationLock = new Object();
private HandlerThread mUpdateThread;
@VisibleForTesting
......@@ -102,22 +103,22 @@ final public class ConnectionFactory extends BroadcastReceiver implements
@VisibleForTesting
public static ConnectionFactory sInstance;
ConnectionFactory(Context ctx, SharedPreferences settings) {
this.ctx = ctx;
this.settings = settings;
this.settings.registerOnSharedPreferenceChangeListener(this);
ConnectionFactory(Context context, SharedPreferences prefs) {
mContext = context;
mPrefs = prefs;
prefs.registerOnSharedPreferenceChangeListener(this);
mTrustManager = new MemorizingTrustManager(ctx);
mTrustManager = new MemorizingTrustManager(context);
mHttpClient = new OkHttpClient.Builder()
.cache(CacheManager.getInstance(ctx).getHttpCache())
.cache(CacheManager.getInstance(context).getHttpCache())
.hostnameVerifier(mTrustManager.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE))
.build();
updateHttpClientForClientCert(true);
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
// Make sure to ignore the initial sticky broadcast, as we're only interested in changes
mIgnoreNextConnectivityChange = ctx.registerReceiver(null, filter) != null;
ctx.registerReceiver(this, filter);
mIgnoreNextConnectivityChange = context.registerReceiver(null, filter) != null;
context.registerReceiver(this, filter);
mUpdateThread = new HandlerThread("ConnectionUpdate");
mUpdateThread.start();
......@@ -136,7 +137,7 @@ final public class ConnectionFactory extends BroadcastReceiver implements
}
public static void shutdown() {
sInstance.ctx.unregisterReceiver(sInstance);
sInstance.mContext.unregisterReceiver(sInstance);
sInstance.mUpdateThread.quit();
}
......@@ -177,7 +178,8 @@ final public class ConnectionFactory extends BroadcastReceiver implements
// When coming back from background, re-do connectivity check for
// local connections, as the reachability of the local server might have
// changed since we went to background
NoUrlInformationException nuie = mConnectionFailureReason instanceof NoUrlInformationException
NoUrlInformationException nuie =
mConnectionFailureReason instanceof NoUrlInformationException
? (NoUrlInformationException) mConnectionFailureReason : null;
boolean local = mAvailableConnection == mLocalConnection
|| (nuie != null && nuie.wouldHaveUsedLocalConnection());
......@@ -274,10 +276,11 @@ final public class ConnectionFactory extends BroadcastReceiver implements
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_AVAILABLE: { // update thread
//noinspection unchecked
Pair<Connection, Connection> connections = (Pair<Connection, Connection>) msg.obj;
Message result = mMainHandler.obtainMessage(MSG_AVAILABLE_DONE);
try {
result.obj = determineAvailableConnection(ctx,
result.obj = determineAvailableConnection(mContext,
connections.first, connections.second);
} catch (ConnectionException e) {
result.obj = e;
......@@ -304,9 +307,10 @@ final public class ConnectionFactory extends BroadcastReceiver implements
handleCloudCheckDone((CloudConnection) msg.obj);
return true;
}
}
default:
return false;
}
}
private boolean updateAvailableConnection(Connection c, ConnectionException failureReason) {
if (failureReason != null) {
......@@ -365,14 +369,16 @@ final public class ConnectionFactory extends BroadcastReceiver implements
@VisibleForTesting
public void updateConnections() {
if (settings.getBoolean(Constants.PREFERENCE_DEMOMODE, false)) {
if (mPrefs.getBoolean(Constants.PREFERENCE_DEMOMODE, false)) {
mLocalConnection = mRemoteConnection = new DemoConnection(mHttpClient);
handleAvailableCheckDone(mLocalConnection, null);
handleCloudCheckDone(null);
} else {
mLocalConnection = makeConnection(Connection.TYPE_LOCAL, Constants.PREFERENCE_LOCAL_URL,
mLocalConnection = makeConnection(Connection.TYPE_LOCAL,
Constants.PREFERENCE_LOCAL_URL,
Constants.PREFERENCE_LOCAL_USERNAME, Constants.PREFERENCE_LOCAL_PASSWORD);
mRemoteConnection = makeConnection(Connection.TYPE_REMOTE, Constants.PREFERENCE_REMOTE_URL,
mRemoteConnection = makeConnection(Connection.TYPE_REMOTE,
Constants.PREFERENCE_REMOTE_URL,
Constants.PREFERENCE_REMOTE_USERNAME, Constants.PREFERENCE_REMOTE_PASSWORD);
synchronized (mInitializationLock) {
......@@ -387,11 +393,11 @@ final public class ConnectionFactory extends BroadcastReceiver implements
}
private void updateHttpClientForClientCert(boolean forceUpdate) {
String clientCertAlias = settings.getBoolean(Constants.PREFERENCE_DEMOMODE, false)
String clientCertAlias = mPrefs.getBoolean(Constants.PREFERENCE_DEMOMODE, false)
? null // No client cert in demo mode
: settings.getString(Constants.PREFERENCE_SSLCLIENTCERT, null);
: mPrefs.getString(Constants.PREFERENCE_SSLCLIENTCERT, null);
KeyManager[] keyManagers = clientCertAlias != null
? new KeyManager[] { new ClientKeyManager(ctx, clientCertAlias) }
? new KeyManager[] { new ClientKeyManager(mContext, clientCertAlias) }
: null;
// Updating the SSL socket factory is an expensive call;
......@@ -441,7 +447,7 @@ final public class ConnectionFactory extends BroadcastReceiver implements
private void handleCloudCheckDone(CloudConnection connection) {
if (connection != mCloudConnection) {
mCloudConnection = connection;
CloudMessagingHelper.onConnectionUpdated(ctx, connection);
CloudMessagingHelper.onConnectionUpdated(mContext, connection);
for (UpdateListener l : mListeners) {
l.onCloudConnectionChanged(connection);
}
......@@ -470,17 +476,17 @@ final public class ConnectionFactory extends BroadcastReceiver implements
private AbstractConnection makeConnection(int type, String urlKey,
String userNameKey, String passwordKey) {
String url = Util.normalizeUrl(settings.getString(urlKey, ""));
String url = Util.normalizeUrl(mPrefs.getString(urlKey, ""));
if (url.isEmpty()) {
return null;
}
return new DefaultConnection(mHttpClient, type, url,
settings.getString(userNameKey, null),
settings.getString(passwordKey, null));
mPrefs.getString(userNameKey, null),
mPrefs.getString(passwordKey, null));
}
private static class ClientKeyManager implements X509KeyManager {
private final static String TAG = ClientKeyManager.class.getSimpleName();
private static final String TAG = ClientKeyManager.class.getSimpleName();
private Context mContext;
private String mAlias;
......
......@@ -3,14 +3,14 @@ package org.openhab.habdroid.core.connection.exception;
import android.net.NetworkInfo;
public class NetworkNotSupportedException extends ConnectionException {
private final NetworkInfo networkInfo;
private final NetworkInfo mNetworkInfo;
public NetworkNotSupportedException(NetworkInfo info) {
super();
networkInfo = info;
mNetworkInfo = info;
}
public NetworkInfo getNetworkInfo() {
return networkInfo;
return mNetworkInfo;
}
}
......@@ -7,11 +7,6 @@
* http://www.eclipse.org/legal/epl-v10.html
*/
/**
* Created by belovictor on 03/04/15.
* This class represents a my.openHAB notification
*/
package org.openhab.habdroid.model;
import android.support.annotation.Nullable;
......@@ -26,7 +21,7 @@ import java.text.SimpleDateFormat;
import java.util.TimeZone;
@AutoValue
public abstract class OpenHABNotification {
public abstract class CloudNotification {
public abstract String id();
public abstract String message();
public abstract long createdTimestamp();
......@@ -43,10 +38,10 @@ public abstract class OpenHABNotification {
abstract Builder icon(@Nullable String icon);
abstract Builder severity(@Nullable String severity);
abstract OpenHABNotification build();
abstract CloudNotification build();
}
public static OpenHABNotification fromJson(JSONObject jsonObject) throws JSONException {
public static CloudNotification fromJson(JSONObject jsonObject) throws JSONException {
long created = 0;
if (jsonObject.has("created")) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'");
......@@ -58,7 +53,7 @@ public abstract class OpenHABNotification {
}
}
return new AutoValue_OpenHABNotification.Builder()
return new AutoValue_CloudNotification.Builder()
.id(jsonObject.getString("_id"))
.icon(jsonObject.optString("icon", null))
.severity(jsonObject.optString("severity", null))
......
......@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
*/
@AutoValue
public abstract class OpenHABItem implements Parcelable {
public abstract class Item implements Parcelable {
public enum Type {
None,
Color,
......@@ -55,16 +55,16 @@ public abstract class OpenHABItem implements Parcelable {
@Nullable
public abstract String link();
public abstract boolean readOnly();
public abstract List<OpenHABItem> members();
public abstract List<Item> members();
@Nullable
public abstract List<OpenHABLabeledValue> options();
public abstract List<LabeledValue> options();
@Nullable
public abstract String state();
public abstract boolean stateAsBoolean();
public abstract float stateAsFloat();
@SuppressWarnings("mutable")
@Nullable
public abstract float[] stateAsHSV();
public abstract float[] stateAsHsv();
@Nullable
public abstract Integer stateAsBrightness();
......@@ -81,14 +81,14 @@ public abstract class OpenHABItem implements Parcelable {
public abstract Builder state(@Nullable String state);
public abstract Builder link(@Nullable String link);
public abstract Builder readOnly(boolean readOnly);
public abstract Builder members(List<OpenHABItem> members);
public abstract Builder options(@Nullable List<OpenHABLabeledValue> options);
public abstract Builder members(List<Item> members);
public abstract Builder options(@Nullable List<LabeledValue> options);
public OpenHABItem build() {
public Item build() {
String state = state();
return stateAsBoolean(parseAsBoolean(state))
.stateAsFloat(parseAsFloat(state))
.stateAsHSV(parseAsHSV(state))
.stateAsHsv(parseAsHsv(state))
.stateAsBrightness(parseAsBrightness(state))
.autoBuild();
}
......@@ -96,9 +96,9 @@ public abstract class OpenHABItem implements Parcelable {
abstract String state();
abstract Builder stateAsBoolean(boolean state);
abstract Builder stateAsFloat(float state);
abstract Builder stateAsHSV(float[] hsv);
abstract Builder stateAsHsv(float[] hsv);
abstract Builder stateAsBrightness(@Nullable Integer brightness);
abstract OpenHABItem autoBuild();
abstract Item autoBuild();
private static boolean parseAsBoolean(String state) {
// For uninitialized/null state return false
......@@ -139,7 +139,7 @@ public abstract class OpenHABItem implements Parcelable {
}
}
private static float[] parseAsHSV(String state) {
private static float[] parseAsHsv(String state) {
if (state != null) {
String[] stateSplit = state.split(",");
if (stateSplit.length == 3) { // We need exactly 3 numbers to operate this
......@@ -171,7 +171,8 @@ public abstract class OpenHABItem implements Parcelable {
return null;
}
private final static Pattern HSB_PATTERN = Pattern.compile("^([0-9]*\\.?[0-9]+),([0-9]*\\.?[0-9]+),([0-9]*\\.?[0-9]+)$");
private static final Pattern HSB_PATTERN =
Pattern.compile("^([0-9]*\\.?[0-9]+),([0-9]*\\.?[0-9]+),([0-9]*\\.?[0-9]+)$");
}
private static Type parseType(String type) {
......@@ -192,7 +193,7 @@ public abstract class OpenHABItem implements Parcelable {
}
}
public static OpenHABItem fromXml(Node startNode) {
public static Item fromXml(Node startNode) {
String name = null, state = null, link = null;
Type type = Type.None, groupType = Type.None;
if (startNode.hasChildNodes()) {
......@@ -205,24 +206,24 @@ public abstract class OpenHABItem implements Parcelable {
case "name": name = childNode.getTextContent(); break;
case "state": state = childNode.getTextContent(); break;
case "link": link = childNode.getTextContent(); break;
default: break;
}
}
}
return new AutoValue_OpenHABItem.Builder()
return new AutoValue_Item.Builder()
.type(type)
.groupType(groupType)
.name(name)
.label(name)
.state("Unitialized".equals(state) ? null : state)
.members(new ArrayList<OpenHABItem>())
.members(new ArrayList<>())
.link(link)
.readOnly(false)
.build();
}
public static OpenHABItem updateFromEvent(OpenHABItem item, JSONObject jsonObject)
throws JSONException {
public static Item updateFromEvent(Item item, JSONObject jsonObject) throws JSONException {
if (jsonObject == null) {
return item;
}
......@@ -234,14 +235,14 @@ public abstract class OpenHABItem implements Parcelable {
return builder.build();
}
public static OpenHABItem fromJson(JSONObject jsonObject) throws JSONException {
public static Item fromJson(JSONObject jsonObject) throws JSONException {
if (jsonObject == null) {
return null;
}
return parseFromJson(jsonObject).build();
}
private static OpenHABItem.Builder parseFromJson(JSONObject jsonObject) throws JSONException {
private static Item.Builder parseFromJson(JSONObject jsonObject) throws JSONException {
String name = jsonObject.getString("name");
String state = jsonObject.optString("state", "");
if ("NULL".equals(state) || "UNDEF".equals(state) || "undefined".equalsIgnoreCase(state)) {
......@@ -250,23 +251,22 @@ public abstract class OpenHABItem implements Parcelable {
JSONObject stateDescription = jsonObject.optJSONObject("stateDescription");
boolean readOnly = stateDescription != null
? stateDescription.optBoolean("readOnly", false)
: false;
&& stateDescription.optBoolean("readOnly", false);
List<OpenHABLabeledValue> options = null;
List<LabeledValue> options = null;
if (stateDescription != null && stateDescription.has("options")) {
JSONArray optionsJson = stateDescription.getJSONArray("options");
options = new ArrayList<>();
for (int i = 0; i < optionsJson.length(); i++) {
JSONObject optionJson = optionsJson.getJSONObject(i);
options.add(OpenHABLabeledValue.newBuilder()
options.add(LabeledValue.newBuilder()
.value(optionJson.getString("value"))
.label(optionJson.getString("label"))
.build());
}
}
List<OpenHABItem> members = new ArrayList<>();
List<Item> members = new ArrayList<>();
JSONArray membersJson = jsonObject.optJSONArray("members");
if (membersJson != null) {
for (int i = 0; i < membersJson.length(); i++) {
......@@ -274,7 +274,7 @@ public abstract class OpenHABItem implements Parcelable {
}
}
return new AutoValue_OpenHABItem.Builder()
return new AutoValue_Item.Builder()
.type(parseType(jsonObject.getString("type")))
.groupType(parseType(jsonObject.optString("groupType")))
.name(name)
......
......@@ -14,19 +14,19 @@ import android.os.Parcelable;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class OpenHABLabeledValue implements Parcelable {
public abstract class LabeledValue implements Parcelable {
public abstract String value();
public abstract String label();
public static Builder newBuilder() {
return new AutoValue_OpenHABLabeledValue.Builder();
return new AutoValue_LabeledValue.Builder();
}
@AutoValue.Builder
public static abstract class Builder {
public abstract static class Builder {
public abstract Builder value(String value);
public abstract Builder label(String label);
public abstract OpenHABLabeledValue build();
public abstract LabeledValue build();
}
}
......@@ -13,7 +13,6 @@ import android.os.Parcelable;
import com.google.auto.value.AutoValue;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
......@@ -23,7 +22,7 @@ import org.w3c.dom.NodeList;
*/
@AutoValue
public abstract class OpenHABLinkedPage implements Parcelable {
public abstract class LinkedPage implements Parcelable {
public abstract String id();
public abstract String title();
public abstract String icon();
......@@ -36,7 +35,7 @@ public abstract class OpenHABLinkedPage implements Parcelable {
public abstract Builder icon(String icon);
public abstract Builder link(String link);
public OpenHABLinkedPage build() {
public LinkedPage build() {
String title = title();
if (title.indexOf('[') > 0) {
title(title.substring(0, title.indexOf('[')));
......@@ -45,10 +44,10 @@ public abstract class OpenHABLinkedPage implements Parcelable {
}
abstract String title();
abstract OpenHABLinkedPage autoBuild();
abstract LinkedPage autoBuild();
}
public static OpenHABLinkedPage fromXml(Node startNode) {
public static LinkedPage fromXml(Node startNode) {
String id = null, title = null, icon = null, link = null;
if (startNode.hasChildNodes()) {
......@@ -60,11 +59,12 @@ public abstract class OpenHABLinkedPage implements Parcelable {
case "title": title = childNode.getTextContent(); break;
case "icon": icon = childNode.getTextContent(); break;
case "link": link = childNode.getTextContent(); break;
default: break;
}
}
}
return new AutoValue_OpenHABLinkedPage.Builder()
return new AutoValue_LinkedPage.Builder()
.id(id)
.title(title)
.icon(icon)
......@@ -72,11 +72,11 @@ public abstract class OpenHABLinkedPage implements Parcelable {
.build();
}
public static OpenHABLinkedPage fromJson(JSONObject jsonObject) throws JSONException {
public static LinkedPage fromJson(JSONObject jsonObject) {
if (jsonObject == null) {
return null;
}
return new AutoValue_OpenHABLinkedPage.Builder()
return new AutoValue_LinkedPage.Builder()
.id(jsonObject.optString("id", null))
.title(jsonObject.optString("title", null))
.icon(jsonObject.optString("icon", null))
......
......@@ -5,6 +5,10 @@ import android.util.Log;
import com.google.auto.value.AutoValue;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -24,10 +28,6 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.Request;
@AutoValue
public abstract class ServerProperties implements Parcelable {
private static final String TAG = ServerProperties.class.getSimpleName();
......@@ -52,12 +52,13 @@ public abstract class ServerProperties implements Parcelable {
public interface UpdateSuccessCallback {
void handleServerPropertyUpdate(ServerProperties props);
}
public interface UpdateFailureCallback {
void handleUpdateFailure(Request request, int statusCode, Throwable error);
}
public abstract int flags();
public abstract List<OpenHABSitemap> sitemaps();
public abstract List<Sitemap> sitemaps();
public boolean hasJsonApi() {
return (flags() & SERVER_FLAG_JSON_REST_API) != 0;
......@@ -70,11 +71,13 @@ public abstract class ServerProperties implements Parcelable {
abstract Builder toBuilder();
@AutoValue.Builder
static abstract class Builder {
abstract static class Builder {
abstract Builder flags(int flags);
abstract Builder sitemaps(List<OpenHABSitemap> sitemaps);
abstract Builder sitemaps(List<Sitemap> sitemaps);
abstract ServerProperties build();
abstract int flags();
}
......@@ -144,7 +147,7 @@ public abstract class ServerProperties implements Parcelable {
@Override
public void onSuccess(String response, Headers headers) {
// OH1 returns XML, later versions return JSON
List<OpenHABSitemap> result = (handle.builder.flags() & SERVER_FLAG_JSON_REST_API) != 0
List<Sitemap> result = (handle.builder.flags() & SERVER_FLAG_JSON_REST_API) != 0
? loadSitemapsFromJson(response)
: loadSitemapsFromXml(response);
Log.d(TAG, "Server returned sitemaps: " + result);
......@@ -154,7 +157,7 @@ public abstract class ServerProperties implements Parcelable {
});
}
private static List<OpenHABSitemap> loadSitemapsFromXml(String response) {
private static List<Sitemap> loadSitemapsFromXml(String response) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = dbf.newDocumentBuilder();
......@@ -166,7 +169,7 @@ public abstract class ServerProperties implements Parcelable {
}
}
private static List<OpenHABSitemap> loadSitemapsFromJson(String response) {
private static List<Sitemap> loadSitemapsFromJson(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
return Util.parseSitemapList(jsonArray);
......
......@@ -14,13 +14,12 @@ import android.support.annotation.Nullable;
import com.google.auto.value.AutoValue;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@AutoValue
public abstract class OpenHABSitemap implements Parcelable {
public abstract class Sitemap implements Parcelable {
public abstract String name();
public abstract String label();
public abstract String link();
......@@ -30,7 +29,7 @@ public abstract class OpenHABSitemap implements Parcelable {
public abstract String homepageLink();
@AutoValue.Builder
static abstract class Builder {
abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder label(String label);
public abstract Builder link(String link);
......@@ -38,10 +37,10 @@ public abstract class OpenHABSitemap implements Parcelable {
public abstract Builder iconPath(String iconPath);
public abstract Builder homepageLink(String homepageLink);
public abstract OpenHABSitemap build();
public abstract Sitemap build();
}
public static OpenHABSitemap fromXml(Node startNode) {
public static Sitemap fromXml(Node startNode) {
String label = null, name = null, icon = null, link = null, homepageLink = null;
if (startNode.hasChildNodes()) {
......@@ -65,11 +64,13 @@ public abstract class OpenHABSitemap implements Parcelable {
}
}
break;
default:
break;
}
}
}
return new AutoValue_OpenHABSitemap.Builder()
return new AutoValue_Sitemap.Builder()
.name(name)
.label(label != null ? label : name)
.link(link)
......@@ -79,19 +80,21 @@ public abstract class OpenHABSitemap implements Parcelable {
.build();
}
public static OpenHABSitemap fromJson(JSONObject jsonObject) throws JSONException {
public static Sitemap fromJson(JSONObject jsonObject) {
String name = jsonObject.optString("name", null);
String label = jsonObject.optString("label", null);
String icon = jsonObject.optString("icon", null);
JSONObject homepageObject = jsonObject.optJSONObject("homepage");
String homepageLink = homepageObject != null
? homepageObject.optString("link", null) : null;
return new AutoValue_OpenHABSitemap.Builder()
return new AutoValue_Sitemap.Builder()
.name(name)
.label(label != null ? label : name)
.icon(icon)
.iconPath(String.format("icon/%s", icon))
.link(jsonObject.optString("link", null))
.homepageLink(homepageObject != null ? homepageObject.optString("link", null) : null)
.homepageLink(homepageLink)
.build();
}
}
......@@ -12,7 +12,6 @@ package org.openhab.habdroid.model;
import android.graphics.Color;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.auto.value.AutoValue;
......@@ -31,7 +30,7 @@ import java.util.Locale;
*/
@AutoValue
public abstract class OpenHABWidget implements Parcelable {
public abstract class Widget implements Parcelable {
public enum Type {
Chart,
Colorpicker,
......@@ -62,10 +61,10 @@ public abstract class OpenHABWidget implements Parcelable {
@Nullable
public abstract String url();
@Nullable
public abstract OpenHABItem item();
public abstract Item item();
@Nullable
public abstract OpenHABLinkedPage linkedPage();
public abstract List<OpenHABLabeledValue> mappings();
public abstract LinkedPage linkedPage();
public abstract List<LabeledValue> mappings();
@Nullable
public abstract String encoding();
@Nullable
......@@ -92,9 +91,9 @@ public abstract class OpenHABWidget implements Parcelable {
return !getMappingsOrItemOptions().isEmpty();
}
public List<OpenHABLabeledValue> getMappingsOrItemOptions() {
List<OpenHABLabeledValue> mappings = mappings();
List<OpenHABLabeledValue> options = item() != null ? item().options() : null;
public List<LabeledValue> getMappingsOrItemOptions() {
List<LabeledValue> mappings = mappings();
List<LabeledValue> options = item() != null ? item().options() : null;
return mappings.isEmpty() && options != null ? options : mappings;
}
......@@ -109,9 +108,9 @@ public abstract class OpenHABWidget implements Parcelable {
public abstract Builder iconPath(String iconPath);
public abstract Builder type(Type type);
public abstract Builder url(@Nullable String url);
public abstract Builder item(@Nullable OpenHABItem item);
public abstract Builder linkedPage(@Nullable OpenHABLinkedPage linkedPage);
public abstract Builder mappings(List<OpenHABLabeledValue> mappings);
public abstract Builder item(@Nullable Item item);
public abstract Builder linkedPage(@Nullable LinkedPage linkedPage);
public abstract Builder mappings(List<LabeledValue> mappings);
public abstract Builder encoding(@Nullable String encoding);
public abstract Builder iconColor(@Nullable String iconColor);
public abstract Builder labelColor(@Nullable String labelColor);
......@@ -125,7 +124,7 @@ public abstract class OpenHABWidget implements Parcelable {
public abstract Builder legend(@Nullable Boolean legend);
public abstract Builder height(int height);
public OpenHABWidget build() {
public Widget build() {
// A 'none' icon equals no icon at all
if ("none".equals(icon())) {
icon(null);
......@@ -151,19 +150,19 @@ public abstract class OpenHABWidget implements Parcelable {
abstract float minValue();
abstract float maxValue();
abstract float step();
abstract OpenHABWidget autoBuild();
abstract Widget autoBuild();
}
public static void parseXml(List<OpenHABWidget> allWidgets, OpenHABWidget parent, Node startNode) {
OpenHABItem item = null;
OpenHABLinkedPage linkedPage = null;
public static void parseXml(List<Widget> allWidgets, Widget parent, Node startNode) {
Item item = null;
LinkedPage linkedPage = null;
String id = null, label = null, icon = null, url = null;
String period = "", service = "", encoding = null;
String iconColor = null, labelColor = null, valueColor = null;
Type type = Type.Unknown;
float minValue = 0f, maxValue = 100f, step = 1f;
int refresh = 0, height = 0;
List<OpenHABLabeledValue> mappings = new ArrayList<>();
List<LabeledValue> mappings = new ArrayList<>();
List<Node> childWidgetNodes = new ArrayList<>();
if (startNode.hasChildNodes()) {
......@@ -171,8 +170,8 @@ public abstract class OpenHABWidget implements Parcelable {
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
switch (childNode.getNodeName()) {
case "item": item = OpenHABItem.fromXml(childNode); break;
case "linkedPage": linkedPage = OpenHABLinkedPage.fromXml(childNode); break;
case "item": item = Item.fromXml(childNode); break;
case "linkedPage": linkedPage = LinkedPage.fromXml(childNode); break;
case "widget": childWidgetNodes.add(childNode); break;
case "type": type = parseType(childNode.getTextContent()); break;
case "widgetId": id = childNode.getTextContent(); break;
......@@ -197,21 +196,29 @@ public abstract class OpenHABWidget implements Parcelable {
for (int k = 0; k < mappingChildNodes.getLength(); k++) {
Node mappingNode = mappingChildNodes.item(k);
switch (mappingNode.getNodeName()) {
case "command": mappingCommand = mappingNode.getTextContent(); break;
case "label": mappingLabel = mappingNode.getTextContent(); break;
case "command":
mappingCommand = mappingNode.getTextContent();
break;
case "label":
mappingLabel = mappingNode.getTextContent();
break;
default:
break;
}
}
OpenHABLabeledValue mapping = OpenHABLabeledValue.newBuilder()
LabeledValue mapping = LabeledValue.newBuilder()
.value(mappingCommand)
.label(mappingLabel)
.build();
mappings.add(mapping);
break;
default:
break;
}
}
}
OpenHABWidget widget = new AutoValue_OpenHABWidget.Builder()
Widget widget = new AutoValue_Widget.Builder()
.id(id)
.parentId(parent != null ? parent.id() : null)
.type(type)
......@@ -241,14 +248,14 @@ public abstract class OpenHABWidget implements Parcelable {
}
}
public static void parseJson(List<OpenHABWidget> allWidgets, OpenHABWidget parent,
public static void parseJson(List<Widget> allWidgets, Widget parent,
JSONObject widgetJson, String iconFormat) throws JSONException {
List<OpenHABLabeledValue> mappings = new ArrayList<>();
List<LabeledValue> mappings = new ArrayList<>();
if (widgetJson.has("mappings")) {
JSONArray mappingsJsonArray = widgetJson.getJSONArray("mappings");
for (int i = 0; i < mappingsJsonArray.length(); i++) {
JSONObject mappingObject = mappingsJsonArray.getJSONObject(i);
OpenHABLabeledValue mapping = OpenHABLabeledValue.newBuilder()
LabeledValue mapping = LabeledValue.newBuilder()
.value(mappingObject.getString("command"))
.label(mappingObject.getString("label"))
.build();
......@@ -256,15 +263,15 @@ public abstract class OpenHABWidget implements Parcelable {
}
}
OpenHABItem item = OpenHABItem.fromJson(widgetJson.optJSONObject("item"));
Item item = Item.fromJson(widgetJson.optJSONObject("item"));
Type type = parseType(widgetJson.getString("type"));
String icon = widgetJson.optString("icon", null);
OpenHABWidget widget = new AutoValue_OpenHABWidget.Builder()
Widget widget = new AutoValue_Widget.Builder()
.id(widgetJson.getString("widgetId"))
.parentId(parent != null ? parent.id() : null)
.item(item)
.linkedPage(OpenHABLinkedPage.fromJson(widgetJson.optJSONObject("linkedPage")))
.linkedPage(LinkedPage.fromJson(widgetJson.optJSONObject("linkedPage")))
.mappings(mappings)
.type(type)
.label(widgetJson.optString("label", null))
......@@ -295,9 +302,9 @@ public abstract class OpenHABWidget implements Parcelable {
}
}
public static OpenHABWidget updateFromEvent(OpenHABWidget source, JSONObject eventPayload,
public static Widget updateFromEvent(Widget source, JSONObject eventPayload,
String iconFormat) throws JSONException {
OpenHABItem item = OpenHABItem.updateFromEvent(
Item item = Item.updateFromEvent(
source.item(), eventPayload.getJSONObject("item"));
String iconPath = determineOH2IconPath(item, source.type(),
source.icon(), iconFormat, !source.mappings().isEmpty());
......@@ -308,11 +315,11 @@ public abstract class OpenHABWidget implements Parcelable {
.build();
}
private static String determineOH2IconPath(OpenHABItem item, Type type, String icon,
private static String determineOH2IconPath(Item item, Type type, String icon,
String iconFormat, boolean hasMappings) {
String itemState = item != null ? item.state() : null;
if (itemState != null) {
if (item.isOfTypeOrGroupType(OpenHABItem.Type.Color)) {
if (item.isOfTypeOrGroupType(Item.Type.Color)) {
// For items that control a color item fetch the correct icon
if (type == Type.Slider || (type == Type.Switch && !hasMappings)) {
try {
......@@ -323,13 +330,13 @@ public abstract class OpenHABWidget implements Parcelable {
} catch (Exception e) {
itemState = "OFF";
}
} else if (item.stateAsHSV() != null) {
int color = Color.HSVToColor(item.stateAsHSV());
} else if (item.stateAsHsv() != null) {
int color = Color.HSVToColor(item.stateAsHsv());
itemState = String.format(Locale.US, "#%02x%02x%02x",
Color.red(color), Color.green(color), Color.blue(color));
}
} else if (type == Type.Switch && !hasMappings
&& !item.isOfTypeOrGroupType(OpenHABItem.Type.Rollershutter)) {
&& !item.isOfTypeOrGroupType(Item.Type.Rollershutter)) {
// For switch items without mappings (just ON and OFF) that control a dimmer item
// and which are not ON or OFF already, set the state to "OFF" instead of 0
// or to "ON" to fetch the correct icon
......
......@@ -26,33 +26,36 @@ import java.util.List;
* It uses a sitemap page XML document to create a list of widgets
*/
public class OpenHABWidgetDataSource {
private static final String TAG = OpenHABWidgetDataSource.class.getSimpleName();
private final String iconFormat;
private List<OpenHABWidget> allWidgets = new ArrayList<>();
private String title;
private String id;
private String icon;
private String link;
public class WidgetDataSource {
private static final String TAG = WidgetDataSource.class.getSimpleName();
public OpenHABWidgetDataSource(String iconFormat) {
this.iconFormat = iconFormat;
private final String mIconFormat;
private final List<Widget> mAllWidgets = new ArrayList<>();
private String mTitle;
private String mId;
private String mIcon;
private String mLink;
public WidgetDataSource(String iconFormat) {
mIconFormat = iconFormat;
}
public void setSourceNode(Node rootNode) {
Log.i(TAG, "Loading new data");
if (rootNode == null)
if (rootNode == null) {
return;
}
if (rootNode.hasChildNodes()) {
NodeList childNodes = rootNode.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
switch (childNode.getNodeName()) {
case "widget": OpenHABWidget.parseXml(allWidgets, null, childNode); break;
case "title": title = childNode.getTextContent(); break;
case "id": id = childNode.getTextContent(); break;
case "icon": icon = childNode.getTextContent(); break;
case "link": link = childNode.getTextContent(); break;
case "widget": Widget.parseXml(mAllWidgets, null, childNode); break;
case "title": mTitle = childNode.getTextContent(); break;
case "id": mId = childNode.getTextContent(); break;
case "icon": mIcon = childNode.getTextContent(); break;
case "link": mLink = childNode.getTextContent(); break;
default: break;
}
}
}
......@@ -60,32 +63,33 @@ public class OpenHABWidgetDataSource {
public void setSourceJson(JSONObject jsonObject) {
Log.d(TAG, jsonObject.toString());
if (!jsonObject.has("widgets"))
if (!jsonObject.has("widgets")) {
return;
}
try {
JSONArray jsonWidgetArray = jsonObject.getJSONArray("widgets");
for (int i = 0; i < jsonWidgetArray.length(); i++) {
JSONObject widgetJson = jsonWidgetArray.getJSONObject(i);
OpenHABWidget.parseJson(allWidgets, null, widgetJson, iconFormat);
Widget.parseJson(mAllWidgets, null, widgetJson, mIconFormat);
}
title = jsonObject.optString("title", null);
id = jsonObject.optString("id", null);
icon = jsonObject.optString("icon", null);
link = jsonObject.optString("link", null);
mTitle = jsonObject.optString("title", null);
mId = jsonObject.optString("id", null);
mIcon = jsonObject.optString("icon", null);
mLink = jsonObject.optString("link", null);
} catch (JSONException e) {
Log.d(TAG, e.getMessage(), e);
}
}
public ArrayList<OpenHABWidget> getWidgets() {
ArrayList<OpenHABWidget> result = new ArrayList<OpenHABWidget>();
public ArrayList<Widget> getWidgets() {
ArrayList<Widget> result = new ArrayList<>();
HashSet<String> firstLevelWidgetIds = new HashSet<>();
for (OpenHABWidget widget : allWidgets) {
for (Widget widget : mAllWidgets) {
if (widget.parentId() == null) {
firstLevelWidgetIds.add(widget.id());
}
}
for (OpenHABWidget widget : allWidgets) {
for (Widget widget : mAllWidgets) {
String parentId = widget.parentId();
if (parentId == null || firstLevelWidgetIds.contains(parentId)) {
result.add(widget);
......@@ -95,27 +99,22 @@ public class OpenHABWidgetDataSource {
}
public String getTitle() {
String[] splitString;
if (title != null) {
splitString = title.split("\\[|\\]");
if (splitString.length > 0) {
return splitString[0];
} else {
return title;
}
if (mTitle != null) {
String[] splitString = mTitle.split("\\[|\\]");
return splitString.length > 0 ? splitString[0] : mTitle;
}
return "";
}
public String getId() {
return id;
return mId;
}
public String getIcon() {
return icon;
return mIcon;
}
public String getLink() {
return link;
return mLink;
}
}
......@@ -46,8 +46,6 @@ import static org.openhab.habdroid.util.Util.obfuscateString;
public class AboutActivity extends AppCompatActivity implements
FragmentManager.OnBackStackChangedListener {
private final static String TAG = AboutActivity.class.getSimpleName();
@Override
public void onCreate(Bundle savedInstanceState) {
Util.setActivityTheme(this);
......@@ -103,8 +101,8 @@ public class AboutActivity extends AppCompatActivity implements
}
public static class AboutMainFragment extends MaterialAboutFragment {
private final static String TAG = AboutMainFragment.class.getSimpleName();
private final static String URL_TO_GITHUB = "https://github.com/openhab/openhab-android";
private static final String TAG = AboutMainFragment.class.getSimpleName();
private static final String URL_TO_GITHUB = "https://github.com/openhab/openhab-android";
private ServerProperties mServerProperties;
private Connection mConnection;
......@@ -115,7 +113,9 @@ public class AboutActivity extends AppCompatActivity implements
mServerProperties = getArguments().getParcelable("serverProperties");
try {
mConnection = ConnectionFactory.getUsableConnection();
} catch (ConnectionException ignored) {}
} catch (ConnectionException ignored) {
// ignored
}
return super.onCreateView(inflater, container, savedInstanceState);
}
......@@ -140,30 +140,28 @@ public class AboutActivity extends AppCompatActivity implements
appCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_changelog)
.icon(R.drawable.ic_track_changes_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect(URL_TO_GITHUB + "/releases"))
.setOnClickAction(clickRedirect(URL_TO_GITHUB + "/releases"))
.build());
appCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_source_code)
.icon(R.drawable.ic_github_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect(URL_TO_GITHUB))
.setOnClickAction(clickRedirect(URL_TO_GITHUB))
.build());
appCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_issues)
.icon(R.drawable.ic_bug_report_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect(URL_TO_GITHUB + "/issues"))
.setOnClickAction(clickRedirect(URL_TO_GITHUB + "/issues"))
.build());
appCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_license_title)
.subText(R.string.about_license)
.icon(R.drawable.ic_account_balance_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect(URL_TO_GITHUB + "/blob/master/LICENSE"))
.setOnClickAction(clickRedirect(URL_TO_GITHUB + "/blob/master/LICENSE"))
.build());
appCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.title_activity_libraries)
.icon(R.drawable.ic_developer_mode_grey_24dp)
.setOnClickAction(new MaterialAboutItemOnClickAction() {
@Override
public void onClick() {
.setOnClickAction(() -> {
Fragment f = new LibsBuilder()
.withFields(R.string.class.getFields())
.withLicenseShown(true)
......@@ -177,13 +175,13 @@ public class AboutActivity extends AppCompatActivity implements
.setBreadCrumbTitle(R.string.title_activity_libraries)
.addToBackStack(null)
.commit();
}
})
.build());
appCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_privacy_policy)
.icon(R.drawable.ic_security_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect("https://www.openhabfoundation.org/privacy.html"))
.setOnClickAction(
clickRedirect("https://www.openhabfoundation.org/privacy.html"))
.build());
MaterialAboutCard.Builder ohServerCard = new MaterialAboutCard.Builder();
......@@ -237,22 +235,22 @@ public class AboutActivity extends AppCompatActivity implements
ohCommunityCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_docs)
.icon(R.drawable.ic_collections_bookmark_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect("https://www.openhab.org/docs/"))
.setOnClickAction(clickRedirect("https://www.openhab.org/docs/"))
.build());
ohCommunityCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_community_forum)
.icon(R.drawable.ic_forum_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect("https://community.openhab.org/"))
.setOnClickAction(clickRedirect("https://community.openhab.org/"))
.build());
ohCommunityCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_translation)
.icon(R.drawable.ic_language_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect("https://crowdin.com/profile/openhab-bot"))
.setOnClickAction(clickRedirect("https://crowdin.com/profile/openhab-bot"))
.build());
ohCommunityCard.addItem(new MaterialAboutActionItem.Builder()
.text(R.string.about_foundation)
.icon(R.drawable.ic_people_grey_24dp)
.setOnClickAction(MaterialAboutItemOnClickRedirect("https://www.openhabfoundation.org/"))
.setOnClickAction(clickRedirect("https://www.openhabfoundation.org/"))
.build());
return new MaterialAboutList.Builder()
......@@ -264,17 +262,14 @@ public class AboutActivity extends AppCompatActivity implements
@Override
protected int getTheme() {
return Util.getActivityThemeID(getActivity());
return Util.getActivityThemeId(getActivity());
}
private MaterialAboutItemOnClickAction MaterialAboutItemOnClickRedirect(final String url) {
return new MaterialAboutItemOnClickAction() {
@Override
public void onClick() {
private MaterialAboutItemOnClickAction clickRedirect(final String url) {
return () -> {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
};
}
......
......@@ -11,38 +11,40 @@
package org.openhab.habdroid.ui;
import android.util.Log;
import android.webkit.HttpAuthHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.HttpAuthHandler;
class AnchorWebViewClient extends WebViewClient {
private static final String TAG = AnchorWebViewClient.class.getSimpleName();
private String anchor = null;
private String username;
private String password;
private String mAnchor;
private String mUserName;
private String mPassword;
public AnchorWebViewClient(String url, String username, String password) {
this.username = username;
this.password = password;
mUserName = username;
mPassword = password;
int pos = url.lastIndexOf("#") + 1;
if (pos != 0 && pos < url.length()) {
this.anchor = url.substring(pos);
Log.d(TAG, "Found anchor " + anchor + " from url "+ url);
mAnchor = url.substring(pos);
Log.d(TAG, "Found anchor " + mAnchor + " from url " + url);
} else {
Log.d(TAG, "Did not find anchor from url " + url);
}
}
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
handler.proceed(this.username, this.password);
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
String host, String realm) {
handler.proceed(mUserName, mPassword);
}
@Override
public void onPageFinished(WebView view, String url) {
if (anchor != null && !anchor.isEmpty()) {
Log.d(TAG, "Now jumping to anchor " + anchor);
view.loadUrl("javascript:location.hash = '#" + anchor + "';");
if (mAnchor != null && !mAnchor.isEmpty()) {
Log.d(TAG, "Now jumping to anchor " + mAnchor);
view.loadUrl("javascript:location.hash = '#" + mAnchor + "';");
}
}
}
......@@ -11,6 +11,7 @@ package org.openhab.habdroid.ui;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
......@@ -23,14 +24,14 @@ import android.widget.TextView;
import org.openhab.habdroid.R;
import org.openhab.habdroid.core.connection.Connection;
import org.openhab.habdroid.core.connection.ConnectionFactory;
import org.openhab.habdroid.model.OpenHABNotification;
import org.openhab.habdroid.model.CloudNotification;
import org.openhab.habdroid.ui.widget.WidgetImageView;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class OpenHABNotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public class CloudNotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public interface LoadMoreListener {
void loadMoreItems();
}
......@@ -38,23 +39,21 @@ public class OpenHABNotificationAdapter extends RecyclerView.Adapter<RecyclerVie
private static final int VIEW_TYPE_NOTIFICATION = 0;
private static final int VIEW_TYPE_LOADING = 1;
private final ArrayList<OpenHABNotification> mItems = new ArrayList<>();
private final ArrayList<CloudNotification> mItems = new ArrayList<>();
private final LayoutInflater mInflater;
private final Context mContext;
private final LoadMoreListener mLoadMoreListener;
private boolean mHasMoreItems;
private boolean mWaitingForMoreData;
private int mHighlightedPosition = -1;
public OpenHABNotificationAdapter(Context context, LoadMoreListener loadMoreListener) {
public CloudNotificationAdapter(Context context, LoadMoreListener loadMoreListener) {
super();
mContext = context;
mInflater = LayoutInflater.from(context);
mLoadMoreListener = loadMoreListener;
mHasMoreItems = false;
}
public void addLoadedItems(List<OpenHABNotification> items, boolean hasMoreItems) {
public void addLoadedItems(List<CloudNotification> items, boolean hasMoreItems) {
mItems.addAll(items);
mHasMoreItems = hasMoreItems;
mWaitingForMoreData = false;
......@@ -92,6 +91,7 @@ public class OpenHABNotificationAdapter extends RecyclerView.Adapter<RecyclerVie
return position == mItems.size() ? VIEW_TYPE_LOADING : VIEW_TYPE_NOTIFICATION;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_LOADING) {
......@@ -144,7 +144,7 @@ public class OpenHABNotificationAdapter extends RecyclerView.Adapter<RecyclerVie
mIconView = itemView.findViewById(R.id.notificationImage);
}
public void bind(OpenHABNotification notification) {
public void bind(CloudNotification notification) {
mCreatedView.setText(DateUtils.getRelativeDateTimeString(mCreatedView.getContext(),
notification.createdTimestamp(),
DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, 0));
......
......@@ -10,6 +10,7 @@
package org.openhab.habdroid.ui;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
......@@ -23,13 +24,17 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.openhab.habdroid.R;
import org.openhab.habdroid.core.connection.Connection;
import org.openhab.habdroid.core.connection.ConnectionFactory;
import org.openhab.habdroid.model.OpenHABNotification;
import org.openhab.habdroid.model.CloudNotification;
import org.openhab.habdroid.ui.widget.DividerItemDecoration;
import org.openhab.habdroid.util.AsyncHttpClient;
import org.openhab.habdroid.util.Util;
......@@ -37,22 +42,18 @@ import org.openhab.habdroid.util.Util;
import java.util.ArrayList;
import java.util.Locale;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.Request;
public class OpenHABNotificationFragment extends Fragment implements
public class CloudNotificationListFragment extends Fragment implements
View.OnClickListener, SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = OpenHABNotificationFragment.class.getSimpleName();
private static final String TAG = CloudNotificationListFragment.class.getSimpleName();
private static final int PAGE_SIZE = 20;
private OpenHABMainActivity mActivity;
private MainActivity mActivity;
// keeps track of current request to cancel it in onPause
private Call mRequestHandle;
private OpenHABNotificationAdapter mNotificationAdapter;
private CloudNotificationAdapter mNotificationAdapter;
private String mInitiallyHighlightedId;
private RecyclerView mRecyclerView;
......@@ -64,8 +65,8 @@ public class OpenHABNotificationFragment extends Fragment implements
private View mRetryButton;
private int mLoadOffset;
public static OpenHABNotificationFragment newInstance(@Nullable String highlightedId) {
OpenHABNotificationFragment f = new OpenHABNotificationFragment();
public static CloudNotificationListFragment newInstance(@Nullable String highlightedId) {
CloudNotificationListFragment f = new CloudNotificationListFragment();
Bundle args = new Bundle();
args.putString("highlightedId", highlightedId);
f.setArguments(args);
......@@ -76,11 +77,11 @@ public class OpenHABNotificationFragment extends Fragment implements
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public OpenHABNotificationFragment() {
public CloudNotificationListFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.i(TAG, "onCreateView");
......@@ -101,8 +102,8 @@ public class OpenHABNotificationFragment extends Fragment implements
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = (OpenHABMainActivity) getActivity();
mNotificationAdapter = new OpenHABNotificationAdapter(mActivity,
mActivity = (MainActivity) getActivity();
mNotificationAdapter = new CloudNotificationAdapter(mActivity,
() -> loadNotifications(false));
mLayoutManager = new LinearLayoutManager(mActivity);
......@@ -167,15 +168,16 @@ public class OpenHABNotificationFragment extends Fragment implements
// we skip that additional effort.
final String url = String.format(Locale.US, "api/v1/notifications?limit=%d&skip=%d",
PAGE_SIZE, mLoadOffset);
mRequestHandle = conn.getAsyncHttpClient().get(url, new AsyncHttpClient.StringResponseHandler() {
final AsyncHttpClient client = conn.getAsyncHttpClient();
mRequestHandle = client.get(url, new AsyncHttpClient.StringResponseHandler() {
@Override
public void onSuccess(String responseBody, Headers headers) {
try {
ArrayList<OpenHABNotification> items = new ArrayList<>();
ArrayList<CloudNotification> items = new ArrayList<>();
JSONArray jsonArray = new JSONArray(responseBody);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject sitemapJson = jsonArray.getJSONObject(i);
items.add(OpenHABNotification.fromJson(sitemapJson));
items.add(CloudNotification.fromJson(sitemapJson));
}
Log.d(TAG, "Notifications request success, got " + items.size() + " items");
mLoadOffset += items.size();
......
package org.openhab.habdroid.ui;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
......@@ -13,33 +14,27 @@ import com.github.paolorotolo.appintro.AppIntroFragment;
import org.openhab.habdroid.R;
public class IntroActivity extends AppIntro {
int colorOpenHABOrange;
int colorOpenHABOrangeDark;
int colorGrey;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
colorOpenHABOrange = ContextCompat.getColor(this, R.color.openhab_orange);
colorOpenHABOrangeDark = ContextCompat.getColor(this, R.color.openhab_orange_dark);
colorGrey = ContextCompat.getColor(this, R.color.grey_300);
// Add slides
addOHSlide(R.string.intro_welcome,
addSlide(R.string.intro_welcome,
R.string.intro_whatis,
R.drawable.ic_openhab_appicon_340dp);
addOHSlide(R.string.intro_themes,
addSlide(R.string.intro_themes,
R.string.intro_themes_description,
R.drawable.ic_color_lens_orange_340dp);
addOHSlide(R.string.mainmenu_openhab_voice_recognition,
addSlide(R.string.mainmenu_openhab_voice_recognition,
R.string.intro_voice_description,
R.drawable.ic_mic_orange_340dp);
addOHSlide(R.string.intro_nfc,
addSlide(R.string.intro_nfc,
R.string.intro_nfc_description,
R.drawable.ic_nfc_orange_340dp);
// Change bar color
setBarColor(colorOpenHABOrange);
setSeparatorColor(colorOpenHABOrangeDark);
setBarColor(ContextCompat.getColor(this, R.color.openhab_orange));
setSeparatorColor(ContextCompat.getColor(this, R.color.openhab_orange_dark));
}
/**
......@@ -68,21 +63,19 @@ public class IntroActivity extends AppIntro {
* @param description
* @param imageDrawable
*/
private void addOHSlide(@StringRes int title, @StringRes int description,
private void addSlide(@StringRes int title, @StringRes int description,
@DrawableRes int imageDrawable) {
@ColorInt int greyColor = ContextCompat.getColor(this, R.color.grey_300);
@ColorInt int blackColor = ContextCompat.getColor(this, R.color.black);
addSlide(AppIntroFragment.newInstance(getString(title),
// Title font: null => default
null,
null, // Title font: null => default
getString(description),
// Description font: null => default
null,
null, // Description font: null => default
imageDrawable,
// Background color
colorGrey,
// Title color
ContextCompat.getColor(getApplicationContext(), R.color.black),
greyColor, // Background color
blackColor, // Title color
// Description color
ContextCompat.getColor(getApplicationContext(), R.color.black)));
ContextCompat.getColor(this, R.color.black))); // Description color
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment