OSDN Git Service

FUJIカメラに接続したときの一括ダウンロードが動かなかったのを修正する。
[gokigen/Gr2Control.git] / app / src / main / java / net / osdn / gokigen / gr2control / playback / ImageGridViewFragment.java
1 package net.osdn.gokigen.gr2control.playback;
2
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Locale;
10 import java.util.Map;
11 import java.util.concurrent.ExecutorService;
12 import java.util.concurrent.Executors;
13
14 import android.app.Activity;
15 import android.app.AlertDialog;
16 import android.content.Context;
17 import android.content.SharedPreferences;
18 import android.graphics.Bitmap;
19 import android.preference.PreferenceManager;
20 import android.os.Bundle;
21 import android.util.Log;
22 import android.util.LruCache;
23 import android.view.LayoutInflater;
24 import android.view.Menu;
25 import android.view.MenuInflater;
26 import android.view.MenuItem;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.AbsListView;
30 import android.widget.AdapterView;
31 import android.widget.BaseAdapter;
32 import android.widget.GridView;
33 import android.widget.ImageView;
34 import android.widget.ProgressBar;
35
36
37 import net.osdn.gokigen.gr2control.R;
38 import net.osdn.gokigen.gr2control.camera.ICameraFileInfo;
39 import net.osdn.gokigen.gr2control.camera.ICameraRunMode;
40 import net.osdn.gokigen.gr2control.camera.ICameraRunModeCallback;
41 import net.osdn.gokigen.gr2control.camera.playback.ICameraContentListCallback;
42 import net.osdn.gokigen.gr2control.camera.playback.IDownloadThumbnailImageCallback;
43 import net.osdn.gokigen.gr2control.camera.playback.IPlaybackControl;
44 import net.osdn.gokigen.gr2control.playback.detail.ImageContentInfoEx;
45 import net.osdn.gokigen.gr2control.playback.detail.ImagePagerViewFragment;
46 import net.osdn.gokigen.gr2control.playback.detail.MyContentDownloader;
47 import net.osdn.gokigen.gr2control.preference.IPreferencePropertyAccessor;
48
49 import androidx.annotation.NonNull;
50 import androidx.appcompat.app.ActionBar;
51 import androidx.appcompat.app.AppCompatActivity;
52 import androidx.fragment.app.Fragment;
53 import androidx.fragment.app.FragmentActivity;
54 import androidx.fragment.app.FragmentTransaction;
55
56 public class ImageGridViewFragment extends Fragment implements ICameraRunModeCallback
57 {
58         private final String TAG = this.toString();
59     private final String MOVIE_SUFFIX = ".mov";
60     private final String JPEG_SUFFIX = ".jpg";
61     private final String DNG_RAW_SUFFIX = ".dng";
62         private final String OLYMPUS_RAW_SUFFIX = ".orf";
63         private final String PENTAX_RAW_PEF_SUFFIX = ".pef";
64
65         private MyContentDownloader contentDownloader;
66     private GridView gridView;
67         private boolean gridViewIsScrolling;
68         private IPlaybackControl playbackControl;
69         private ICameraRunMode runMode;
70                 
71     private List<ImageContentInfoEx> contentList;
72         private ExecutorService executor;
73         private LruCache<String, Bitmap> imageCache;
74
75         public static ImageGridViewFragment newInstance(@NonNull IPlaybackControl playbackControl, @NonNull ICameraRunMode runMode)
76         {
77                 ImageGridViewFragment fragment = new ImageGridViewFragment();
78                 fragment.setControllers(playbackControl, runMode);
79                 return (fragment);
80         }
81
82         private void setControllers(IPlaybackControl playbackControl, ICameraRunMode runMode)
83         {
84                 this.playbackControl = playbackControl;
85                 this.runMode = runMode;
86                 Activity activity = getActivity();
87                 if (activity != null)
88                 {
89             this.contentDownloader = new MyContentDownloader(getActivity(), playbackControl);
90         }
91         else
92         {
93             this.contentDownloader = null;
94         }
95         }
96
97         @Override
98         public void onCreate(Bundle savedInstanceState)
99         {
100                 super.onCreate(savedInstanceState);
101         Log.v(TAG, "ImageGridViewFragment::onCreate()");
102
103                 executor = Executors.newFixedThreadPool(1);
104                 imageCache = new LruCache<>(160);
105                 setHasOptionsMenu(true);
106         }
107         
108         @Override
109         public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
110         {
111                 Log.v(TAG, "ImageGridViewFragment::onCreateView()");
112                 View view = inflater.inflate(R.layout.fragment_image_grid_view, container, false);
113                 
114                 gridView = view.findViewById(R.id.gridView1);
115                 gridView.setAdapter(new GridViewAdapter(inflater));
116         GridViewOnItemClickListener listener = new GridViewOnItemClickListener();
117                 gridView.setOnItemClickListener(listener);
118         gridView.setOnItemLongClickListener(listener);
119                 gridView.setOnScrollListener(new GridViewOnScrollListener());
120                 
121                 return (view);
122         }
123         
124         @Override
125         public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater)
126         {
127                 inflater.inflate(R.menu.image_grid_view, menu);
128                 String title = getString(R.string.app_name);
129                 AppCompatActivity activity = (AppCompatActivity) getActivity();
130                 if (activity != null)
131                 {
132             ActionBar bar = activity.getSupportActionBar();
133             if (bar != null)
134             {
135                 bar.setTitle(title);
136             }
137         }
138         }
139         
140         @Override
141         public boolean onOptionsItemSelected(MenuItem item)
142         {
143             int id = item.getItemId();
144                 if (id == R.id.action_refresh)
145                 {
146                         refresh();
147                         return (true);
148                 }
149         if (id == R.id.action_batch_download_original_size_raw)
150         {
151             // オリジナルサイズのダウンロード
152             startDownloadBatch(false);
153             return (true);
154         }
155         if (id == R.id.action_batch_download_640x480_raw)
156         {
157             // 小さいサイズのダウンロード
158             startDownloadBatch(true);
159             return (true);
160         }
161         if (id == R.id.action_select_all)
162         {
163             selectUnselectAll();
164             return (true);
165         }
166                 return (super.onOptionsItemSelected(item));
167         }
168
169         @Override
170         public void onResume()
171         {
172                 super.onResume();
173                 Log.v(TAG, "onResume() Start");
174                 AppCompatActivity activity = (AppCompatActivity)getActivity();
175                 if (activity != null)
176                 {
177             ActionBar bar = activity.getSupportActionBar();
178             if (bar != null)
179             {
180                 // アクションバーの表示をするかどうか
181                 boolean isShowActionBar = false;
182                 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
183                 if (preferences != null)
184                 {
185                     isShowActionBar = preferences.getBoolean(IPreferencePropertyAccessor.USE_PLAYBACK_MENU, true);
186                 }
187                 if (isShowActionBar)
188                 {
189                     bar.show();  // ActionBarの表示を出す
190                 }
191                 else
192                 {
193                     bar.hide();   // ActionBarの表示を消す
194                 }
195             }
196         }
197
198         try
199         {
200             refresh();
201         }
202         catch (Exception e)
203         {
204             e.printStackTrace();
205         }
206         Log.v(TAG, "onResume() End");
207         }
208         
209         @Override
210         public void onPause()
211         {
212         Log.v(TAG, "onPause() Start");
213         if (!runMode.isRecordingMode())
214         {
215             // Threadで呼んではダメみたいだ...
216             //runMode.changeRunMode(true, this);
217             super.onPause();
218             Log.v(TAG, "onPause() End");
219             return;
220         }
221         postProcessChangeRunMode(true);
222                 super.onPause();
223         Log.v(TAG, "onPause() End");
224     }
225
226     private void postProcessChangeRunMode(boolean isRecording)
227     {
228         try
229         {
230             if (isRecording)
231             {
232                 if (!executor.isShutdown())
233                 {
234                     executor.shutdownNow();
235                 }
236             }
237             else
238             {
239                 refresh();
240             }
241         }
242         catch (Exception e)
243         {
244             e.printStackTrace();
245         }
246     }
247
248     @Override
249     public void onCompleted(boolean isRecording)
250     {
251         postProcessChangeRunMode(isRecording);
252     }
253
254     @Override
255     public void onErrorOccurred(boolean isRecording)
256     {
257         postProcessChangeRunMode(isRecording);
258     }
259
260         @Override
261         public void onStop()
262         {
263                 Log.v(TAG, "onStop()");
264                 super.onStop();
265         }
266
267         private void refresh()
268     {
269         try
270         {
271             if (runMode.isRecordingMode())
272             {
273                 runMode.changeRunMode(false, this);
274                 return;
275             }
276         }
277         catch (Exception e)
278         {
279             e.printStackTrace();
280         }
281
282         Thread thread = new Thread(new Runnable() {
283             @Override
284             public void run() {
285                 refreshImpl();
286             }
287         });
288         try
289         {
290             runOnUiThread(new Runnable() {
291                 @Override
292                 public void run() {
293                     showHideProgressBar(true);
294                 }
295             });
296             thread.start();
297         }
298         catch (Exception e)
299         {
300             e.printStackTrace();
301         }
302     }
303
304     private void showHideProgressBar(final boolean isVisible)
305     {
306         Activity activity = getActivity();
307         if (activity != null)
308         {
309             ProgressBar bar = getActivity().findViewById(R.id.progress_bar);
310             if (bar != null)
311             {
312                 bar.setVisibility((isVisible) ? View.VISIBLE : View.GONE);
313                 bar.invalidate();
314             }
315         }
316     }
317
318         private void refreshImpl()
319         {
320                 contentList = null;
321                 Log.v(TAG, "refreshImpl() start");
322
323                 playbackControl.downloadContentList(new ICameraContentListCallback() {
324                         @Override
325                         public void onCompleted(List<ICameraFileInfo> list) {
326                                 // Sort contents in chronological order (or alphabetical order).
327                                 Collections.sort(list, new Comparator<ICameraFileInfo>() {
328                                         @Override
329                                         public int compare(ICameraFileInfo lhs, ICameraFileInfo rhs)
330                                         {
331                                                 long diff = rhs.getDatetime().getTime() - lhs.getDatetime().getTime();
332                                                 if (diff == 0)
333                         {
334                                                         diff = rhs.getFilename().compareTo(lhs.getFilename());
335                                                 }
336                                                 return (int)Math.min(Math.max(-1, diff), 1);
337                                         }
338                                 });
339
340                 List<ImageContentInfoEx> contentItems = new ArrayList<>();
341                 HashMap<String, ImageContentInfoEx> rawItems = new HashMap<>();
342                 for (ICameraFileInfo item : list)
343                 {
344                     String path = item.getFilename().toLowerCase(Locale.getDefault());
345                     if ((path.toLowerCase().endsWith(JPEG_SUFFIX))||(path.toLowerCase().endsWith(MOVIE_SUFFIX)))
346                     {
347                         contentItems.add(new ImageContentInfoEx(item, false, ""));
348                     }
349                     else if (path.toLowerCase().endsWith(DNG_RAW_SUFFIX))
350                     {
351                         //rawItems.put(path, new ImageContentInfoEx(item, true, DNG_RAW_SUFFIX));
352                         contentItems.add(new ImageContentInfoEx(item, true, DNG_RAW_SUFFIX));
353                     }
354                     else if (path.toLowerCase().endsWith(OLYMPUS_RAW_SUFFIX))
355                     {
356                         rawItems.put(path, new ImageContentInfoEx(item, true, OLYMPUS_RAW_SUFFIX));
357                     }
358                     else if (path.toLowerCase().endsWith(PENTAX_RAW_PEF_SUFFIX))
359                     {
360                         //rawItems.put(path, new ImageContentInfoEx(item, true, PENTAX_RAW_PEF_SUFFIX));
361                         contentItems.add(new ImageContentInfoEx(item, true, PENTAX_RAW_PEF_SUFFIX));
362                     }
363                 }
364
365                 //List<ImageContentInfoEx> appendRawContents = new ArrayList<>();
366                 for (ImageContentInfoEx item : contentItems)
367                 {
368                     String path = item.getFileInfo().getFilename().toLowerCase(Locale.getDefault());
369                     if (path.toLowerCase().endsWith(JPEG_SUFFIX))
370                     {
371 /*
372                         String target1 = path.replace(JPEG_SUFFIX, DNG_RAW_SUFFIX);
373                         ImageContentInfoEx raw1 = rawItems.get(target1);
374                         if (raw1 != null)
375                         {
376                                 // JPEGファイルとRAWファイルがあるので、それをマークする
377                             item.setHasRaw(true, DNG_RAW_SUFFIX);
378                             Log.v(TAG, "DETECT RAW FILE: " + target1);
379                         }
380                         else
381                         {
382                             // RAWだけあった場合、一覧に追加する
383                             appendRawContents.add(rawItems.get(path));
384                         }
385 */
386                         String target2 = path.replace(JPEG_SUFFIX, OLYMPUS_RAW_SUFFIX);
387                         ImageContentInfoEx raw2 = rawItems.get(target2);
388                         if (raw2 != null)
389                         {
390                             // RAW は、JPEGファイルがあった場合にのみリストする
391                             item.setHasRaw(true, OLYMPUS_RAW_SUFFIX);
392                             Log.v(TAG, "DETECT RAW FILE: " + target2);
393                         }
394 /*
395                         String target3 = path.replace(JPEG_SUFFIX, PENTAX_RAW_PEF_SUFFIX);
396                         ImageContentInfoEx raw3 = rawItems.get(target3);
397                         if (raw3 != null)
398                         {
399                             // RAW は、JPEGファイルがあった場合にのみリストする
400                             item.setHasRaw(true, PENTAX_RAW_PEF_SUFFIX);
401                             Log.v(TAG, "DETECT RAW FILE: " + target3);
402                         }
403                         else
404                         {
405                             // RAWだけあった場合、一覧に追加する
406                             appendRawContents.add(rawItems.get(path));
407                         }
408 */
409                     }
410                 }
411                 //contentItems.addAll(appendRawContents);
412                 contentList = contentItems;
413
414                                 runOnUiThread(new Runnable() {
415                                         @Override
416                                         public void run() {
417                         showHideProgressBar(false);
418                         gridView.invalidateViews();
419                                         }
420                                 });
421                         }
422                         
423                         @Override
424                         public void onErrorOccurred(Exception e) {
425                                 final String message = e.getMessage();
426                                 runOnUiThread(new Runnable() {
427                                         @Override
428                                         public void run() {
429                         showHideProgressBar(false);
430                                                 presentMessage("Load failed", message);
431                                         }
432                                 });
433                         }
434                 });
435         Log.v(TAG, "refreshImpl() end");
436     }
437
438     /**
439      *   全選択・全選択解除
440      *
441      */
442     private void selectUnselectAll()
443     {
444         if ((contentList == null)||(contentList.size() == 0))
445         {
446             // 選択されていない時は終わる。
447             return;
448         }
449
450         int nofSelected = 0;
451         for (ImageContentInfoEx content : contentList)
452         {
453             if (content.isSelected())
454             {
455                 nofSelected++;
456             }
457         }
458
459         // 全部選択されているときは全選択解除・そうでない時は全選択
460         boolean setSelected = (nofSelected != contentList.size());
461         for (ImageContentInfoEx content : contentList)
462         {
463             content.setSelected(setSelected);
464         }
465
466         // グリッドビューの再描画
467         redrawGridView();
468     }
469
470     private void redrawGridView()
471     {
472         // グリッドビューの再描画
473         Activity activity = getActivity();
474         if (activity != null)
475         {
476             getActivity().runOnUiThread(new Runnable()
477             {
478                 @Override
479                 public void run()
480                 {
481                     if (gridView != null)
482                     {
483                         gridView.invalidateViews();
484                     }
485                 }
486             });
487         }
488     }
489
490     /**
491      *    一括ダウンロードの開始
492      *
493      * @param isSmall  小さいサイズ(JPEG)
494      */
495     private void startDownloadBatch(final boolean isSmall)
496     {
497         try
498         {
499             // 念のため、contentDownloader がなければ作る
500             if (contentDownloader == null)
501             {
502                 Activity activity = getActivity();
503                 if (activity == null)
504                 {
505                     // activityが取れない時には終わる。
506                     return;
507                 }
508                 this.contentDownloader = new MyContentDownloader(getActivity(), playbackControl);
509             }
510             Thread thread = new Thread(new Runnable()
511             {
512                 @Override
513                 public void run()
514                 {
515                     try
516                     {
517                         // ダウンロード枚数を取得
518                         int totalSize = 0;
519                         for (ImageContentInfoEx content : contentList)
520                         {
521                             if (content.isSelected())
522                             {
523                                 totalSize++;
524                             }
525                         }
526                         if (totalSize == 0)
527                         {
528                             // 画像が選択されていなかった...終了する
529                             return;
530                         }
531                         int count = 1;
532                         for (ImageContentInfoEx content : contentList)
533                         {
534                             if (content.isSelected())
535                             {
536                                 contentDownloader.startDownload(content.getFileInfo(), " (" + count + "/" + totalSize + ") ", null, isSmall);
537                                 count++;
538
539                                 // 画像の選択を落とす
540                                 content.setSelected(false);
541
542                                 // ここでダウンロードが終わるまで、すこし待つ
543                                 do
544                                 {
545                                     try
546                                     {
547                                         Thread.sleep(300);
548                                     }
549                                     catch (Exception e)
550                                     {
551                                         e.printStackTrace();
552                                     }
553                                 } while (contentDownloader.isDownloading());
554                             }
555                         }
556
557                         // グリッドビューの再描画
558                         redrawGridView();
559                     }
560                     catch (Exception e)
561                     {
562                         e.printStackTrace();
563                     }
564                 }
565             });
566             thread.start();
567         }
568         catch (Exception e)
569         {
570             e.printStackTrace();
571         }
572     }
573
574
575     private static class GridCellViewHolder
576     {
577                 ImageView imageView;
578                 ImageView iconView;
579                 ImageView selectView;
580         }
581         
582         private class GridViewAdapter extends BaseAdapter
583     {
584                 private LayoutInflater inflater;
585
586                 GridViewAdapter(LayoutInflater inflater)
587                 {
588                         this.inflater = inflater;
589                 }
590
591                 private List<?> getItemList()
592         {
593             return (contentList);
594                 }
595                 
596                 @Override
597                 public int getCount()
598         {
599                         if (getItemList() == null)
600                         {
601                                 return (0);
602                         }
603                         return getItemList().size();
604                 }
605
606                 @Override
607                 public Object getItem(int position)
608         {
609                         if (getItemList() == null)
610                         {
611                                 return null;
612                         }
613                         return (getItemList().get(position));
614                 }
615
616                 @Override
617                 public long getItemId(int position)
618         {
619                         return (position);
620                 }
621
622                 @Override
623                 public View getView(int position, View convertView, ViewGroup parent)
624         {
625                         GridCellViewHolder viewHolder;
626                         if (convertView == null)
627                         {
628                                 convertView = inflater.inflate(R.layout.view_grid_cell, parent, false);
629                                 
630                                 viewHolder = new GridCellViewHolder();
631                                 viewHolder.imageView = convertView.findViewById(R.id.imageViewY);
632                                 viewHolder.iconView = convertView.findViewById(R.id.imageViewZ);
633                 viewHolder.selectView = convertView.findViewById(R.id.imageViewX);
634
635                 convertView.setTag(viewHolder);
636                         }
637             else
638             {
639                                 viewHolder = (GridCellViewHolder)convertView.getTag();
640                         }
641
642                         ImageContentInfoEx infoEx = (ImageContentInfoEx) getItem(position);
643             ICameraFileInfo item = (infoEx != null) ? infoEx.getFileInfo() : null;
644                         if (item == null)
645             {
646                 viewHolder.imageView.setImageResource(R.drawable.ic_satellite_grey_24dp);
647                                 viewHolder.iconView.setImageDrawable(null);
648                 viewHolder.selectView.setImageDrawable(null);
649                                 return convertView;
650                         }
651                         String path = new File(item.getDirectoryPath(), item.getFilename()).getPath();
652                         Bitmap thumbnail = imageCache.get(path);
653                         if (thumbnail == null)
654             {
655                 viewHolder.imageView.setImageResource(R.drawable.ic_satellite_grey_24dp);
656                                 viewHolder.iconView.setImageDrawable(null);
657                                 if (!gridViewIsScrolling)
658                 {
659                                         if (executor.isShutdown())
660                     {
661                                                 executor = Executors.newFixedThreadPool(1);
662                                         }
663                                         executor.execute(new ThumbnailLoader(viewHolder, path, infoEx.hasRaw()));
664                                 }
665                         }
666             else
667             {
668                                 viewHolder.imageView.setImageBitmap(thumbnail);
669                                 if (path.toLowerCase().endsWith(MOVIE_SUFFIX))
670                 {
671                                         viewHolder.iconView.setImageResource(R.drawable.ic_videocam_black_24dp);
672                                 }
673                 else if (infoEx.hasRaw())
674                 {
675                     viewHolder.iconView.setImageResource(R.drawable.ic_raw_black_1x);
676                 }
677                 else
678                 {
679                                         viewHolder.iconView.setImageDrawable(null);
680                                 }
681                         }
682                         if (infoEx.isSelected())
683             {
684                 viewHolder.selectView.setImageResource(R.drawable.ic_check_green_24dp);
685             }
686             else
687             {
688                 viewHolder.selectView.setImageDrawable(null);
689             }
690                         return convertView;
691                 }
692         }
693         
694         private class GridViewOnItemClickListener implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener
695     {
696                 @Override
697                 public void onItemClick(AdapterView<?> parent, View view, int position, long id)
698         {
699                 ImagePagerViewFragment fragment = ImagePagerViewFragment.newInstance(playbackControl, runMode, contentList, position);
700             FragmentActivity activity = getActivity();
701                 if (activity != null)
702                 {
703                 FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
704                 transaction.replace(getId(), fragment);
705                 transaction.addToBackStack(null);
706                 transaction.commit();
707             }
708                 }
709
710         @Override
711         public boolean onItemLongClick(final AdapterView<?> parent, View view, int position, long id)
712         {
713             try
714             {
715                 if (contentList == null)
716                 {
717                     return (false);
718                 }
719                 ImageContentInfoEx infoEx = contentList.get(position);
720                 if (infoEx != null)
721                 {
722                     boolean isChecked = infoEx.isSelected();
723                     infoEx.setSelected(!isChecked);
724                 }
725                 view.invalidate();
726                 runOnUiThread(new Runnable()
727                 {
728                     @Override
729                     public void run()
730                     {
731                         try
732                         {
733                             GridViewAdapter adapter = (GridViewAdapter) parent.getAdapter();
734                             adapter.notifyDataSetChanged();
735                         }
736                         catch (Exception e)
737                         {
738                             e.printStackTrace();
739                         }
740                     }
741                 });
742                 return (true);
743             }
744             catch (Exception e)
745             {
746                 e.printStackTrace();
747             }
748             return (false);
749         }
750     }
751         
752         private class GridViewOnScrollListener implements AbsListView.OnScrollListener
753     {
754                 @Override
755                 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
756         {
757                         // No operation.
758                 }
759
760                 @Override
761                 public void onScrollStateChanged(AbsListView view, int scrollState)
762         {
763                         if (scrollState == SCROLL_STATE_IDLE)
764                         {
765                                 gridViewIsScrolling = false;
766                                 gridView.invalidateViews();
767                         }
768                         else if ((scrollState == SCROLL_STATE_FLING) || (scrollState == SCROLL_STATE_TOUCH_SCROLL))
769                         {
770                                 gridViewIsScrolling = true;
771                                 if (!executor.isShutdown())
772                                 {
773                                         executor.shutdownNow();
774                                 }
775                         }
776                 }
777         }
778
779         private class ThumbnailLoader implements Runnable
780     {
781                 private GridCellViewHolder viewHolder;
782                 private String path;
783         private final boolean hasRaw;
784                 
785                 ThumbnailLoader(GridCellViewHolder viewHolder, String path, boolean hasRaw)
786         {
787                         this.viewHolder = viewHolder;
788                         this.path = path;
789             this.hasRaw = hasRaw;
790                 }
791                 
792                 @Override
793                 public void run()
794         {
795                         class Box {
796                                 boolean isDownloading = true;
797                         }
798                         final Box box = new Box();
799
800                         playbackControl.downloadContentThumbnail(null, path, new IDownloadThumbnailImageCallback()
801             {
802                                 @Override
803                                 public void onCompleted(final Bitmap thumbnail, Map<String, Object> metadata)
804                                 {
805                                         if (thumbnail != null)
806                                         {
807                         try {
808                             Log.v(TAG, "Thumbnail PATH : " + path + " size : " + thumbnail.getByteCount());
809                             imageCache.put(path, thumbnail);
810                             runOnUiThread(new Runnable() {
811                                 @Override
812                                 public void run() {
813                                     viewHolder.imageView.setImageBitmap(thumbnail);
814                                     if (path.toLowerCase().endsWith(MOVIE_SUFFIX)) {
815                                         viewHolder.iconView.setImageResource(R.drawable.ic_videocam_black_24dp);
816                                     } else if (hasRaw) {
817                                         viewHolder.iconView.setImageResource(R.drawable.ic_raw_black_1x);
818                                     } else {
819                                         viewHolder.iconView.setImageDrawable(null);
820                                     }
821                                 }
822                             });
823                         } catch (Exception e) {
824                             e.printStackTrace();
825                         }
826                     }
827                                         box.isDownloading = false;  
828                                 }
829                                 
830                                 @Override
831                                 public void onErrorOccurred(Exception e)
832                                 {
833                                         box.isDownloading = false;
834                                 }
835                         });
836
837                         // Waits to realize the serial download.
838                         while (box.isDownloading) {
839                                 Thread.yield();
840                         }
841                 }
842         }
843         
844         
845         // -------------------------------------------------------------------------
846         // Helpers
847         // -------------------------------------------------------------------------
848         
849         private void presentMessage(String title, String message)
850     {
851                 Context context = getActivity();
852                 if (context == null)
853                 {
854             return;
855         }
856                 
857                 AlertDialog.Builder builder = new AlertDialog.Builder(context);
858                 builder.setTitle(title).setMessage(message);
859                 builder.show();
860         }
861         
862         private void runOnUiThread(Runnable action)
863     {
864                 Activity activity = getActivity();
865                 if (activity == null)
866                 {
867             return;
868         }
869                 activity.runOnUiThread(action);
870         }
871
872 /*
873         private Bitmap createRotatedBitmap(byte[] data, Map<String, Object> metadata)
874     {
875                 Bitmap bitmap = null;
876                 try
877         {
878                         bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
879                 }
880                 catch (Throwable e)
881         {
882                         e.printStackTrace();
883                 }
884                 if (bitmap == null)
885                 {
886                     Log.v(TAG, "createRotatedBitmap() : bitmap is null : " + data.length);
887                         return (null);
888                 }
889                 
890                 int degrees = getRotationDegrees(data, metadata);
891                 if (degrees != 0)
892                 {
893                         Matrix m = new Matrix();
894                         m.postRotate(degrees);
895                         try
896             {
897                                 bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
898                         }
899                         catch (Throwable e)
900             {
901                                 e.printStackTrace();
902                         }
903                 }
904                 return (bitmap);
905         }
906         
907         private int getRotationDegrees(byte[] data, Map<String, Object> metadata)
908     {
909                 int degrees = 0;
910                 int orientation = ExifInterface.ORIENTATION_UNDEFINED;
911                 
912                 if (metadata != null && metadata.containsKey("Orientation")) {
913                         orientation = Integer.parseInt((String)metadata.get("Orientation"));
914                 } else {
915                         // Gets image orientation to display a picture.
916                         try {
917                                 File tempFile = File.createTempFile("temp", null);
918                                 {
919                                         FileOutputStream outStream = new FileOutputStream(tempFile.getAbsolutePath());
920                                         outStream.write(data);
921                                         outStream.close();
922                                 }
923                                 
924                                 ExifInterface exifInterface = new ExifInterface(tempFile.getAbsolutePath());
925                                 orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
926
927                                 if (!tempFile.delete())
928                 {
929                     Log.v(TAG, "File delete fail...");
930                 }
931                         }
932                         catch (IOException e)
933             {
934                                 e.printStackTrace();
935                         }
936                 }
937
938                 switch (orientation)
939         {
940             case ExifInterface.ORIENTATION_NORMAL:
941                 degrees = 0;
942                 break;
943             case ExifInterface.ORIENTATION_ROTATE_90:
944                 degrees = 90;
945                 break;
946             case ExifInterface.ORIENTATION_ROTATE_180:
947                 degrees = 180;
948                 break;
949             case ExifInterface.ORIENTATION_ROTATE_270:
950                 degrees = 270;
951                 break;
952             default:
953                 break;
954                 }
955                 return (degrees);
956         }
957 */
958 }