add local weather, chart activity and fix orientation bug
float parsing with null check and nan as default
12
.idea/dictionaries/weatherstation.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="weatherstation">
|
||||||
|
<words>
|
||||||
|
<w>appid</w>
|
||||||
|
<w>dateandtime</w>
|
||||||
|
<w>openweathermap</w>
|
||||||
|
<w>ssid</w>
|
||||||
|
<w>weseng</w>
|
||||||
|
<w>wifiweatherstation</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
||||||
35
.idea/misc.xml
generated
@@ -1,5 +1,40 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="NullableNotNullManager">
|
||||||
|
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
||||||
|
<option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" />
|
||||||
|
<option name="myNullables">
|
||||||
|
<value>
|
||||||
|
<list size="10">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||||
|
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||||
|
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
||||||
|
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
||||||
|
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="myNotNulls">
|
||||||
|
<value>
|
||||||
|
<list size="9">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||||
|
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
||||||
|
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
||||||
|
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ android {
|
|||||||
applicationId "de.weseng.wifiweatherstation"
|
applicationId "de.weseng.wifiweatherstation"
|
||||||
minSdkVersion 26
|
minSdkVersion 26
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 20190310
|
versionCode 20190317
|
||||||
versionName "2019.3.10"
|
versionName "2019.3.17"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -18,6 +18,10 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||||
@@ -27,4 +31,5 @@ dependencies {
|
|||||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||||
implementation 'com.android.support:design:28.0.0'
|
implementation 'com.android.support:design:28.0.0'
|
||||||
|
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,10 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="de.weseng.wifiweatherstation">
|
package="de.weseng.wifiweatherstation">
|
||||||
|
|
||||||
<!-- To auto-complete the email text field in the login form with the user's emails -->
|
<!-- To auto-complete the email text field in the login form with the user's emails -->
|
||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||||
<!--<uses-permission android:name="android.permission.READ_PROFILE" />-->
|
<!-- <uses-permission android:name="android.permission.READ_PROFILE" /> -->
|
||||||
<!--<uses-permission android:name="android.permission.READ_CONTACTS" />--> <!-- for email completions -->
|
<!-- <uses-permission android:name="android.permission.READ_CONTACTS" /> --> <!-- for email completions -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- or ACCESS_FINE_LOCATION for SSID -->
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- or ACCESS_FINE_LOCATION for SSID -->
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:noHistory="true"> <!--android:label="@string/title_activity_login"-->
|
android:noHistory="true"> <!-- android:label="@string/title_activity_login" -->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
@@ -33,7 +32,8 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainNativeActivity"
|
android:name=".MainNativeActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name"
|
||||||
|
android:configChanges="orientation|screenSize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@@ -43,6 +43,11 @@
|
|||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".DetailActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".SettingsActivity"
|
android:name=".SettingsActivity"
|
||||||
android:parentActivityName=".MainActivity" />
|
android:parentActivityName=".MainActivity" />
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package de.weseng.wifiweatherstation;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.style.ImageSpan;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
public class CenteredImageSpan extends ImageSpan {
|
||||||
|
private WeakReference<Drawable> mDrawableRef;
|
||||||
|
|
||||||
|
CenteredImageSpan(Context context, final int drawableRes) {
|
||||||
|
super(context, drawableRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize(@NonNull Paint paint, CharSequence text,
|
||||||
|
int start, int end,
|
||||||
|
Paint.FontMetricsInt fm) {
|
||||||
|
Drawable d = getCachedDrawable();
|
||||||
|
Rect rect = d.getBounds();
|
||||||
|
|
||||||
|
float drawableHeight = rect.height();
|
||||||
|
if (fm != null) {
|
||||||
|
Paint.FontMetricsInt pfm = paint.getFontMetricsInt();
|
||||||
|
float fontHeight = pfm.descent - pfm.ascent;
|
||||||
|
int paintOversizeHalf = (int) (drawableHeight/2-fontHeight*1.25);
|
||||||
|
|
||||||
|
// keep it the same as paint's fm plus some space
|
||||||
|
fm.ascent = pfm.ascent - paintOversizeHalf;
|
||||||
|
fm.descent = pfm.descent + paintOversizeHalf;
|
||||||
|
fm.top = pfm.top;
|
||||||
|
fm.bottom = pfm.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rect.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(@NonNull Canvas canvas, CharSequence text,
|
||||||
|
int start, int end, float x,
|
||||||
|
int top, int y, int bottom, @NonNull Paint paint) {
|
||||||
|
Drawable b = getCachedDrawable();
|
||||||
|
canvas.save();
|
||||||
|
|
||||||
|
int drawableHeight = b.getIntrinsicHeight();
|
||||||
|
int fontAscent = paint.getFontMetricsInt().ascent;
|
||||||
|
int fontDescent = paint.getFontMetricsInt().descent;
|
||||||
|
|
||||||
|
Paint.FontMetricsInt pfm = paint.getFontMetricsInt();
|
||||||
|
int fontHeightRelativeCorrection = (int) ((pfm.descent - pfm.ascent)/5.0);
|
||||||
|
|
||||||
|
int transY = bottom - b.getBounds().bottom + // align bottom to bottom
|
||||||
|
(drawableHeight - fontDescent + fontAscent) / 2 - fontHeightRelativeCorrection; // align center to center
|
||||||
|
canvas.translate(x, transY);
|
||||||
|
b.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redefined locally because it is a private member from DynamicDrawableSpan
|
||||||
|
private Drawable getCachedDrawable() {
|
||||||
|
WeakReference<Drawable> wr = mDrawableRef;
|
||||||
|
Drawable d = null;
|
||||||
|
|
||||||
|
if (wr != null)
|
||||||
|
d = wr.get();
|
||||||
|
|
||||||
|
if (d == null) {
|
||||||
|
d = getDrawable();
|
||||||
|
mDrawableRef = new WeakReference<>(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,287 @@
|
|||||||
|
package de.weseng.wifiweatherstation;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.github.mikephil.charting.charts.LineChart;
|
||||||
|
import com.github.mikephil.charting.components.Legend;
|
||||||
|
import com.github.mikephil.charting.components.XAxis;
|
||||||
|
import com.github.mikephil.charting.components.YAxis;
|
||||||
|
import com.github.mikephil.charting.data.Entry;
|
||||||
|
import com.github.mikephil.charting.data.LineData;
|
||||||
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
|
import com.github.mikephil.charting.formatter.IFillFormatter;
|
||||||
|
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
|
||||||
|
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||||
|
import com.github.mikephil.charting.utils.ColorTemplate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class DetailActivity extends AppCompatActivity {
|
||||||
|
private final String TAG = getClass().getSimpleName();
|
||||||
|
private LineChart chart;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_detail);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
ArrayList<String> dataList1 = intent.getStringArrayListExtra("temperature");
|
||||||
|
ArrayList<String> dataList2 = intent.getStringArrayListExtra("humidity");
|
||||||
|
Log.d(TAG, "dataList1: " + dataList1);
|
||||||
|
Log.d(TAG, "dataList2: " + dataList2);
|
||||||
|
|
||||||
|
chart = findViewById(R.id.chart1);
|
||||||
|
|
||||||
|
// background color for the whole view
|
||||||
|
//chart.setBackgroundColor(Color.TRANSPARENT);
|
||||||
|
|
||||||
|
// background color for the chart area
|
||||||
|
//chart.setDrawGridBackground(true);
|
||||||
|
//chart.setGridBackgroundColor(Color.TRANSPARENT);
|
||||||
|
|
||||||
|
// disable description text
|
||||||
|
chart.getDescription().setEnabled(false);
|
||||||
|
|
||||||
|
// enable touch gestures, default true
|
||||||
|
//chart.setTouchEnabled(false);
|
||||||
|
|
||||||
|
// enable dragging (default true) and scaling (default true)
|
||||||
|
//chart.setDragEnabled(false);
|
||||||
|
//chart.setScaleEnabled(false);
|
||||||
|
//chart.setScaleXEnabled(false);
|
||||||
|
chart.setScaleYEnabled(false);
|
||||||
|
|
||||||
|
// force pinch zoom along both axis (default false)
|
||||||
|
//chart.setPinchZoom(true);
|
||||||
|
|
||||||
|
// animates the rendering of the chart
|
||||||
|
chart.animateX(1000);
|
||||||
|
//chart.animateY(1500);
|
||||||
|
//chart.animateXY(1500, 1500);
|
||||||
|
|
||||||
|
{ // x axis
|
||||||
|
|
||||||
|
XAxis xAxis = chart.getXAxis();
|
||||||
|
//xAxis.setTypeface(tfLight);
|
||||||
|
//xAxis.setTextSize(11f);
|
||||||
|
xAxis.setDrawLabels(false);
|
||||||
|
//xAxis.setTextColor(Color.LTGRAY);
|
||||||
|
xAxis.setDrawGridLines(false);
|
||||||
|
xAxis.setDrawAxisLine(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // y axis
|
||||||
|
|
||||||
|
//YAxis yAxis = chart.getAxisLeft();
|
||||||
|
|
||||||
|
// disable dual axis (only use LEFT axis)
|
||||||
|
//chart.getAxisRight().setEnabled(false);
|
||||||
|
|
||||||
|
//leftAxis.setTypeface(tfLight);
|
||||||
|
//yAxis.setTextColor(ColorTemplate.getHoloBlue());
|
||||||
|
//yAxis.setAxisMinimum(12f);
|
||||||
|
//yAxis.setAxisMaximum(30f);
|
||||||
|
//yAxis.setDrawGridLines(true);
|
||||||
|
|
||||||
|
// horizontal grid lines
|
||||||
|
//yAxis.enableGridDashedLine(10f, 10f, 0f);
|
||||||
|
|
||||||
|
//yAxis.setGranularityEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{ // y axis left
|
||||||
|
|
||||||
|
YAxis leftAxis = chart.getAxisLeft();
|
||||||
|
leftAxis.setTypeface(Typeface.DEFAULT_BOLD);
|
||||||
|
leftAxis.setTextColor(MainNativeActivity.red.toArgb());
|
||||||
|
leftAxis.setAxisMinimum(12);
|
||||||
|
leftAxis.setAxisMaximum(30);
|
||||||
|
leftAxis.setDrawGridLines(true);
|
||||||
|
leftAxis.setGranularityEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // y axis right
|
||||||
|
YAxis rightAxis = chart.getAxisRight();
|
||||||
|
rightAxis.setTypeface(Typeface.DEFAULT_BOLD);
|
||||||
|
rightAxis.setTextColor(ColorTemplate.getHoloBlue());
|
||||||
|
rightAxis.setAxisMinimum(20);
|
||||||
|
rightAxis.setAxisMaximum(80);
|
||||||
|
//rightAxis.setDrawGridLines(false);
|
||||||
|
//rightAxis.setDrawZeroLine(false);
|
||||||
|
//rightAxis.setGranularityEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(dataList1, getString(R.string.temperature), dataList2, getString(R.string.humidity));
|
||||||
|
|
||||||
|
{ // ### Legend ###
|
||||||
|
|
||||||
|
// get the legend (only possible after setting data)
|
||||||
|
Legend l = chart.getLegend();
|
||||||
|
|
||||||
|
// draw legend entries as lines, default square
|
||||||
|
l.setForm(Legend.LegendForm.LINE);
|
||||||
|
|
||||||
|
l.setTypeface(Typeface.DEFAULT_BOLD);
|
||||||
|
//l.setTextSize(11f);
|
||||||
|
l.setTextColor(Color.LTGRAY);
|
||||||
|
|
||||||
|
// position, default: bottom left
|
||||||
|
//l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
|
||||||
|
//l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
|
||||||
|
|
||||||
|
// default horizontal
|
||||||
|
//l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
|
||||||
|
|
||||||
|
// default false
|
||||||
|
//l.setDrawInside(true);
|
||||||
|
|
||||||
|
//l.setYOffset(11f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setData(ArrayList<String> dataList1, String label1,
|
||||||
|
ArrayList<String> dataList2, String label2) {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = dataList1.size();
|
||||||
|
ArrayList<Entry> values1 = new ArrayList<>();
|
||||||
|
if (n > 0) {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
float val = Float.parseFloat(dataList1.get(i));
|
||||||
|
values1.add(new Entry(i, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = dataList2.size();
|
||||||
|
ArrayList<Entry> values2 = new ArrayList<>();
|
||||||
|
if (n > 0) {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
float val = Float.parseFloat(dataList2.get(i));
|
||||||
|
values2.add(new Entry(i, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// create a DataSet and give it a type
|
||||||
|
LineDataSet set1 = new LineDataSet(values1, label1);
|
||||||
|
set1.setAxisDependency(YAxis.AxisDependency.LEFT);
|
||||||
|
|
||||||
|
{ // ### Lines ###
|
||||||
|
|
||||||
|
//set1.setColor(Color.BLACK);
|
||||||
|
set1.setColor(MainNativeActivity.red.toArgb());
|
||||||
|
//set1.setColor(ColorTemplate.getHoloBlue());
|
||||||
|
|
||||||
|
// line thickness (min = 0.2f, max = 10f, default 1f)
|
||||||
|
//set1.setLineWidth(1f);
|
||||||
|
|
||||||
|
// draw dashed line, see also legend
|
||||||
|
//set1.enableDashedLine(10f, 5f, 0f);
|
||||||
|
|
||||||
|
// set interpolation
|
||||||
|
//set1.setMode(LineDataSet.Mode.STEPPED);
|
||||||
|
//set1.setMode(LineDataSet.Mode.LINEAR);
|
||||||
|
//set1.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||||
|
//set1.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // ### Points ###
|
||||||
|
|
||||||
|
// points, circles over the data point, def: true
|
||||||
|
//set1.setDrawCircles(false);
|
||||||
|
|
||||||
|
//set1.setCircleColor(Color.BLACK);
|
||||||
|
set1.setCircleColor(MainNativeActivity.red.toArgb());
|
||||||
|
|
||||||
|
// point size (default radius = 4f, min = 1f)
|
||||||
|
//set1.setCircleRadius(3f);
|
||||||
|
|
||||||
|
// icons over the data point, def: false
|
||||||
|
//set1.setDrawIcons(false);
|
||||||
|
|
||||||
|
// false to draw points as solid circles (default true)
|
||||||
|
set1.setDrawCircleHole(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // ### Values ###
|
||||||
|
|
||||||
|
// values over the data point, def: true
|
||||||
|
set1.setDrawValues(false);
|
||||||
|
|
||||||
|
// text size of values
|
||||||
|
//set1.setValueTextSize(9f);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // ### Legend ###
|
||||||
|
|
||||||
|
//set1.setFormLineWidth(1f);
|
||||||
|
//set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
|
||||||
|
//set1.setFormSize(15.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw selection line as dashed
|
||||||
|
set1.setHighLightColor(Color.LTGRAY);
|
||||||
|
//set1.enableDashedHighlightLine(10f, 5f, 0f);
|
||||||
|
|
||||||
|
{ // ### Filled area ###
|
||||||
|
|
||||||
|
// set the filled area
|
||||||
|
//set1.setDrawFilled(true);
|
||||||
|
set1.setFillFormatter(new IFillFormatter() {
|
||||||
|
@Override
|
||||||
|
public float getFillLinePosition(ILineDataSet dataSet, LineDataProvider dataProvider) {
|
||||||
|
return chart.getAxisLeft().getAxisMinimum();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// set color of filled area
|
||||||
|
set1.setFillColor(MainNativeActivity.red.toArgb());
|
||||||
|
//if (Utils.getSDKInt() >= 18) {
|
||||||
|
// // drawables only supported on api level 18 and above
|
||||||
|
// Drawable drawable = ContextCompat.getDrawable(this, R.drawable.fade_red);
|
||||||
|
// set1.setFillDrawable(drawable);
|
||||||
|
//} else {
|
||||||
|
// set1.setFillColor(Color.BLACK);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LineDataSet set2 = new LineDataSet(values2, label2);
|
||||||
|
set2.setAxisDependency(YAxis.AxisDependency.RIGHT);
|
||||||
|
set2.setColor(ColorTemplate.getHoloBlue());
|
||||||
|
set2.setCircleColor(ColorTemplate.getHoloBlue());
|
||||||
|
//set2.setCircleColor(MainNativeActivity.red.toArgb());
|
||||||
|
set2.setDrawCircleHole(false);
|
||||||
|
set2.setDrawValues(false);
|
||||||
|
set2.setHighLightColor(Color.LTGRAY);
|
||||||
|
//set2.setDrawFilled(true);
|
||||||
|
set2.setFillFormatter(new IFillFormatter() {
|
||||||
|
@Override
|
||||||
|
public float getFillLinePosition(ILineDataSet dataSet, LineDataProvider dataProvider) {
|
||||||
|
return chart.getAxisRight().getAxisMinimum();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
|
dataSets.add(set1); // add the data sets
|
||||||
|
dataSets.add(set2); // add the data sets
|
||||||
|
|
||||||
|
// create a data object with the data sets
|
||||||
|
LineData data = new LineData(dataSets);
|
||||||
|
|
||||||
|
//data.setValueTextColor(Color.WHITE);
|
||||||
|
//data.setValueTextSize(9f);
|
||||||
|
|
||||||
|
// set data
|
||||||
|
chart.setData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package de.weseng.wifiweatherstation;
|
package de.weseng.wifiweatherstation;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -8,6 +10,9 @@ import android.os.AsyncTask;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -22,20 +27,38 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import static de.weseng.wifiweatherstation.SettingsActivity.PREFS_NAME;
|
import static de.weseng.wifiweatherstation.SettingsActivity.PREFS_NAME;
|
||||||
|
import static java.lang.Math.pow;
|
||||||
|
|
||||||
public class MainNativeActivity extends AppCompatActivity {
|
public class MainNativeActivity extends AppCompatActivity {
|
||||||
private final String TAG = getClass().getSimpleName();
|
private final String TAG = getClass().getSimpleName();
|
||||||
|
|
||||||
|
static Color green = Color.valueOf(0x71ff5f);
|
||||||
|
static Color red = Color.valueOf(0xffd1655d);
|
||||||
|
static Color blue = Color.valueOf(Color.rgb(113, 157, 195));
|
||||||
|
|
||||||
private int pBarLockCount = 0;
|
private int pBarLockCount = 0;
|
||||||
// In Android 4.4 (API 19) AsyncTask MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; (maximum number of threads)
|
// In Android 4.4 (API 19) AsyncTask MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; (maximum number of threads)
|
||||||
ArrayList<AsyncTask<String, Void, Void>> endlessTasks = new ArrayList<>();
|
ArrayList<AsyncTask<String, Void, Void>> endlessTasks = new ArrayList<>();
|
||||||
|
|
||||||
|
ArrayList<String> dataListStringTemp1 = new ArrayList<>();
|
||||||
|
ArrayList<String> dataListStringTemp2 = new ArrayList<>();
|
||||||
|
ArrayList<String> dataListStringTemp3 = new ArrayList<>();
|
||||||
|
ArrayList<String> dataListStringHumidity1 = new ArrayList<>();
|
||||||
|
ArrayList<String> dataListStringHumidity2 = new ArrayList<>();
|
||||||
|
ArrayList<String> dataListStringHumidity3 = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -45,36 +68,48 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
String urlLocal = settings.getString("urlLocal", getString(R.string.url_local));
|
String urlLocal = settings.getString("urlLocal", getString(R.string.url_local));
|
||||||
String urlGlobal = settings.getString("urlGlobal", getString(R.string.url_global));
|
String urlGlobal = settings.getString("urlGlobal", getString(R.string.url_global));
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
TableLayout tr1 = findViewById(R.id.tableRow1);
|
||||||
TableLayout tr1 = findViewById(R.id.tableRow1);
|
tr1.setOnClickListener(new View.OnClickListener() {
|
||||||
tr1.setOnClickListener(new View.OnClickListener() {
|
@Override
|
||||||
@Override
|
public void onClick(View v) {
|
||||||
public void onClick(View v) {
|
Intent intent = new Intent(MainNativeActivity.this, DetailActivity.class);
|
||||||
// TODO: do your logic here
|
intent.putExtra("temperature", dataListStringTemp1);
|
||||||
}
|
intent.putExtra("humidity", dataListStringHumidity1);
|
||||||
});
|
startActivity(intent);
|
||||||
TableLayout tr2 = findViewById(R.id.tableRow2);
|
}
|
||||||
tr2.setOnClickListener(new View.OnClickListener() {
|
});
|
||||||
@Override
|
TableLayout tr2 = findViewById(R.id.tableRow2);
|
||||||
public void onClick(View v) {
|
tr2.setOnClickListener(new View.OnClickListener() {
|
||||||
// TODO: do your logic here
|
@Override
|
||||||
}
|
public void onClick(View v) {
|
||||||
});
|
Intent intent = new Intent(MainNativeActivity.this, DetailActivity.class);
|
||||||
TableLayout tr3 = findViewById(R.id.tableRow3);
|
intent.putExtra("temperature", dataListStringTemp2);
|
||||||
tr3.setOnClickListener(new View.OnClickListener() {
|
intent.putExtra("humidity", dataListStringHumidity2);
|
||||||
@Override
|
startActivity(intent);
|
||||||
public void onClick(View v) {
|
}
|
||||||
// TODO: do your logic here
|
});
|
||||||
}
|
TableLayout tr3 = findViewById(R.id.tableRow3);
|
||||||
});
|
tr3.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent(MainNativeActivity.this, DetailActivity.class);
|
||||||
|
intent.putExtra("temperature", dataListStringTemp3);
|
||||||
|
intent.putExtra("humidity", dataListStringHumidity3);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TextView tv = findViewById(R.id.textViewWeatherOutdoor);
|
||||||
|
tv.setText(Html.fromHtml(getString(R.string.weather_outdoor), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
String urlPre = "";
|
String urlPre = "";
|
||||||
if (SettingsActivity.isLocal(getApplicationContext())) {
|
if (SettingsActivity.isLocal(getApplicationContext())) {
|
||||||
//Toast.makeText(getApplicationContext(), "intern", Toast.LENGTH_LONG).show();
|
//Toast.makeText(getApplicationContext(), "intern", Toast.LENGTH_LONG).show();
|
||||||
if (urlLocal != null && urlLocal.length() > 0)
|
if (urlLocal != null && urlLocal.length() > 0)
|
||||||
urlPre = urlLocal.substring(urlLocal.length() - 1).equals("/") ? urlLocal : urlLocal + "/";
|
urlPre = urlLocal.substring(urlLocal.length() - 1).equals("/") ? urlLocal : urlLocal + "/";
|
||||||
} else {
|
} else {
|
||||||
//Toast.makeText(getApplicationContext(), "extern", Toast.LENGTH_LONG).show();
|
//Toast.makeText(getApplicationContext(), "external", Toast.LENGTH_LONG).show();
|
||||||
if (urlGlobal != null && urlGlobal.length() > 0)
|
if (urlGlobal != null && urlGlobal.length() > 0)
|
||||||
urlPre = urlGlobal.substring(urlGlobal.length() - 1).equals("/") ? urlGlobal : urlGlobal + "/";
|
urlPre = urlGlobal.substring(urlGlobal.length() - 1).equals("/") ? urlGlobal : urlGlobal + "/";
|
||||||
}
|
}
|
||||||
@@ -85,18 +120,20 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
executeAsyncTask(new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3),
|
executeAsyncTask(new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3),
|
||||||
urlPre + "api.php?host=192.168.1.73&last");
|
urlPre + "api.php?host=192.168.1.73&last");
|
||||||
|
|
||||||
|
executeAsyncTask(new OpenWeatherMap(R.id.textViewWeatherOutdoor), urlPre + "openweathermap/api.php");
|
||||||
|
|
||||||
endlessTasks.add(new GetData(R.id.textViewTemperatureValue1, R.id.textViewHumidityValue1,
|
endlessTasks.add(new GetData(R.id.textViewTemperatureValue1, R.id.textViewHumidityValue1,
|
||||||
R.id.textViewTemperatureMin1, R.id.textViewTemperatureMax1, R.id.textViewTemperatureDelta1,
|
R.id.textViewTemperatureMin1, R.id.textViewTemperatureMax1, R.id.textViewTemperatureDelta1,
|
||||||
R.id.textViewHumidityMin1, R.id.textViewHumidityMax1, R.id.textViewHumidityDelta1,
|
R.id.textViewHumidityMin1, R.id.textViewHumidityMax1, R.id.textViewHumidityDelta1,
|
||||||
true));
|
true, dataListStringTemp1, dataListStringHumidity1));
|
||||||
endlessTasks.add(new GetData(R.id.textViewTemperatureValue2, R.id.textViewHumidityValue2,
|
endlessTasks.add(new GetData(R.id.textViewTemperatureValue2, R.id.textViewHumidityValue2,
|
||||||
R.id.textViewTemperatureMin2, R.id.textViewTemperatureMax2, R.id.textViewTemperatureDelta2,
|
R.id.textViewTemperatureMin2, R.id.textViewTemperatureMax2, R.id.textViewTemperatureDelta2,
|
||||||
R.id.textViewHumidityMin2, R.id.textViewHumidityMax2, R.id.textViewHumidityDelta2,
|
R.id.textViewHumidityMin2, R.id.textViewHumidityMax2, R.id.textViewHumidityDelta2,
|
||||||
true));
|
true, dataListStringTemp2, dataListStringHumidity2));
|
||||||
endlessTasks.add(new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3,
|
endlessTasks.add(new GetData(R.id.textViewTemperatureValue3, R.id.textViewHumidityValue3,
|
||||||
R.id.textViewTemperatureMin3, R.id.textViewTemperatureMax3, R.id.textViewTemperatureDelta3,
|
R.id.textViewTemperatureMin3, R.id.textViewTemperatureMax3, R.id.textViewTemperatureDelta3,
|
||||||
R.id.textViewHumidityMin3, R.id.textViewHumidityMax3, R.id.textViewHumidityDelta3,
|
R.id.textViewHumidityMin3, R.id.textViewHumidityMax3, R.id.textViewHumidityDelta3,
|
||||||
true));
|
true, dataListStringTemp3, dataListStringHumidity3));
|
||||||
executeAsyncTask(endlessTasks.get(0), urlPre + "api.php?host=192.168.1.71&day");
|
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(1), urlPre + "api.php?host=192.168.1.72&day");
|
||||||
executeAsyncTask(endlessTasks.get(2), urlPre + "api.php?host=192.168.1.73&day");
|
executeAsyncTask(endlessTasks.get(2), urlPre + "api.php?host=192.168.1.73&day");
|
||||||
@@ -148,6 +185,8 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
return super.onKeyDown(keyCode, event);
|
return super.onKeyDown(keyCode, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
|
@SafeVarargs
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
|
||||||
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
|
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
|
||||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||||
@@ -159,6 +198,7 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
/**
|
/**
|
||||||
* Async task class to get json by making HTTP call
|
* Async task class to get json by making HTTP call
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
private class GetData extends AsyncTask<String, Void, Void> {
|
private class GetData extends AsyncTask<String, Void, Void> {
|
||||||
String TAG = getClass().getSimpleName();
|
String TAG = getClass().getSimpleName();
|
||||||
private ProgressBar pBar;
|
private ProgressBar pBar;
|
||||||
@@ -178,6 +218,9 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
private final Condition tryAgain = lock.newCondition();
|
private final Condition tryAgain = lock.newCondition();
|
||||||
private volatile boolean finished = false;
|
private volatile boolean finished = false;
|
||||||
|
|
||||||
|
ArrayList<String> dataListString1 = new ArrayList<>();
|
||||||
|
ArrayList<String> dataListString2 = new ArrayList<>();
|
||||||
|
|
||||||
GetData(int v1, int v2) {
|
GetData(int v1, int v2) {
|
||||||
this.v1 = v1;
|
this.v1 = v1;
|
||||||
this.v2 = v2;
|
this.v2 = v2;
|
||||||
@@ -202,6 +245,12 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
this.endless = endless;
|
this.endless = endless;
|
||||||
pBarLockCount -= 1; // do not count for endless tasks, pBarSmall is used
|
pBarLockCount -= 1; // do not count for endless tasks, pBarSmall is used
|
||||||
}
|
}
|
||||||
|
GetData(int v1, int v2, int min1, int max1, int delta1, int min2, int max2, int delta2, boolean endless,
|
||||||
|
ArrayList<String> dataListString1, ArrayList<String> dataListString2) {
|
||||||
|
this(v1, v2, min1, max1, delta1, min2, max2, delta2, endless);
|
||||||
|
this.dataListString1 = dataListString1;
|
||||||
|
this.dataListString2 = dataListString2;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
@@ -228,7 +277,7 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
lock.lock();
|
lock.lock();
|
||||||
do {
|
do {
|
||||||
getJsonOverHttpData(params);
|
getJsonOverHttpData(params);
|
||||||
publishProgress();
|
publishProgress(); // goes to onProgressUpdate
|
||||||
tryAgain.awaitUninterruptibly();
|
tryAgain.awaitUninterruptibly();
|
||||||
//terminateTask();
|
//terminateTask();
|
||||||
} while(!finished);
|
} while(!finished);
|
||||||
@@ -250,7 +299,7 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void getJsonOverHttpData(String... params) {
|
void getJsonOverHttpData(String... params) {
|
||||||
// URL to get contacts JSON
|
// URL to get data JSON
|
||||||
String url = params[0];
|
String url = params[0];
|
||||||
|
|
||||||
HttpHandler sh = new HttpHandler();
|
HttpHandler sh = new HttpHandler();
|
||||||
@@ -268,6 +317,7 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
//JSONArray data = jsonObj.getJSONArray("contacts");
|
//JSONArray data = jsonObj.getJSONArray("contacts");
|
||||||
|
|
||||||
JSONArray data = new JSONArray(jsonStr);
|
JSONArray data = new JSONArray(jsonStr);
|
||||||
|
dataList.clear();
|
||||||
|
|
||||||
// looping through all data
|
// looping through all data
|
||||||
for (int i = 0; i < data.length(); i++) {
|
for (int i = 0; i < data.length(); i++) {
|
||||||
@@ -324,43 +374,51 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
HashMap<String, String> hm = dataList.get(n - 1);
|
HashMap<String, String> hm = dataList.get(n - 1);
|
||||||
|
|
||||||
float temp = Float.parseFloat(hm.get("temperature"));
|
String temp, humidity;
|
||||||
String temperature = String.format(Locale.getDefault(), "%.1f", temp);
|
float tempF = Float.NaN, humidityF = Float.NaN;
|
||||||
|
|
||||||
float humi = Float.parseFloat(hm.get("humidity"));
|
temp = hm.get("temperature");
|
||||||
String humidity = String.format(Locale.getDefault(), "%.1f", humi);
|
if (temp != null) tempF = Float.parseFloat(temp);
|
||||||
|
temp = String.format(Locale.getDefault(), "%.1f", tempF);
|
||||||
|
|
||||||
Color green = Color.valueOf(0x71ff5f);
|
humidity = hm.get("humidity");
|
||||||
Color red = Color.valueOf(0xffd1655d);
|
if (humidity != null) humidityF = Float.parseFloat(humidity);
|
||||||
Color blue = Color.valueOf(Color.rgb(113, 157, 195));
|
humidity = String.format(Locale.getDefault(), "%.1f", humidityF);
|
||||||
|
|
||||||
Color textColor;
|
Color textColor;
|
||||||
|
|
||||||
textColor = valueToColor(temp, 17, 19, 23, 25, blue, green, red);
|
textColor = valueToColor(tempF, 17, 19, 23, 25, blue, green, red);
|
||||||
TextView tv1 = findViewById(v1);
|
TextView tv1 = findViewById(v1);
|
||||||
tv1.setText(temperature);
|
tv1.setText(temp);
|
||||||
tv1.setTextColor(textColor.toArgb());
|
tv1.setTextColor(textColor.toArgb());
|
||||||
|
|
||||||
textColor = valueToColor(humi, 25, 40, 60, 75, red, green, blue);
|
textColor = valueToColor(humidityF, 25, 40, 60, 75, red, green, blue);
|
||||||
TextView tv2 = findViewById(v2);
|
TextView tv2 = findViewById(v2);
|
||||||
tv2.setText(humidity);
|
tv2.setText(humidity);
|
||||||
tv2.setTextColor(textColor.toArgb());
|
tv2.setTextColor(textColor.toArgb());
|
||||||
|
|
||||||
if (idMin1 != 0) {
|
if (idMin1 != 0) {
|
||||||
float min1 = 100, max1 = 0, val1;
|
float min1 = 100, max1 = 0, val1 = Float.NaN;
|
||||||
float min2 = 100, max2 = 0, val2;
|
float min2 = 100, max2 = 0, val2 = Float.NaN;
|
||||||
|
dataListString1.clear();
|
||||||
|
dataListString2.clear();
|
||||||
|
String valString1, valString2;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
hm = dataList.get(i);
|
hm = dataList.get(i);
|
||||||
val1 = Float.parseFloat(hm.get("temperature"));
|
valString1 = hm.get("temperature");
|
||||||
if (val1 < min1)
|
if (valString1 != null)
|
||||||
min1 = val1;
|
val1 = Float.parseFloat(valString1);
|
||||||
if (val1 > max1)
|
valString2 = hm.get("humidity");
|
||||||
max1 = val1;
|
if (valString2 != null)
|
||||||
val2 = Float.parseFloat(hm.get("humidity"));
|
val2 = Float.parseFloat(valString2);
|
||||||
if (val2 < min2)
|
if (val2 <= 100 && val2 >= 0) {
|
||||||
min2 = val2;
|
dataListString1.add(valString1);
|
||||||
if (val2 > max2)
|
dataListString2.add(valString2);
|
||||||
max2 = val2;
|
if (val1 < min1) min1 = val1;
|
||||||
|
if (val1 > max1) max1 = val1;
|
||||||
|
if (val2 < min2) min2 = val2;
|
||||||
|
if (val2 > max2) max2 = val2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TextView tv;
|
TextView tv;
|
||||||
tv = findViewById(idMin1);
|
tv = findViewById(idMin1);
|
||||||
@@ -418,6 +476,369 @@ public class MainNativeActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async task class to get json by making HTTP call
|
||||||
|
*/
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private class OpenWeatherMap extends AsyncTask<String, Void, Void> {
|
||||||
|
String TAG = getClass().getSimpleName();
|
||||||
|
private ProgressBar pBar;
|
||||||
|
|
||||||
|
// OpenWeatherMap API
|
||||||
|
String url = "http://api.openweathermap.org/data/2.5/weather";
|
||||||
|
|
||||||
|
// APPID (API key)
|
||||||
|
String APPID = "f66f296d1ced9a6121998493b84fbaeb";
|
||||||
|
|
||||||
|
// Location id
|
||||||
|
int id = 2850872;
|
||||||
|
|
||||||
|
// Units
|
||||||
|
String units = "metric";
|
||||||
|
|
||||||
|
// Language
|
||||||
|
String lang = "de";
|
||||||
|
|
||||||
|
ArrayList<HashMap<String, String>> dataList = new ArrayList<>();
|
||||||
|
|
||||||
|
int v;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
OpenWeatherMap(int v) {
|
||||||
|
this.v = v;
|
||||||
|
pBarLockCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor to run endless
|
||||||
|
*/
|
||||||
|
// OpenWeatherMap(int v, boolean endless) {
|
||||||
|
// this(v);
|
||||||
|
// this.endless = endless;
|
||||||
|
// pBarLockCount -= 1; // do not count for endless tasks, pBarSmall is used
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
super.onPreExecute();
|
||||||
|
// Showing progress bar
|
||||||
|
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(); // goes to onProgressUpdate
|
||||||
|
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 data JSON
|
||||||
|
if (params.length > 0)
|
||||||
|
url = params[0]; // overwrite openweathermap url with given url
|
||||||
|
else {
|
||||||
|
Map<String, Object> query = new LinkedHashMap<>();
|
||||||
|
query.put("APPID", APPID);
|
||||||
|
query.put("id", id);
|
||||||
|
query.put("units", units);
|
||||||
|
query.put("lang", lang);
|
||||||
|
Log.d(TAG, url + "?" + URLBuilder.httpBuildQuery(query, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpHandler sh = new HttpHandler();
|
||||||
|
|
||||||
|
// Making a request to url and getting response
|
||||||
|
String jsonStr = sh.makeServiceCall(url);
|
||||||
|
|
||||||
|
Log.d(TAG, "Response from url: " + jsonStr);
|
||||||
|
|
||||||
|
if (jsonStr != null) {
|
||||||
|
try {
|
||||||
|
dataList.clear();
|
||||||
|
|
||||||
|
JSONObject jsonObj = new JSONObject(jsonStr);
|
||||||
|
String name = jsonObj.getString("name"); // City name
|
||||||
|
String dt = jsonObj.getString("dt"); // Time of data calculation, unix, UTC
|
||||||
|
|
||||||
|
JSONObject weather = jsonObj.getJSONArray("weather").getJSONObject(0);
|
||||||
|
String weatherId = weather.getString("id"); // Weather condition id
|
||||||
|
String weatherDescription = weather.getString("description"); // Weather condition within the group
|
||||||
|
String weatherIcon = weather.getString("icon"); // Weather icon id
|
||||||
|
|
||||||
|
JSONObject main = jsonObj.getJSONObject("main");
|
||||||
|
String mainTemp = main.getString("temp"); // Temperature. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
|
||||||
|
String mainTempMin = main.getString("temp_min"); // Minimum temperature at the moment. This is deviation from current temp that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
|
||||||
|
String mainTempMax = main.getString("temp_max"); // Maximum temperature at the moment. This is deviation from current temp that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
|
||||||
|
String mainHumidity = main.getString("humidity"); // Humidity, %
|
||||||
|
String mainPressure = main.getString("pressure"); // Atmospheric pressure (on the sea level, if there is no sea_level or grnd_level data), hPa
|
||||||
|
|
||||||
|
JSONObject sys = jsonObj.getJSONObject("sys");
|
||||||
|
String sunrise = sys.getString("sunrise"); // Sunrise time, unix, UTC
|
||||||
|
String sunset = sys.getString("sunset"); // Sunset time, unix, UTC
|
||||||
|
|
||||||
|
JSONObject wind = jsonObj.getJSONObject("wind");
|
||||||
|
String windSpeed = wind.getString("speed"); // Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour.
|
||||||
|
String windDeg = wind.getString("deg"); // Wind direction, degrees (meteorological)
|
||||||
|
String windGust = wind.optString("gust");
|
||||||
|
|
||||||
|
JSONObject clouds = jsonObj.getJSONObject("clouds");
|
||||||
|
String cloudsAll = clouds.getString("all"); // Cloudiness, %
|
||||||
|
|
||||||
|
// tmp hash map for single datum
|
||||||
|
HashMap<String, String> datum = new HashMap<>();
|
||||||
|
|
||||||
|
// adding each child node to HashMap key => value
|
||||||
|
datum.put("name", name);
|
||||||
|
datum.put("dt", dt);
|
||||||
|
datum.put("weather.id", weatherId);
|
||||||
|
datum.put("description", weatherDescription);
|
||||||
|
datum.put("icon", weatherIcon);
|
||||||
|
datum.put("temp", mainTemp);
|
||||||
|
datum.put("temp_min", mainTempMin);
|
||||||
|
datum.put("temp_max", mainTempMax);
|
||||||
|
datum.put("humidity", mainHumidity);
|
||||||
|
datum.put("pressure", mainPressure);
|
||||||
|
datum.put("speed", windSpeed);
|
||||||
|
datum.put("deg", windDeg);
|
||||||
|
datum.put("gust", windGust);
|
||||||
|
datum.put("clouds", cloudsAll);
|
||||||
|
datum.put("sunrise", sunrise);
|
||||||
|
datum.put("sunset", sunset);
|
||||||
|
|
||||||
|
// adding datum to data list
|
||||||
|
dataList.add(datum);
|
||||||
|
} catch (final JSONException e) {
|
||||||
|
Log.e(TAG, "Json parsing error: " + e.getMessage());
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(getApplicationContext(),
|
||||||
|
"Json parsing error: " + e.getMessage(),
|
||||||
|
Toast.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Couldn't get json from server.");
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(getApplicationContext(),
|
||||||
|
"Couldn't get json from server. Check LogCat for possible errors!",
|
||||||
|
Toast.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String degToCompass(int deg) {
|
||||||
|
int val = (int) ((deg / 22.5) + .5);
|
||||||
|
String[] arr = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W",
|
||||||
|
"WNW", "NW", "NNW"};
|
||||||
|
return arr[(val % 16)];
|
||||||
|
}
|
||||||
|
|
||||||
|
float mps2kmph(float speed) {
|
||||||
|
return speed*3.6f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// temp in °C
|
||||||
|
// speed (wind) in m/s
|
||||||
|
float apparentTemperature(float temp, float speed, float humidity) {
|
||||||
|
speed = mps2kmph(speed);
|
||||||
|
float temp_a, temp2, humidity2;
|
||||||
|
// Windchill
|
||||||
|
// http://en.wikipedia.org/wiki/Wind_chill
|
||||||
|
if (temp <= 10 && speed >= 4) {
|
||||||
|
temp_a = 13.12f + 0.6215f * temp - 11.37f * (float) pow(speed, 0.16f) +
|
||||||
|
0.3965f * temp * (float) pow(speed, 0.16f);
|
||||||
|
}
|
||||||
|
// Heat index
|
||||||
|
// http://de.wikipedia.org/wiki/Hitzeindex
|
||||||
|
else if(temp >= 26.7 && humidity >= 40) {
|
||||||
|
temp2 = (float) pow(temp, 2);
|
||||||
|
humidity2 = (float) pow(humidity, 2);
|
||||||
|
temp_a = -8.784695f + 1.61139411f * temp + 2.338549f * humidity +
|
||||||
|
-0.14611605f * temp * humidity + -1.2308094e-2f * temp2 +
|
||||||
|
-1.6424828e-2f * humidity2 + 2.211732e-3f * temp2 * humidity +
|
||||||
|
7.2546e-4f * temp * humidity2 + -3.582e-6f * temp2 * humidity2;
|
||||||
|
} else{
|
||||||
|
temp_a = temp;
|
||||||
|
}
|
||||||
|
return temp_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updating parsed JSON data into Views
|
||||||
|
*/
|
||||||
|
void updateViews() {
|
||||||
|
int n = dataList.size();
|
||||||
|
if (n > 0) {
|
||||||
|
HashMap<String, String> hm = dataList.get(n - 1);
|
||||||
|
DateTimeFormatter formatter;
|
||||||
|
float tempF = Float.NaN, humidityF = Float.NaN;
|
||||||
|
float speedF = Float.NaN;
|
||||||
|
|
||||||
|
String name = hm.get("name");
|
||||||
|
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
String dt = hm.get("dt");
|
||||||
|
if (dt != null) dt = Instant.ofEpochSecond(Long.parseLong(dt)).atZone(ZoneId.systemDefault()).format(formatter);
|
||||||
|
String weatherId = hm.get("weather.id");
|
||||||
|
String description = hm.get("description");
|
||||||
|
String icon = hm.get("icon");
|
||||||
|
|
||||||
|
String temp = hm.get("temp");
|
||||||
|
if (temp != null) tempF = Float.parseFloat(temp);
|
||||||
|
temp = String.format(Locale.getDefault(), "%.1f", tempF);
|
||||||
|
String tempMin = hm.get("temp_min");
|
||||||
|
if (tempMin != null) tempMin = String.format(Locale.getDefault(), "%.1f", Float.parseFloat(tempMin));
|
||||||
|
String tempMax = hm.get("temp_max");
|
||||||
|
if (tempMax != null) tempMax = String.format(Locale.getDefault(), "%.1f", Float.parseFloat(tempMax));
|
||||||
|
String humidity = hm.get("humidity");
|
||||||
|
if (humidity != null) humidityF = Float.parseFloat(humidity);
|
||||||
|
humidity = String.format(Locale.getDefault(), "%.0f", humidityF);
|
||||||
|
|
||||||
|
String pressure = hm.get("pressure");
|
||||||
|
String speed = hm.get("speed");
|
||||||
|
if (speed != null) speedF = Float.parseFloat(speed);
|
||||||
|
speed = String.format(Locale.getDefault(), "%.1f", mps2kmph(speedF));
|
||||||
|
String deg = hm.get("deg");
|
||||||
|
int degI = Integer.MIN_VALUE;
|
||||||
|
if (deg != null) degI = Integer.parseInt(deg);
|
||||||
|
deg = degToCompass(degI);
|
||||||
|
String gust = hm.get("gust");
|
||||||
|
assert gust != null;
|
||||||
|
if (!gust.equals("")) {
|
||||||
|
float gustF = Float.parseFloat(gust);
|
||||||
|
gust = String.format(Locale.getDefault(), "%.1f", mps2kmph(gustF));
|
||||||
|
}
|
||||||
|
String clouds = hm.get("clouds");
|
||||||
|
formatter = DateTimeFormatter.ofPattern("HH:mm");
|
||||||
|
String sunrise = hm.get("sunrise");
|
||||||
|
if (sunrise != null) sunrise = Instant.ofEpochSecond(Long.parseLong(sunrise)).atZone(ZoneId.systemDefault()).format(formatter);
|
||||||
|
String sunset = hm.get("sunset");
|
||||||
|
if (sunset != null) sunset = Instant.ofEpochSecond(Long.parseLong(sunset)).atZone(ZoneId.systemDefault()).format(formatter);
|
||||||
|
|
||||||
|
String apparent = String.format(Locale.getDefault(), "%.1f", apparentTemperature(tempF, speedF, humidityF));
|
||||||
|
|
||||||
|
TextView tv = findViewById(v);
|
||||||
|
if (weatherId != null && weatherId.startsWith("5")){ // 5xx rain
|
||||||
|
if (!gust.equals(""))
|
||||||
|
tv.setText(Html.fromHtml(String.format(getString(R.string.weather_outdoor_rain_and_gust),
|
||||||
|
name, dt, description, clouds,
|
||||||
|
temp, tempMin, tempMax, apparent,
|
||||||
|
humidity, pressure, speed, deg, gust,
|
||||||
|
sunrise, sunset), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
else
|
||||||
|
tv.setText(Html.fromHtml(String.format(getString(R.string.weather_outdoor_rain),
|
||||||
|
name, dt, description, clouds,
|
||||||
|
temp, tempMin, tempMax, apparent,
|
||||||
|
humidity, pressure, speed, deg,
|
||||||
|
sunrise, sunset), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
} else if (!gust.equals(""))
|
||||||
|
tv.setText(Html.fromHtml(String.format(getString(R.string.weather_outdoor_gust),
|
||||||
|
name, dt, description, clouds,
|
||||||
|
temp, tempMin, tempMax, apparent,
|
||||||
|
humidity, pressure, speed, deg, gust,
|
||||||
|
sunrise, sunset), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
else tv.setText(Html.fromHtml(String.format(getString(R.string.weather_outdoor),
|
||||||
|
name, dt, description, clouds,
|
||||||
|
temp, tempMin, tempMax, apparent,
|
||||||
|
humidity, pressure, speed, deg,
|
||||||
|
sunrise, sunset), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
|
||||||
|
// insert image
|
||||||
|
SpannableStringBuilder ssb = new SpannableStringBuilder(tv.getText());
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
int id = context.getResources().getIdentifier("openweathermap_" + icon, "drawable", context.getPackageName());
|
||||||
|
String weather = tv.getText().toString();
|
||||||
|
ssb.setSpan(new CenteredImageSpan(context, id), weather.indexOf("{icon}"), weather.indexOf("{icon}")+6, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||||
|
tv.setText(ssb, TextView.BufferType.SPANNABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void runAgain() {
|
||||||
|
// Call this to request data from the server again
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
tryAgain.signal();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminateTask() {
|
||||||
|
// The task will only finish when we call this method
|
||||||
|
finished = true;
|
||||||
|
//lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
|||||||
168
app/src/main/java/de/weseng/wifiweatherstation/URLBuilder.java
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
package de.weseng.wifiweatherstation;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class: URLBuilder
|
||||||
|
*
|
||||||
|
* Utility that helps to build URL String
|
||||||
|
*
|
||||||
|
* Test functions in URLBuilderTest.java
|
||||||
|
*
|
||||||
|
* Source
|
||||||
|
* - User: Gilad Tiram
|
||||||
|
* - Date: 6/12/13
|
||||||
|
* - Time: 4:02 PM
|
||||||
|
*/
|
||||||
|
class URLBuilder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build URL string from Map of params. Nested Map and Collection is also supported
|
||||||
|
*
|
||||||
|
* @param params Map of params for constructing the URL Query String
|
||||||
|
* @param encoding encoding type. If not set the "UTF-8" is selected by default
|
||||||
|
* @return String of type key=value&...key=value
|
||||||
|
*/
|
||||||
|
static String httpBuildQuery(Map<String, Object> params, String encoding) {
|
||||||
|
if (isEmpty(encoding)) {
|
||||||
|
encoding = "UTF-8";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
|
||||||
|
|
||||||
|
if (value instanceof Map) {
|
||||||
|
List<String> baseParam = new ArrayList<>();
|
||||||
|
baseParam.add(name);
|
||||||
|
String str = buildUrlFromMap(baseParam, (Map) value, encoding);
|
||||||
|
sb.append(str);
|
||||||
|
|
||||||
|
} else if (value instanceof Collection) {
|
||||||
|
List<String> baseParam = new ArrayList<>();
|
||||||
|
baseParam.add(name);
|
||||||
|
String str = buildUrlFromCollection(baseParam, (Collection) value, encoding);
|
||||||
|
sb.append(str);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sb.append(encodeParam(name));
|
||||||
|
sb.append("=");
|
||||||
|
sb.append(encodeParam(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildUrlFromMap(List<String> baseParam, Map<Object, Object> map, String encoding) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String token;
|
||||||
|
|
||||||
|
//Build string of first level - related with params of provided Map
|
||||||
|
for (Map.Entry<Object, Object> entry : map.entrySet()) {
|
||||||
|
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = String.valueOf(entry.getKey());
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof Map) {
|
||||||
|
List<String> baseParam2 = new ArrayList<>(baseParam);
|
||||||
|
baseParam2.add(name);
|
||||||
|
String str = buildUrlFromMap(baseParam2, (Map) value, encoding);
|
||||||
|
sb.append(str);
|
||||||
|
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
List<String> baseParam2 = new ArrayList<>(baseParam);
|
||||||
|
baseParam2.add(name);
|
||||||
|
String str = buildUrlFromCollection(baseParam2, (List) value, encoding);
|
||||||
|
sb.append(str);
|
||||||
|
} else {
|
||||||
|
token = getBaseParamString(baseParam) + "[" + name + "]=" + encodeParam(value);
|
||||||
|
sb.append(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildUrlFromCollection(List<String> baseParam, Collection coll, String encoding) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String token;
|
||||||
|
if (!(coll instanceof List)) {
|
||||||
|
coll = new ArrayList(coll);
|
||||||
|
}
|
||||||
|
List arrColl = (List) coll;
|
||||||
|
|
||||||
|
//Build string of first level - related with params of provided Map
|
||||||
|
for (int i = 0; i < arrColl.size(); i++) {
|
||||||
|
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = arrColl.get(i);
|
||||||
|
if (value instanceof Map) {
|
||||||
|
List<String> baseParam2 = new ArrayList<>(baseParam);
|
||||||
|
baseParam2.add(String.valueOf(i));
|
||||||
|
String str = buildUrlFromMap(baseParam2, (Map) value, encoding);
|
||||||
|
sb.append(str);
|
||||||
|
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
List<String> baseParam2 = new ArrayList<>(baseParam);
|
||||||
|
baseParam2.add(String.valueOf(i));
|
||||||
|
String str = buildUrlFromCollection(baseParam2, (List) value, encoding);
|
||||||
|
sb.append(str);
|
||||||
|
} else {
|
||||||
|
token = getBaseParamString(baseParam) + "[" + i + "]=" + encodeParam(value);
|
||||||
|
sb.append(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String getBaseParamString(List<String> baseParam) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < baseParam.size(); i++) {
|
||||||
|
String s = baseParam.get(i);
|
||||||
|
if (i == 0) {
|
||||||
|
sb.append(s);
|
||||||
|
} else {
|
||||||
|
sb.append("[" + s + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if String is either empty or null
|
||||||
|
*
|
||||||
|
* @param str string to check
|
||||||
|
* @return true if string is empty. Else return false
|
||||||
|
*/
|
||||||
|
private static boolean isEmpty(String str) {
|
||||||
|
return str == null || str.length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String encodeParam(Object param) {
|
||||||
|
try {
|
||||||
|
// @throws java.io.UnsupportedEncodingException if encoding is not supported
|
||||||
|
return URLEncoder.encode(String.valueOf(param), "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
return URLEncoder.encode(String.valueOf(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
BIN
app/src/main/res/drawable/openweathermap_01d.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/drawable/openweathermap_01n.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/drawable/openweathermap_02d.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable/openweathermap_02n.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable/openweathermap_03d.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable/openweathermap_03n.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable/openweathermap_04d.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_04n.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_09d.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_09n.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_10d.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_10n.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_11d.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_11n.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable/openweathermap_13d.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/drawable/openweathermap_13n.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/drawable/openweathermap_50d.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/drawable/openweathermap_50n.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
17
app/src/main/res/layout/activity_detail.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".DetailActivity">
|
||||||
|
|
||||||
|
<com.github.mikephil.charting.charts.LineChart
|
||||||
|
android:id="@+id/chart1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginBottom="@dimen/activity_vertical_margin" />
|
||||||
|
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
android:layout_marginEnd="@dimen/activity_horizontal_margin"
|
android:layout_marginEnd="@dimen/widget_horizontal_margin"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="1.0"
|
app:layout_constraintHorizontal_bias="1.0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="-8dp"
|
android:layout_marginBottom="-8dp"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
android:weightSum="6">
|
android:weightSum="6">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -60,7 +61,9 @@
|
|||||||
|
|
||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textViewTemperatureValue1"
|
android:id="@+id/textViewTemperatureValue1"
|
||||||
@@ -110,6 +113,8 @@
|
|||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin"
|
||||||
android:weightSum="6">
|
android:weightSum="6">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -189,7 +194,9 @@
|
|||||||
|
|
||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textViewTemperatureValue2"
|
android:id="@+id/textViewTemperatureValue2"
|
||||||
@@ -239,6 +246,8 @@
|
|||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin"
|
||||||
android:weightSum="6">
|
android:weightSum="6">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -318,7 +327,9 @@
|
|||||||
|
|
||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textViewTemperatureValue3"
|
android:id="@+id/textViewTemperatureValue3"
|
||||||
@@ -368,6 +379,8 @@
|
|||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin"
|
||||||
android:weightSum="6">
|
android:weightSum="6">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -436,6 +449,18 @@
|
|||||||
android:background="?android:attr/listDivider"
|
android:background="?android:attr/listDivider"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textViewWeatherOutdoor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/widget_vertical_margin"
|
||||||
|
android:layout_marginBottom="@dimen/widget_vertical_margin"
|
||||||
|
android:layout_marginStart="@dimen/widget_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/widget_horizontal_margin"
|
||||||
|
android:text="@string/weather_outdoor" />
|
||||||
|
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -4,6 +4,41 @@
|
|||||||
<!-- Strings related to native view -->
|
<!-- Strings related to native view -->
|
||||||
<string name="temperature">Temperatur</string>
|
<string name="temperature">Temperatur</string>
|
||||||
<string name="humidity">Feuchtigkeit</string>
|
<string name="humidity">Feuchtigkeit</string>
|
||||||
|
<string name="weather_outdoor"><![CDATA[<b>Wetterdaten für %s</b> %s
|
||||||
|
<br/>{icon} %s (%s %%)
|
||||||
|
<br/>Temperatur: %s °C — %s° / %s° gefühlt: %s°
|
||||||
|
<br/>Feuchtigkeit: %s %%
|
||||||
|
<br/>Druck: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s
|
||||||
|
<br/>Sonnenaufgang / -untergang: %s / %s]]></string>
|
||||||
|
<string name="weather_outdoor_rain"><![CDATA[<b>Wetterdaten für %s</b> %s
|
||||||
|
<br/>{icon} %s, Bewölkung: %s %%
|
||||||
|
<br/>Temperatur: %s °C — %s° / %s° gefühlt: %s°
|
||||||
|
<br/>Feuchtigkeit: %s %%
|
||||||
|
<br/>Druck: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s
|
||||||
|
<br/>Sonnenaufgang / -untergang: %s / %s]]></string>
|
||||||
|
<string name="weather_outdoor_rain_and_gust"><![CDATA[<b>Wetterdaten für %s</b> %s
|
||||||
|
<br/>{icon} %s, Bewölkung: %s %%
|
||||||
|
<br/>Temperatur: %s °C — %s° / %s° gefühlt: %s°
|
||||||
|
<br/>Feuchtigkeit: %s %%
|
||||||
|
<br/>Druck: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s Windböe %s km/h
|
||||||
|
<br/>Sonnenaufgang / -untergang: %s / %s]]></string>
|
||||||
|
<string name="weather_outdoor_gust"><![CDATA[<b>Wetterdaten für %s</b> %s
|
||||||
|
<br/>{icon} %s (%s %%)
|
||||||
|
<br/>Temperatur: %s °C — %s° / %s° gefühlt: %s°
|
||||||
|
<br/>Feuchtigkeit: %s %%
|
||||||
|
<br/>Druck: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s Windböe %s km/h
|
||||||
|
<br/>Sonnenaufgang / -untergang: %s / %s]]></string>
|
||||||
|
<string name="weather_outdoor_rainfall"><![CDATA[<b>Wetterdaten für %s</b> %s
|
||||||
|
<br/>{icon} %s, Niederschlagsmenge: %s mm, Bewölkung: %s %%
|
||||||
|
<br/>Temperatur: %s °C — %s° / %s° gefühlt: %s°
|
||||||
|
<br/>Feuchtigkeit: %s %%
|
||||||
|
<br/>Druck: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s
|
||||||
|
<br/>Sonnenaufgang / -untergang: %s / %s]]></string>
|
||||||
<!-- Strings related to settings -->
|
<!-- Strings related to settings -->
|
||||||
<string name="settings">Einstellungen</string>
|
<string name="settings">Einstellungen</string>
|
||||||
<string name="message_connection_internal">Verbindung: intern</string>
|
<string name="message_connection_internal">Verbindung: intern</string>
|
||||||
|
|||||||
@@ -8,6 +8,45 @@
|
|||||||
<string name="humidity_unit" translatable="false">%</string>
|
<string name="humidity_unit" translatable="false">%</string>
|
||||||
<string name="dummy_value" translatable="false">__._</string>
|
<string name="dummy_value" translatable="false">__._</string>
|
||||||
<string name="dummy_value2" translatable="false">o</string>
|
<string name="dummy_value2" translatable="false">o</string>
|
||||||
|
<!-- name, dt; description, clouds; temp, tempMin, tempMax, apparent; humidity; pressure; speed, deg; sunrise, sunset -->
|
||||||
|
<string name="weather_outdoor"><![CDATA[<b>Weather data for %s</b> %s
|
||||||
|
<br/>{icon} %s (%s %%)
|
||||||
|
<br/>Temperature: %s °C — %s° / %s° feels: %s°
|
||||||
|
<br/>Humidity: %s %%
|
||||||
|
<br/>Pressure: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s
|
||||||
|
<br/>Sunrise / sunset: %s / %s]]></string>
|
||||||
|
<!-- print clouds before clouds value if the description is about raining, so no misunderstanding applies -->
|
||||||
|
<!-- name, dt; description, clouds; temp, tempMin, tempMax, apparent; humidity; pressure; speed, deg; sunrise, sunset -->
|
||||||
|
<string name="weather_outdoor_rain"><![CDATA[<b>Weather data for %s</b> %s
|
||||||
|
<br/>{icon} %s, clouds: %s %%
|
||||||
|
<br/>Temperature: %s °C — %s° / %s° feels: %s°
|
||||||
|
<br/>Humidity: %s %%
|
||||||
|
<br/>Pressure: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s
|
||||||
|
<br/>Sunrise / sunset: %s / %s]]></string>
|
||||||
|
<string name="weather_outdoor_rain_and_gust"><![CDATA[<b>Weather data for %s</b> %s
|
||||||
|
<br/>{icon} %s, clouds: %s %%
|
||||||
|
<br/>Temperature: %s °C — %s° / %s° feels: %s°
|
||||||
|
<br/>Humidity: %s %%
|
||||||
|
<br/>Pressure: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s gust: %s km/h
|
||||||
|
<br/>Sunrise / sunset: %s / %s]]></string>
|
||||||
|
<string name="weather_outdoor_gust"><![CDATA[<b>Weather data for %s</b> %s
|
||||||
|
<br/>{icon} %s (%s %%)
|
||||||
|
<br/>Temperature: %s °C — %s° / %s° feels: %s°
|
||||||
|
<br/>Humidity: %s %%
|
||||||
|
<br/>Pressure: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s gust: %s km/h
|
||||||
|
<br/>Sunrise / sunset: %s / %s]]></string>
|
||||||
|
<!-- name, dt; description, rain, clouds; temp, tempMin, tempMax, apparent; humidity; pressure; speed, deg; sunrise, sunset -->
|
||||||
|
<string name="weather_outdoor_rainfall"><![CDATA[<b>Weather data for %s</b> %s
|
||||||
|
<br/>{icon} %s, rainfall: %s mm, clouds: %s %%
|
||||||
|
<br/>Temperature: %s °C — %s° / %s° feels: %s°
|
||||||
|
<br/>Humidity: %s %%
|
||||||
|
<br/>Pressure: %s hPa
|
||||||
|
<br/>Wind: %s km/h %s
|
||||||
|
<br/>Sunrise / sunset: %s / %s]]></string>
|
||||||
<!-- Strings related to settings -->
|
<!-- Strings related to settings -->
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="message" translatable="false">de.weseng.wifiweatherstation.MESSAGE</string>
|
<string name="message" translatable="false">de.weseng.wifiweatherstation.MESSAGE</string>
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package de.weseng.wifiweatherstation;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static de.weseng.wifiweatherstation.URLBuilder.httpBuildQuery;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class URLBuilderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basicTest() {
|
||||||
|
Map<String, Object> params = new LinkedHashMap<>();
|
||||||
|
params.put("a", "1");
|
||||||
|
params.put("b", "2");
|
||||||
|
params.put("c", "3");
|
||||||
|
|
||||||
|
assertEquals("a=1&b=2&c=3",
|
||||||
|
httpBuildQuery(params, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithMap() {
|
||||||
|
Map<String, Object> params = new LinkedHashMap<>();
|
||||||
|
params.put("a", "1");
|
||||||
|
params.put("b", "2");
|
||||||
|
|
||||||
|
Map<String, Object> cParams = new LinkedHashMap<>();
|
||||||
|
cParams.put("c1", "c1val");
|
||||||
|
cParams.put("c2", "c2val");
|
||||||
|
params.put("c", cParams);
|
||||||
|
|
||||||
|
assertEquals("a=1&b=2&c[c1]=c1val&c[c2]=c2val",
|
||||||
|
httpBuildQuery(params, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithNestedMap() {
|
||||||
|
Map<String, Object> params = new LinkedHashMap<>();
|
||||||
|
params.put("a", "1");
|
||||||
|
params.put("b", "2");
|
||||||
|
|
||||||
|
Map<String, Object> cParamsLevel1 = new LinkedHashMap<>();
|
||||||
|
cParamsLevel1.put("cL1-1", "cLevel1-1val");
|
||||||
|
cParamsLevel1.put("cL1-2", "cLevel1-2val");
|
||||||
|
|
||||||
|
Map<String, Object> cParamsLevel2 = new LinkedHashMap<>();
|
||||||
|
cParamsLevel2.put("cL2-1", "cLevel2-1val");
|
||||||
|
cParamsLevel2.put("cL2-2", "cLevel2-2val");
|
||||||
|
cParamsLevel1.put("cL1-3", cParamsLevel2);
|
||||||
|
|
||||||
|
params.put("c", cParamsLevel1);
|
||||||
|
|
||||||
|
assertEquals("a=1&b=2&c[cL1-1]=cLevel1-1val&c[cL1-2]=cLevel1-2val&c[cL1-3][cL2-1]=cLevel2-1val&c[cL1-3][cL2-2]=cLevel2-2val",
|
||||||
|
httpBuildQuery(params, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithList() {
|
||||||
|
Map<String, Object> params = new LinkedHashMap<>();
|
||||||
|
params.put("a", "1");
|
||||||
|
params.put("b", "2");
|
||||||
|
|
||||||
|
List<Object> cParams = new ArrayList<>();
|
||||||
|
cParams.add("c1val");
|
||||||
|
cParams.add("c2val");
|
||||||
|
params.put("c", cParams);
|
||||||
|
|
||||||
|
assertEquals("a=1&b=2&c[0]=c1val&c[1]=c2val",
|
||||||
|
httpBuildQuery(params, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithNestedList() {
|
||||||
|
Map<String, Object> params = new LinkedHashMap<>();
|
||||||
|
params.put("a", "1");
|
||||||
|
params.put("b", "2");
|
||||||
|
|
||||||
|
List<Object> cParamsLevel1 = new ArrayList<>();
|
||||||
|
cParamsLevel1.add("cL1-val1");
|
||||||
|
cParamsLevel1.add("cL12-val2");
|
||||||
|
|
||||||
|
List<Object> cParamsLevel2 = new ArrayList<>();
|
||||||
|
cParamsLevel2.add("cL2-val1");
|
||||||
|
cParamsLevel2.add("cL2-val2");
|
||||||
|
cParamsLevel1.add(cParamsLevel2);
|
||||||
|
|
||||||
|
params.put("c", cParamsLevel1);
|
||||||
|
|
||||||
|
assertEquals("a=1&b=2&c[0]=cL1-val1&c[1]=cL12-val2&c[2][0]=cL2-val1&c[2][1]=cL2-val2",
|
||||||
|
httpBuildQuery(params, "UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompound() {
|
||||||
|
Map<String, Object> params = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
//flat
|
||||||
|
params.put("a", "1");
|
||||||
|
params.put("b", "2");
|
||||||
|
|
||||||
|
//Map level 1
|
||||||
|
Map<String, Object> cParamsLevel1 = new LinkedHashMap<>();
|
||||||
|
cParamsLevel1.put("cL1-1", "cLevel1-1val");
|
||||||
|
cParamsLevel1.put("cL1-2", "cLevel1-2val");
|
||||||
|
|
||||||
|
//Map level 2
|
||||||
|
Map<String, Object> cParamsLevel2 = new LinkedHashMap<>();
|
||||||
|
cParamsLevel2.put("cL2-1", "cLevel2-1val");
|
||||||
|
cParamsLevel2.put("cL2-2", "cLevel2-2val");
|
||||||
|
cParamsLevel1.put("cL1-3", cParamsLevel2);
|
||||||
|
|
||||||
|
params.put("c", cParamsLevel1);
|
||||||
|
|
||||||
|
//List level 1
|
||||||
|
List<Object> dParamsLevel1 = new ArrayList<>();
|
||||||
|
dParamsLevel1.add("dL1-val1");
|
||||||
|
dParamsLevel1.add("dL12-val2");
|
||||||
|
|
||||||
|
//List level 2
|
||||||
|
List<Object> dParamsLevel2 = new ArrayList<>();
|
||||||
|
dParamsLevel2.add("dL2-val1");
|
||||||
|
dParamsLevel2.add("dL2-val2");
|
||||||
|
dParamsLevel1.add(dParamsLevel2);
|
||||||
|
|
||||||
|
params.put("d", dParamsLevel1);
|
||||||
|
|
||||||
|
assertEquals("a=1&b=2&c[cL1-1]=cLevel1-1val&c[cL1-2]=cLevel1-2val&c[cL1-3][cL2-1]=cLevel2-1val&c[cL1-3][cL2-2]=cLevel2-2val&d[0]=dL1-val1&d[1]=dL12-val2&d[2][0]=dL2-val1&d[2][1]=dL2-val2",
|
||||||
|
httpBuildQuery(params, "UTF-8"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||