Skip to content

Commit

Permalink
Added code to download a single image from a mjpeg source
Browse files Browse the repository at this point in the history
  • Loading branch information
evilbunny2008 committed Mar 28, 2018
1 parent 8f824b3 commit 0237a2a
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 26 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ android {
applicationId "com.odiousapps.weewxweather"
minSdkVersion 16
targetSdkVersion 26
versionCode 2004
versionName "0.2.4"
versionCode 2005
versionName "0.2.5"
}
buildTypes {
release {
Expand Down
8 changes: 5 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.odiousapps.weewxweather"
<manifest xmlns:tools="http://schemas.android.com/tools"
package="com.odiousapps.weewxweather"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning"
android:fullBackupContent="@xml/backup_descriptor">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/java/com/odiousapps/weewxweather/Common.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.widget.RemoteViews;

class Common
Expand All @@ -28,8 +29,8 @@ static void LogMessage(String value)

static void LogMessage(String value, boolean showAnyway)
{
if (debug_on || showAnyway)
System.out.println("WeeWx Weather: ts=" + System.currentTimeMillis() + ", message='" + value + "'");
if(debug_on || showAnyway)
Log.i("WeeWx Weather", "message='" + value + "'");
}

void SetStringPref(String name, String value)
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/java/com/odiousapps/weewxweather/Custom.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

Expand Down Expand Up @@ -63,11 +64,13 @@ public boolean onKey(View v, int keyCode, KeyEvent event)
if(wv.canGoBack())
{
wv.goBack();
return true;
}
}
}
}
return true;

return false;
}
});

Expand All @@ -90,6 +93,10 @@ private void reloadWebView()
if (custom == null || custom.equals(""))
return;

wv.getSettings().setAppCacheEnabled(false);
wv.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
wv.getSettings().setUserAgentString(Common.UA);
wv.clearCache(true);
wv.loadUrl(custom);
}

Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/com/odiousapps/weewxweather/Forecast.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,11 @@ private void generateForecast()
}
}

