From 1e809e8e65173eb1495180fd8f1d05af3367bf5c Mon Sep 17 00:00:00 2001
From: mastermichi <68911754+mastermichi@users.noreply.github.com>
Date: Sun, 6 Nov 2022 21:04:22 +0100
Subject: [PATCH] Hue Bridge
---
build.gradle | 1 +
res/drawable/ic_hue_bridge.xml | 39 +++
res/drawable/ic_hue_bridge_connect.xml | 34 +++
res/layout/hue_connect_preferences.xml | 24 ++
res/xml-v14/preferences_about.xml | 11 +
res/xml-v14/preferences_smarthome.xml | 23 +-
.../HueApi/HueBridgeSearch.java | 52 ++++
.../HueApi/models/HueViewModel.java | 242 ++++++++++++++++++
.../SmartHomePreferenceFragment.java | 210 ++++++++++++++-
.../nightdream/ui/HueConnectPreference.java | 39 +++
.../HueConnectPreferenceFragmentCompat.java | 99 +++++++
11 files changed, 769 insertions(+), 5 deletions(-)
create mode 100644 res/drawable/ic_hue_bridge.xml
create mode 100644 res/drawable/ic_hue_bridge_connect.xml
create mode 100644 res/layout/hue_connect_preferences.xml
create mode 100644 src/com/firebirdberlin/HueApi/HueBridgeSearch.java
create mode 100644 src/com/firebirdberlin/HueApi/models/HueViewModel.java
create mode 100644 src/com/firebirdberlin/nightdream/ui/HueConnectPreference.java
create mode 100644 src/com/firebirdberlin/nightdream/ui/HueConnectPreferenceFragmentCompat.java
diff --git a/build.gradle b/build.gradle
index 32744e96..b75ff4aa 100644
--- a/build.gradle
+++ b/build.gradle
@@ -56,6 +56,7 @@ dependencies {
implementation 'androidx.work:work-runtime-ktx:2.7.1'
implementation 'androidx.work:work-multiprocess:2.7.1'
implementation 'com.prof18.rssparser:rssparser:4.0.2'
+ implementation 'io.github.zeroone3010:yetanotherhueapi:2.7.0'
// https://developer.android.com/studio/build/multidex
diff --git a/res/drawable/ic_hue_bridge.xml b/res/drawable/ic_hue_bridge.xml
new file mode 100644
index 00000000..d0f03c77
--- /dev/null
+++ b/res/drawable/ic_hue_bridge.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
diff --git a/res/drawable/ic_hue_bridge_connect.xml b/res/drawable/ic_hue_bridge_connect.xml
new file mode 100644
index 00000000..406c8786
--- /dev/null
+++ b/res/drawable/ic_hue_bridge_connect.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
diff --git a/res/layout/hue_connect_preferences.xml b/res/layout/hue_connect_preferences.xml
new file mode 100644
index 00000000..bf9b1fed
--- /dev/null
+++ b/res/layout/hue_connect_preferences.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/xml-v14/preferences_about.xml b/res/xml-v14/preferences_about.xml
index fdb5de45..f7f1358f 100644
--- a/res/xml-v14/preferences_about.xml
+++ b/res/xml-v14/preferences_about.xml
@@ -307,6 +307,17 @@ vi - Phong Nguyen"/>
/>
+
+
+
+
-
+
+
+
+
+
+
diff --git a/src/com/firebirdberlin/HueApi/HueBridgeSearch.java b/src/com/firebirdberlin/HueApi/HueBridgeSearch.java
new file mode 100644
index 00000000..cf4d6121
--- /dev/null
+++ b/src/com/firebirdberlin/HueApi/HueBridgeSearch.java
@@ -0,0 +1,52 @@
+package com.firebirdberlin.HueApi;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.work.Data;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import io.github.zeroone3010.yahueapi.discovery.HueBridgeDiscoveryService;
+
+public class HueBridgeSearch extends Worker {
+ private static final String TAG = "HueBridgeSearch";
+
+ public HueBridgeSearch(@NonNull Context context, @NonNull WorkerParameters params) {
+ super(context, params);
+ }
+
+ @NonNull
+ @Override
+ public Result doWork() {
+ Log.d(TAG, "HueBridgeSearch doWork()");
+
+ Future> bridgesFuture = new HueBridgeDiscoveryService()
+ .discoverBridges(bridge -> Log.d(TAG, "ppt Bridge found: " + bridge));
+ final List bridges;
+ try {
+ bridges = bridgesFuture.get();
+ if (!bridges.isEmpty()) {
+ final String bridgeIp = bridges.get(0).getIp();
+ Log.d(TAG, "Bridge found at " + bridgeIp);
+ // Then follow the code snippets below under the "Once you have a Bridge IP address" header
+ Data myData = new Data.Builder()
+ .putString("bridgeIP", bridgeIp)
+ .build();
+ return Result.success(myData);
+ }
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ return Result.failure();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ return Result.failure();
+ }
+ return Result.success();
+ }
+}
diff --git a/src/com/firebirdberlin/HueApi/models/HueViewModel.java b/src/com/firebirdberlin/HueApi/models/HueViewModel.java
new file mode 100644
index 00000000..2d0e384b
--- /dev/null
+++ b/src/com/firebirdberlin/HueApi/models/HueViewModel.java
@@ -0,0 +1,242 @@
+package com.firebirdberlin.HueApi.models;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.NetworkOnMainThreadException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelStoreOwner;
+import androidx.work.Constraints;
+import androidx.work.ExistingWorkPolicy;
+import androidx.work.NetworkType;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
+
+import com.firebirdberlin.nightdream.Utility;
+import com.firebirdberlin.HueApi.HueBridgeSearch;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import io.github.zeroone3010.yahueapi.Hue;
+import io.github.zeroone3010.yahueapi.TrustEverythingManager;
+
+
+public class HueViewModel extends ViewModel {
+ private static final String TAG = "HueViewModel";
+
+ private final MutableLiveData hueIPLiveData = new MutableLiveData<>();
+ private static MutableLiveData hueKeyLiveData = new MutableLiveData<>();
+ private static ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ private void findHueBridge(Context context, LifecycleOwner lifecycleOwner) {
+ Log.d(TAG, "findHueBridge()");
+
+ //return no LAN
+ if (!Utility.hasNetworkConnection(context)) {
+ Log.e(TAG, "findHueBridge() no Network Connection");
+ hueIPLiveData.postValue("Error:No Network connection");
+ return;
+ }
+
+ //return IP already found
+ if (hueIPLiveData.getValue() != null && !hueIPLiveData.getValue().isEmpty() && !hueIPLiveData.getValue().contains("Error")) {
+ return;
+ }
+
+ Constraints constraints =
+ new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build();
+
+ OneTimeWorkRequest getHueBridgeIP =
+ new OneTimeWorkRequest.Builder(
+ HueBridgeSearch.class)
+ .addTag(TAG)
+ .setConstraints(constraints)
+ .build();
+
+ WorkManager manager = WorkManager.getInstance(context);
+ manager.enqueueUniqueWork(TAG, ExistingWorkPolicy.KEEP, getHueBridgeIP);
+
+ WorkManager.getInstance(context).getWorkInfoByIdLiveData(getHueBridgeIP.getId())
+ .observe(lifecycleOwner, info -> {
+ if (info != null && info.getState().isFinished()) {
+ Log.d(TAG, "findHueBridge() onChanged");
+ manager.getWorkInfoByIdLiveData(getHueBridgeIP.getId()).removeObservers(lifecycleOwner);
+ String myResult = info.getOutputData().getString("bridgeIP");
+ if (myResult == null){
+ hueIPLiveData.setValue("");
+ }else {
+ hueIPLiveData.setValue(myResult);
+ }
+ }
+ });
+ }
+
+ private void findHueKey(Context context, String bridgeIP) {
+ Log.d(TAG, "findHueKey() bridgeIP: " + bridgeIP);
+
+ if (!Utility.hasNetworkConnection(context)) {
+ Log.e(TAG, "findHueKey() no Network Connection");
+ hueKeyLiveData.setValue("Error:No Network connection");
+ } else {
+ if (executor.isShutdown()) {
+ executor = Executors.newSingleThreadExecutor();
+ }
+
+ executor.execute(() -> { //background thread
+ Log.d(TAG, "findHueKey() executor");
+ final String appName = "nightdream"; // Fill in the name of your application
+ final CompletableFuture apiKey = Hue.hueBridgeConnectionBuilder(bridgeIP).initializeApiConnection(appName);
+ String key;
+
+ // Push the button on your Hue Bridge to resolve the apiKey future:
+ try {
+ key = apiKey.get();
+ Log.d(TAG, "findHueKey() Store this API key for future use: " + key);
+ String finalKey = key;
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(() -> { //like onPostExecute()
+ if (!finalKey.isEmpty()) {
+ hueKeyLiveData.postValue(finalKey);
+ Log.d(TAG, "findHueKey() executor after: " + Hue.hueBridgeConnectionBuilder(bridgeIP).initializeApiConnection(appName).isDone());
+ testHueConnection(bridgeIP, finalKey);
+ }
+ apiKey.cancel(true);
+ executor.shutdown();
+ });
+ } catch (ExecutionException e) {
+ Log.e(TAG, "findHueKey() ExecutionException: " + e.getMessage());
+ handleHueApiException(e.getMessage());
+ apiKey.cancel(true);
+ executor.shutdown();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "findHueKey() InterruptedException: " + e.toString());
+ handleHueApiException(e.getMessage());
+ apiKey.cancel(true);
+ executor.shutdown();
+ }
+ });
+ }
+ }
+
+ private void handleHueApiException(String exception) {
+ if (exception != null) {
+ String[] splitStr = exception.split(":");
+ Log.e(TAG, "handleHueApiException() Error: " + splitStr[splitStr.length - 1].trim());
+ hueKeyLiveData.postValue("Error:" + splitStr[splitStr.length - 1].trim());
+ } else {
+ hueKeyLiveData.postValue("Error:unknown");
+ }
+ }
+
+ private MutableLiveData getHueIP() {
+ return hueIPLiveData;
+ }
+
+ private MutableLiveData getHueKey() {
+ return hueKeyLiveData;
+ }
+
+ public static void stopExecutor() {
+ Log.d(TAG, "stopExecutor()");
+ executor.shutdownNow();
+ }
+
+ public static void observeIP(Context context, LifecycleOwner lifecycleOwner, @NonNull Observer observer) {
+ HueViewModel model = new ViewModelProvider((ViewModelStoreOwner) context).get(HueViewModel.class);
+ model.findHueBridge(context, lifecycleOwner);
+ model.getHueIP().observe(lifecycleOwner, observer);
+ }
+
+ public static void observeKey(Context context, LifecycleOwner lifecycleOwner, String BridgeIP, @NonNull Observer observer) {
+ hueKeyLiveData = new MutableLiveData<>();
+ HueViewModel model = new ViewModelProvider((ViewModelStoreOwner) context).get(HueViewModel.class);
+ model.findHueKey(context, BridgeIP);
+ LiveDataUtil.observeOnce(model.getHueKey(), observer);
+ }
+
+ public static boolean testHueIP(String bridgeIP) {
+ Log.d(TAG, "testHueIP (" + bridgeIP + ")");
+ final AtomicBoolean b = new AtomicBoolean(false);
+
+ Thread thread = new Thread(() -> {
+ try {
+ TrustEverythingManager.trustAllSslConnectionsByDisablingCertificateVerification();
+ HttpURLConnection urlConnection = (HttpURLConnection) new URL("https://" + bridgeIP + "/api/config").openConnection();
+ int responseCode = urlConnection.getResponseCode();
+ Log.d(TAG, "testHueIP(): " + responseCode);
+ if (HttpURLConnection.HTTP_OK == responseCode){
+ b.set(true);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "testHueIP(): " + e.toString());
+ b.set(false);
+ }
+ });
+
+ thread.start();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return b.get();
+ }
+
+ public static boolean testHueConnection(String bridgeIP, String apiKey) {
+ Log.d(TAG, "testHueConnection (" + bridgeIP + "," + apiKey + ")");
+ final AtomicBoolean b = new AtomicBoolean(false);
+ final Hue hue = new Hue(bridgeIP, apiKey);
+
+ Thread thread = new Thread(() -> {
+ try {
+ try {
+ hue.getAllLights();
+ b.set(true);
+ Log.d(TAG, "testHueConnection() true");
+ } catch (NetworkOnMainThreadException e) {
+ Log.d(TAG, "testHueConnection() failed: " + e);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+
+ thread.start();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return b.get();
+ }
+
+ private static class LiveDataUtil {
+ public static void observeOnce(final LiveData liveData, final Observer observer) {
+ liveData.observeForever(new Observer() {
+ @Override
+ public void onChanged(T t) {
+ liveData.removeObserver(this);
+ observer.onChanged(t);
+ }
+ });
+ }
+ }
+
+}
diff --git a/src/com/firebirdberlin/nightdream/SmartHomePreferenceFragment.java b/src/com/firebirdberlin/nightdream/SmartHomePreferenceFragment.java
index 896544a1..7f08fc04 100644
--- a/src/com/firebirdberlin/nightdream/SmartHomePreferenceFragment.java
+++ b/src/com/firebirdberlin/nightdream/SmartHomePreferenceFragment.java
@@ -1,22 +1,28 @@
package com.firebirdberlin.nightdream;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
+import android.util.Log;
import android.widget.EditText;
import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentResultListener;
+import androidx.fragment.app.FragmentTransaction;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference.SummaryProvider;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
+import com.firebirdberlin.HueApi.models.HueViewModel;
+import com.firebirdberlin.nightdream.ui.HueConnectPreferenceFragmentCompat;
+import com.firebirdberlin.nightdream.ui.HueConnectPreference;
public class SmartHomePreferenceFragment extends PreferenceFragmentCompat {
public static final String PREFS_KEY = "NightDream preferences";
+ public static final String TAG = "SmartHomePrefFragment";
Settings settings = null;
@@ -24,11 +30,16 @@ public class SmartHomePreferenceFragment extends PreferenceFragmentCompat {
new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ Log.d(TAG, "onSharedPreferenceChanged: " + key);
+ switch (key) {
+ case "switchHue":
+ connectToHueBridge(sharedPreferences);
+ break;
+ }
}
};
-
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
getPreferenceManager().setSharedPreferencesName(PREFS_KEY);
@@ -67,6 +78,8 @@ public void onBindEditText(@NonNull final EditText editText) {
}
);
}
+
+ connectToHueBridge(prefs);
}
private void showPreference(String key, boolean visible) {
@@ -75,4 +88,193 @@ private void showPreference(String key, boolean visible) {
preference.setVisible(visible);
}
}
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Log.d(TAG, "onCreate()");
+ super.onCreate(savedInstanceState);
+
+ getParentFragmentManager().setFragmentResultListener("hueKey", this, new FragmentResultListener() {
+ @Override
+ public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) {
+ SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+
+ // We use a String here, but any type that can be put in a Bundle is supported
+ String hueKey = bundle.getString("hueKey");
+ Log.d(TAG, "onCreate() setFragmentResultListener: " + hueKey);
+
+ // Do something with the result
+
+ if (hueKey.contains("Error")) {
+ handleHueError("connectHue", hueKey);
+ } else {
+ Log.d(TAG, "onCreate() Key found");
+ //Key found
+ if (prefs != null) {
+ testHueKey(prefs.getString("hueBridgeIP", ""), hueKey);
+ }
+ }
+ }
+ });
+ }
+
+ private void connectToHueBridge(SharedPreferences prefs) {
+ Log.d(TAG, "connectToHueBridge()");
+ Preference switchHuePreference = findPreference("switchHue");
+ Preference hueKeyPreference = findPreference("connectHue");
+
+ if (switchHuePreference != null) {
+ boolean on = prefs.getBoolean("switchHue", false);
+ Log.d(TAG, "connectToHueBridge() enable:" + on);
+
+ if (on) {
+ //return no Network connection
+ if (getContext() != null && !Utility.hasNetworkConnection(getContext())) {
+ Log.e(TAG, "connectToHueBridge() no Network Connection");
+ handleHueError("switchHue", "No Network connection");
+ return;
+ }
+
+ switchHuePreference.setSummary("suche nach Hue Bridge");
+ Log.d(TAG, "connectToHueBridge() prefs hueBridgeIP: " + prefs.getString("hueBridgeIP", "No IP"));
+ String hueBridgeIP = prefs.getString("hueBridgeIP", "");
+
+ if (hueBridgeIP.isEmpty() || !HueViewModel.testHueIP(hueBridgeIP)) {
+ Log.d(TAG, "connectToHueBridge() no working hueBridgeIP in prefs");
+ HueViewModel.observeIP(getContext(), getViewLifecycleOwner(), bridgeIP -> {
+ Log.d(TAG, "connectToHueBridge() found hueBridgeIP: " + bridgeIP);
+
+ //Save IP
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("hueBridgeIP", bridgeIP);
+ editor.apply();
+
+ boolean showIp = prefs.getBoolean("switchHue", false);
+ if (showIp && !bridgeIP.isEmpty()) {
+ if (bridgeIP.contains("Error")) {
+ handleHueError("switchHue", bridgeIP);
+ } else {
+ switchHuePreference.setSummary(bridgeIP);
+ enablePreference("connectHue", true);
+
+ String hueKey = prefs.getString("hueKey", "");
+ if (hueKey.isEmpty()) {
+ Log.d(TAG, "connectToHueBridge() empty hueKey in prefs");
+ if (hueKeyPreference != null) {
+ hueKeyPreference.setSummary("not connected");
+ }
+ showHueDialog(prefs, "connectHue");
+ } else {
+ Log.d(TAG, "connectToHueBridge() found hueKey in prefs: " + hueKey);
+ testHueKey(bridgeIP, hueKey);
+ }
+ }
+ }
+ });
+ } else {
+ //bridge IP found in prefs
+ Log.d(TAG, "connectToHueBridge() hueBridgeIP found in prefs: "+hueBridgeIP);
+ switchHuePreference.setSummary(hueBridgeIP);
+ enablePreference("connectHue", true);
+ String hueKey = prefs.getString("hueKey", "");
+ if (hueKey.isEmpty()) {
+ Log.d(TAG, "connectToHueBridge() empty hueKey in prefs");
+ if (hueKeyPreference != null) {
+ hueKeyPreference.setSummary("not connected");
+ }
+ } else {
+ Log.d(TAG, "connectToHueBridge() found hueKey in prefs: " + hueKey);
+ testHueKey(hueBridgeIP, hueKey);
+ }
+ }
+ } else {
+ switchHuePreference.setSummary("");
+ if (hueKeyPreference != null) {
+ hueKeyPreference.setSummary("");
+ }
+ enablePreference("connectHue", false);
+ switchHuePreference.setIcon(R.drawable.ic_hue_bridge_connect);
+ }
+ }
+ }
+
+ private void testHueKey(String hueBridgeIP, String hueKey) {
+ SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ Preference switchHuePreference = findPreference("switchHue");
+ Preference switchHueKeyPreference = findPreference("connectHue");
+
+ if (prefs != null) {
+ if (HueViewModel.testHueConnection(hueBridgeIP, hueKey)) {
+ Log.d(TAG, "onCreate() testHueConnection ok");
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("hueKey", hueKey);
+ editor.apply();
+
+ if (switchHuePreference != null) {
+ switchHuePreference.setIcon(R.drawable.ic_hue_bridge);
+ }
+
+ if (switchHueKeyPreference != null) {
+ switchHueKeyPreference.setSummary("Connected");
+ }
+ } else {
+ Log.e(TAG, "onCreate() testHueConnection failed");
+ handleHueError("connectHue", "Can not connect to Hue Bridge");
+ }
+ }
+ }
+
+ private void showHueDialog(SharedPreferences prefs, String key) {
+ Log.d(TAG, "showHueDialog");
+ FragmentTransaction ft = getParentFragmentManager().beginTransaction();
+ Fragment prev = getParentFragmentManager().findFragmentByTag("HueDialog");
+ if (prev != null) {
+ ft.remove(prev);
+ }
+ ft.addToBackStack(null);
+ DialogFragment dialogFragment = HueConnectPreferenceFragmentCompat
+ .newInstance(key, prefs.getString("hueBridgeIP", ""));
+
+ dialogFragment.setTargetFragment(this, 0);
+ dialogFragment.show(ft, "HueDialog");
+ }
+
+ private void handleHueError(String huePreferenceKey, String errorMessage) {
+ Log.d(TAG, "handleHueError() : "+errorMessage);
+ Preference huePreference = findPreference(huePreferenceKey);
+ if (huePreference != null) {
+ String[] splitStr = errorMessage.split(":");
+ Log.e(TAG, "handleHueError(): " + splitStr[splitStr.length - 1].trim());
+ switch (splitStr[splitStr.length - 1].trim()) {
+ case "No Network connection":
+ case "Host unreachable":
+ case "link button not pressed":
+ case "Can not connect to Hue Bridge":
+ case "No address associated with hostname":
+ huePreference.setSummary(splitStr[splitStr.length - 1].trim());
+ break;
+ default:
+ huePreference.setSummary("Unknown Error");
+ break;
+ }
+ }
+ }
+
+ private void enablePreference(String key, boolean on) {
+ Preference preference = findPreference(key);
+ if (preference != null) {
+ Log.d(TAG, "enablePreference(): " + preference.getKey());
+ preference.setEnabled(on);
+ } else {
+ Log.w(TAG, "WARNING: preference " + key + " not found.");
+ }
+ }
+
+ @Override
+ public void onDisplayPreferenceDialog(@NonNull Preference preference) {
+ if (preference instanceof HueConnectPreference) {
+ Log.d(TAG, "onDisplayPreferenceDialog() preference instanceof HueConnectPreference");
+ showHueDialog(getPreferenceManager().getSharedPreferences(), preference.getKey());
+ } else super.onDisplayPreferenceDialog(preference);
+ }
}
diff --git a/src/com/firebirdberlin/nightdream/ui/HueConnectPreference.java b/src/com/firebirdberlin/nightdream/ui/HueConnectPreference.java
new file mode 100644
index 00000000..fa70c530
--- /dev/null
+++ b/src/com/firebirdberlin/nightdream/ui/HueConnectPreference.java
@@ -0,0 +1,39 @@
+package com.firebirdberlin.nightdream.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import androidx.preference.DialogPreference;
+
+import com.firebirdberlin.nightdream.R;
+
+public class HueConnectPreference extends DialogPreference {
+ private static final String TAG = "HueConnectPreference";
+
+ public HueConnectPreference(Context context) {
+ this(context, null);
+ }
+
+ public HueConnectPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.dialogPreferenceStyle);
+ }
+
+ public HueConnectPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, defStyleAttr);
+ }
+
+ public HueConnectPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ Log.d(TAG, "HueConnectPreference()");
+
+ // Do custom stuff here, read attributes etc.
+ setPositiveButtonText(null);
+ setNegativeButtonText(android.R.string.cancel);
+ }
+
+ @Override
+ public int getDialogLayoutResource() {
+ return R.layout.hue_connect_preferences;
+ }
+}
diff --git a/src/com/firebirdberlin/nightdream/ui/HueConnectPreferenceFragmentCompat.java b/src/com/firebirdberlin/nightdream/ui/HueConnectPreferenceFragmentCompat.java
new file mode 100644
index 00000000..b5517702
--- /dev/null
+++ b/src/com/firebirdberlin/nightdream/ui/HueConnectPreferenceFragmentCompat.java
@@ -0,0 +1,99 @@
+package com.firebirdberlin.nightdream.ui;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceDialogFragmentCompat;
+
+import com.firebirdberlin.nightdream.R;
+import com.firebirdberlin.HueApi.models.HueViewModel;
+
+public class HueConnectPreferenceFragmentCompat extends PreferenceDialogFragmentCompat {
+ private static final String TAG = "HueConnectPrefFragmentC";
+ private static String bridgeIP;
+ private boolean isDismissible = false;
+
+ public static HueConnectPreferenceFragmentCompat newInstance(String key, String bridge_IP) {
+ final HueConnectPreferenceFragmentCompat
+ fragment = new HueConnectPreferenceFragmentCompat();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+
+ bridgeIP = bridge_IP;
+
+ return fragment;
+ }
+
+ @Override
+ protected void onBindDialogView(@NonNull View view) {
+ super.onBindDialogView(view);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ Log.d(TAG, "onCreateView()");
+
+ HueViewModel.observeKey(getContext(), getViewLifecycleOwner(), bridgeIP, Key -> {
+
+ Log.d(TAG, "onCreateView() found Key: " + Key);
+
+ if (!Key.isEmpty()) {
+ setFragmentResult(Key);
+ dismissAllowingStateLoss();
+ } else {
+ Log.d(TAG, "onCreateView() Key empty");
+ }
+
+ });
+
+ return inflater.inflate(R.layout.hue_connect_preferences, container, false);
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ Log.d(TAG, "onDialogClosed(): " + positiveResult);
+ HueViewModel.stopExecutor();
+ }
+
+ @Override
+ public void dismiss() {
+ Log.d(TAG, "dismiss()");
+ try {
+ isDismissible = true;
+ super.dismiss();
+ Log.d(TAG, "dismiss() Dialog dismissed!");
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "dismiss() error: " + e.toString());
+ }
+ }
+
+ @Override
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ Log.d(TAG, "onDismiss()");
+ if (isDismissible) {
+ super.onDismiss(dialog);
+ }
+ }
+
+ private void setFragmentResult(String hueKey) {
+ if (isAdded()) {
+ Bundle result = new Bundle();
+ result.putString("hueKey", hueKey);
+ getParentFragmentManager().setFragmentResult("hueKey", result);
+ }
+ }
+
+}