From f20bdfdf408863985be14a9a428b1c4af6726464 Mon Sep 17 00:00:00 2001 From: MRSa Date: Sun, 10 Jan 2021 00:34:11 +0900 Subject: [PATCH] =?utf8?q?ConnectionMethod=E3=81=AE=E9=81=95=E3=81=84?= =?utf8?q?=E3=81=A7=E8=83=8C=E6=99=AF=E7=94=BB=E5=83=8F=E3=82=92=E5=A4=89?= =?utf8?q?=E6=9B=B4=E3=81=97=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../java/jp/sfjp/gokigen/a01c/MainActivity.java | 18 +- .../gokigen/a01c/liveview/CameraLiveImageView.java | 15 +- .../jp/sfjp/gokigen/a01c/utils/SimpleHttpClient.kt | 524 +++++++++++++++++++++ .../gokigen/a01c/utils/SimpleLiveviewSlicer.java | 404 ++++++++++++++++ .../sfjp/gokigen/a01c/utils/SimpleLogDumper.java | 78 +++ .../jp/sfjp/gokigen/a01c/utils/XmlElement.java | 183 +++++++ wear/src/main/res/values-ja/strings.xml | 4 + wear/src/main/res/values/strings.xml | 4 + 8 files changed, 1227 insertions(+), 3 deletions(-) create mode 100644 wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleHttpClient.kt create mode 100644 wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLiveviewSlicer.java create mode 100644 wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLogDumper.java create mode 100644 wear/src/main/java/jp/sfjp/gokigen/a01c/utils/XmlElement.java diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/MainActivity.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/MainActivity.java index 1006d9c..14d7f9c 100644 --- a/wear/src/main/java/jp/sfjp/gokigen/a01c/MainActivity.java +++ b/wear/src/main/java/jp/sfjp/gokigen/a01c/MainActivity.java @@ -821,7 +821,6 @@ public class MainActivity extends AppCompatActivity implements IChangeScene, IS { liveView.hideDialog(); listener.setEnableOperation(operation.ENABLE); - } } catch (Exception e) @@ -830,6 +829,20 @@ public class MainActivity extends AppCompatActivity implements IChangeScene, IS } } + private void updateConnectionMethodMessage() + { + try + { + String connectionMethod = preferences.getString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE); + int methodId = (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) ? R.string.connection_method_theta : R.string.connection_method_opc; + setMessage(IShowInformation.AREA_5, Color.MAGENTA, getString(methodId)); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + private void updateConnectionMethod(String parameter, ICameraController method) { try @@ -845,7 +858,7 @@ public class MainActivity extends AppCompatActivity implements IChangeScene, IS } /** - * 接続方式を変更するか確認する + * 接続方式を変更するか確認する (OPC ⇔ THETA) * */ private void changeConnectionMethod() @@ -882,6 +895,7 @@ public class MainActivity extends AppCompatActivity implements IChangeScene, IS // 接続方式を Theta に切り替える updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA, olyAirCoordinator); // thetaCoordinator } + updateConnectionMethodMessage(); } }); } diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/CameraLiveImageView.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/CameraLiveImageView.java index 16d3f93..3f0b13f 100644 --- a/wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/CameraLiveImageView.java +++ b/wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/CameraLiveImageView.java @@ -120,7 +120,20 @@ public class CameraLiveImageView extends View implements IImageDataReceiver, IAu // ダミーのビットマップデータ読み込み...画面表示のテスト用ロジック try { - imageBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.momonga); + int imageId = R.drawable.momonga; + try + { + String connectionMethod = preferences.getString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE); + if (connectionMethod != null) + { + imageId = (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) ? R.drawable.kamakura : R.drawable.momonga; + } + } + catch (Throwable tt) + { + tt.printStackTrace(); + } + imageBitmap = BitmapFactory.decodeResource(context.getResources(), imageId); } catch (Throwable t) { diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleHttpClient.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleHttpClient.kt new file mode 100644 index 0000000..3e81231 --- /dev/null +++ b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleHttpClient.kt @@ -0,0 +1,524 @@ +package jp.sfjp.gokigen.a01c.utils + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.util.Log +import java.io.* +import java.net.HttpURLConnection +import java.net.URL + +class SimpleHttpClient() +{ + /** + * + * + * + */ + fun httpGet(url: String, timeoutMs: Int): String + { + var inputStream : InputStream? = null + var replyString = "" + var timeout = timeoutMs + if (timeoutMs < 0) + { + timeout = DEFAULT_TIMEOUT + } + + // HTTP GETメソッドで要求を投げる + try + { + val httpConn = URL(url).openConnection() as HttpURLConnection + try + { + httpConn.requestMethod = "GET" + httpConn.connectTimeout = timeout + httpConn.readTimeout = timeout + httpConn.connect() + val responseCode = httpConn.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) + { + inputStream = httpConn.inputStream + } + if (inputStream == null) + { + Log.w(TAG, "httpGet: Response Code Error: $responseCode: $url") + return ("") + } + } + catch (ee : Exception) + { + Log.w(TAG, "httpGet: " + url + " " + ee.message) + ee.printStackTrace() + httpConn.disconnect() + return ("") + } + } + catch (e: Exception) + { + Log.w(TAG, "httpGet(2): " + url + " " + e.message) + e.printStackTrace() + return ("") + } + + // 応答を確認する + try + { + val responseBuf = StringBuilder() + val reader = BufferedReader(InputStreamReader(inputStream)) + var c: Int + while (reader.read().also { c = it } != -1) + { + responseBuf.append(c.toChar()) + } + replyString = responseBuf.toString() + reader.close() + } + catch (e: Exception) + { + Log.w(TAG, "httpGet: exception: " + e.message) + e.printStackTrace() + } + finally + { + try + { + inputStream.close() + } + catch (e: Exception) + { + e.printStackTrace() + } + } + return (replyString) + } + + /** + * + * + * + */ + fun httpGetBytes(url: String, setProperty: Map?, timeoutMs: Int, callback: IReceivedMessageCallback) + { + httpCommandBytes(url, "GET", null, setProperty, null, timeoutMs, callback) + } + + /** + * + * + * + */ + fun httpPostBytes(url: String, postData: String?, setProperty: Map?, timeoutMs: Int, callback: IReceivedMessageCallback) + { + httpCommandBytes(url, "POST", postData, setProperty, null, timeoutMs, callback) + } + + private fun httpCommandBytes(url: String, requestMethod: String, postData: String?, setProperty: Map?, contentType: String?, timeoutMs: Int, callback: IReceivedMessageCallback) + { + var inputStream: InputStream? = null + var timeout = timeoutMs + if (timeoutMs < 0) + { + timeout = DEFAULT_TIMEOUT + } + + // HTTP メソッドで要求を送出 + try + { + val httpConn = URL(url).openConnection() as HttpURLConnection + httpConn.requestMethod = requestMethod + if (setProperty != null) + { + for (key in setProperty.keys) + { + val value = setProperty[key] + httpConn.setRequestProperty(key, value) + } + } + if (contentType != null) + { + httpConn.setRequestProperty("Content-Type", contentType) + } + httpConn.connectTimeout = timeout + httpConn.readTimeout = timeout + if (postData == null) + { + httpConn.connect() + } + else + { + httpConn.doInput = true + httpConn.doOutput = true + val outputStream = httpConn.outputStream + val writer = OutputStreamWriter(outputStream, "UTF-8") + writer.write(postData) + writer.flush() + writer.close() + outputStream.close() + } + val responseCode = httpConn.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) + { + inputStream = httpConn.inputStream + } + if (inputStream == null) + { + Log.w(TAG, " http $requestMethod Response Code Error: $responseCode: $url") + callback.onErrorOccurred(NullPointerException()) + callback.onCompleted() + return + } + + // 応答を確認する + try + { + var contentLength = httpConn.contentLength + if (contentLength < 0) + { + // コンテンツ長が取れない場合の処理... + try + { + val headers = httpConn.headerFields + // コンテンツ長さが取れない場合は、HTTP応答ヘッダから取得する + val valueList = headers["X-FILE_SIZE"] + try + { + if (valueList != null) + { + contentLength = getValue(valueList).toInt() + } + } + catch (ee: Exception) + { + ee.printStackTrace() + } + } + catch (e: Exception) + { + e.printStackTrace() + } + } + val buffer = ByteArray(BUFFER_SIZE) + var readBytes = 0 + var readSize = inputStream.read(buffer, 0, BUFFER_SIZE) + while (readSize != -1) + { + callback.onReceive(readBytes, contentLength, readSize, buffer) + readBytes += readSize + readSize = inputStream.read(buffer, 0, BUFFER_SIZE) + } + Log.v(TAG, "RECEIVED $readBytes BYTES. (contentLength : $contentLength)") + inputStream.close() + } + catch (e: Exception) + { + Log.w(TAG, "httpGet: exception: " + e.message) + e.printStackTrace() + callback.onErrorOccurred(e) + } + finally + { + try + { + inputStream.close() + } + catch (e: Exception) + { + e.printStackTrace() + } + } + } + catch (e: Exception) + { + Log.w(TAG, "http " + requestMethod + " " + url + " " + e.message) + e.printStackTrace() + callback.onErrorOccurred(e) + callback.onCompleted() + return + } + callback.onCompleted() + } + + + private fun getValue(valueList: List): String + { + // 応答ヘッダの値切り出し用... + var isFirst = true + val values = StringBuilder() + for (value in valueList) + { + values.append(value) + if (isFirst) + { + isFirst = false + } + else + { + values.append(" ") + } + } + return values.toString() + } + + fun httpGetBitmap(url: String, setProperty: Map?, timeoutMs: Int): Bitmap? + { + return (httpCommandBitmap(url, "GET", null, setProperty, null, timeoutMs)) + } + + /** + * + * + * + */ + fun httpPostBitmap(url: String, postData: String?, timeoutMs: Int): Bitmap? + { + return (httpCommandBitmap(url, "POST", postData, null, null, timeoutMs)) + } + + /** + * + * + * + */ + private fun httpCommandBitmap(url: String, requestMethod: String, postData: String?, setProperty: Map?, contentType: String?, timeoutMs: Int): Bitmap? + { + //var httpConn: HttpURLConnection? = null + var inputStream: InputStream? = null + //var outputStream: OutputStream? = null + //var writer: OutputStreamWriter? = null + var bmp: Bitmap? = null + var timeout = timeoutMs + if (timeoutMs < 0) + { + timeout = DEFAULT_TIMEOUT + } + + // HTTP メソッドで要求を送出 + try + { + val httpConn = URL(url).openConnection() as HttpURLConnection + httpConn.requestMethod = requestMethod + if (setProperty != null) + { + for (key in setProperty.keys) + { + val value = setProperty[key] + httpConn.setRequestProperty(key, value) + } + } + if (contentType != null) + { + httpConn.setRequestProperty("Content-Type", contentType) + } + httpConn.connectTimeout = timeout + httpConn.readTimeout = timeout + if (postData == null) + { + httpConn.connect() + } + else + { + httpConn.doInput = true + httpConn.doOutput = true + val outputStream = httpConn.outputStream + val writer = OutputStreamWriter(outputStream, "UTF-8") + writer.write(postData) + writer.flush() + writer.close() + outputStream.close() + } + val responseCode = httpConn.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) + { + inputStream = httpConn.inputStream + if (inputStream != null) + { + bmp = BitmapFactory.decodeStream(inputStream) + } + } + if (inputStream == null) + { + Log.w(TAG, "http: ($requestMethod) Response Code Error: $responseCode: $url") + return (null) + } + inputStream.close() + } + catch (e: Exception) + { + Log.w(TAG, "http: (" + requestMethod + ") " + url + " " + e.message) + e.printStackTrace() + return (null) + } + return (bmp) + } + + /** + * + * + * + */ + fun httpPost(url: String, postData: String?, timeoutMs: Int): String? + { + return (httpCommand(url, "POST", postData, null, null, timeoutMs)) + } + + /** + * + * + * + */ + fun httpGetWithHeader(url: String, headerMap: Map?, contentType: String?, timeoutMs: Int): String? + { + return (httpCommand(url, "GET", null, headerMap, contentType, timeoutMs)) + } + + /** + * + * + * + */ + fun httpPostWithHeader(url: String, postData: String?, headerMap: Map?, contentType: String?, timeoutMs: Int): String? + { + return (httpCommand(url, "POST", postData, headerMap, contentType, timeoutMs)) + } + + /** + * + * + * + */ + fun httpPutWithHeader(url: String, putData: String?, headerMap: Map?, contentType: String?, timeoutMs: Int): String? + { + return (httpCommand(url, "PUT", putData, headerMap, contentType, timeoutMs)) + } + + /** + * + * + * + */ + fun httpPut(url: String, postData: String?, timeoutMs: Int): String? + { + return (httpCommand(url, "PUT", postData, null, null, timeoutMs)) + } + + /** + * + * + * + */ + fun httpOptions(url: String, optionsData: String?, timeoutMs: Int): String? + { + return (httpCommand(url, "OPTIONS", optionsData, null, null, timeoutMs)) + } + + /** + * + * + * + */ + private fun httpCommand(url: String, requestMethod: String, postData: String?, setProperty: Map?, contentType: String?, timeoutMs: Int): String? + { + var inputStream: InputStream? = null + var timeout = timeoutMs + if (timeoutMs < 0) + { + timeout = DEFAULT_TIMEOUT + } + + // HTTP メソッドで要求を送出 + try + { + val httpConn = URL(url).openConnection() as HttpURLConnection + httpConn.requestMethod = requestMethod + if (setProperty != null) + { + for (key in setProperty.keys) + { + val value = setProperty[key] + httpConn.setRequestProperty(key, value) + } + } + if (contentType != null) + { + httpConn.setRequestProperty("Content-Type", contentType) + } + httpConn.connectTimeout = timeout + httpConn.readTimeout = timeout + if (postData == null) + { + httpConn.connect() + } + else + { + httpConn.doInput = true + httpConn.doOutput = true + val outputStream = httpConn.outputStream + val writer = OutputStreamWriter(outputStream, "UTF-8") + writer.write(postData) + writer.flush() + writer.close() + outputStream.close() + } + val responseCode = httpConn.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) + { + inputStream = httpConn.inputStream + } + if (inputStream == null) + { + Log.w(TAG, "http $requestMethod : Response Code Error: $responseCode: $url") + return "" + } + } + catch (e: Exception) + { + Log.w(TAG, "http " + requestMethod + " : IOException: " + e.message) + e.printStackTrace() + return ("") + } + + // 応答の読み出し + return readFromInputStream(inputStream) + } + + private fun readFromInputStream(inputStream: InputStream?): String + { + //var reader: BufferedReader? = null + var replyString = "" + if (inputStream == null) + { + return "" + } + try + { + val responseBuf = StringBuilder() + val reader = BufferedReader(InputStreamReader(inputStream)) + var c: Int + while (reader.read().also { c = it } != -1) + { + responseBuf.append(c.toChar()) + } + replyString = responseBuf.toString() + reader.close() + } + catch (e: Exception) + { + e.printStackTrace() + } + return replyString + } + + interface IReceivedMessageCallback + { + fun onCompleted() + fun onErrorOccurred(e: Exception?) + fun onReceive(readBytes: Int, length: Int, size: Int, data: ByteArray?) + } + + companion object + { + private val TAG = SimpleHttpClient::class.java.simpleName + private const val DEFAULT_TIMEOUT = 10 * 1000 // [ms] + private const val BUFFER_SIZE = 131072 * 2 // 256kB + } +} diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLiveviewSlicer.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLiveviewSlicer.java new file mode 100644 index 0000000..e966102 --- /dev/null +++ b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLiveviewSlicer.java @@ -0,0 +1,404 @@ +package jp.sfjp.gokigen.a01c.utils; + + +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; + +public class SimpleLiveviewSlicer +{ + private static final String TAG = SimpleLiveviewSlicer.class.getSimpleName(); + public static final class Payload + { + // jpeg data container + final byte[] jpegData; + + // padding data container + final byte[] paddingData; + + /** + * Constructor + */ + private Payload(byte[] jpeg, byte[] padding) + { + this.jpegData = jpeg; + this.paddingData = padding; + } + public byte[] getJpegData() + { + return (jpegData); + } + } + + private static final int CONNECTION_TIMEOUT = 2000; // [msec] + private int[] mJpegStartMarker = { 0x0d, 0x0a, 0x0d, 0x0a, 0xff, 0xd8 }; + private HttpURLConnection mHttpConn; + private InputStream mInputStream; + + public void setMJpegStartMarker(@NonNull int[] startMarker) + { + mJpegStartMarker = startMarker; + } + +/* + public void open(InputStream inputStream) + { + mInputStream = inputStream; + } +*/ + + public void open(String liveviewUrl, String postData, String contentType) + { + OutputStream outputStream = null; + OutputStreamWriter writer = null; + try + { + if ((mInputStream != null)||(mHttpConn != null)) + { + Log.v(TAG, "Slicer is already open."); + return; + } + + final URL urlObj = new URL(liveviewUrl); + mHttpConn = (HttpURLConnection) urlObj.openConnection(); + mHttpConn.setRequestMethod("POST"); + mHttpConn.setConnectTimeout(CONNECTION_TIMEOUT); + if (contentType != null) + { + mHttpConn.setRequestProperty("Content-Type", contentType); + } + { + mHttpConn.setDoInput(true); + mHttpConn.setDoOutput(true); + outputStream = mHttpConn.getOutputStream(); + //noinspection CharsetObjectCanBeUsed + writer = new OutputStreamWriter(outputStream, "UTF-8"); + writer.write(postData); + writer.flush(); + writer.close(); + writer = null; + outputStream.close(); + outputStream = null; + } + if (mHttpConn.getResponseCode() == HttpURLConnection.HTTP_OK) + { + mInputStream = mHttpConn.getInputStream(); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + finally + { + try + { + if (writer != null) + { + writer.close(); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + try + { + if (outputStream != null) + { + outputStream.close(); + } + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + + public void open(String liveviewUrl) + { + try + { + if ((mInputStream != null)||(mHttpConn != null)) + { + Log.v(TAG, "Slicer is already open."); + return; + } + + final URL urlObj = new URL(liveviewUrl); + mHttpConn = (HttpURLConnection) urlObj.openConnection(); + mHttpConn.setRequestMethod("GET"); + mHttpConn.setConnectTimeout(CONNECTION_TIMEOUT); + mHttpConn.connect(); + if (mHttpConn.getResponseCode() == HttpURLConnection.HTTP_OK) + { + mInputStream = mHttpConn.getInputStream(); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public void close() + { + try + { + if (mInputStream != null) + { + mInputStream.close(); + mInputStream = null; + } + } + catch (Exception e) + { + e.printStackTrace(); + } + try + { + if (mHttpConn != null) + { + mHttpConn.disconnect(); + mHttpConn = null; + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public Payload nextPayload() + { + Payload payload = null; + try + { + while ((mInputStream != null)&&(payload == null)) + { + // Common Header + int readLength = 1 + 1 + 2 + 4; + byte[] commonHeader = readBytes(mInputStream, readLength); + if ((commonHeader == null)||(commonHeader.length != readLength)) + { + Log.v(TAG, "Cannot read stream for common header."); + payload = null; + break; + } + if (commonHeader[0] != (byte) 0xFF) + { + Log.v(TAG, "Unexpected data format. (Start byte)"); + payload = null; + break; + } + switch (commonHeader[1]) + { + case (byte) 0x12: + // This is information header for streaming. skip this packet. + readLength = 4 + 3 + 1 + 2 + 118 + 4 + 4 + 24; + //commonHeader = null; + readBytes(mInputStream, readLength); + break; + + case (byte) 0x01: + case (byte) 0x11: + payload = readPayload(); + break; + + default: + break; + } + } + } + catch (Exception e) + { + e.printStackTrace(); + System.gc(); + } + return (payload); + } + + private Payload readPayload() + { + try + { + if (mInputStream != null) + { + // Payload Header + int readLength = 4 + 3 + 1 + 4 + 1 + 115; + byte[] payloadHeader = readBytes(mInputStream, readLength); + if ((payloadHeader == null)||(payloadHeader.length != readLength)) + { + throw new EOFException("Cannot read stream for payload header."); + } + if (payloadHeader[0] != (byte) 0x24 || payloadHeader[1] != (byte) 0x35 + || payloadHeader[2] != (byte) 0x68 + || payloadHeader[3] != (byte) 0x79) + { + throw new EOFException("Unexpected data format. (Start code)"); + } + int jpegSize = bytesToInt(payloadHeader, 4, 3); + int paddingSize = bytesToInt(payloadHeader, 7, 1); + + // Payload Data + byte[] jpegData = readBytes(mInputStream, jpegSize); + byte[] paddingData = readBytes(mInputStream, paddingSize); + + return (new Payload(jpegData, paddingData)); + } + } + catch (EOFException eo) + { + eo.printStackTrace(); + close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + return (null); + } + + private static int bytesToInt(byte[] byteData, int startIndex, int count) + { + int ret = 0; + try + { + for (int i = startIndex; i < startIndex + count; i++) + { + ret = (ret << 8) | (byteData[i] & 0xff); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + return (ret); + } + + private static byte[] readBytes(InputStream in, int length) + { + byte[] ret; + try + { + ByteArrayOutputStream tmpByteArray = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + while (true) + { + int trialReadlen = Math.min(buffer.length, length - tmpByteArray.size()); + int readlen = in.read(buffer, 0, trialReadlen); + if (readlen < 0) + { + break; + } + tmpByteArray.write(buffer, 0, readlen); + if (length <= tmpByteArray.size()) + { + break; + } + } + ret = tmpByteArray.toByteArray(); + tmpByteArray.close(); + } + catch (Exception e) + { + e.printStackTrace(); + ret = null; + } + return (ret); + } + + /** + * 先頭のjpegマーカーが出てくるまで読み飛ばす + * + */ + private void skipJpegMarkStart(InputStream stream) + { + int searchIndex = 0; + while (true) + { + try + { + int data = stream.read(); + if (data == mJpegStartMarker[searchIndex]) + { + searchIndex++; + if (searchIndex >= mJpegStartMarker.length) + { + break; + } + } + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + } + } + + /** + * + * + */ + public Payload nextPayloadForMotionJpeg() + { + int searchIndex = 0; + int[] endmarker = { 0xff, 0xd9 }; + Payload payload = null; + try + { + while ((mInputStream != null)&&(payload == null)) + { + skipJpegMarkStart(mInputStream); + ByteArrayOutputStream tmpByteArray = new ByteArrayOutputStream(); + // 先頭にJPEGのマークを詰める + tmpByteArray.write(0xff); + tmpByteArray.write(0xd8); + while (true) + { + try + { + // 1byteづつの読み込み... 本当は複数バイト読み出しで処理したい + int data = mInputStream.read(); + tmpByteArray.write(data); + if (data == endmarker[searchIndex]) + { + searchIndex++; + if (searchIndex >= endmarker.length) + { + break; + } + } + else + { + searchIndex = 0; + } + } + catch (Throwable e) + { + Log.v(TAG, "INPUT STREAM EXCEPTION : " + e.getLocalizedMessage()); + // e.printStackTrace(); + return (null); + } + } + payload = new Payload(tmpByteArray.toByteArray(), null); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + return (payload); + } +} diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLogDumper.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLogDumper.java new file mode 100644 index 0000000..def8fa0 --- /dev/null +++ b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLogDumper.java @@ -0,0 +1,78 @@ +package jp.sfjp.gokigen.a01c.utils; + +import android.app.Activity; +import android.os.Environment; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.File; +import java.io.FileOutputStream; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +import jp.sfjp.gokigen.a01c.R; + +public class SimpleLogDumper +{ + private static final String TAG = SimpleLogDumper.class.getSimpleName(); + + /** + * デバッグ用:ログにバイト列を出力する + * + */ + public static void dump_bytes(String header, byte[] data) + { + if (data == null) + { + Log.v(TAG, "DATA IS NULL"); + return; + } + if (data.length > 8192) + { + Log.v(TAG, " --- DUMP DATA IS TOO LONG... " + data.length + " bytes."); + return; + } + + int index = 0; + StringBuffer message; + message = new StringBuffer(); + for (byte item : data) + { + index++; + message.append(String.format("%02x ", item)); + if (index >= 16) + { + Log.v(TAG, header + " " + message); + index = 0; + message = new StringBuffer(); + } + } + if (index != 0) + { + Log.v(TAG, header + " " + message); + } + System.gc(); + } + + public static void binaryOutputToFile(@NonNull Activity activity, String fileNamePrefix, byte[] rx_body) + { + try + { + Calendar calendar = Calendar.getInstance(); + String extendName = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.getDefault()).format(calendar.getTime()); + final String directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath() + "/" + activity.getString(R.string.app_name2) + "/"; + String outputFileName = fileNamePrefix + "_" + extendName + ".bin"; + String filepath = new File(directoryPath.toLowerCase(), outputFileName.toLowerCase()).getPath(); + FileOutputStream outputStream = new FileOutputStream(filepath); + outputStream.write(rx_body, 0, rx_body.length); + outputStream.flush(); + outputStream.close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/XmlElement.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/XmlElement.java new file mode 100644 index 0000000..04d4449 --- /dev/null +++ b/wear/src/main/java/jp/sfjp/gokigen/a01c/utils/XmlElement.java @@ -0,0 +1,183 @@ +package jp.sfjp.gokigen.a01c.utils; + +import android.util.Log; +import android.util.Xml; + +import org.xmlpull.v1.XmlPullParser; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import androidx.annotation.NonNull; + +public class XmlElement +{ + private static final String TAG = XmlElement.class.getSimpleName(); + private static final XmlElement NULL_ELEMENT = new XmlElement(); + + private String tagName = ""; + private String tagValue; + + private final LinkedList childElements; + private final Map attributes; + private XmlElement parentElement; + + private XmlElement() + { + //Log.v(TAG, "XmlElement()"); + parentElement = null; + childElements = new LinkedList<>(); + attributes = new HashMap<>(); + tagValue = ""; + } + + public XmlElement getParent() + { + return (parentElement); + } + public String getTagName() + { + //Log.v(TAG, "XmlElement Tag [" + tagName + "]"); + return (tagName); + } + + private void setTagName(String name) + { + tagName = name; + } + + public String getValue() + { + //Log.v(TAG, "XmlElement Value [" + tagValue + "]"); + return (tagValue); + } + private void setValue(String value) + { + tagValue = value; + } + + private void putChild(XmlElement childItem) + { + childElements.add(childItem); + childItem.setParent(this); + } + + public XmlElement findChild(String name) + { + for (final XmlElement child : childElements) + { + if (child.getTagName().equals(name)) + { + return (child); + } + } + return (new XmlElement()); + } + + public List findChildren(String name) + { + final List tagItemList = new ArrayList<>(); + for (final XmlElement child : childElements) + { + if (child.getTagName().equals(name)) + { + tagItemList.add(child); + } + } + return (tagItemList); + } + + private void setParent(XmlElement parent) + { + parentElement = parent; + } + + private void putAttribute(String name, String value) + { + attributes.put(name, value); + } + + public String getAttribute(String name, String defaultValue) + { + String ret = attributes.get(name); + if (ret == null) + { + ret = defaultValue; + } + return (ret); + } + + private static XmlElement parse(XmlPullParser xmlPullParser) + { + XmlElement rootElement = XmlElement.NULL_ELEMENT; + try + { + XmlElement parsingElement = XmlElement.NULL_ELEMENT; + MAINLOOP: + while (true) + { + switch (xmlPullParser.next()) + { + case XmlPullParser.START_DOCUMENT: + Log.v(TAG, "------- START DOCUMENT -----"); + break; + case XmlPullParser.START_TAG: + final XmlElement childItem = new XmlElement(); + childItem.setTagName(xmlPullParser.getName()); + if (parsingElement == XmlElement.NULL_ELEMENT) { + rootElement = childItem; + } else { + parsingElement.putChild(childItem); + } + parsingElement = childItem; + + // Set Attribute + for (int i = 0; i < xmlPullParser.getAttributeCount(); i++) + { + parsingElement.putAttribute(xmlPullParser.getAttributeName(i), xmlPullParser.getAttributeValue(i)); + } + break; + + case XmlPullParser.TEXT: + parsingElement.setValue(xmlPullParser.getText()); + break; + + case XmlPullParser.END_TAG: + parsingElement = parsingElement.getParent(); + break; + + case XmlPullParser.END_DOCUMENT: + Log.v(TAG, "------- END DOCUMENT -------"); + break MAINLOOP; + + default: + break MAINLOOP; + } + } + } + catch (Exception e) + { + e.printStackTrace(); + rootElement = XmlElement.NULL_ELEMENT; + } + return (rootElement); + } + + public static XmlElement parse(@NonNull String xmlStr) + { + try + { + XmlPullParser xmlPullParser = Xml.newPullParser(); + xmlPullParser.setInput(new StringReader(xmlStr)); + return parse(xmlPullParser); + } + catch (Exception e) + { + e.printStackTrace(); + } + return (new XmlElement()); + } +} diff --git a/wear/src/main/res/values-ja/strings.xml b/wear/src/main/res/values-ja/strings.xml index 664ef12..2264523 100644 --- a/wear/src/main/res/values-ja/strings.xml +++ b/wear/src/main/res/values-ja/strings.xml @@ -1,6 +1,7 @@ A01c + A01c Hello Round World! Hello Square World @@ -70,4 +71,7 @@ OPCに接続 接続方式をOPCにしますか? + OPC + THETA + diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml index 96dc574..22bac36 100644 --- a/wear/src/main/res/values/strings.xml +++ b/wear/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ A01c + A01c Hello Round World! Hello Square World! @@ -68,4 +69,7 @@ Change To OPC Change To OPC, OK? + OPC + THETA + -- 2.11.0