private void updateForecast(String bits, String desc)
private void updateForecast(final String bits, final String desc)
{
String fc = "<html><body style='text-align:center'>";
fc += bits + "</body></html>";

wv.loadDataWithBaseURL(null, fc, "text/html", "utf-8", null);

TextView tv1 = rootView.findViewById(R.id.forecast);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
Forecast forecast = new Forecast(common);
return forecast.myForecast(inflater, container);
} else if(getArguments().getInt(ARG_SECTION_NUMBER) == 4) {
String webURL = common.GetStringPref("WEBCAM_URL", "");
Webcam webcam = new Webcam(common);
return webcam.myWebcam(inflater, container);
} else if(getArguments().getInt(ARG_SECTION_NUMBER) == 5) {
Expand Down
118 changes: 118 additions & 0 deletions app/src/main/java/com/odiousapps/weewxweather/MjpegRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.odiousapps.weewxweather;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;

public class MjpegRunner implements Runnable
{
// https://github.com/andrealaforgia/mjpeg-client/blob/master/src/main/java/com/andrealaforgia/mjpegclient/MjpegRunner.java

private static final String CONTENT_LENGTH = "Content-Length: ";
private final URL url;
private InputStream urlStream;
private boolean isRunning = true;
Bitmap bm = null;

MjpegRunner(URL url) throws IOException
{
this.url = url;
start();
}

private void start() throws IOException
{
URLConnection urlConn = url.openConnection();
urlConn.setReadTimeout(5000);
urlConn.connect();
urlStream = urlConn.getInputStream();
}

/**
* Stop the loop, and allow it to clean up
*/
private synchronized void stop()
{
isRunning = false;
}

public void run() {
while (isRunning) {
try {
Common.LogMessage("waiting for an image.");
byte[] imageBytes = retrieveNextImage();
ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
bm = BitmapFactory.decodeStream(bais);
Common.LogMessage("got an image... wooo!");
isRunning = false;
} catch (SocketTimeoutException ste) {
System.err.println("failed stream read: " + ste);
stop();

} catch (IOException e) {
System.err.println("failed stream read: " + e);
stop();
}
}

// close streams
try {
urlStream.close();
} catch (IOException ioe) {
System.err.println("Failed to close the stream: " + ioe);
}
}

private byte[] retrieveNextImage() throws IOException
{
int currByte;

boolean captureContentLength = false;
StringWriter contentLengthStringWriter = new StringWriter(128);
StringWriter headerWriter = new StringWriter(128);

int contentLength = 0;

while ((currByte = urlStream.read()) > -1) {
if (captureContentLength) {
if (currByte == 10 || currByte == 13) {
contentLength = Integer.parseInt(contentLengthStringWriter.toString());
break;
}
contentLengthStringWriter.write(currByte);

} else {
headerWriter.write(currByte);
String tempString = headerWriter.toString();
int indexOf = tempString.indexOf(CONTENT_LENGTH);
if (indexOf > 0) {
captureContentLength = true;
}
}
}

// 255 indicates the start of the jpeg image
//noinspection StatementWithEmptyBody
while ((urlStream.read()) != 255) {}

// rest is the buffer
byte[] imageBytes = new byte[contentLength + 1];
// since we ate the original 255 , shove it back in
imageBytes[0] = (byte) 255;
int offset = 1;
int numRead;
while (offset < imageBytes.length
&& (numRead = urlStream.read(imageBytes, offset, imageBytes.length - offset)) >= 0) {
offset += numRead;
}

return imageBytes;
}
}
60 changes: 51 additions & 9 deletions app/src/main/java/com/odiousapps/weewxweather/Settings.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.odiousapps.weewxweather;

import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
Expand Down Expand Up @@ -30,6 +33,7 @@ class Settings implements AdapterView.OnItemSelectedListener
{
private Common common;
private EditText et1;
private Button b1;

private ProgressDialog dialog;

Expand Down Expand Up @@ -65,11 +69,13 @@ View mySettings(LayoutInflater inflater, ViewGroup container)
if(!metric)
cb2.setChecked(false);

Button b1 = rootView.findViewById(R.id.button);
b1 = rootView.findViewById(R.id.button);
b1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
b1.setEnabled(false);

Common.LogMessage("show dialog");
dialog = ProgressDialog.show(common.context, "Testing submitted URLs", "Please wait while we verify the URL you submitted.", false);
dialog.show();
Expand All @@ -85,7 +91,7 @@ public void run()
boolean validURL3 = false;
boolean validURL4 = false;
boolean validURL5 = false;
String data = "", radar = "", forecast = "", webcam = "", custom = "";
String data = "", radar = "", forecast = "", webcam = "", custom = "", oldurl = common.GetStringPref("WEBCAM_URL", "");

CheckBox cb1 = rootView.findViewById(R.id.cb1);
CheckBox cb2 = rootView.findViewById(R.id.cb2);
Expand Down Expand Up @@ -305,10 +311,11 @@ public void run()
common.SetStringPref("WEBCAM_URL", webcam);
common.SetStringPref("CUSTOM_URL", custom);
common.SetBoolPref("metric", cb2.isChecked());
Intent intent = new Intent();
intent.putExtra("urlChanged", true);

handlerDone.sendEmptyMessage(0);
if(!oldurl.equals(webcam) && !oldurl.equals(""))
handlerNeedRestart.sendEmptyMessage(0);
else
handlerDone.sendEmptyMessage(0);
}
});

Expand All @@ -328,38 +335,69 @@ public void handleMessage(Message msg)
Common.LogMessage("sending intents");
dialog.dismiss();
Intent intent = new Intent();
intent.putExtra("urlChanged", true);
intent = new Intent();
intent.setAction(myService.TAB0_INTENT);
common.context.sendBroadcast(intent);
Common.LogMessage("sent intents");
}
};

@SuppressLint("HandlerLeak")
private Handler handlerSettings = new Handler()
private Handler handlerNeedRestart = new Handler()
{
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
.setMessage("Wasn't able to connect or download settings from your server")
.setPositiveButton("I'll Fix It and Try Again", new DialogInterface.OnClickListener()
.setTitle("App needs a restart")
.setMessage("This app needs a restart to reload config.")
.setPositiveButton("Restart now", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
Intent mStartActivity = new Intent(common.context, MainActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(common.context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)common.context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
}
}).show();
}
};

@SuppressLint("HandlerLeak")
private Handler handlerSettings = new Handler()
{
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
.setMessage("Wasn't able to connect or download settings from your server")
.setPositiveButton("I'll Fix It and Try Again", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
}
}).show();
}
};

@SuppressLint("HandlerLeak")
private Handler handlerDATA = new Handler()
{
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
Expand All @@ -380,6 +418,7 @@ public void onClick(DialogInterface dialog, int which)
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
Expand All @@ -400,6 +439,7 @@ public void onClick(DialogInterface dialog, int which)
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
Expand All @@ -420,6 +460,7 @@ public void onClick(DialogInterface dialog, int which)
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
Expand All @@ -440,6 +481,7 @@ public void onClick(DialogInterface dialog, int which)
@Override
public void handleMessage(Message msg)
{
b1.setEnabled(true);
dialog.dismiss();
new AlertDialog.Builder(common.context)
.setTitle("Invalid URL")
Expand Down
Loading

0 comments on commit 0237a2a

Please sign in to comment.