diff --git a/app/src/main/java/de/weseng/wifiweatherstation/MainNativeActivity.java b/app/src/main/java/de/weseng/wifiweatherstation/MainNativeActivity.java index b9d7519..a115ee8 100644 --- a/app/src/main/java/de/weseng/wifiweatherstation/MainNativeActivity.java +++ b/app/src/main/java/de/weseng/wifiweatherstation/MainNativeActivity.java @@ -1,12 +1,15 @@ package de.weseng.wifiweatherstation; +import android.annotation.TargetApi; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.os.AsyncTask; +import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; +import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -20,11 +23,16 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import static de.weseng.wifiweatherstation.SettingsActivity.PREFS_NAME; public class MainNativeActivity extends AppCompatActivity { - private int pDialogLockCount = 0; + private final String TAG = getClass().getSimpleName(); + private int pBarLockCount = 0; + // In Android 4.4 (API 19) AsyncTask MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; (maximum number of threads) + ArrayList> endlessTasks = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -46,17 +54,84 @@ public class MainNativeActivity extends AppCompatActivity { if (urlGlobal != null && urlGlobal.length() > 0) urlPre = urlGlobal.substring(urlGlobal.length() - 1).equals("/") ? urlGlobal : urlGlobal + "/"; } - //Toast.makeText(getApplicationContext(), urlPre, Toast.LENGTH_LONG).show(); - new GetData(R.id.textViewTemperatureValue1, R.id.textViewHumidityValue1).execute( + executeAsyncTask(new GetData(R.id.textViewTemperatureValue1, R.id.textViewHumidityValue1), urlPre + "api.php?host=192.168.1.71&last"); - new GetData(R.id.textViewTemperatureValue2, R.id.textViewHumidityValue2).execute( + executeAsyncTask(new GetData(R.id.textViewTemperatureValue2, R.id.textViewHumidityValue2), urlPre + "api.php?host=192.168.1.72&last"); - new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3).execute( + executeAsyncTask(new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3), urlPre + "api.php?host=192.168.1.73&last"); + endlessTasks.add(new GetData(R.id.textViewTemperatureValue1, R.id.textViewHumidityValue1, + R.id.textViewTemperatureMin1, R.id.textViewTemperatureMax1, R.id.textViewTemperatureDelta1, + R.id.textViewHumidityMin1, R.id.textViewHumidityMax1, R.id.textViewHumidityDelta1, + true)); + endlessTasks.add(new GetData(R.id.textViewTemperatureValue2, R.id.textViewHumidityValue2, + R.id.textViewTemperatureMin2, R.id.textViewTemperatureMax2, R.id.textViewTemperatureDelta2, + R.id.textViewHumidityMin2, R.id.textViewHumidityMax2, R.id.textViewHumidityDelta2, + true)); + endlessTasks.add(new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3, + R.id.textViewTemperatureMin3, R.id.textViewTemperatureMax3, R.id.textViewTemperatureDelta3, + R.id.textViewHumidityMin3, R.id.textViewHumidityMax3, R.id.textViewHumidityDelta3, + true)); + executeAsyncTask(endlessTasks.get(0), urlPre + "api.php?host=192.168.1.71&day"); + executeAsyncTask(endlessTasks.get(1), urlPre + "api.php?host=192.168.1.72&day"); + executeAsyncTask(endlessTasks.get(2), urlPre + "api.php?host=192.168.1.73&day"); } } + @Override + public void onPause() { + super.onPause(); + Log.d(TAG, "onPause() called"); + } + + @Override + public void onStop() { + super.onStop(); + Log.d(TAG, "onStop() called"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(TAG, "onDestroy() called"); + } + + @Override + public void onStart() { + super.onStart(); + Log.d(TAG, "onStart() called"); + } + + @Override + public void onResume() { + super.onResume(); + Log.d(TAG, "onResume() called"); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + // Check if the key event was the Back button and if there's history + if (keyCode == KeyEvent.KEYCODE_BACK) { + for(int i=0; i void executeAsyncTask(AsyncTask asyncTask, T... params) { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); + else + asyncTask.execute(params); + } + /** * Async task class to get json by making HTTP call */ @@ -67,28 +142,90 @@ public class MainNativeActivity extends AppCompatActivity { ArrayList> dataList = new ArrayList<>(); int v1, v2; + int idMin1, idMax1, idDelta1; + int idMin2, idMax2, idDelta2; + + /* + * Properties to run endless + */ + boolean endless = false; + private ProgressBar pBarSmall; + private final ReentrantLock lock = new ReentrantLock(); + private final Condition tryAgain = lock.newCondition(); + private volatile boolean finished = false; GetData(int v1, int v2) { this.v1 = v1; this.v2 = v2; - pDialogLockCount += 1; + pBarLockCount += 1; + } + + GetData(int v1, int v2, int min1, int max1, int delta1, int min2, int max2, int delta2) { + this(v1, v2); + idMin1 = min1; + idMax1 = max1; + idDelta1 = delta1; + idMin2 = min2; + idMax2 = max2; + idDelta2 = delta2; + } + + /* + * Constructor to run endless + */ + GetData(int v1, int v2, int min1, int max1, int delta1, int min2, int max2, int delta2, boolean endless) { + this(v1, v2, min1, max1, delta1, min2, max2, delta2); + this.endless = endless; + pBarLockCount -= 1; // do not count for endless tasks, pBarSmall is used } @Override protected void onPreExecute() { super.onPreExecute(); // Showing progress bar -// if (pBar == null) { -// pBar= new ProgressBar(MainNativeActivity.this); -// } pBar = findViewById(R.id.progressBar); if (pBar.getVisibility() == View.INVISIBLE) { pBar.setVisibility(View.VISIBLE); } + if (endless) { + // Showing progress bar + pBarSmall = findViewById(R.id.progressBarSmall); + if (pBarSmall.getVisibility() == View.INVISIBLE) { + pBarSmall.setVisibility(View.VISIBLE); + } + } } @Override protected Void doInBackground(String... params) { + if(!endless) + getJsonOverHttpData(params); + else{ + lock.lock(); + do { + getJsonOverHttpData(params); + publishProgress(); + tryAgain.awaitUninterruptibly(); + //terminateTask(); + } while(!finished); + lock.unlock(); + } + + return null; + } + + @Override + protected void onPostExecute(Void result) { + super.onPostExecute(result); + pBarLockCount -= 1; + // Dismiss the progress bar + if (pBar.getVisibility() == View.VISIBLE && pBarLockCount == 0) { + pBar.setVisibility(View.GONE); + } + updateViews(); + } + + void getJsonOverHttpData(String... params) { // URL to get contacts JSON String url = params[0]; @@ -140,7 +277,6 @@ public class MainNativeActivity extends AppCompatActivity { .show(); } }); - } } else { Log.e(TAG, "Couldn't get json from server."); @@ -153,103 +289,13 @@ public class MainNativeActivity extends AppCompatActivity { .show(); } }); - - } - - return null; - } - - int interpolate(int pBegin, int pEnd, int pStep, int pMax) { - if (pBegin < pEnd) { - return ((pEnd - pBegin) * (pStep / pMax)) + pBegin; - } else { - return ((pBegin - pEnd) * (1 - (pStep / pMax))) + pEnd; } } - int interpolateColor(int theColorBegin, int theColorEnd, - int theNumStep, int theNumSteps) { - int theR0 = (theColorBegin & 0xff0000) >> 16; - int theG0 = (theColorBegin & 0x00ff00) >> 8; - int theB0 = (theColorBegin & 0x0000ff); - //int theB0 = (theColorBegin & 0x0000ff) >> 0; - - int theR1 = (theColorEnd & 0xff0000) >> 16; - int theG1 = (theColorEnd & 0x00ff00) >> 8; - int theB1 = (theColorEnd & 0x0000ff); - //int theB1 = (theColorEnd & 0x0000ff) >> 0; - - int theR = interpolate(theR0, theR1, theNumStep, theNumSteps); - int theG = interpolate(theG0, theG1, theNumStep, theNumSteps); - int theB = interpolate(theB0, theB1, theNumStep, theNumSteps); - - return (((theR << 8) | theG) << 8) | theB; - } - - Color valueToColor(float value, float lowMin, float lowMax, float highMin, float highMax, - Color below, Color ideal, Color above) { - return Color.valueOf(Color.parseColor(String.format("#%06X", - valueToColorRGB(value, lowMin, lowMax, highMin, highMax, below, ideal, above)))); - } - - int valueToColorRGB(float value, float lowMin, float lowMax, float highMin, float highMax, - Color below, Color ideal, Color above) { - int bel = Integer.parseInt(String.format("%06X", (0xFFFFFF & below.toArgb())), 16); - int ide = Integer.parseInt(String.format("%06X", (0xFFFFFF & ideal.toArgb())), 16); - int abo = Integer.parseInt(String.format("%06X", (0xFFFFFF & above.toArgb())), 16); - - return valueToColorRGB(value, lowMin, lowMax, highMin, highMax, bel, ide, abo); - } - - int valueToColorRGB(float value, float lowMin, float lowMax, float highMin, float highMax, - int below, int ideal, int above) { - /* - * lowMin < lowMax < highMin < highMax - * - * Example use for temperatures with color blue for too cold (below), green for ideal - * and red for too warm (above) temperatures: - * - Below lowMin the color is blue - * - Between lowMin and lowMax is color is linear interpolated between blue and green - * - Between lowMax and highMin the color is green - * - Between highMin and highMax the color is linear interpolated between green and red - * - Above highMax the color is red - */ - int result = 0xFFFFFF; // white - int theNumSteps = 100; - int theColorBegin, theColorEnd, ratio; - - if (value <= highMin && value >= lowMax) - result = ideal; - else if (value > highMax) - result = above; - else if (value > highMin) { - theColorBegin = ideal; - theColorEnd = above; - ratio = (int) ((value - highMin) / (highMax - highMin) * 100); - result = interpolateColor(theColorBegin, theColorEnd, ratio, theNumSteps); - } else if (value < lowMin) - result = below; - else if (value < lowMax) { - theColorBegin = ideal; - theColorEnd = below; - ratio = (int) ((lowMax - value) / (lowMax - lowMin) * 100); - result = interpolateColor(theColorBegin, theColorEnd, ratio, theNumSteps); - } - return result; - } - - @Override - protected void onPostExecute(Void result) { - super.onPostExecute(result); - pDialogLockCount -= 1; - // Dismiss the progress bar - if (pBar.getVisibility() == View.VISIBLE && pDialogLockCount == 0) { - pBar.setVisibility(View.GONE); - } - /* - * Updating parsed JSON data into Views - * */ - + /** + * Updating parsed JSON data into Views + */ + void updateViews() { int n = dataList.size(); if (n > 0) { HashMap hm = dataList.get(n - 1); @@ -275,9 +321,77 @@ public class MainNativeActivity extends AppCompatActivity { TextView tv2 = findViewById(v2); tv2.setText(humidity); tv2.setTextColor(textColor.toArgb()); + + if (idMin1 != 0) { + float min1 = 100, max1 = 0, val1; + float min2 = 100, max2 = 0, val2; + for (int i = 0; i < n; i++) { + hm = dataList.get(i); + val1 = Float.parseFloat(hm.get("temperature")); + if (val1 < min1) + min1 = val1; + if (val1 > max1) + max1 = val1; + val2 = Float.parseFloat(hm.get("humidity")); + if (val2 < min2) + min2 = val2; + if (val2 > max2) + max2 = val2; + } + TextView tv; + tv = findViewById(idMin1); + tv.setText(String.format("%.1f", min1)); + tv = findViewById(idMax1); + tv.setText(String.format("%.1f", max1)); + tv = findViewById(idDelta1); + tv.setText(String.format("%.1f", max1 - min1)); + tv = findViewById(idMin2); + tv.setText(String.format("%.1f", min2)); + tv = findViewById(idMax2); + tv.setText(String.format("%.1f", max2)); + tv = findViewById(idDelta2); + tv.setText(String.format("%.1f", max2 - min2)); + } } } + /* + * Functions to run endless + */ + + @Override + protected void onProgressUpdate(Void... result) { + //super.onProgressUpdate(result); + // Treat this like onPostExecute(), do something with result + if(endless) { + updateViews(); + runAgain(); + } + } + + @Override + protected void onCancelled() { + // Make sure we clean up if the task is killed + if(endless) + terminateTask(); + } + + public void runAgain() { + // Call this to request data from the server again + lock.lock(); + try { + tryAgain.signal(); + } finally { + lock.unlock(); + } + } + + public void terminateTask() { + // The task will only finish when we call this method + finished = true; + //lock.unlock(); + } + } @Override @@ -300,11 +414,90 @@ public class MainNativeActivity extends AppCompatActivity { } /** - * Called when the user taps the Send button + * Called when the user taps the Settings button */ public void settings() { Intent intentSettings = new Intent(this, SettingsActivity.class); //intentSettings.putExtra(MESSAGE, MESSAGE); startActivity(intentSettings); } + + int interpolate(int pBegin, int pEnd, int pStep, int pMax) { + if (pBegin < pEnd) { + return ((pEnd - pBegin) * (pStep / pMax)) + pBegin; + } else { + return ((pBegin - pEnd) * (1 - (pStep / pMax))) + pEnd; + } + } + + int interpolateColor(int theColorBegin, int theColorEnd, + int theNumStep, int theNumSteps) { + int theR0 = (theColorBegin & 0xff0000) >> 16; + int theG0 = (theColorBegin & 0x00ff00) >> 8; + int theB0 = (theColorBegin & 0x0000ff); + //int theB0 = (theColorBegin & 0x0000ff) >> 0; + + int theR1 = (theColorEnd & 0xff0000) >> 16; + int theG1 = (theColorEnd & 0x00ff00) >> 8; + int theB1 = (theColorEnd & 0x0000ff); + //int theB1 = (theColorEnd & 0x0000ff) >> 0; + + int theR = interpolate(theR0, theR1, theNumStep, theNumSteps); + int theG = interpolate(theG0, theG1, theNumStep, theNumSteps); + int theB = interpolate(theB0, theB1, theNumStep, theNumSteps); + + return (((theR << 8) | theG) << 8) | theB; + } + + Color valueToColor(float value, float lowMin, float lowMax, float highMin, float highMax, + Color below, Color ideal, Color above) { + return Color.valueOf(Color.parseColor(String.format("#%06X", + valueToColorRGB(value, lowMin, lowMax, highMin, highMax, below, ideal, above)))); + } + + int valueToColorRGB(float value, float lowMin, float lowMax, float highMin, float highMax, + Color below, Color ideal, Color above) { + int bel = Integer.parseInt(String.format("%06X", (0xFFFFFF & below.toArgb())), 16); + int ide = Integer.parseInt(String.format("%06X", (0xFFFFFF & ideal.toArgb())), 16); + int abo = Integer.parseInt(String.format("%06X", (0xFFFFFF & above.toArgb())), 16); + + return valueToColorRGB(value, lowMin, lowMax, highMin, highMax, bel, ide, abo); + } + + /** + * lowMin < lowMax < highMin < highMax + * + * Example use for temperatures with color blue for too cold (below), green for ideal + * and red for too warm (above) temperatures: + * - Below lowMin the color is blue + * - Between lowMin and lowMax is color is linear interpolated between blue and green + * - Between lowMax and highMin the color is green + * - Between highMin and highMax the color is linear interpolated between green and red + * - Above highMax the color is red + */ + int valueToColorRGB(float value, float lowMin, float lowMax, float highMin, float highMax, + int below, int ideal, int above) { + int result = 0xFFFFFF; // white + int theNumSteps = 100; + int theColorBegin, theColorEnd, ratio; + + if (value <= highMin && value >= lowMax) + result = ideal; + else if (value > highMax) + result = above; + else if (value > highMin) { + theColorBegin = ideal; + theColorEnd = above; + ratio = (int) ((value - highMin) / (highMax - highMin) * 100); + result = interpolateColor(theColorBegin, theColorEnd, ratio, theNumSteps); + } else if (value < lowMin) + result = below; + else if (value < lowMax) { + theColorBegin = ideal; + theColorEnd = below; + ratio = (int) ((lowMax - value) / (lowMax - lowMin) * 100); + result = interpolateColor(theColorBegin, theColorEnd, ratio, theNumSteps); + } + return result; + } } diff --git a/app/src/main/res/layout/activity_main_native.xml b/app/src/main/res/layout/activity_main_native.xml index 40cd2ef..23f37e7 100644 --- a/app/src/main/res/layout/activity_main_native.xml +++ b/app/src/main/res/layout/activity_main_native.xml @@ -9,11 +9,9 @@ + android:weightSum="6"> @@ -37,8 +35,8 @@ android:id="@+id/textViewHumidity" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_span="3" android:layout_weight="1" - android:layout_span="2" android:text="@string/humidity" android:textStyle="bold" /> @@ -46,146 +44,359 @@ + android:layout_height="match_parent" + android:layout_marginTop="@dimen/widget_vertical_margin"> + + + + + android:layout_height="match_parent" + android:weightSum="6"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:layout_height="match_parent" + android:weightSum="6"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index c591852..832e704 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -4,4 +4,5 @@ 16dp 8dp 8dp + 40sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5c1e2f4..b4b2373 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,8 +3,11 @@ Please wait, the view is loading… Temperature + °C Humidity - _._ + % + __._ + o Settings de.weseng.wifiweatherstation.MESSAGE diff --git a/app/src/test/java/de/weseng/wifiweatherstation/MainNativeActivityTest.java b/app/src/test/java/de/weseng/wifiweatherstation/MainNativeActivityTest.java new file mode 100644 index 0000000..95c7c5d --- /dev/null +++ b/app/src/test/java/de/weseng/wifiweatherstation/MainNativeActivityTest.java @@ -0,0 +1,33 @@ +package de.weseng.wifiweatherstation; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class MainNativeActivityTest { + + @Test + public void valueToColorRGB_below() { + assertEquals(new MainNativeActivity().valueToColorRGB( + 10, 17, 19, 23, 25, + 0x719dc3, 0xff00ff00, 0xffd1655d), + 0x719dc3); + } + + @Test + public void valueToColorRGB_ideal() { + assertEquals(new MainNativeActivity().valueToColorRGB( + 20, 17, 19, 23, 25, + 0x719DC3, 0xff00ff00, 0xffd1655d), + 0xff00ff00); + } + + @Test + public void valueToColorRGB_above() { + assertEquals(new MainNativeActivity().valueToColorRGB( + 30, 17, 19, 23, 25, + 0x719DC3, 0xff00ff00, 0xffd1655d), + 0xffd1655d); + } + +} \ No newline at end of file