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