Pentax DSLR Remote Control app.
Revisão | 6001157eddcd8454ba4284ba0ab264813df520d1 (tree) |
---|---|
Hora | 2021-01-01 22:22:16 |
Autor | MRSa <mrsa@myad...> |
Commiter | MRSa |
スモール画像を取得するシーケンスを複数化。
@@ -38,7 +38,7 @@ import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpComma | ||
38 | 38 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher; |
39 | 39 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommunication; |
40 | 40 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpAsyncResponseReceiver; |
41 | -import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpCommandPublisher; | |
41 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpCommandPublisher0; | |
42 | 42 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.connection.NikonConnection; |
43 | 43 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.liveview.PtpIpLiveViewControl; |
44 | 44 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.IPtpIpRunModeHolder; |
@@ -61,7 +61,7 @@ public class NikonInterfaceProvider implements INikonInterfaceProvider, IDisplay | ||
61 | 61 | private final PtpIpHardwareStatus hardwareStatus; |
62 | 62 | private PtpIpButtonControl ptpIpButtonControl; |
63 | 63 | private NikonConnection nikonConnection; |
64 | - private PtpIpCommandPublisher commandPublisher; | |
64 | + private PtpIpCommandPublisher0 commandPublisher; | |
65 | 65 | private PtpIpLiveViewControl liveViewControl; |
66 | 66 | private PtpIpAsyncResponseReceiver asyncReceiver; |
67 | 67 | private PtpIpZoomControl zoomControl; |
@@ -85,7 +85,7 @@ public class NikonInterfaceProvider implements INikonInterfaceProvider, IDisplay | ||
85 | 85 | { |
86 | 86 | e.printStackTrace(); |
87 | 87 | } |
88 | - commandPublisher = new PtpIpCommandPublisher(ipAddress, CONTROL_PORT); | |
88 | + commandPublisher = new PtpIpCommandPublisher0(ipAddress, CONTROL_PORT); | |
89 | 89 | liveViewControl = new PtpIpLiveViewControl(context, ipAddress, STREAM_PORT); |
90 | 90 | asyncReceiver = new PtpIpAsyncResponseReceiver(ipAddress, ASYNC_RESPONSE_PORT); |
91 | 91 | statusChecker = new NikonStatusChecker(activity, commandPublisher, ipAddress, EVENT_PORT); |
@@ -34,6 +34,7 @@ import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpComma | ||
34 | 34 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommunication; |
35 | 35 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpAsyncResponseReceiver; |
36 | 36 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpCommandPublisher; |
37 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpCommandPublisher0; | |
37 | 38 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.connection.CanonConnection; |
38 | 39 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.liveview.PtpIpLiveViewControl; |
39 | 40 | import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.CanonPlaybackControl; |
@@ -57,6 +58,7 @@ public class PtpIpInterfaceProvider implements IPtpIpInterfaceProvider, IDisplay | ||
57 | 58 | private final PtpIpHardwareStatus hardwareStatus; |
58 | 59 | private final PtpIpButtonControl ptpIpButtonControl; |
59 | 60 | private final CanonConnection canonConnection; |
61 | + //private final PtpIpCommandPublisher0 commandPublisher; | |
60 | 62 | private final PtpIpCommandPublisher commandPublisher; |
61 | 63 | private final PtpIpLiveViewControl liveViewControl; |
62 | 64 | private final PtpIpAsyncResponseReceiver asyncReceiver; |
@@ -100,7 +102,8 @@ public class PtpIpInterfaceProvider implements IPtpIpInterfaceProvider, IDisplay | ||
100 | 102 | ipAddress = "192.168.0.1"; |
101 | 103 | } |
102 | 104 | |
103 | - commandPublisher = new PtpIpCommandPublisher(ipAddress, CONTROL_PORT); | |
105 | + commandPublisher = new PtpIpCommandPublisher(ipAddress, CONTROL_PORT, false, false); | |
106 | + //commandPublisher = new PtpIpCommandPublisher0(ipAddress, CONTROL_PORT); | |
104 | 107 | liveViewControl = new PtpIpLiveViewControl(context, ipAddress, STREAM_PORT); |
105 | 108 | asyncReceiver = new PtpIpAsyncResponseReceiver(ipAddress, ASYNC_RESPONSE_PORT); |
106 | 109 | statusChecker = new PtpIpStatusChecker(context, commandPublisher, ipAddress, EVENT_PORT); |
@@ -52,4 +52,17 @@ public interface IPtpIpCommand | ||
52 | 52 | |
53 | 53 | // デバッグ用: ログ(logcat)に通信結果を残すかどうか |
54 | 54 | boolean dumpLog(); |
55 | + | |
56 | + // リトライオーバー発生時、コマンドを再送するか? | |
57 | + boolean isRetrySend(); | |
58 | + | |
59 | + // 最後に1回余計に受信をするか? | |
60 | + boolean isLastReceiveRetry(); | |
61 | + | |
62 | + // 受信待ち再試行回数 | |
63 | + int maxRetryCount(); | |
64 | + | |
65 | + // リトライオーバーで再送するとき、SeqNoをインクリメントするか | |
66 | + boolean isIncrementSequenceNumberToRetry(); | |
67 | + | |
55 | 68 | } |
@@ -9,6 +9,10 @@ public interface IPtpIpCommandPublisher | ||
9 | 9 | |
10 | 10 | boolean flushHoldQueue(); |
11 | 11 | |
12 | + int isExistCommandMessageQueue(int id); | |
13 | + int getCurrentQueueSize(); | |
14 | + boolean flushQueue(); | |
15 | + | |
12 | 16 | void start(); |
13 | 17 | void stop(); |
14 | 18 | } |
@@ -0,0 +1,762 @@ | ||
1 | +package net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command | |
2 | + | |
3 | +import android.util.Log | |
4 | +import net.osdn.gokigen.pkremote.camera.utils.SimpleLogDumper | |
5 | +import java.io.BufferedReader | |
6 | +import java.io.ByteArrayOutputStream | |
7 | +import java.io.DataOutputStream | |
8 | +import java.io.InputStream | |
9 | +import java.net.InetSocketAddress | |
10 | +import java.net.Socket | |
11 | +import java.util.* | |
12 | + | |
13 | +class PtpIpCommandPublisher(private val ipAddress : String, private val portNumber : Int, private val tcpNoDelay : Boolean, private val waitForever: Boolean) : IPtpIpCommandPublisher, IPtpIpCommunication | |
14 | +{ | |
15 | + private var isConnected = false | |
16 | + private var isStart = false | |
17 | + private var isHold = false | |
18 | + private var holdId = 0 | |
19 | + | |
20 | + private var socket : Socket? = null | |
21 | + private var dos: DataOutputStream? = null | |
22 | + private var bufferedReader: BufferedReader? = null | |
23 | + | |
24 | + private var sequenceNumber = SEQUENCE_START_NUMBER | |
25 | + private var commandQueue: Queue<IPtpIpCommand> = ArrayDeque() | |
26 | + private var holdCommandQueue: Queue<IPtpIpCommand> = ArrayDeque() | |
27 | + | |
28 | + init | |
29 | + { | |
30 | + commandQueue.clear() | |
31 | + holdCommandQueue.clear() | |
32 | + } | |
33 | + | |
34 | + override fun isConnected(): Boolean | |
35 | + { | |
36 | + return (isConnected) | |
37 | + } | |
38 | + | |
39 | + override fun connect(): Boolean | |
40 | + { | |
41 | + try | |
42 | + { | |
43 | + Log.v(TAG, " connect()") | |
44 | + socket = Socket() | |
45 | + socket?.tcpNoDelay = tcpNoDelay | |
46 | + if (tcpNoDelay) | |
47 | + { | |
48 | + //socket?.tcpNoDelay = true | |
49 | + //socket?.keepAlive = false | |
50 | + socket?.keepAlive = false | |
51 | + //socket?.setPerformancePreferences(0, 1, 2) | |
52 | + socket?.setPerformancePreferences(0, 1, 2) | |
53 | + //socket?.setPerformancePreferences(0, 1, 2) | |
54 | + //socket?.setPerformancePreferences(1, 0, 0) | |
55 | + //socket?.setPerformancePreferences(0, 0, 2) | |
56 | + socket?.oobInline = true | |
57 | + //socket?.reuseAddress = false | |
58 | + socket?.trafficClass = 0x80 // 0x80 | |
59 | + socket?.soTimeout = 0 | |
60 | + //socket?.soTimeout = 0 | |
61 | + //socket?.receiveBufferSize = 8192 // 10240 // 16384 // 6144// 8192 // 49152 // 65536 // 32768 | |
62 | + //socket?.sendBufferSize = 1024 // 8192 // 4096 // 2048 // 10240 | |
63 | + socket?.setSoLinger(true, 500) | |
64 | + //socket?.setReceiveBufferSize(2097152); | |
65 | + //socket?.setSendBufferSize(524288); | |
66 | + | |
67 | + Log.v(TAG, " SOCKET (SEND:${socket?.sendBufferSize}, RECV:${socket?.receiveBufferSize}) oob:${socket?.oobInline} SO_TIMEOUT:${socket?.soTimeout}ms trafficClass:${socket?.trafficClass}") | |
68 | + } | |
69 | + socket?.connect(InetSocketAddress(ipAddress, portNumber), 0) | |
70 | + isConnected = true | |
71 | + } | |
72 | + catch (e: Exception) | |
73 | + { | |
74 | + e.printStackTrace() | |
75 | + isConnected = false | |
76 | + socket = null | |
77 | + } | |
78 | + return (isConnected) | |
79 | + } | |
80 | + | |
81 | + override fun disconnect() | |
82 | + { | |
83 | + try | |
84 | + { | |
85 | + dos?.close() | |
86 | + bufferedReader?.close() | |
87 | + socket?.close() | |
88 | + commandQueue.clear() | |
89 | + } | |
90 | + catch (e : Exception) | |
91 | + { | |
92 | + e.printStackTrace() | |
93 | + } | |
94 | + System.gc() | |
95 | + | |
96 | + sequenceNumber = SEQUENCE_START_NUMBER | |
97 | + isConnected = false | |
98 | + isStart = false | |
99 | + dos = null | |
100 | + bufferedReader = null | |
101 | + socket = null | |
102 | + } | |
103 | + | |
104 | + override fun start() | |
105 | + { | |
106 | + if (isStart) | |
107 | + { | |
108 | + // すでにコマンドのスレッド動作中なので抜ける | |
109 | + return | |
110 | + } | |
111 | + if (socket == null) | |
112 | + { | |
113 | + isStart = false | |
114 | + Log.v(TAG, " SOCKET IS NULL. (cannot start)") | |
115 | + return | |
116 | + } | |
117 | + | |
118 | + isStart = true | |
119 | + Log.v(TAG, " start()") | |
120 | + val thread = Thread { | |
121 | + try | |
122 | + { | |
123 | + dos = DataOutputStream(socket?.getOutputStream()) | |
124 | + while (isStart) | |
125 | + { | |
126 | + try | |
127 | + { | |
128 | + val command = commandQueue.poll() | |
129 | + command?.let { issueCommand(it) } | |
130 | + Thread.sleep(COMMAND_POLL_QUEUE_MS.toLong()) | |
131 | + } | |
132 | + catch (e: Exception) | |
133 | + { | |
134 | + e.printStackTrace() | |
135 | + } | |
136 | + } | |
137 | + } | |
138 | + catch (e: Exception) | |
139 | + { | |
140 | + Log.v(TAG, "<<<<< IP : $ipAddress port : $portNumber >>>>>") | |
141 | + e.printStackTrace() | |
142 | + } | |
143 | + } | |
144 | + try | |
145 | + { | |
146 | + thread.start() | |
147 | + } | |
148 | + catch (e: Exception) | |
149 | + { | |
150 | + e.printStackTrace() | |
151 | + } | |
152 | + } | |
153 | + | |
154 | + override fun stop() | |
155 | + { | |
156 | + isStart = false | |
157 | + commandQueue.clear() | |
158 | + } | |
159 | + | |
160 | + override fun enqueueCommand(command: IPtpIpCommand): Boolean | |
161 | + { | |
162 | + try | |
163 | + { | |
164 | + if (isHold) | |
165 | + { | |
166 | + return (if (holdId == command.holdId) { | |
167 | + if (command.isRelease) | |
168 | + { | |
169 | + // コマンドをキューに積んだ後、リリースする | |
170 | + val ret = commandQueue.offer(command) | |
171 | + isHold = false | |
172 | + | |
173 | + // 溜まっているキューを積みなおす | |
174 | + while (holdCommandQueue.size != 0) | |
175 | + { | |
176 | + val queuedCommand = holdCommandQueue.poll() | |
177 | + commandQueue.offer(queuedCommand) | |
178 | + if (queuedCommand != null && queuedCommand.isHold) | |
179 | + { | |
180 | + // 特定シーケンスに入った場合は、そこで積みなおすのをやめる | |
181 | + isHold = true | |
182 | + holdId = queuedCommand.holdId | |
183 | + break | |
184 | + } | |
185 | + } | |
186 | + return ret | |
187 | + } | |
188 | + commandQueue.offer(command) | |
189 | + } | |
190 | + else | |
191 | + { | |
192 | + // 特定シーケンスではなかったので HOLD | |
193 | + holdCommandQueue.offer(command) | |
194 | + }) | |
195 | + } | |
196 | + if (command.isHold) | |
197 | + { | |
198 | + isHold = true | |
199 | + holdId = command.holdId | |
200 | + } | |
201 | + if (commandQueue.size > 1) | |
202 | + { | |
203 | + // たまっているときだけログを吐く | |
204 | + Log.v(TAG, "Enqueue [ID: " + command.id + "] size: " + commandQueue.size) | |
205 | + } | |
206 | + return (commandQueue.offer(command)) | |
207 | + } | |
208 | + catch (e: Exception) | |
209 | + { | |
210 | + e.printStackTrace() | |
211 | + } | |
212 | + return (false) | |
213 | + } | |
214 | + | |
215 | + override fun getCurrentQueueSize(): Int | |
216 | + { | |
217 | + return commandQueue.size | |
218 | + } | |
219 | + | |
220 | + override fun flushQueue(): Boolean | |
221 | + { | |
222 | + Log.v(TAG, " flushQueue() size: ${commandQueue.size}") | |
223 | + // TODO: たまっているキューをダンプする | |
224 | + commandQueue.clear() | |
225 | + System.gc() | |
226 | + return (true) | |
227 | + } | |
228 | + | |
229 | + override fun isExistCommandMessageQueue(id: Int): Int | |
230 | + { | |
231 | + var count = 0 | |
232 | + for (cmd in commandQueue) | |
233 | + { | |
234 | + if (cmd.id == id) | |
235 | + { | |
236 | + count++ | |
237 | + } | |
238 | + } | |
239 | + return count | |
240 | + } | |
241 | + | |
242 | + override fun flushHoldQueue(): Boolean | |
243 | + { | |
244 | + Log.v(TAG, " flushHoldQueue()") | |
245 | + holdCommandQueue.clear() | |
246 | + System.gc() | |
247 | + return (true) | |
248 | + } | |
249 | + | |
250 | + private fun issueCommand(command: IPtpIpCommand) | |
251 | + { | |
252 | + try | |
253 | + { | |
254 | + var retryOver = true | |
255 | + while (retryOver) | |
256 | + { | |
257 | + //Log.v(TAG, "issueCommand : " + command.getId()); | |
258 | + val commandBody = command.commandBody() | |
259 | + if (commandBody != null) | |
260 | + { | |
261 | + // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち) | |
262 | + sendToCamera(command.dumpLog(), commandBody, command.useSequenceNumber(), command.embeddedSequenceNumberIndex()) | |
263 | + val commandBody2 = command.commandBody2() | |
264 | + if (commandBody2 != null) | |
265 | + { | |
266 | + // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する | |
267 | + sendToCamera(command.dumpLog(), commandBody2, command.useSequenceNumber(), command.embeddedSequenceNumberIndex2()) | |
268 | + } | |
269 | + val commandBody3 = command.commandBody3() | |
270 | + if (commandBody3 != null) | |
271 | + { | |
272 | + // コマンドボディの3つめが入っていた場合には、コマンドを連続送信する | |
273 | + sendToCamera(command.dumpLog(), commandBody3, command.useSequenceNumber(), command.embeddedSequenceNumberIndex3()) | |
274 | + } | |
275 | + if (command.isIncrementSeqNumber) | |
276 | + { | |
277 | + // シーケンス番号を更新する | |
278 | + sequenceNumber++ | |
279 | + } | |
280 | + } | |
281 | + retryOver = receiveFromCamera(command) | |
282 | + if ((retryOver)&&(commandBody != null)) | |
283 | + { | |
284 | + if (!command.isRetrySend) | |
285 | + { | |
286 | + while (retryOver) | |
287 | + { | |
288 | + // コマンドを再送信しない場合はここで応答を待つ... | |
289 | + retryOver = receiveFromCamera(command) | |
290 | + } | |
291 | + break | |
292 | + } | |
293 | + if (!command.isIncrementSequenceNumberToRetry) | |
294 | + { | |
295 | + // 再送信...のために、シーケンス番号を戻す... | |
296 | + sequenceNumber-- | |
297 | + } | |
298 | + } | |
299 | + } | |
300 | + } | |
301 | + catch (e: Exception) | |
302 | + { | |
303 | + e.printStackTrace() | |
304 | + } | |
305 | + } | |
306 | + | |
307 | + /** | |
308 | + * カメラにコマンドを送信する(メイン部分) | |
309 | + * | |
310 | + */ | |
311 | + private fun sendToCamera(isDumpReceiveLog: Boolean, byte_array: ByteArray, useSequenceNumber: Boolean, embeddedSequenceIndex: Int) | |
312 | + { | |
313 | + try | |
314 | + { | |
315 | + if (dos == null) | |
316 | + { | |
317 | + Log.v(TAG, " DataOutputStream is null.") | |
318 | + return | |
319 | + } | |
320 | + | |
321 | + // メッセージボディを加工: 最初に4バイトのレングス長をつける | |
322 | + val sendData = ByteArray(byte_array.size + 4) | |
323 | + sendData[0] = (byte_array.size + 4).toByte() | |
324 | + sendData[1] = 0x00 | |
325 | + sendData[2] = 0x00 | |
326 | + sendData[3] = 0x00 | |
327 | + System.arraycopy(byte_array, 0, sendData, 4, byte_array.size) | |
328 | + if (useSequenceNumber) | |
329 | + { | |
330 | + // Sequence Number を反映させる | |
331 | + sendData[embeddedSequenceIndex ] = (0x000000ff and sequenceNumber).toByte() | |
332 | + sendData[embeddedSequenceIndex + 1] = (0x0000ff00 and sequenceNumber ushr 8 and 0x000000ff).toByte() | |
333 | + sendData[embeddedSequenceIndex + 2] = (0x00ff0000 and sequenceNumber ushr 16 and 0x000000ff).toByte() | |
334 | + sendData[embeddedSequenceIndex + 3] = (-0x1000000 and sequenceNumber ushr 24 and 0x000000ff).toByte() | |
335 | + if (isDumpReceiveLog) | |
336 | + { | |
337 | + Log.v(TAG, "----- SEQ No. : $sequenceNumber -----") | |
338 | + } | |
339 | + } | |
340 | + if (isDumpReceiveLog) | |
341 | + { | |
342 | + // ログに送信メッセージを出力する | |
343 | + SimpleLogDumper.dump_bytes("SEND[" + sendData.size + "] ", sendData) | |
344 | + } | |
345 | + | |
346 | + // (データを)送信 | |
347 | + dos?.write(sendData) | |
348 | + dos?.flush() | |
349 | + } | |
350 | + catch (e: Exception) | |
351 | + { | |
352 | + e.printStackTrace() | |
353 | + } | |
354 | + } | |
355 | + | |
356 | + private fun sleep(delayMs: Int) | |
357 | + { | |
358 | + try | |
359 | + { | |
360 | + Thread.sleep(delayMs.toLong()) | |
361 | + } | |
362 | + catch (e: Exception) | |
363 | + { | |
364 | + e.printStackTrace() | |
365 | + } | |
366 | + } | |
367 | + | |
368 | + /** | |
369 | + * カメラからにコマンドの結果を受信する(メイン部分) | |
370 | + * | |
371 | + */ | |
372 | + private fun receiveFromCamera(command: IPtpIpCommand): Boolean | |
373 | + { | |
374 | + val callback = command.responseCallback() | |
375 | + var delayMs = command.receiveDelayMs() | |
376 | + if (delayMs < 0 || delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX) | |
377 | + { | |
378 | + delayMs = COMMAND_SEND_RECEIVE_DURATION_MS | |
379 | + } | |
380 | + | |
381 | + return (if (callback != null && callback.isReceiveMulti) | |
382 | + { | |
383 | + // 受信したら逐次「受信したよ」と応答するパターン | |
384 | + //Log.v(TAG, " receiveMulti() : $delayMs [id:${command.id}] SEQ: $sequenceNumber") | |
385 | + receiveMulti(command, delayMs) | |
386 | + } | |
387 | + else | |
388 | + { | |
389 | + //Log.v(TAG, " receiveSingle() : $delayMs [id:${command.id}] SEQ: $sequenceNumber") | |
390 | + receiveSingle(command, delayMs) | |
391 | + }) | |
392 | + // 受信した後、すべてをまとめて「受信したよ」と応答するパターン | |
393 | + } | |
394 | + | |
395 | + private fun receiveSingle(command: IPtpIpCommand, delayMs: Int): Boolean | |
396 | + { | |
397 | + val isDumpReceiveLog = command.dumpLog() | |
398 | + val id = command.id | |
399 | + val callback = command.responseCallback() | |
400 | + try | |
401 | + { | |
402 | + val receiveMessageBufferSize = BUFFER_SIZE | |
403 | + val byteArray = ByteArray(receiveMessageBufferSize) | |
404 | + val inputStream = socket?.getInputStream() | |
405 | + if (inputStream == null) | |
406 | + { | |
407 | + Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.") | |
408 | + receivedAllMessage(isDumpReceiveLog, id, null, callback) | |
409 | + return (false) | |
410 | + } | |
411 | + | |
412 | + // 初回データが受信バッファにデータが溜まるまで待つ... | |
413 | + var readBytes = waitForReceive(inputStream, delayMs, command.maxRetryCount()) | |
414 | + if (readBytes <= 0) | |
415 | + { | |
416 | + // リトライオーバー... | |
417 | + Log.v(TAG, " RECEIVE : RETRY OVER...... : $delayMs ms x ${command.maxRetryCount()} SEQ: $sequenceNumber isRetry: ${command.isRetrySend}") | |
418 | + if (!command.isRetrySend) | |
419 | + { | |
420 | + // 再送しない場合には、応答がないことを通知する | |
421 | + receivedAllMessage(isDumpReceiveLog, id, null, callback) | |
422 | + return (false) | |
423 | + } | |
424 | + return (true) | |
425 | + } | |
426 | + | |
427 | + // 受信したデータをバッファに突っ込む | |
428 | + var receivedLength = 0 | |
429 | + val byteStream = ByteArrayOutputStream() | |
430 | + while (readBytes > 0) | |
431 | + { | |
432 | + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) | |
433 | + if (readBytes <= 0) | |
434 | + { | |
435 | + Log.v(TAG, " RECEIVED MESSAGE FINISHED ($readBytes)") | |
436 | + break | |
437 | + } | |
438 | + byteStream.write(byteArray, 0, readBytes) | |
439 | + sleep(delayMs) | |
440 | + receivedLength += readBytes | |
441 | + readBytes = inputStream.available() | |
442 | + } | |
443 | + | |
444 | + Log.v(TAG, " receivedLength : $receivedLength") | |
445 | + if (receivedLength >= 4) | |
446 | + { | |
447 | + val outputStream = cutHeader(byteStream) | |
448 | + receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback) | |
449 | + } | |
450 | + else | |
451 | + { | |
452 | + receivedAllMessage(isDumpReceiveLog, id, byteStream.toByteArray(), callback) | |
453 | + } | |
454 | + System.gc() | |
455 | + } | |
456 | + catch (e: Throwable) | |
457 | + { | |
458 | + e.printStackTrace() | |
459 | + System.gc() | |
460 | + } | |
461 | + return false | |
462 | + } | |
463 | + | |
464 | + private fun receivedAllMessage(isDumpReceiveLog: Boolean, id: Int, body: ByteArray?, callback: IPtpIpCommandCallback?) | |
465 | + { | |
466 | + Log.v(TAG, "receivedAllMessage() : " + (body?.size ?: 0) + " bytes.") | |
467 | + if ((isDumpReceiveLog)&&(body != null)) | |
468 | + { | |
469 | + // ログに受信メッセージを出力する | |
470 | + SimpleLogDumper.dump_bytes("RECV[" + body.size + "] ", body) | |
471 | + } | |
472 | + callback?.receivedMessage(id, body) | |
473 | + } | |
474 | + | |
475 | + private fun receiveMulti(command: IPtpIpCommand, delayMs: Int): Boolean | |
476 | + { | |
477 | + val isDumpLog = command.dumpLog() | |
478 | + var maxRetryCount = command.maxRetryCount() | |
479 | + val id = command.id | |
480 | + val callback = command.responseCallback() | |
481 | + try | |
482 | + { | |
483 | + // Log.v(TAG, " ===== receive_multi() =====") | |
484 | + val receiveMessageBufferSize = BUFFER_SIZE | |
485 | + val byteArray = ByteArray(receiveMessageBufferSize) | |
486 | + val inputStream = socket?.getInputStream() | |
487 | + if (inputStream == null) | |
488 | + { | |
489 | + Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.") | |
490 | + return (false) | |
491 | + } | |
492 | + | |
493 | + // 初回データが受信バッファにデータが溜まるまで待つ... | |
494 | + var readBytes = waitForReceive(inputStream, delayMs, command.maxRetryCount()) | |
495 | + if (readBytes <= 0) | |
496 | + { | |
497 | + // リトライオーバー... | |
498 | + Log.v(TAG, " RECEIVE : RETRY OVER...... : $delayMs ms x ${command.maxRetryCount()} SEQ: $sequenceNumber ") | |
499 | + if (command.isRetrySend) | |
500 | + { | |
501 | + // 要求を再送する場合、、、ダメな場合は受信待ちとする | |
502 | + Log.v(TAG, " --- SEND RETRY ---") | |
503 | + return (true) | |
504 | + } | |
505 | + callback?.receivedMessage(id, null) | |
506 | + return (false) | |
507 | + } | |
508 | + | |
509 | + // 初回データの読み込み... | |
510 | + var targetLength = parseDataLength(byteArray, readBytes) | |
511 | + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) | |
512 | + var receivedLength = readBytes | |
513 | + if (targetLength <= 0) | |
514 | + { | |
515 | + // もう一回データを読み直す... | |
516 | + targetLength = parseDataLength(byteArray, readBytes) | |
517 | + } | |
518 | + if ((targetLength == 0)&&(readBytes > 0)) | |
519 | + { | |
520 | + // 知らないデータがついている...ダンプしてみる | |
521 | + // Log.v(TAG, " RECEIVE UNKNOWN BYTES : ${readBytes}") | |
522 | + if (isDumpLog) | |
523 | + { | |
524 | + // ログに送信メッセージを出力する | |
525 | + SimpleLogDumper.dump_bytes("RECV.UNKNOWN[${readBytes}] ", byteArray) | |
526 | + } | |
527 | + callback?.receivedMessage(id, null) | |
528 | + return (false) | |
529 | + } | |
530 | + | |
531 | + if ((targetLength <= 0)||(readBytes <= 0)) | |
532 | + { | |
533 | + // 受信サイズ異常の場合... | |
534 | + if (isDumpLog) | |
535 | + { | |
536 | + if (receivedLength > 0) | |
537 | + { | |
538 | + SimpleLogDumper.dump_bytes("WRONG DATA : ", byteArray.copyOfRange(0, Math.min(receivedLength, 64))) | |
539 | + } | |
540 | + Log.v(TAG, " WRONG LENGTH. : $targetLength READ : $receivedLength bytes.") | |
541 | + } | |
542 | + callback?.receivedMessage(id, null) | |
543 | + | |
544 | + // 受信したデータが不足しているので、もう一度受信待ち | |
545 | + Log.v(TAG, " 1st receive : AGAIN. [$readBytes][$targetLength]") | |
546 | + return (true) | |
547 | + } | |
548 | + | |
549 | + // 初回データの受信を報告する。 | |
550 | + if (isDumpLog) | |
551 | + { | |
552 | + Log.v(TAG, " -=-=-=- 1st CALL : read_bytes : " + readBytes + "(" + receivedLength + ") : target_length : " + targetLength + " buffer SIZE : " + byteArray.size) | |
553 | + } | |
554 | + callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(fromIndex = 0, toIndex = receivedLength)) | |
555 | + | |
556 | + var isWaitLogging = true | |
557 | + while ((maxRetryCount > 0)&&(readBytes >= 0)&&(receivedLength < targetLength)) | |
558 | + { | |
559 | + sleep(delayMs) | |
560 | + readBytes = inputStream.available() | |
561 | + if (readBytes <= 0) | |
562 | + { | |
563 | + if (isWaitLogging) | |
564 | + { | |
565 | + Log.v(TAG, " WAIT is.available() ... [length: $receivedLength, target: $targetLength] $readBytes bytes, retry : $maxRetryCount SEQ: $sequenceNumber") | |
566 | + isWaitLogging = false | |
567 | + } | |
568 | + maxRetryCount-- | |
569 | + continue | |
570 | + } | |
571 | + if (!isWaitLogging) | |
572 | + { | |
573 | + Log.v(TAG, " WAIT FOR RECEIVE COUNT: $maxRetryCount (SEQ: $sequenceNumber)") | |
574 | + } | |
575 | + | |
576 | + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) | |
577 | + if (readBytes <= 0) | |
578 | + { | |
579 | + if (isDumpLog) | |
580 | + { | |
581 | + Log.v(TAG, " RECEIVED MESSAGE FINISHED ($readBytes) [receivedLength: $receivedLength, targetLength: $targetLength]") | |
582 | + } | |
583 | + break | |
584 | + } | |
585 | + receivedLength += readBytes | |
586 | + callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(0, readBytes)) | |
587 | + maxRetryCount = command.maxRetryCount() | |
588 | + } | |
589 | + | |
590 | + // 最後のデータを受信した後にもう一度受信が必要な場合の処理... | |
591 | + if (command.isLastReceiveRetry) | |
592 | + { | |
593 | + var responseReceive = true | |
594 | + try | |
595 | + { | |
596 | + while (responseReceive) | |
597 | + { | |
598 | + Log.v(TAG, " --- isLastReceiveRetry is true --- SEQ: $sequenceNumber") | |
599 | + sleep(delayMs) | |
600 | + if (inputStream.available() > 0) | |
601 | + { | |
602 | + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) | |
603 | + if (readBytes > 0) | |
604 | + { | |
605 | + receivedLength += readBytes | |
606 | + callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(0, readBytes)) | |
607 | + Log.v(TAG, " --- isLastReceiveRetry: onReceiveProgress() $readBytes bytes. --- SEQ: $sequenceNumber ") | |
608 | + } | |
609 | + responseReceive = false | |
610 | + } | |
611 | + else | |
612 | + { | |
613 | + Log.v(TAG, " --- inputStream.available() is <= 0 --- : ${inputStream.available()} SEQ: $sequenceNumber") | |
614 | + responseReceive = false | |
615 | + } | |
616 | + } | |
617 | + } | |
618 | + catch (ex: Exception) | |
619 | + { | |
620 | + ex.printStackTrace() | |
621 | + } | |
622 | + } | |
623 | + | |
624 | + // 終了報告... | |
625 | + if (isDumpLog) | |
626 | + { | |
627 | + Log.v(TAG, " --- receive_multi : $id ($readBytes) [$maxRetryCount] $receiveMessageBufferSize ($receivedLength) SEQ: $sequenceNumber") | |
628 | + } | |
629 | + val copyBytes = if (byteArray.size > receivedLength) { receivedLength } else { byteArray.size } | |
630 | + callback?.receivedMessage(id, byteArray.copyOfRange(0, copyBytes)) | |
631 | + } | |
632 | + catch (e: Throwable) | |
633 | + { | |
634 | + e.printStackTrace() | |
635 | + } | |
636 | + return (false) | |
637 | + } | |
638 | + | |
639 | + private fun parseDataLength(byte_array: ByteArray, read_bytes: Int): Int | |
640 | + { | |
641 | + var offset = 0 | |
642 | + var lenlen = 0 | |
643 | + try | |
644 | + { | |
645 | + if (read_bytes > 20) | |
646 | + { | |
647 | + if (byte_array[offset + 4].toUByte().toInt() == 0x07) | |
648 | + { | |
649 | + // 前の応答が入っていると考える... レングスバイト分読み飛ばす | |
650 | + offset = byte_array[offset].toUByte().toInt() | |
651 | + } | |
652 | + if (byte_array[offset + 4].toUByte().toInt() == 0x09) | |
653 | + { | |
654 | + // データバイト... | |
655 | + lenlen = (byte_array[offset + 15].toUByte().toInt() and 0xff shl 24) + (byte_array[offset + 14].toUByte().toInt() and 0xff shl 16) + (byte_array[offset + 13].toUByte().toInt() and 0xff shl 8) + (byte_array[offset + 12].toUByte().toInt() and 0xff) | |
656 | + } | |
657 | + } | |
658 | + } | |
659 | + catch (e: Exception) | |
660 | + { | |
661 | + e.printStackTrace() | |
662 | + } | |
663 | + return (lenlen) | |
664 | + } | |
665 | + | |
666 | + private fun cutHeader(receivedBuffer: ByteArrayOutputStream): ByteArrayOutputStream | |
667 | + { | |
668 | + try | |
669 | + { | |
670 | + val byteArray = receivedBuffer.toByteArray() | |
671 | + val limit = byteArray.size | |
672 | + var lenlen = 0 | |
673 | + val len = (byteArray[3].toUByte().toInt() and 0xff shl 24) + (byteArray[2].toUByte().toInt() and 0xff shl 16) + (byteArray[1].toUByte().toInt() and 0xff shl 8) + (byteArray[0].toUByte().toInt() and 0xff) | |
674 | + val packetType = byteArray[4].toUByte().toInt() and 0xff | |
675 | + if ((limit == len)||(limit < 16384)) | |
676 | + { | |
677 | + // 応答は1つしか入っていない。もしくは受信データサイズが16kBの場合は、そのまま返す。 | |
678 | + return (receivedBuffer) | |
679 | + } | |
680 | + | |
681 | + if (packetType == 0x09) | |
682 | + { | |
683 | + lenlen = (byteArray[15].toUByte().toInt() and 0xff shl 24) + (byteArray[14].toUByte().toInt() and 0xff shl 16) + (byteArray[13].toUByte().toInt() and 0xff shl 8) + (byteArray[12].toUByte().toInt() and 0xff) | |
684 | + } | |
685 | + | |
686 | + if (lenlen == 0) | |
687 | + { | |
688 | + // データとしては変なので、なにもしない | |
689 | + return receivedBuffer | |
690 | + } | |
691 | + val outputStream = ByteArrayOutputStream() | |
692 | + var position = 20 // ヘッダ込の先頭 | |
693 | + while (position < limit) | |
694 | + { | |
695 | + lenlen = (byteArray[position + 3].toUByte().toInt() and 0xff shl 24) + (byteArray[position + 2].toUByte().toInt() and 0xff shl 16) + (byteArray[position + 1].toUByte().toInt() and 0xff shl 8) + (byteArray[position].toUByte().toInt() and 0xff) | |
696 | + | |
697 | + val copyByte = Math.min(limit - (position + 12), lenlen - 12) | |
698 | + outputStream.write(byteArray, position + 12, copyByte) | |
699 | + position += lenlen | |
700 | + } | |
701 | + return (outputStream) | |
702 | + } | |
703 | + catch (e: Throwable) | |
704 | + { | |
705 | + e.printStackTrace() | |
706 | + System.gc() | |
707 | + } | |
708 | + return (receivedBuffer) | |
709 | + } | |
710 | + | |
711 | + private fun waitForReceive(inputStream : InputStream, delayMs: Int, retryCnt : Int): Int | |
712 | + { | |
713 | + var retryCount = retryCnt | |
714 | + var isLogOutput = true | |
715 | + var readBytes = 0 | |
716 | + try | |
717 | + { | |
718 | + while ((retryCount >= 0) && (readBytes <= 0)) | |
719 | + { | |
720 | + sleep(delayMs) | |
721 | + readBytes = inputStream.available() | |
722 | + if (readBytes <= 0) // if (readBytes <= 0) | |
723 | + { | |
724 | + if (isLogOutput) | |
725 | + { | |
726 | + Log.v(TAG, "waitForReceive:: is.available() WAIT... : $delayMs ms (Count : $retryCount/$retryCnt) SEQ: $sequenceNumber") | |
727 | + isLogOutput = false | |
728 | + } | |
729 | + if (!waitForever) | |
730 | + { | |
731 | + retryCount-- | |
732 | + } | |
733 | + else | |
734 | + { | |
735 | + Log.v(TAG, "waitForReceive: wait forever ") | |
736 | + isLogOutput = false | |
737 | + } | |
738 | + } | |
739 | + } | |
740 | + if (!isLogOutput) | |
741 | + { | |
742 | + Log.v(TAG, " --- waitForReceive : $readBytes bytes. (RetryCount : $retryCount/$retryCnt)") | |
743 | + } | |
744 | + } | |
745 | + catch (e: Exception) | |
746 | + { | |
747 | + e.printStackTrace() | |
748 | + } | |
749 | + return (readBytes) | |
750 | + } | |
751 | + | |
752 | + companion object | |
753 | + { | |
754 | + private val TAG = PtpIpCommandPublisher::class.java.simpleName | |
755 | + | |
756 | + private const val SEQUENCE_START_NUMBER = 1 | |
757 | + private const val BUFFER_SIZE = 1024 * 1024 + 16 // 受信バッファは 1MB | |
758 | + private const val COMMAND_SEND_RECEIVE_DURATION_MS = 5 | |
759 | + private const val COMMAND_SEND_RECEIVE_DURATION_MAX = 3000 | |
760 | + private const val COMMAND_POLL_QUEUE_MS = 5 // 5 | |
761 | + } | |
762 | +} |
@@ -15,9 +15,9 @@ import java.util.Queue; | ||
15 | 15 | |
16 | 16 | import static net.osdn.gokigen.pkremote.camera.utils.SimpleLogDumper.dump_bytes; |
17 | 17 | |
18 | -public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpCommunication | |
18 | +public class PtpIpCommandPublisher0 implements IPtpIpCommandPublisher, IPtpIpCommunication | |
19 | 19 | { |
20 | - private static final String TAG = PtpIpCommandPublisher.class.getSimpleName(); | |
20 | + private static final String TAG = PtpIpCommandPublisher0.class.getSimpleName(); | |
21 | 21 | |
22 | 22 | private static final int SEQUENCE_START_NUMBER = 1; |
23 | 23 | private static final int BUFFER_SIZE = 1024 * 1024 + 16; // 受信バッファは 256kB |
@@ -35,10 +35,10 @@ public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpComm | ||
35 | 35 | private DataOutputStream dos = null; |
36 | 36 | private BufferedReader bufferedReader = null; |
37 | 37 | private int sequenceNumber = SEQUENCE_START_NUMBER; |
38 | - private Queue<IPtpIpCommand> commandQueue; | |
39 | - private Queue<IPtpIpCommand> holdCommandQueue; | |
38 | + private final Queue<IPtpIpCommand> commandQueue; | |
39 | + private final Queue<IPtpIpCommand> holdCommandQueue; | |
40 | 40 | |
41 | - public PtpIpCommandPublisher(@NonNull String ip, int portNumber) | |
41 | + public PtpIpCommandPublisher0(@NonNull String ip, int portNumber) | |
42 | 42 | { |
43 | 43 | this.ipAddress = ip; |
44 | 44 | this.portNumber = portNumber; |
@@ -233,6 +233,34 @@ public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpComm | ||
233 | 233 | return (true); |
234 | 234 | } |
235 | 235 | |
236 | + @Override | |
237 | + public int isExistCommandMessageQueue(int id) | |
238 | + { | |
239 | + int count = 0; | |
240 | + for (IPtpIpCommand cmd : commandQueue) | |
241 | + { | |
242 | + if (cmd.getId() == id) | |
243 | + { | |
244 | + count++; | |
245 | + } | |
246 | + } | |
247 | + return (count); | |
248 | + } | |
249 | + | |
250 | + @Override | |
251 | + public int getCurrentQueueSize() | |
252 | + { | |
253 | + return (commandQueue.size()); | |
254 | + } | |
255 | + | |
256 | + @Override | |
257 | + public boolean flushQueue() | |
258 | + { | |
259 | + commandQueue.clear(); | |
260 | + System.gc(); | |
261 | + return (true); | |
262 | + } | |
263 | + | |
236 | 264 | private void issueCommand(@NonNull IPtpIpCommand command) |
237 | 265 | { |
238 | 266 | try |
@@ -34,7 +34,7 @@ public class PtpIpCommandBase implements IPtpIpCommand, IPtpIpMessages | ||
34 | 34 | @Override |
35 | 35 | public int receiveDelayMs() |
36 | 36 | { |
37 | - return (15); | |
37 | + return (30); | |
38 | 38 | } |
39 | 39 | |
40 | 40 | @Override |
@@ -108,4 +108,29 @@ public class PtpIpCommandBase implements IPtpIpCommand, IPtpIpMessages | ||
108 | 108 | { |
109 | 109 | return (true); |
110 | 110 | } |
111 | + | |
112 | + @Override | |
113 | + public boolean isRetrySend() | |
114 | + { | |
115 | + return (false); | |
116 | + } | |
117 | + | |
118 | + @Override | |
119 | + public boolean isLastReceiveRetry() | |
120 | + { | |
121 | + return (false); | |
122 | + } | |
123 | + | |
124 | + @Override | |
125 | + public int maxRetryCount() | |
126 | + { | |
127 | + return (3500); | |
128 | + } | |
129 | + | |
130 | + @Override | |
131 | + public boolean isIncrementSequenceNumberToRetry() | |
132 | + { | |
133 | + return (false); | |
134 | + } | |
135 | + | |
111 | 136 | } |
@@ -32,20 +32,20 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
32 | 32 | private final Activity activity; |
33 | 33 | private final PtpIpInterfaceProvider provider; |
34 | 34 | private final CanonFullImageReceiver fullImageReceiver; |
35 | - private final CanonSmallImageReceiver smallImageReciever; | |
36 | - //private int delayMs = 20; | |
35 | + private final ICanonSmallImageReceiver smallImageReciever; | |
37 | 36 | private String raw_suffix = "CR2"; |
38 | - private boolean use_screennail_image = false; | |
39 | - private CanonImageObjectReceiver canonImageObjectReceiver; | |
37 | + private boolean useScreennailImage = false; | |
38 | + private final CanonImageObjectReceiver canonImageObjectReceiver; | |
40 | 39 | |
41 | 40 | public CanonPlaybackControl(Activity activity, PtpIpInterfaceProvider provider) |
42 | 41 | { |
42 | + int smallImageSequence = 0; | |
43 | 43 | int delayMs = 20; |
44 | 44 | try |
45 | 45 | { |
46 | 46 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); |
47 | 47 | raw_suffix = preferences.getString(IPreferencePropertyAccessor.CANON_RAW_SUFFIX, IPreferencePropertyAccessor.CANON_RAW_SUFFIX_DEFAULT_VALUE); |
48 | - use_screennail_image = preferences.getBoolean(IPreferencePropertyAccessor.CANON_USE_SCREENNAIL_AS_SMALL, false); | |
48 | + useScreennailImage = preferences.getBoolean(IPreferencePropertyAccessor.CANON_USE_SCREENNAIL_AS_SMALL, false); | |
49 | 49 | try |
50 | 50 | { |
51 | 51 | delayMs = Integer.parseInt(preferences.getString(IPreferencePropertyAccessor.CANON_RECEIVE_WAIT, IPreferencePropertyAccessor.CANON_RECEIVE_WAIT_DEFAULT_VALUE)); |
@@ -58,6 +58,14 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
58 | 58 | { |
59 | 59 | delayMs = 10; // 最短は 10msにする |
60 | 60 | } |
61 | + try | |
62 | + { | |
63 | + smallImageSequence = Integer.parseInt(preferences.getString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE)); | |
64 | + } | |
65 | + catch (Exception ee) | |
66 | + { | |
67 | + ee.printStackTrace(); | |
68 | + } | |
61 | 69 | } |
62 | 70 | catch (Exception e) |
63 | 71 | { |
@@ -66,9 +74,15 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
66 | 74 | this.activity = activity; |
67 | 75 | this.provider = provider; |
68 | 76 | this.fullImageReceiver = new CanonFullImageReceiver(activity, provider.getCommandPublisher()); |
69 | - this.smallImageReciever = new CanonSmallImageReceiver(activity, provider.getCommandPublisher()); | |
77 | + if (smallImageSequence == 1) | |
78 | + { | |
79 | + this.smallImageReciever = new CanonReducedImageReceiver(activity, provider.getCommandPublisher()); | |
80 | + } | |
81 | + else | |
82 | + { | |
83 | + this.smallImageReciever = new CanonSmallImageReceiver(activity, provider.getCommandPublisher()); | |
84 | + } | |
70 | 85 | canonImageObjectReceiver = new CanonImageObjectReceiver(provider, delayMs); |
71 | - | |
72 | 86 | } |
73 | 87 | |
74 | 88 | @Override |
@@ -101,7 +115,7 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
101 | 115 | { |
102 | 116 | Log.v(TAG, " downloadContentScreennail() " + path); |
103 | 117 | |
104 | - if (!use_screennail_image) | |
118 | + if (!useScreennailImage) | |
105 | 119 | { |
106 | 120 | // Thumbnail と同じ画像を表示する |
107 | 121 | downloadContentThumbnail(path, callback); |
@@ -152,17 +166,13 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
152 | 166 | { |
153 | 167 | start = 1; |
154 | 168 | } |
155 | - //String indexStr = path.substring(start, path.indexOf(".")); | |
156 | - final String indexStr = path.substring(start); | |
157 | - //Log.v(TAG, "downloadContentThumbnail() : [" + path + "] " + indexStr); | |
158 | 169 | |
170 | + final String indexStr = path.substring(start); | |
159 | 171 | CanonImageContentInfo content = canonImageObjectReceiver.getContentObject(indexStr); |
160 | 172 | if (content != null) |
161 | 173 | { |
162 | - IPtpIpCommandPublisher publisher = provider.getCommandPublisher(); | |
163 | - //int storageId = content.getStorageId(); | |
164 | 174 | int objectId = content.getId(); |
165 | - // Log.v(TAG, "downloadContentThumbnail() " + indexStr + " [" + objectId + "] (" + storageId + ")"); | |
175 | + IPtpIpCommandPublisher publisher = provider.getCommandPublisher(); | |
166 | 176 | publisher.enqueueCommand(new PtpIpCommandGeneric(new PtpIpThumbnailImageReceiver(activity, callback), objectId, false, 0, 0x910a, 8, objectId, 0x00032000)); |
167 | 177 | } |
168 | 178 | } |
@@ -211,7 +221,6 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
211 | 221 | { |
212 | 222 | return; |
213 | 223 | } |
214 | - | |
215 | 224 | try |
216 | 225 | { |
217 | 226 | Thread thread = new Thread(new Runnable() { |
@@ -235,7 +244,6 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
235 | 244 | try |
236 | 245 | { |
237 | 246 | Log.v(TAG, " showPictureStarted() "); |
238 | - | |
239 | 247 | IPtpIpCommandPublisher publisher = provider.getCommandPublisher(); |
240 | 248 | publisher.flushHoldQueue(); |
241 | 249 | System.gc(); |
@@ -252,7 +260,6 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
252 | 260 | try |
253 | 261 | { |
254 | 262 | Log.v(TAG, " showPictureFinished() "); |
255 | - | |
256 | 263 | IPtpIpCommandPublisher publisher = provider.getCommandPublisher(); |
257 | 264 | publisher.flushHoldQueue(); |
258 | 265 | System.gc(); |
@@ -262,5 +269,4 @@ public class CanonPlaybackControl implements IPlaybackControl | ||
262 | 269 | e.printStackTrace(); |
263 | 270 | } |
264 | 271 | } |
265 | - | |
266 | 272 | } |
@@ -0,0 +1,217 @@ | ||
1 | +package net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback | |
2 | + | |
3 | +import android.app.Activity | |
4 | +import android.util.Log | |
5 | +import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback | |
6 | +import net.osdn.gokigen.pkremote.camera.interfaces.playback.IProgressEvent | |
7 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandCallback | |
8 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher | |
9 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.PtpIpCommandCanonGetPartialObject | |
10 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.PtpIpCommandGeneric | |
11 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.CanonRequestInnerDevelopEnd | |
12 | +import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.CanonRequestInnerDevelopStart | |
13 | +import java.io.ByteArrayOutputStream | |
14 | + | |
15 | +class CanonReducedImageReceiver(private val activity: Activity, private val publisher: IPtpIpCommandPublisher) : IPtpIpCommandCallback, ICanonSmallImageReceiver | |
16 | +{ | |
17 | + private val mine = this | |
18 | + | |
19 | + private var callback: IDownloadContentCallback? = null | |
20 | + private var objectId = 0 | |
21 | + private var isReceiveMulti = false | |
22 | + private var receivedFirstData = false | |
23 | + | |
24 | + private var receivedTotalBytes = 0 | |
25 | + private var receivedRemainBytes = 0 | |
26 | + | |
27 | + | |
28 | + override fun issueCommand(objectId: Int, callback: IDownloadContentCallback?) | |
29 | + { | |
30 | + Log.v(TAG, " issueCommand() : ${objectId}") | |
31 | + if (this.objectId != 0) | |
32 | + { | |
33 | + // already issued | |
34 | + Log.v(TAG, " COMMAND IS ALREADY ISSUED. : $objectId") | |
35 | + return | |
36 | + } | |
37 | + this.callback = callback | |
38 | + this.objectId = objectId | |
39 | + publisher.enqueueCommand(CanonRequestInnerDevelopStart(object : IPtpIpCommandCallback { | |
40 | + override fun receivedMessage(id: Int, rx_body: ByteArray?) { | |
41 | + Log.v(TAG, " getRequestStatusEvent : $objectId " + (rx_body?.size ?: 0)) | |
42 | + publisher.enqueueCommand(PtpIpCommandGeneric(mine, objectId + 5, false, objectId, 0x9116)) | |
43 | + } | |
44 | + override fun onReceiveProgress(currentBytes: Int, totalBytes: Int, rx_body: ByteArray?) { } | |
45 | + override fun isReceiveMulti(): Boolean { return (false) } | |
46 | + }, objectId, false, objectId, objectId)) // 0x9141 : RequestInnerDevelopStart | |
47 | + } | |
48 | + | |
49 | + override fun receivedMessage(id: Int, rx_body: ByteArray?) | |
50 | + { | |
51 | + try | |
52 | + { | |
53 | + when (id) | |
54 | + { | |
55 | + (objectId + 1) -> { | |
56 | + sendTransferComplete(rx_body) | |
57 | + } | |
58 | + (objectId + 2) -> { | |
59 | + Log.v(TAG, " requestInnerDevelopEnd() : $objectId") | |
60 | + publisher.enqueueCommand(CanonRequestInnerDevelopEnd(this, objectId + 3, false, objectId)) // 0x9143 : RequestInnerDevelopEnd | |
61 | + } | |
62 | + (objectId + 3) -> { | |
63 | + //Log.v(TAG, " --- COMMAND RESET : " + objectId + " --- "); | |
64 | + | |
65 | + // リセットコマンドを送ってみる | |
66 | + publisher.enqueueCommand(PtpIpCommandGeneric(this, objectId + 4, false, objectId, 0x902f)) | |
67 | + } | |
68 | + (objectId + 4) -> { | |
69 | + // 画像取得終了 | |
70 | + Log.v(TAG, " ----- SMALL IMAGE RECEIVE SEQUENCE FINISHED : $objectId") | |
71 | + callback!!.onCompleted() | |
72 | + objectId = 0 | |
73 | + callback = null | |
74 | + receivedTotalBytes = 0 | |
75 | + receivedRemainBytes = 0 | |
76 | + receivedFirstData = false | |
77 | + System.gc() | |
78 | + } | |
79 | + (objectId + 5) -> { | |
80 | + requestGetPartialObject(rx_body) | |
81 | + } | |
82 | + else -> { | |
83 | + Log.v(TAG, " RECEIVED UNKNOWN ID : $id") | |
84 | + } | |
85 | + } | |
86 | + } | |
87 | + catch (e: Exception) | |
88 | + { | |
89 | + e.printStackTrace() | |
90 | + callback?.onErrorOccurred(e) | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + override fun onReceiveProgress(currentBytes: Int, totalBytes: Int, rx_body: ByteArray?) | |
95 | + { | |
96 | + val body = cutHeader(rx_body) | |
97 | + val length = body?.size ?: 0 | |
98 | + Log.v(TAG, " onReceiveProgress() $currentBytes/$totalBytes ($length bytes.)") | |
99 | + callback?.onProgress(body, length, object : IProgressEvent | |
100 | + { | |
101 | + override fun getProgress(): Float { return (currentBytes.toFloat() / totalBytes.toFloat()) } | |
102 | + override fun isCancellable(): Boolean { return (false) } | |
103 | + override fun requestCancellation() { } | |
104 | + }) | |
105 | + } | |
106 | + | |
107 | + private fun cutHeader(rx_body: ByteArray?): ByteArray? | |
108 | + { | |
109 | + if (rx_body == null) | |
110 | + { | |
111 | + return (null) | |
112 | + } | |
113 | + val length = rx_body.size | |
114 | + var dataPosition = 0 | |
115 | + val byteStream = ByteArrayOutputStream() | |
116 | + if (!receivedFirstData) | |
117 | + { | |
118 | + // 初回データを読み込んだ | |
119 | + receivedFirstData = true | |
120 | + | |
121 | + // データを最初に読んだとき。ヘッダ部分を読み飛ばす | |
122 | + dataPosition = rx_body[0].toInt() and 0xff | |
123 | + } | |
124 | + else if (receivedRemainBytes > 0) | |
125 | + { | |
126 | + //Log.v(TAG, " >>> [ remain_bytes : " + received_remain_bytes + "] ( length : " + length + ") " + data_position); | |
127 | + //SimpleLogDumper.dump_bytes("[zzz]", Arrays.copyOfRange(rx_body, data_position, (data_position + 160))); | |
128 | + | |
129 | + // データの読み込みが途中だった場合... | |
130 | + if (length < receivedRemainBytes) | |
131 | + { | |
132 | + // 全部コピーする、足りないバイト数は残す | |
133 | + receivedRemainBytes = receivedRemainBytes - length | |
134 | + receivedTotalBytes = receivedTotalBytes + rx_body.size | |
135 | + return rx_body | |
136 | + } | |
137 | + else | |
138 | + { | |
139 | + byteStream.write(rx_body, dataPosition, receivedRemainBytes) | |
140 | + dataPosition = receivedRemainBytes | |
141 | + receivedRemainBytes = 0 | |
142 | + } | |
143 | + } | |
144 | + while (dataPosition <= length - 12) | |
145 | + { | |
146 | + val bodySize: Int = (rx_body[dataPosition].toUByte().toInt() and 0xff) + (rx_body[dataPosition + 1].toUByte().toInt() and 0xff shl 8) + (rx_body[dataPosition + 2].toUByte().toInt() and 0xff shl 16) + (rx_body[dataPosition + 3].toUByte().toInt() and 0xff shl 24) | |
147 | + if (bodySize <= 12) | |
148 | + { | |
149 | + Log.v(TAG, " BODY SIZE IS SMALL : " + dataPosition + " (" + bodySize + ") [" + receivedRemainBytes + "] " + rx_body.size + " ") | |
150 | + //int startpos = (data_position > 48) ? (data_position - 48) : 0; | |
151 | + //SimpleLogDumper.dump_bytes("[xxx]", Arrays.copyOfRange(rx_body, startpos, (data_position + 48))); | |
152 | + break | |
153 | + } | |
154 | + | |
155 | + // Log.v(TAG, " RX DATA : " + data_position + " (" + body_size + ") [" + received_remain_bytes + "] (" + received_total_bytes + ")"); | |
156 | + //SimpleLogDumper.dump_bytes("[yyy] " + data_position + ": ", Arrays.copyOfRange(rx_body, data_position, (data_position + 64))); | |
157 | + if (dataPosition + bodySize > length) | |
158 | + { | |
159 | + // データがすべてバッファ内になかったときは、バッファすべてコピーして残ったサイズを記憶しておく。 | |
160 | + val copysize = length - (dataPosition + 12) | |
161 | + byteStream.write(rx_body, dataPosition + 12, copysize) | |
162 | + receivedRemainBytes = bodySize - copysize - 12 // マイナス12は、ヘッダ分 | |
163 | + receivedTotalBytes = receivedTotalBytes + copysize | |
164 | + // Log.v(TAG, " --- copy : " + (data_position + 12) + " " + copysize + " remain : " + received_remain_bytes + " body size : " + body_size); | |
165 | + break | |
166 | + } | |
167 | + try | |
168 | + { | |
169 | + byteStream.write(rx_body, dataPosition + 12, bodySize - 12) | |
170 | + dataPosition = dataPosition + bodySize | |
171 | + receivedTotalBytes = receivedTotalBytes + 12 | |
172 | + //Log.v(TAG, " --- COPY : " + (data_position + 12) + " " + (body_size - 12) + " remain : " + received_remain_bytes); | |
173 | + } | |
174 | + catch (e: Exception) | |
175 | + { | |
176 | + Log.v(TAG, " pos : $dataPosition size : $bodySize length : $length") | |
177 | + e.printStackTrace() | |
178 | + } | |
179 | + } | |
180 | + return byteStream.toByteArray() | |
181 | + } | |
182 | + | |
183 | + override fun isReceiveMulti(): Boolean | |
184 | + { | |
185 | + return (isReceiveMulti) | |
186 | + } | |
187 | + | |
188 | + private fun requestGetPartialObject(rx_body: ByteArray?) { | |
189 | + Log.v(TAG, " requestGetPartialObject() : $objectId") | |
190 | + isReceiveMulti = true | |
191 | + receivedFirstData = false | |
192 | + | |
193 | + // 0x9107 : GetPartialObject (元は 0x00020000) | |
194 | + val pictureLength: Int | |
195 | + if (rx_body != null && rx_body.size > 52) { | |
196 | + val dataIndex = 48 | |
197 | + pictureLength = (rx_body[dataIndex].toUByte().toInt() and 0xff) + (rx_body[dataIndex + 1].toUByte().toInt() and 0xff shl 8) + (rx_body[dataIndex + 2].toUByte().toInt() and 0xff shl 16) + (rx_body[dataIndex + 3].toUByte().toInt() and 0xff shl 24) | |
198 | + } | |
199 | + else | |
200 | + { | |
201 | + pictureLength = 0x020000 | |
202 | + } | |
203 | + publisher.enqueueCommand(PtpIpCommandCanonGetPartialObject(this, objectId + 1, false, objectId, 0x01, 0x00, pictureLength, pictureLength)) | |
204 | + } | |
205 | + | |
206 | + private fun sendTransferComplete(rx_body: ByteArray?) | |
207 | + { | |
208 | + Log.v(TAG, " sendTransferComplete(), id : $objectId size: " + (rx_body?.size ?: 0)) | |
209 | + publisher.enqueueCommand(PtpIpCommandGeneric(this, objectId + 2, false, objectId, 0x9117, 4, 0x01)) // 0x9117 : TransferComplete | |
210 | + isReceiveMulti = false | |
211 | + } | |
212 | + | |
213 | + companion object | |
214 | + { | |
215 | + private val TAG = CanonReducedImageReceiver::class.java.simpleName | |
216 | + } | |
217 | +} |
@@ -18,7 +18,7 @@ import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.sp | ||
18 | 18 | import java.io.ByteArrayOutputStream; |
19 | 19 | |
20 | 20 | |
21 | -public class CanonSmallImageReceiver implements IPtpIpCommandCallback | |
21 | +public class CanonSmallImageReceiver implements IPtpIpCommandCallback, ICanonSmallImageReceiver | |
22 | 22 | { |
23 | 23 | private static final String TAG = CanonSmallImageReceiver.class.getSimpleName(); |
24 | 24 |
@@ -40,6 +40,7 @@ public class CanonSmallImageReceiver implements IPtpIpCommandCallback | ||
40 | 40 | this.mine = this; |
41 | 41 | } |
42 | 42 | |
43 | + @Override | |
43 | 44 | public void issueCommand(final int objectId, IDownloadContentCallback callback) |
44 | 45 | { |
45 | 46 | if (this.objectId != 0) |
@@ -0,0 +1,8 @@ | ||
1 | +package net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback; | |
2 | + | |
3 | +import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback; | |
4 | + | |
5 | +public interface ICanonSmallImageReceiver | |
6 | +{ | |
7 | + void issueCommand(final int objectId, IDownloadContentCallback callback); | |
8 | +} |
@@ -137,6 +137,9 @@ public interface IPreferencePropertyAccessor | ||
137 | 137 | String CANON_CONNECTION_SEQUENCE = "canon_connection_mode"; |
138 | 138 | String CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE = "0"; |
139 | 139 | |
140 | + String CANON_SMALL_PICTURE_TYPE = "canon_small_picture_type"; | |
141 | + String CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE = "0"; | |
142 | + | |
140 | 143 | /* |
141 | 144 | //String GR2_DISPLAY_MODE = "gr2_display_mode"; |
142 | 145 | //String GR2_DISPLAY_MODE_DEFAULT_VALUE = "0"; |
@@ -179,6 +179,9 @@ public class CanonPreferenceFragment extends PreferenceFragmentCompat implement | ||
179 | 179 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
180 | 180 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
181 | 181 | } |
182 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
183 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
184 | + } | |
182 | 185 | editor.apply(); |
183 | 186 | } |
184 | 187 | catch (Exception e) |
@@ -179,6 +179,9 @@ public class FujiXPreferenceFragment extends PreferenceFragmentCompat implement | ||
179 | 179 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
180 | 180 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
181 | 181 | } |
182 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
183 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
184 | + } | |
182 | 185 | editor.apply(); |
183 | 186 | } |
184 | 187 | catch (Exception e) |
@@ -176,6 +176,9 @@ public class NikonPreferenceFragment extends PreferenceFragmentCompat implement | ||
176 | 176 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
177 | 177 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
178 | 178 | } |
179 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
180 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
181 | + } | |
179 | 182 | editor.apply(); |
180 | 183 | } |
181 | 184 | catch (Exception e) |
@@ -205,6 +205,9 @@ public class OpcPreferenceFragment extends PreferenceFragmentCompat implements S | ||
205 | 205 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
206 | 206 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
207 | 207 | } |
208 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
209 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
210 | + } | |
208 | 211 | editor.apply(); |
209 | 212 | } |
210 | 213 |
@@ -170,6 +170,9 @@ public class OlympusPenPreferenceFragment extends PreferenceFragmentCompat impl | ||
170 | 170 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
171 | 171 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
172 | 172 | } |
173 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
174 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
175 | + } | |
173 | 176 | editor.apply(); |
174 | 177 | } |
175 | 178 | catch (Exception e) |
@@ -168,6 +168,9 @@ public class PanasonicPreferenceFragment extends PreferenceFragmentCompat imple | ||
168 | 168 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
169 | 169 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
170 | 170 | } |
171 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
172 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
173 | + } | |
171 | 174 | editor.apply(); |
172 | 175 | } |
173 | 176 | catch (Exception e) |
@@ -167,6 +167,9 @@ public class PixproPreferenceFragment extends PreferenceFragmentCompat implemen | ||
167 | 167 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
168 | 168 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
169 | 169 | } |
170 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
171 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
172 | + } | |
170 | 173 | editor.apply(); |
171 | 174 | } |
172 | 175 | catch (Exception e) |
@@ -183,6 +183,9 @@ public class RicohGr2PreferenceFragment extends PreferenceFragmentCompat implem | ||
183 | 183 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
184 | 184 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
185 | 185 | } |
186 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
187 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
188 | + } | |
186 | 189 | editor.apply(); |
187 | 190 | } |
188 | 191 | catch (Exception e) |
@@ -165,6 +165,9 @@ public class SonyPreferenceFragment extends PreferenceFragmentCompat implements | ||
165 | 165 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
166 | 166 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
167 | 167 | } |
168 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
169 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
170 | + } | |
168 | 171 | editor.apply(); |
169 | 172 | } |
170 | 173 | catch (Exception e) |
@@ -167,6 +167,9 @@ public class ThetaPreferenceFragment extends PreferenceFragmentCompat implement | ||
167 | 167 | if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { |
168 | 168 | editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); |
169 | 169 | } |
170 | + if (!items.containsKey(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE)) { | |
171 | + editor.putString(IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE, IPreferencePropertyAccessor.CANON_SMALL_PICTURE_TYPE_DEFAULT_VALUE); | |
172 | + } | |
170 | 173 | editor.apply(); |
171 | 174 | } |
172 | 175 | catch (Exception e) |
@@ -378,4 +378,7 @@ | ||
378 | 378 | <string name="pref_canon_connection_mode">接続シーケンス</string> |
379 | 379 | <string name="pref_summary_canon_connection_mode">通常、変更は不要です (初期値: TYPE0)</string> |
380 | 380 | |
381 | + <string name="pref_canon_small_picture_type">スモール画像取得シーケンス</string> | |
382 | + <string name="pref_summary_canon_small_picture_type">(初期値: TYPE0)</string> | |
383 | + | |
381 | 384 | </resources> |
@@ -116,4 +116,14 @@ | ||
116 | 116 | <item>2</item> |
117 | 117 | </string-array> |
118 | 118 | |
119 | + <string-array name="canon_small_picture_type"> | |
120 | + <item>TYPE0</item> | |
121 | + <item>TYPE1</item> | |
122 | + </string-array> | |
123 | + | |
124 | + <string-array name="canon_small_picture_type_value"> | |
125 | + <item>0</item> | |
126 | + <item>1</item> | |
127 | + </string-array> | |
128 | + | |
119 | 129 | </resources> |
@@ -380,4 +380,7 @@ | ||
380 | 380 | <string name="pref_canon_connection_mode">Connection Sequence</string> |
381 | 381 | <string name="pref_summary_canon_connection_mode">default: TYPE0 </string> |
382 | 382 | |
383 | + <string name="pref_canon_small_picture_type">Small Picture Getting Sequence</string> | |
384 | + <string name="pref_summary_canon_small_picture_type">default: TYPE0 </string> | |
385 | + | |
383 | 386 | </resources> |
@@ -50,6 +50,14 @@ | ||
50 | 50 | android:summary="@string/pref_summary_canon_host_ip" /> |
51 | 51 | |
52 | 52 | <ListPreference |
53 | + android:title="@string/pref_canon_small_picture_type" | |
54 | + android:summary="@string/pref_summary_canon_small_picture_type" | |
55 | + android:entryValues="@array/canon_small_picture_type_value" | |
56 | + android:entries="@array/canon_small_picture_type" | |
57 | + android:key="canon_small_picture_type" | |
58 | + android:defaultValue="0"/> | |
59 | + | |
60 | + <ListPreference | |
53 | 61 | android:title="@string/pref_canon_connection_mode" |
54 | 62 | android:summary="@string/pref_summary_canon_connection_mode" |
55 | 63 | android:entryValues="@array/canon_connection_mode_value" |