OSDN Git Service

カメラのモード切替結果取得ができていなかったのを修正する。
[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 import java.util.List;
33 import java.util.Map;
34
35 public class SonyPlaybackControl implements IPlaybackControl
36 {
37     private final String TAG = toString();
38     private final Activity activity;
39     private final IInformationReceiver informationReceiver;
40     private ISonyCameraApi cameraApi = null;
41     private HashMap<String, SonyImageContentInfo> contentList;
42     private int timeoutMs = 55000;
43     private boolean contentListIsCreating = false;
44
45     public SonyPlaybackControl(@NonNull Activity activity, @NonNull IInformationReceiver informationReceiver)
46     {
47         Log.v(TAG, "SonyPlaybackControl()");
48         this.activity = activity;
49         this.informationReceiver = informationReceiver;
50         contentList = new HashMap<>();
51     }
52
53     public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi) {
54         cameraApi = sonyCameraApi;
55     }
56
57     @Override
58     public String getRawFileSuffix() {
59         return "ARW";
60     }
61
62     @Override
63     public void downloadContentList(IDownloadContentListCallback callback)
64     {
65         Log.v(TAG, "downloadContentList()");
66
67     }
68
69     @Override
70     public void getContentInfo(String path, String name, IContentInfoCallback callback)
71     {
72         Log.v(TAG, "getContentInfo()");
73     }
74
75     @Override
76     public void updateCameraFileInfo(ICameraFileInfo info) {
77         Log.v(TAG, "updateCameraFileInfo()");
78     }
79
80     @Override
81     public void downloadContentScreennail(String path, IDownloadThumbnailImageCallback callback)
82     {
83         //Log.v(TAG, "downloadContentScreennail()" + path);
84         try
85         {
86             SonyImageContentInfo content = contentList.get(path.substring(path.indexOf('/') + 1));
87             if (content == null)
88             {
89                 Log.v(TAG, " CONTENT IS NULL... : " + path);
90                 return;
91             }
92             try
93             {
94                 String url = content.getSmallUrl();   // Screennail は VGAサイズ
95                 if (url.length() < 1)
96                 {
97                     url = content.getThumbnailUrl();  // VGAサイズが取れなかった場合はサムネイルサイズ
98                 }
99                 if (url.length() > 1)
100                 {
101                     Bitmap bmp = SimpleHttpClient.httpGetBitmap(url, timeoutMs);
102                     HashMap<String, Object> map = new HashMap<>();
103                     map.put("Orientation", 0);
104                     callback.onCompleted(bmp, map);
105                 }
106             }
107             catch (Throwable e)
108             {
109                 e.printStackTrace();
110                 callback.onErrorOccurred(new NullPointerException());
111             }
112         }
113         catch (Exception e)
114         {
115             e.printStackTrace();
116         }
117     }
118
119     @Override
120     public void downloadContentThumbnail(String path, IDownloadThumbnailImageCallback callback)
121     {
122         //Log.v(TAG, "downloadContentThumbnail() : " + path);
123         try
124         {
125             SonyImageContentInfo content = contentList.get(path.substring(path.indexOf('/') + 1));
126             if (content == null)
127             {
128                 Log.v(TAG, " CONTENT IS NULL... : " + path);
129                 return;
130             }
131             try
132             {
133                 String url = content.getThumbnailUrl();
134                 if (url.length() > 1)
135                 {
136                     Bitmap bmp = SimpleHttpClient.httpGetBitmap(url, timeoutMs);
137                     HashMap<String, Object> map = new HashMap<>();
138                     map.put("Orientation", 0);
139                     callback.onCompleted(bmp, map);
140                 }
141             }
142             catch (Throwable e)
143             {
144                 e.printStackTrace();
145                 callback.onErrorOccurred(new NullPointerException());
146             }
147         }
148         catch (Exception e)
149         {
150             e.printStackTrace();
151         }
152     }
153
154     @Override
155     public void downloadContent(String path, boolean isSmallSize, final IDownloadContentCallback callback)
156     {
157         //Log.v(TAG, "downloadContent() : " + path);
158         try
159         {
160             SonyImageContentInfo content = contentList.get(path.substring(path.indexOf('/') + 1));
161             if (content == null)
162             {
163                 Log.v(TAG, " CONTENT IS NULL... : " + path);
164                 return;
165             }
166             try
167             {
168                 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
169                 boolean isVgaSize = preferences.getBoolean(IPreferencePropertyAccessor.GET_SMALL_PICTURE_AS_VGA, false);
170                 String url = (isSmallSize) ? ((isVgaSize) ? content.getSmallUrl() : content.getLargeUrl()) : content.getOriginalUrl();
171                 if (url.length() < 1)
172                 {
173                     url = content.getOriginalUrl();
174                     if (url.length() < 1)
175                     {
176                         //  全然だめなら、サムネイルサイズ...
177                         url = content.getThumbnailUrl();
178                     }
179                 }
180                 Log.v(TAG, "downloadContent()  PATH : " + path + "  [SMALL:" + isSmallSize + "][VGA:" + isVgaSize + "]" + " GET URL : " + url);
181
182                 SimpleHttpClient.httpGetBytes(url, timeoutMs, new SimpleHttpClient.IReceivedMessageCallback()
183                 {
184                     @Override
185                     public void onCompleted() {
186                         callback.onCompleted();
187                     }
188
189                     @Override
190                     public void onErrorOccurred(Exception e) {
191                         callback.onErrorOccurred(e);
192                     }
193
194                     @Override
195                     public void onReceive(int readBytes, int length, int size, byte[] data) {
196                         float percent = (length == 0) ? 0.0f : ((float) readBytes / (float) length);
197                         //Log.v(TAG, " onReceive : " + readBytes + " " + length + " " + size);
198                         ProgressEvent event = new ProgressEvent(percent, null);
199                         callback.onProgress(data, size, event);
200                     }
201                 });
202             }
203             catch (Throwable e)
204             {
205                 e.printStackTrace();
206                 callback.onErrorOccurred(new NullPointerException());
207             }
208         }
209         catch (Exception e)
210         {
211             e.printStackTrace();
212         }
213     }
214
215     @Override
216     public void getCameraContentList(ICameraContentListCallback callback)
217     {
218         Log.v(TAG, "getCameraContentList()");
219         try
220         {
221             if (cameraApi == null)
222             {
223                 Log.v(TAG, "CAMERA API is NULL.");
224                 return;
225             }
226             if (contentListIsCreating)
227             {
228                 // すでにコンテントリストを作り始めているので、処理は継続しない。
229                 Log.v(TAG, "ALREADY CREATING CONTENT LIST.");
230                 return;
231             }
232             contentListIsCreating = true;
233
234             // 画像転送に「スマートフォン転送機能」を使う場合...
235             SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
236             boolean useSmartphoneTransfer = preferences.getBoolean(IPreferencePropertyAccessor.USE_SMARTPHONE_TRANSFER_MODE, false);
237             if (useSmartphoneTransfer)
238             {
239                 // DLNAを使用したコンテンツ特定モードを使う
240                 try
241                 {
242                     getContentDirectorySoapAction();
243                 }
244                 catch (Exception ee)
245                 {
246                     ee.printStackTrace();
247                 }
248                 contentListIsCreating = false;
249
250                 // 解析終了を報告する
251                 informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " +  contentList.size() + "/" + contentList.size() + " ", false, false, 0);
252                 if (callback != null)
253                 {
254                     // コレクションを詰めなおして応答する
255                     callback.onCompleted(new ArrayList<ICameraContent>(contentList.values()));
256                 }
257                 return;
258             }
259
260             informationReceiver.updateMessage(activity.getString(R.string.get_image_list), false, false, 0);
261             boolean ret = changeContentsTransferMode();  // コンテンツトランスファモードに切り替える
262             if (!ret)
263             {
264                 informationReceiver.updateMessage(activity.getString(R.string.change_transfer_mode_failure), true, true, Color.RED);
265                 contentListIsCreating = false;
266                 return;
267             }
268
269             JSONObject storageInformationObj = cameraApi.getStorageInformation();
270             JSONObject schemeListObj = cameraApi.getSchemeList();
271             //JSONArray schemeArray = schemeListObj.getJSONArray("result");
272             JSONObject sourceObj = cameraApi.getSourceList("storage");
273             //JSONArray sourceArray = sourceObj.getJSONArray("result");
274             JSONObject countObject = cameraApi.getContentCountFlatAll("storage:memoryCard1");
275             JSONArray resultArray = countObject.getJSONArray("result");
276             int objectCount = resultArray.getJSONObject(0).getInt("count");
277             Log.v(TAG, "  OBJECT COUNT  : " + objectCount);
278             if (objectCount < 1)
279             {
280                 // コンテンツ一覧の取得失敗...
281                 informationReceiver.updateMessage(activity.getString(R.string.content_is_nothing), true, false, 0);
282                 contentListIsCreating = false;
283                 return;
284             }
285             contentList.clear();
286
287             int index = 0;
288             // データを解析してリストを作る
289             while ((index >= 0) && (index < objectCount))
290             {
291                 informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + index + "/" + objectCount + " ", false, false, 0);
292
293                 int remainCount = objectCount - index;
294                 JSONObject paramsObj = new JSONObject();
295                 paramsObj.put("uri", "storage:memoryCard1");
296                 paramsObj.put("stIdx", index);
297                 paramsObj.put("cnt", (remainCount > 100 ? 100 : remainCount));      // 一括取得数...最大100
298                 //paramsObj.put("cnt", (remainCount > 50 ? 50 : remainCount)); // 一括取得数
299                 paramsObj.put("view", "flat");
300                 paramsObj.put("sort", "descending");
301                 try
302                 {
303                     JSONObject responseObject = cameraApi.getContentList(new JSONArray().put(paramsObj));
304                     JSONArray resultsArray = responseObject.getJSONArray("result").getJSONArray(0);
305                     int nofContents = resultsArray.length();
306                     for (int pos = 0; pos < nofContents; pos++)
307                     {
308                         //  ひろったデータを全部入れていく
309                         SonyImageContentInfo contentInfo = new SonyImageContentInfo(resultsArray.getJSONObject(pos), null);
310                         String contentName = contentInfo.getContentName();
311                         //Date createdTime = contentInfo.getCapturedDate();
312                         //String folderNo = contentInfo.getContentPath();
313                         if (contentName.length() > 0)
314                         {
315                             contentList.put(contentName, contentInfo);
316                         }
317                         //Log.v(TAG, " [" + pos + "] " + "  " + contentName + " " + " " + createdTime + " " + folderNo);
318                     }
319                     index = index + nofContents;
320                     //Log.v(TAG, "  COUNT : " + index);
321                 }
322                 catch (Exception e)
323                 {
324                     e.printStackTrace();
325                     break;
326                 }
327             }
328             contentListIsCreating = false;
329             informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + index + "/" + objectCount + " ", false, false, 0);
330             if (callback != null)
331             {
332                 // コレクションを詰めなおして応答する
333                 callback.onCompleted(new ArrayList<ICameraContent>(contentList.values()));
334             }
335         }
336         catch (Exception e)
337         {
338             e.printStackTrace();
339         }
340         contentListIsCreating = false;
341     }
342
343     private boolean changeContentsTransferMode()
344     {
345         try
346         {
347             if (cameraApi == null)
348             {
349                 return (false);
350             }
351
352             boolean isAvailable = false;
353             int maxRetryCount = 10;    // 最大リトライ回数
354             while ((!isAvailable) && (maxRetryCount > 0))
355             {
356                 isAvailable = setCameraFunction(false);
357                 maxRetryCount--;
358             }
359             if (maxRetryCount <= 0)
360             {
361                 // Retry over
362                 informationReceiver.updateMessage(activity.getString(R.string.change_transfer_mode_retry_over), true, true, Color.RED);
363
364                 // QX10のコマンドを有効化する。
365                 QX10actEnableMethods actEnableMethods = new QX10actEnableMethods(cameraApi);
366                 boolean ret = actEnableMethods.actEnableMethods();
367                 if (!ret)
368                 {
369                     // actEnableMethods がうまく動かなかった場合... ここで処理を止める
370                     getContentDirectorySoapAction();   //  ← やっても動かないはず
371                     return (false);
372                 }
373
374                 //  DLNAで画像取得に入る...。
375                 informationReceiver.updateMessage(activity.getString(R.string.image_checking), false, false, Color.BLACK);
376                 getContentDirectorySoapAction();
377                 return (false);
378             }
379         }
380         catch (Exception e)
381         {
382             e.printStackTrace();
383         }
384         return (true);
385     }
386
387     private boolean setCameraFunction(boolean isRecording)
388     {
389         try
390         {
391             JSONObject reply = cameraApi.setCameraFunction((isRecording) ? "Remote Shooting" : "Contents Transfer");
392             try
393             {
394                 int value = reply.getJSONArray("result").getInt(0);
395                 Log.v(TAG, "CHANGE RUN MODE : " + value);
396                 return (true);
397             }
398             catch (Exception ee)
399             {
400                 ee.printStackTrace();
401                 informationReceiver.updateMessage(activity.getString(R.string.change_transfer_mode_retry), false, false, 0);
402                 Thread.sleep(500); //  500ms 待つ
403             }
404         }
405         catch (Exception e)
406         {
407             e.printStackTrace();
408         }
409         return (false);
410     }
411
412     /**
413      *   スマートフォン転送(DLNAを使用したコンテンツ一覧取得)時の一覧取得処理
414      *
415      */
416     private void getContentDirectorySoapAction()
417     {
418         try
419         {
420             String accessUrl = cameraApi.getDdUrl();
421             accessUrl = accessUrl.substring(0, accessUrl.lastIndexOf("/"));
422
423             //String reply = getSortCapabilities(accessUrl);
424             String reply = browseRootDirectory(accessUrl);
425             ContentDirectoryInfo directoryInfo = parseObjectId(parseResult(reply, true));
426
427             // PhotoRoot Directory
428             int returnedCount = 0;
429             int totalCount = directoryInfo.getCount();
430             List<ContentDirectoryInfo> dateFolderInfoList = new ArrayList<>();
431             while (returnedCount < totalCount)
432             {
433                 reply = browsePhotoSubRootDirectory(accessUrl, directoryInfo.getObjectId(), returnedCount);
434                 List<ContentDirectoryInfo> objectInfoList = parseObjectIds(parseResult(reply, true));
435                 returnedCount = objectInfoList.size();
436                 dateFolderInfoList.addAll(objectInfoList);
437             }
438
439             /////////////////  Date Directories  /////////////////
440             int totalObjectCount = 0;
441             List<ContentDirectoryInfo> folderInfoList = new ArrayList<>();
442             for (ContentDirectoryInfo  rootObjectInfo : dateFolderInfoList)
443             {
444                 int returnedFolderCount = 0;
445                 reply = browsePhotoSubRootDirectory(accessUrl, rootObjectInfo.getObjectId(), returnedFolderCount);
446                 List<ContentDirectoryInfo> folderList = parseObjectIds(parseResult(reply, true));
447                 folderInfoList.addAll(folderList);
448                 for (ContentDirectoryInfo  folderInfo : folderList)
449                 {
450                     totalObjectCount = totalObjectCount + folderInfo.getCount();
451                 }
452             }
453
454             ///////////////// GET CONTENTS /////////////////
455             contentList.clear();
456             int objectCount = 0;
457             informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + contentList.size() + "/" + totalObjectCount + " ", false, false, 0);
458             Log.v(TAG, " TOTAL OBJECT COUNT : " + contentList.size() + "/" + totalObjectCount);
459             for (ContentDirectoryInfo  dateFolderInfo : folderInfoList)
460             {
461                 objectCount = objectCount + getObjects(accessUrl, dateFolderInfo, totalObjectCount);
462             }
463         }
464         catch (Exception e)
465         {
466             e.printStackTrace();
467         }
468     }
469
470     private int getObjects(String accessUrl, ContentDirectoryInfo  dateFolderInfo, int totalObjectCount)
471     {
472         int currentCount = 0;
473         while (currentCount < dateFolderInfo.getCount())
474         {
475             String reply = browsePhotoSubRootDirectory(accessUrl, dateFolderInfo.getObjectId(), currentCount);
476             currentCount = currentCount + parseContentObject(parseResult(reply, false));
477
478             informationReceiver.updateMessage(activity.getString(R.string.get_image_list) + " " + contentList.size() + "/" + totalObjectCount + " ", false, false, 0);
479             Log.v(TAG, " TOTAL OBJECT COUNT : " + contentList.size() + "/" + totalObjectCount);
480         }
481         return (currentCount);
482     }
483
484     private String getSortCapabilities(String accessUrl)
485     {
486         String url =   accessUrl + "/upnp/control/ContentDirectory";
487         String postData = "<?xml version=\"1.0\"?>" +
488                 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
489                 "<s:Body>" +
490                 "<u:GetSortCapabilities xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:1\">" +
491                 "</u:GetSortCapabilities>" +
492                 "</s:Body>" +
493                 "</s:Envelope>\r\n\r\n";
494         Map<String, String> header = new HashMap<>();
495         header.clear();
496         header.put("SOAPACTION", "\"urn:schemas-upnp-org:service:ContentDirectory:1" + "#GetSortCapabilities\"");
497         return (SimpleHttpClient.httpPostWithHeader(url, postData, header, "text/xml; charset=\"utf-8\"", timeoutMs));
498     }
499
500     private String browseRootDirectory(String accessUrl)
501     {
502         String url =   accessUrl + "/upnp/control/ContentDirectory";
503         String postData = "<?xml version=\"1.0\"?>" +
504                 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
505                 "<s:Body>" +
506                 "<u:Browse xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:1\">" +
507                 "<ObjectID>0</ObjectID>" +
508                 "<BrowseFlag>BrowseDirectChildren</BrowseFlag>" +
509                 "<Filter>*</Filter>" +
510                 "<StartingIndex>0</StartingIndex>" +
511                 "<RequestedCount>8000</RequestedCount>" +
512                 "<SortCriteria></SortCriteria>" +
513                 "</u:Browse>" +
514                 "</s:Body>" +
515                 "</s:Envelope>";
516
517         Map<String, String> header = new HashMap<>();
518         header.clear();
519         header.put("SOAPACTION", "\"urn:schemas-upnp-org:service:ContentDirectory:1" + "#Browse\"");
520         return (SimpleHttpClient.httpPostWithHeader(url, postData, header, "text/xml; charset=\"utf-8\"", timeoutMs));
521     }
522
523     private List<ContentDirectoryInfo> parseObjectIds(String targetString)
524     {
525         try
526         {
527             List<ContentDirectoryInfo> objectIds = new ArrayList<>();
528             objectIds.clear();
529
530             int parsedIndex = 0;
531             int maxSize = targetString.length();
532             while (parsedIndex < maxSize)
533             {
534                 String checkString = targetString.substring(parsedIndex);
535                 int startIndex = checkString.toLowerCase().indexOf("<container ");
536                 if (startIndex < 0)
537                 {
538                     // containerタグが見つからない
539                     break;
540                 }
541                 int endIndex = checkString.indexOf(">", startIndex);
542                 if (startIndex > endIndex)
543                 {
544                     // タグの末尾が見つからない
545                     //Log.v(TAG, " NOT FOUND END CLAUSE TAG");
546                     break;
547                 }
548                 ContentDirectoryInfo objectInfo = parseObjectId(checkString.substring(startIndex, endIndex + 1));
549                 if (objectInfo.getObjectId().length() > 0)
550                 {
551                     objectIds.add(objectInfo);
552                 }
553                 parsedIndex = parsedIndex + endIndex;
554             }
555             return (objectIds);
556         }
557         catch (Exception e)
558         {
559             e.printStackTrace();
560         }
561         return (new ArrayList<>());
562     }
563
564     private ContentDirectoryInfo parseObjectId(String targetString)
565     {
566         String objectId = "";
567         String childCount = "0";
568         int count = 0;
569         try
570         {
571             int startIndex = targetString.toLowerCase().indexOf("<container ");
572             if (startIndex < 0)
573             {
574                 // パース失敗
575                 return (new ContentDirectoryInfo("", 0));
576             }
577             int endIndex = targetString.indexOf(">", startIndex);
578             String containerString = targetString.substring(startIndex + 11, endIndex - 1);
579             String[] attrList = containerString.split(" ");
580             for (String attribute : attrList)
581             {
582                 if (attribute.indexOf("id=") == 0)
583                 {
584                     objectId = attribute.substring(3).replaceAll("\"","");
585                 }
586                 else if (attribute.toLowerCase().indexOf("childcount=") == 0)
587                 {
588                     childCount = attribute.substring(12).replaceAll("\"","");
589                 }
590             }
591             count = Integer.parseInt(childCount);
592         }
593         catch (Exception e)
594         {
595             e.printStackTrace();
596         }
597         Log.v(TAG, "  OBJECT ID : " + objectId + "  COUNT : " + childCount);
598         return (new ContentDirectoryInfo(objectId, count));
599     }
600
601     private String browsePhotoSubRootDirectory(String accessUrl, String objectId, int startIndex)
602     {
603         String url =   accessUrl + "/upnp/control/ContentDirectory";
604         String postData = "<?xml version=\"1.0\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>" +
605                 "<u:Browse xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:1\">" +
606                 "<ObjectID>" + objectId + "</ObjectID>" +
607                 "<BrowseFlag>BrowseDirectChildren</BrowseFlag>" +
608                 "<Filter>*</Filter>" +
609                 "<StartingIndex>" + startIndex + "</StartingIndex>" +
610                 "<RequestedCount>80000</RequestedCount>" +
611                 "<SortCriteria></SortCriteria>" +
612                 "</u:Browse></s:Body></s:Envelope>";
613
614         Map<String, String> header = new HashMap<>();
615         header.clear();
616         header.put("SOAPACTION", "\"urn:schemas-upnp-org:service:ContentDirectory:1" + "#Browse\"");
617         return (SimpleHttpClient.httpPostWithHeader(url, postData, header, "text/xml; charset=\"utf-8\"", timeoutMs));
618     }
619
620     private int parseContentObject(String receivedData)
621     {
622         int entryCount = 0;
623         int startIndex = 0;
624         int endLength = receivedData.length();
625         try
626         {
627             //  <item> ~ </item> を切り出して保管する
628             while (startIndex < endLength)
629             {
630                 int index = receivedData.indexOf("<item", startIndex);
631                 if (index < 0)
632                 {
633                     // もうコンテントがない
634                     break;
635                 }
636                 int endIndex = receivedData.indexOf("</item>", index);
637                 if (endIndex < 0)
638                 {
639                     endIndex = endLength;
640                 }
641                 String itemString = receivedData.substring(index, endIndex + 7);
642                 SonyImageContentInfo contentInfo = new SonyImageContentInfo(null, itemString);
643                 String contentName = contentInfo.getContentName();
644                 if (contentName.length() > 0)
645                 {
646                     contentList.put(contentName, contentInfo);
647                     entryCount++;
648                 }
649                 startIndex = endIndex;
650             }
651         }
652         catch (Exception e)
653         {
654             e.printStackTrace();
655         }
656         return (entryCount);
657     }
658
659     private String parseResult(String reply, boolean isResultSubstring)
660     {
661         String decordReply = reply;
662         try
663         {
664             int startIndex = reply.indexOf("<Result>");
665             int endIndex = reply.indexOf("</Result>");
666             if ((isResultSubstring)&&(startIndex < endIndex) && (startIndex > 0))
667             {
668                 decordReply = reply.substring((startIndex + 8), endIndex); // = URLDecoder.decode(reply.substring((startIndex + 8), endIndex), "UTF-8");
669             }
670             decordReply = decordReply.replaceAll("&lt;", "<");
671             decordReply = decordReply.replaceAll("&gt;", ">");
672             decordReply = decordReply.replaceAll("&quot;", "\"");
673         }
674         catch (Exception e)
675         {
676             e.printStackTrace();
677         }
678         return (decordReply);
679     }
680 }