OSDN Git Service

SONYの画像取得のために確認中。いったん保存。
[gokigen/PKRemote.git] / app / src / main / java / net / osdn / gokigen / pkremote / camera / vendor / sony / wrapper / playback / SonyPlaybackControl.java
1 package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.playback;
2
3 import android.app.Activity;
4 import android.content.SharedPreferences;
5 import android.graphics.Bitmap;
6 import android.graphics.Color;
7 import android.util.Log;
8
9 import androidx.annotation.NonNull;
10 import androidx.preference.PreferenceManager;
11
12 import net.osdn.gokigen.pkremote.IInformationReceiver;
13 import net.osdn.gokigen.pkremote.R;
14 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContent;
15 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContentListCallback;
16 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraFileInfo;
17 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IContentInfoCallback;
18 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback;
19 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentListCallback;
20 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadThumbnailImageCallback;
21 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
22 import net.osdn.gokigen.pkremote.camera.playback.ProgressEvent;
23 import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
24 import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
25 import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
26
27 import org.json.JSONArray;
28 import org.json.JSONObject;
29
30 import java.util.ArrayList;
31 import java.util.HashMap;
32
33 public class SonyPlaybackControl implements IPlaybackControl {
34     private final String TAG = toString();
35     private final Activity activity;
36     private final IInformationReceiver informationReceiver;
37     private ISonyCameraApi cameraApi = null;
38     private HashMap<String, SonyImageContentInfo> contentList;
39     private int timeoutMs = 55000;
40     private boolean contentListIsCreating = false;
41
42     public SonyPlaybackControl(@NonNull Activity activity, @NonNull IInformationReceiver informationReceiver) {
43         Log.v(TAG, "SonyPlaybackControl()");
44         this.activity = activity;
45         this.informationReceiver = informationReceiver;
46         contentList = new HashMap<>();
47
48     }
49
50     public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi) {
51         cameraApi = sonyCameraApi;
52     }
53
54     @Override
55     public String getRawFileSuffix() {
56         return "ARW";
57     }
58
59     @Override
60     public void downloadContentList(IDownloadContentListCallback callback) {
61         Log.v(TAG, "downloadContentList()");
62
63     }
64
65     @Override
66     public void getContentInfo(String path, String name, IContentInfoCallback callback) {
67         Log.v(TAG, "getContentInfo()");
68     }
69
70     @Override
71     public void updateCameraFileInfo(ICameraFileInfo info) {
72         Log.v(TAG, "updateCameraFileInfo()");
73     }
74
75     @Override
76     public void downloadContentScreennail(String path, IDownloadThumbnailImageCallback callback) {
77         //Log.v(TAG, "downloadContentScreennail()" + path);
78         try {
79             SonyImageContentInfo content = contentList.get(path.substring(path.indexOf('/') + 1));
80             if (content == null) {
81                 Log.v(TAG, " CONTENT IS NULL... : " + path);
82                 return;
83             }
84             try {
85                 String url = content.getSmallUrl();   // Screennail は VGAサイズ
86                 if (url.length() < 1) {
87                     url = content.getThumbnailUrl();  // VGAサイズが取れなかった場合はサムネイルサイズ
88                 }
89                 if (url.length() > 1) {
90                     Bitmap bmp = SimpleHttpClient.httpGetBitmap(url, timeoutMs);
91                     HashMap<String, Object> map = new HashMap<>();
92                     map.put("Orientation", 0);
93                     callback.onCompleted(bmp, map);
94                 }
95             } catch (Throwable e) {
96                 e.printStackTrace();
97                 callback.onErrorOccurred(new NullPointerException());
98             }
99         } catch (Exception e) {
100             e.printStackTrace();
101         }
102     }
103
104     @Override
105     public void downloadContentThumbnail(String path, IDownloadThumbnailImageCallback callback) {
106         //Log.v(TAG, "downloadContentThumbnail() : " + path);
107         try {
108             SonyImageContentInfo content = contentList.get(path.substring(path.indexOf('/') + 1));
109             if (content == null) {
110                 Log.v(TAG, " CONTENT IS NULL... : " + path);
111                 return;
112             }
113             try {
114                 String url = content.getThumbnailUrl();
115                 if (url.length() > 1) {
116                     Bitmap bmp = SimpleHttpClient.httpGetBitmap(url, timeoutMs);
117                     HashMap<String, Object> map = new HashMap<>();
118                     map.put("Orientation", 0);
119                     callback.onCompleted(bmp, map);
120                 }
121             } catch (Throwable e) {
122                 e.printStackTrace();
123                 callback.onErrorOccurred(new NullPointerException());
124             }
125         } catch (Exception e) {
126             e.printStackTrace();
127         }
128     }
129
130     @Override
131     public void downloadContent(String path, boolean isSmallSize, final IDownloadContentCallback callback) {
132         //Log.v(TAG, "downloadContent() : " + path);
133         try {
134             SonyImageContentInfo content = contentList.get(path.substring(path.indexOf('/') + 1));
135             if (content == null) {
136                 Log.v(TAG, " CONTENT IS NULL... : " + path);
137                 return;
138             }
139             try {
140                 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
141                 boolean isVgaSize = preferences.getBoolean(IPreferencePropertyAccessor.GET_SMALL_PICTURE_AS_VGA, false);
142                 String url = (isSmallSize) ? ((isVgaSize) ? content.getSmallUrl() : content.getLargeUrl()) : content.getOriginalUrl();
143                 if (url.length() < 1) {
144                     url = content.getOriginalUrl();
145                     if (url.length() < 1) {
146                         //  全然だめなら、サムネイルサイズ...
147                         url = content.getThumbnailUrl();
148                     }
149                 }
150                 Log.v(TAG, "downloadContent()  PATH : " + path + "  [SMALL:" + isSmallSize + "][VGA:" + isVgaSize + "]" + " GET URL : " + url);
151
152                 SimpleHttpClient.httpGetBytes(url, timeoutMs, new SimpleHttpClient.IReceivedMessageCallback() {
153                     @Override
154                     public void onCompleted() {
155                         callback.onCompleted();
156                     }
157
158                     @Override
159                     public void onErrorOccurred(Exception e) {
160                         callback.onErrorOccurred(e);
161                     }
162
163                     @Override
164                     public void onReceive(int readBytes, int length, int size, byte[] data) {
165                         float percent = (length == 0) ? 0.0f : ((float) readBytes / (float) length);
166                         //Log.v(TAG, " onReceive : " + readBytes + " " + length + " " + size);
167                         ProgressEvent event = new ProgressEvent(percent, null);
168                         callback.onProgress(data, size, event);
169                     }
170                 });
171             } catch (Throwable e) {
172                 e.printStackTrace();
173                 callback.onErrorOccurred(new NullPointerException());
174             }
175         } catch (Exception e) {
176             e.printStackTrace();
177         }
178     }
179
180     @Override
181     public void getCameraContentList(ICameraContentListCallback callback) {
182         Log.v(TAG, "getCameraContentList()");
183         try {
184             if (cameraApi == null) {
185                 Log.v(TAG, "CAMERA API is NULL.");
186                 return;
187             }
188             if (contentListIsCreating) {
189                 // すでにコンテントリストを作り始めているので、処理は継続しない。
190                 Log.v(TAG, "ALREADY CREATING CONTENT LIST.");
191                 return;
192             }
193             contentListIsCreating = true;
194             informationReceiver.updateMessage(activity.getString(R.string.get_image_list), false, false, 0);
195             changeContentsTransferMode();  // コンテンツトランスファモードに切り替える
196
197             JSONObject storageInformationObj = cameraApi.getStorageInformation();
198             JSONObject schemeListObj = cameraApi.getSchemeList();
199             //JSONArray schemeArray = schemeListObj.getJSONArray("result");
200             JSONObject sourceObj = cameraApi.getSourceList("storage");
201             //JSONArray sourceArray = sourceObj.getJSONArray("result");
202             JSONObject countObject = cameraApi.getContentCountFlatAll("storage:memoryCard1");
203             JSONArray resultArray = countObject.getJSONArray("result");
204             int objectCount = resultArray.getJSONObject(0).getInt("count");
205             Log.v(TAG, "  OBJECT COUNT  : " + objectCount);
206             if (objectCount < 1) {
207                 // コンテンツ一覧の取得失敗...
208                 informationReceiver.updateMessage(activity.getString(R.string.content_is_nothing), true, false, 0);
209                 contentListIsCreating = false;
210                 return;
211             }
212             contentList.clear();
213
214             int index = 0;
215             // データを解析してリストを作る
216             while ((index >= 0) && (index < objectCount)) {
217                 informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + index + "/" + objectCount + " ", false, false, 0);
218
219                 int remainCount = objectCount - index;
220                 JSONObject paramsObj = new JSONObject();
221                 paramsObj.put("uri", "storage:memoryCard1");
222                 paramsObj.put("stIdx", index);
223                 paramsObj.put("cnt", (remainCount > 100 ? 100 : remainCount));      // 一括取得数...最大100
224                 //paramsObj.put("cnt", (remainCount > 50 ? 50 : remainCount)); // 一括取得数
225                 paramsObj.put("view", "flat");
226                 paramsObj.put("sort", "descending");
227                 try {
228                     JSONObject responseObject = cameraApi.getContentList(new JSONArray().put(paramsObj));
229                     JSONArray resultsArray = responseObject.getJSONArray("result").getJSONArray(0);
230                     int nofContents = resultsArray.length();
231                     for (int pos = 0; pos < nofContents; pos++) {
232                         //  ひろったデータを全部入れていく
233                         SonyImageContentInfo contentInfo = new SonyImageContentInfo(resultsArray.getJSONObject(pos));
234                         String contentName = contentInfo.getContentName();
235                         //Date createdTime = contentInfo.getCapturedDate();
236                         //String folderNo = contentInfo.getContentPath();
237                         if (contentName.length() > 0) {
238                             contentList.put(contentName, contentInfo);
239                         }
240                         //Log.v(TAG, " [" + pos + "] " + "  " + contentName + " " + " " + createdTime + " " + folderNo);
241                     }
242                     index = index + nofContents;
243                     //Log.v(TAG, "  COUNT : " + index);
244                 } catch (Exception e) {
245                     e.printStackTrace();
246                     break;
247                 }
248             }
249             contentListIsCreating = false;
250             informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + index + "/" + objectCount + " ", false, false, 0);
251             if (callback != null) {
252                 // コレクションを詰めなおして応答する
253                 callback.onCompleted(new ArrayList<ICameraContent>(contentList.values()));
254             }
255         } catch (Exception e) {
256             e.printStackTrace();
257         }
258         contentListIsCreating = false;
259     }
260
261     private void changeContentsTransferMode() {
262         try {
263             if (cameraApi == null) {
264                 return;
265             }
266             boolean isAvailable = false;
267             int maxRetryCount = 10;    // 最大リトライ回数
268             while ((!isAvailable) && (maxRetryCount > 0)) {
269                 isAvailable = setCameraFunction(false);
270                 maxRetryCount--;
271             }
272             if (maxRetryCount <= 0) {
273                 // Retry over
274                 informationReceiver.updateMessage(activity.getString(R.string.change_transfer_mode_retry_over), true, true, Color.RED);
275
276                 // 試しに呼んでみる。
277                 getContentDirectorySoapAction();
278             }
279
280         } catch (Exception e) {
281             e.printStackTrace();
282         }
283     }
284
285     private boolean setCameraFunction(boolean isRecording) {
286         try {
287             JSONObject reply = cameraApi.setCameraFunction((isRecording) ? "Remote Shooting" : "Contents Transfer");
288             try {
289                 int value = reply.getInt("result");
290                 Log.v(TAG, "CHANGE RUN MODE : " + value);
291                 return (true);
292             } catch (Exception ee) {
293                 ee.printStackTrace();
294                 informationReceiver.updateMessage(activity.getString(R.string.change_transfer_mode_retry), false, false, 0);
295                 Thread.sleep(500); //  500ms 待つ
296             }
297         } catch (Exception e) {
298             e.printStackTrace();
299         }
300         return (false);
301     }
302
303     private void getContentDirectorySoapAction()
304     {
305
306         ////////////  ある程度の数に区切って送られてくる... 何度か繰り返す必要があるようだ  ////////////
307         int sequenceNumber = 0;
308         int totalCount = 100000;
309         int returnedCount = 0;
310         while (totalCount > returnedCount)
311         {
312             Log.v(TAG, "  ===== getContentList() " + sequenceNumber + " =====");
313             sequenceNumber++;
314             String accessUrl = cameraApi.getDdUrl();
315             String url =  accessUrl.substring(0, accessUrl.lastIndexOf("/")) + "/upnp/control/ContentDirectory";
316
317             String postData = "<?xml version=\"1.0\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
318                     "<s:Body><u:Browse xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:" + sequenceNumber + "\">" +
319                     //"<ObjectID>0</ObjectID>" +
320                     "<ObjectID>03_01_0002002552_000002_000000_000000</ObjectID>" +
321                     "<BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter>*</Filter>" +
322                     "<StartingIndex>" + returnedCount + "</StartingIndex>" +
323                     //"<RequestedCount>3500</RequestedCount>" +
324                     "<RequestedCount>1</RequestedCount>" +
325                     //"<SortCriteria>" + "-dc:flat" +  "</SortCriteria>" +
326                     "<SortCriteria>" + "-dc:date" +  "</SortCriteria>" +
327                     "</u:Browse></s:Body></s:Envelope>";
328 /*
329             String postData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>" +
330                     "<u:Browse xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:" + sequenceNumber + "\" xmlns:pana=\"urn:schemas-panasonic-com:pana\">" +
331                     "<ObjectID>0</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter>*</Filter><StartingIndex>" + returnedCount + "</StartingIndex><RequestedCount>3500</RequestedCount><SortCriteria></SortCriteria>" +
332                     "<pana:X_FromCP>LumixLink2.0</pana:X_FromCP></u:Browse></s:Body></s:Envelope>";
333 */
334             String reply = SimpleHttpClient.httpPostWithHeader(url, postData, "SOAPACTION", "urn:schemas-upnp-org:service:ContentDirectory:" + sequenceNumber + "#Browse", "text/xml; charset=\"utf-8\"", timeoutMs);
335             if (reply.length() < 10)
336             {
337                 Log.v(TAG, postData);
338                 Log.v(TAG, "ContentDirectory is FAILURE. [" + sequenceNumber + "]");
339                 //break;
340             }
341             Log.v(TAG, " < REPLY > " + reply);
342 /*
343             getObjectLists = getObjectLists.append(reply);
344             String matches = reply.substring(reply.indexOf("<TotalMatches>") + 14, reply.indexOf("</TotalMatches>"));
345             try
346             {
347                 totalCount = Integer.parseInt(matches);
348             }
349             catch (Exception e)
350             {
351                 e.printStackTrace();
352                 totalCount = 0;
353             }
354
355             String returned = reply.substring(reply.indexOf("<NumberReturned>") + 16, reply.indexOf("</NumberReturned>"));
356             try
357             {
358                 returnedCount = returnedCount + Integer.parseInt(returned);
359             }
360             catch (Exception e)
361             {
362                 e.printStackTrace();
363             }
364             Log.v(TAG, "  REPLY DATA : (" + matches + "/" + totalCount + ") [" + returned + "/" + returnedCount + "] " + " " + reply.length() + "bytes");
365             informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + returnedCount + "/" + totalCount + " ", false, false, 0);
366 */
367         }
368     }
369 }