Automatic preview after download in PreviewImageActivity
authorDavid A. Velasco <dvelasco@solidgear.es>
Tue, 26 Feb 2013 11:33:28 +0000 (12:33 +0100)
committerDavid A. Velasco <dvelasco@solidgear.es>
Tue, 26 Feb 2013 11:33:28 +0000 (12:33 +0100)
AndroidManifest.xml
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/PreviewImageActivity.java [deleted file]
src/com/owncloud/android/ui/fragment/FileDownloadFragment.java
src/com/owncloud/android/ui/fragment/PreviewImageFragment.java [deleted file]
src/com/owncloud/android/ui/preview/PreviewImageActivity.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewImageFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java [new file with mode: 0644]

index f0dc61b..218f20f 100644 (file)
@@ -86,7 +86,7 @@
         <activity android:name=".ui.activity.PreferencesNewSessionewSession" >\r
         </activity>\r
         \r
-               <activity       android:name="com.owncloud.android.ui.activity.PreviewImageActivity" />\r
+               <activity       android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />\r
                        \r
         <activity      android:name="com.owncloud.android.ui.activity.PreviewVideoActivity"\r
                                        android:label="@string/app_name"\r
index 2031aad..bff3869 100644 (file)
@@ -92,6 +92,7 @@ import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;\r
 import com.owncloud.android.ui.fragment.FilePreviewFragment;\r
 import com.owncloud.android.ui.fragment.OCFileListFragment;\r
+import com.owncloud.android.ui.preview.PreviewImageActivity;\r
 \r
 import com.owncloud.android.R;\r
 import eu.alefzero.webdav.WebdavClient;\r
diff --git a/src/com/owncloud/android/ui/activity/PreviewImageActivity.java b/src/com/owncloud/android/ui/activity/PreviewImageActivity.java
deleted file mode 100644 (file)
index 11889a5..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013  ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.ui.activity;
-
-import java.util.Vector;
-
-import android.accounts.Account;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.datamodel.DataStorageManager;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileDownloader;
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
-import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.ui.fragment.FileDetailFragment;
-import com.owncloud.android.ui.fragment.FileDownloadFragment;
-import com.owncloud.android.ui.fragment.FileFragment;
-import com.owncloud.android.ui.fragment.FilePreviewFragment;
-import com.owncloud.android.ui.fragment.PreviewImageFragment;
-
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.R;
-
-/**
- *  Used as an utility to preview image files contained in an ownCloud account.
- *  
- *  @author David A. Velasco
- */
-public class PreviewImageActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity, ViewPager.OnPageChangeListener {
-    
-    public static final int DIALOG_SHORT_WAIT = 0;
-
-    public static final String TAG = PreviewImageActivity.class.getSimpleName();
-    
-    public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
-    
-    private OCFile mFile;
-    private OCFile mParentFolder;  
-    private Account mAccount;
-    private DataStorageManager mStorageManager;
-    
-    private ViewPager mViewPager; 
-    private PreviewImagePagerAdapter mPreviewImagePagerAdapter;    
-    
-    private FileDownloaderBinder mDownloaderBinder = null;
-    private ServiceConnection mDownloadConnection, mUploadConnection = null;
-    private FileUploaderBinder mUploaderBinder = null;
-    private boolean mWaitingToPreview;
-    
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
-        mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
-        if (mFile == null) {
-            throw new IllegalStateException("Instanced with a NULL OCFile");
-        }
-        if (mAccount == null) {
-            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
-        }
-        if (!mFile.isImage()) {
-            throw new IllegalArgumentException("Non-image file passed as argument");
-        }
-        
-        setContentView(R.layout.preview_image_activity);
-    
-        ActionBar actionBar = getSupportActionBar();
-        actionBar.setDisplayHomeAsUpEnabled(true);
-        actionBar.setTitle(mFile.getFileName());
-        
-        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
-        mParentFolder = mStorageManager.getFileById(mFile.getParentId());
-        if (mParentFolder == null) {
-            // should not be necessary
-            mParentFolder = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
-        }
-
-        createViewPager();
-
-        if (savedInstanceState == null) {
-            mWaitingToPreview = false;
-        } else {
-            mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);
-        }
-        
-        mDownloadConnection = new DetailsServiceConnection();
-        bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
-        mUploadConnection = new DetailsServiceConnection();
-        bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
-        
-    }
-
-    private void createViewPager() {
-        mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), mParentFolder);
-        mViewPager = (ViewPager) findViewById(R.id.fragmentPager);
-        mViewPager.setAdapter(mPreviewImagePagerAdapter);        
-        mViewPager.setOnPageChangeListener(this);
-    }
-    
-
-    /**
-     * Adapter class that provides Fragment instances  
-     * 
-     * @author David A. Velasco
-     */
-    public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
-        
-        Vector<OCFile> mImageFiles; 
-        
-        public PreviewImagePagerAdapter(FragmentManager fm, OCFile parentFolder) {
-            super(fm);
-            mImageFiles = mStorageManager.getDirectoryImages(parentFolder);
-        }
-    
-        @Override
-        public Fragment getItem(int i) {
-            Log.e(TAG, "GETTING PAGE " + i);
-            OCFile file = mImageFiles.get(i);
-            Fragment fragment = null;
-            if (file.isDown()) {
-                fragment = new PreviewImageFragment(file, mAccount);
-                mWaitingToPreview = false;
-            } else {
-                fragment = new FileDownloadFragment(file, mAccount);    // TODO
-                //mWaitingToPreview = true;
-            }
-            return fragment;
-        }
-    
-        @Override
-        public int getCount() {
-            return mImageFiles.size();
-        }
-    
-        @Override
-        public CharSequence getPageTitle(int position) {
-            return mImageFiles.get(position).getFileName();
-        }
-    }
-
-     
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
-    }
-
-
-    /** Defines callbacks for service binding, passed to bindService() */
-    private class DetailsServiceConnection implements ServiceConnection {
-
-        @Override
-        public void onServiceConnected(ComponentName component, IBinder service) {
-                
-            if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
-                Log.d(TAG, "Download service connected");
-                mDownloaderBinder = (FileDownloaderBinder) service;
-                if (mWaitingToPreview) {
-                    requestForDownload();
-                }
-                    
-            } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service connected");
-                mUploaderBinder = (FileUploaderBinder) service;
-            } else {
-                return;
-            }
-            
-            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
-            FileDetailFragment detailsFragment = (fragment instanceof FileDetailFragment) ? (FileDetailFragment) fragment : null;
-            if (detailsFragment != null) {
-                detailsFragment.listenForTransferProgress();
-                detailsFragment.updateFileDetails(mWaitingToPreview);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName component) {
-            if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
-                Log.d(TAG, "Download service disconnected");
-                mDownloaderBinder = null;
-            } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service disconnected");
-                mUploaderBinder = null;
-            }
-        }
-    };    
-    
-    
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (mDownloadConnection != null) {
-            unbindService(mDownloadConnection);
-            mDownloadConnection = null;
-        }
-        if (mUploadConnection != null) {
-            unbindService(mUploadConnection);
-            mUploadConnection = null;
-        }
-    }
-    
-    
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        boolean returnValue = false;
-        
-        switch(item.getItemId()){
-        case android.R.id.home:
-            backToDisplayActivity();
-            returnValue = true;
-            break;
-        default:
-               returnValue = super.onOptionsItemSelected(item);
-        }
-        
-        return returnValue;
-    }
-
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
-        if (fragment != null && fragment instanceof FileDetailFragment) {
-            ((FileDetailFragment) fragment).updateFileDetails(false);
-        }
-    }
-    
-
-    private void backToDisplayActivity() {
-        /*
-        Intent intent = new Intent(this, FileDisplayActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        intent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
-        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
-        startActivity(intent);
-        */
-        finish();
-    }
-    
-    
-    @Override
-    protected Dialog onCreateDialog(int id) {
-        Dialog dialog = null;
-        switch (id) {
-        case DIALOG_SHORT_WAIT: {
-            ProgressDialog working_dialog = new ProgressDialog(this);
-            working_dialog.setMessage(getResources().getString(
-                    R.string.wait_a_moment));
-            working_dialog.setIndeterminate(true);
-            working_dialog.setCancelable(false);
-            dialog = working_dialog;
-            break;
-        }
-        default:
-            dialog = null;
-        }
-        return dialog;
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFileStateChanged() {
-        // nothing to do here!
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileDownloaderBinder getFileDownloaderBinder() {
-        return mDownloaderBinder;
-    }
-
-
-    @Override
-    public FileUploaderBinder getFileUploaderBinder() {
-        return mUploaderBinder;
-    }
-
-
-    @Override
-    public void showFragmentWithDetails(OCFile file) {
-        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
-        showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
-        startActivity(showDetailsIntent);
-    }
-
-    
-    private void requestForDownload() {
-        if (!mDownloaderBinder.isDownloading(mAccount, mFile)) {
-            Intent i = new Intent(this, FileDownloader.class);
-            i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
-            i.putExtra(FileDownloader.EXTRA_FILE, mFile);
-            startService(i);
-        }
-    }
-
-    @Override
-    public void notifySuccessfulDownload(OCFile file, Intent intent, boolean success) {
-        if (success) {
-            if (mWaitingToPreview) {
-                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-                transaction.replace(R.id.fragment, new FilePreviewFragment(file, mAccount), FileDetailFragment.FTAG); 
-                transaction.commit();
-                mWaitingToPreview = false;
-            }
-        }
-    }
-
-    
-    /**
-     * This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
-     * 
-     *  @param  Position        Position index of the new selected page
-     */
-    @Override
-    public void onPageSelected(int position) {
-        OCFile currentFile = ((FileFragment)mPreviewImagePagerAdapter.getItem(position)).getFile();
-        getSupportActionBar().setTitle(currentFile.getFileName());
-    }
-    
-    /**
-     * Called when the scroll state changes. Useful for discovering when the user begins dragging, 
-     * when the pager is automatically settling to the current page, or when it is fully stopped/idle.
-     * 
-     * @param   State       The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
-     */
-    @Override
-    public void onPageScrollStateChanged(int state) {
-    }
-
-    /**
-     * This method will be invoked when the current page is scrolled, either as part of a programmatically 
-     * initiated smooth scroll or a user initiated touch scroll.
-     * 
-     * @param   position                Position index of the first page currently being displayed. 
-     *                                  Page position+1 will be visible if positionOffset is nonzero.
-     *                                  
-     * @param   positionOffset          Value from [0, 1) indicating the offset from the page at position.
-     * @param   positionOffsetPixels    Value in pixels indicating the offset from position. 
-     */
-    @Override
-    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-    }
-    
-}
index c8318fd..6734c04 100644 (file)
@@ -65,6 +65,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
     
     private DownloadFinishReceiver mDownloadFinishReceiver;
     public ProgressListener mProgressListener;
+    private boolean mListening;
     
     private static final String TAG = FileDownloadFragment.class.getSimpleName();
 
@@ -79,6 +80,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
         mAccount = null;
         mStorageManager = null;
         mProgressListener = null;
+        mListening = false;
     }
     
     
@@ -95,6 +97,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
         mAccount = ocAccount;
         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
         mProgressListener = null;
+        mListening = false;
     }
     
     
@@ -123,7 +126,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
         view = inflater.inflate(R.layout.file_download_fragment, container, false);
         mView = view;
         
-        ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.fdProgressBar);
+        ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.progressBar);
         mProgressListener = new ProgressListener(progressBar);
         
         return view;
@@ -136,6 +139,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
+        Log.e(TAG, "PREVIEW_DOWNLOAD_FRAGMENT ONATTACH " + ((mFile == null)?" (NULL)":mFile.getFileName()));
         try {
             mContainerActivity = (ContainerActivity) activity;
             
@@ -151,6 +155,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
+        Log.e(TAG, "PREVIEW_DOWNLOAD_FRAGMENT ONACTIVITYCREATED " + ((mFile == null)?" (NULL)":mFile.getFileName()));
         if (mAccount != null) {
             mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;
         }
@@ -209,6 +214,9 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
     
     @Override
     public View getView() {
+        if (!mListening) {
+            listenForTransferProgress();
+        }
         return super.getView() == null ? mView : super.getView();
     }
 
@@ -244,11 +252,14 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
     
     /**
      * Updates the view depending upon the state of the downloading file.
+     * 
+     * @param   transferring    When true, the view must be updated assuming that the holded file is 
+     *                          downloading, no matter what the downloaderBinder says.
      */
-    public void updateView() {
+    public void updateView(boolean transferring) {
         // configure UI for depending upon local state of the file
         FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-        if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+        if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile))) {
             setButtonsForTransferring();
             
         } else if (mFile.isDown()) {
@@ -270,9 +281,9 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
         downloadButton.setText(R.string.common_cancel);
     
         // show the progress bar for the transfer
-        ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+        ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.progressBar);
         progressBar.setVisibility(View.VISIBLE);
-        TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+        TextView progressText = (TextView)getView().findViewById(R.id.progressText);
         progressText.setText(R.string.downloader_download_in_progress_ticker);
     }
     
@@ -285,11 +296,11 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
         downloadButton.setVisibility(View.GONE);
     
         // hides the progress bar
-        ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+        ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.progressBar);
         progressBar.setVisibility(View.GONE);
         
         // updates the text message
-        TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+        TextView progressText = (TextView)getView().findViewById(R.id.progressText);
         progressText.setText(R.string.common_loading);
     }
 
@@ -303,11 +314,11 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
         //downloadButton.setText(R.string.filedetails_download);
         
         // hides the progress bar
-        ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+        ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.progressBar);
         progressBar.setVisibility(View.GONE);
         
         // updates the text message
-        TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+        TextView progressText = (TextView)getView().findViewById(R.id.progressText);
         progressText.setText(R.string.downloader_not_downloaded_yet);
     }
     
@@ -326,9 +337,9 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
                     if (downloadWasFine) {
                         mFile = mStorageManager.getFileByPath(downloadedRemotePath);
                     }
-                    mContainerActivity.notifySuccessfulDownload(mFile, intent, downloadWasFine);
+                    updateView(false);
                     getActivity().removeStickyBroadcast(intent);
-                    updateView();
+                    mContainerActivity.notifySuccessfulDownload(mFile, intent, downloadWasFine);
                 }
             }
         }
@@ -336,12 +347,11 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
     
     
     public void listenForTransferProgress() {
-        if (mProgressListener != null) {
+        if (mProgressListener != null && !mListening) {
             if (mContainerActivity.getFileDownloaderBinder() != null) {
                 mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
-            }
-            if (mContainerActivity.getFileUploaderBinder() != null) {
-                mContainerActivity.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+                mListening = true;
+                setButtonsForTransferring();
             }
         }
     }
@@ -352,9 +362,6 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
             if (mContainerActivity.getFileDownloaderBinder() != null) {
                 mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
             }
-            if (mContainerActivity.getFileUploaderBinder() != null) {
-                mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
-            }
         }
     }
 
diff --git a/src/com/owncloud/android/ui/fragment/PreviewImageFragment.java b/src/com/owncloud/android/ui/fragment/PreviewImageFragment.java
deleted file mode 100644 (file)
index d6ba33b..0000000
+++ /dev/null
@@ -1,600 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc. 
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.ui.fragment;
-
-import java.io.File;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-
-import android.accounts.Account;
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.Point;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.actionbarsherlock.app.SherlockFragment;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.ui.activity.PreviewImageActivity;
-
-import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-
-
-/**
- * This fragment shows a preview of a downloaded image.
- * 
- * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
- * 
- * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
- * 
- * @author David A. Velasco
- */
-public class PreviewImageFragment extends SherlockFragment implements   FileFragment, 
-                                                                        OnRemoteOperationListener, 
-                                                                        ConfirmationDialogFragment.ConfirmationDialogFragmentListener{
-    public static final String EXTRA_FILE = "FILE";
-    public static final String EXTRA_ACCOUNT = "ACCOUNT";
-
-    private View mView;
-    private OCFile mFile;
-    private Account mAccount;
-    private FileDataStorageManager mStorageManager;
-    private ImageView mImageView;
-    public Bitmap mBitmap = null;
-    
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
-    private static final String TAG = PreviewImageFragment.class.getSimpleName();
-
-    
-    /**
-     * Creates a fragment to preview an image.
-     * 
-     * When 'imageFile' or 'ocAccount' are null
-     * 
-     * @param imageFile         An {@link OCFile} to preview as an image in the fragment
-     * @param ocAccount         An ownCloud account; needed to start downloads
-     */
-    public PreviewImageFragment(OCFile fileToDetail, Account ocAccount) {
-        mFile = fileToDetail;
-        mAccount = ocAccount;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
-    }
-    
-    
-    /**
-     *  Creates an empty fragment for image previews.
-     * 
-     *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
-     * 
-     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
-     */
-    public PreviewImageFragment() {
-        mFile = null;
-        mAccount = null;
-        mStorageManager = null;
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONCREATE " + ((mFile == null)? "(NULL)" : mFile.getFileName()));
-        mHandler = new Handler();
-        setHasOptionsMenu(true);
-    }
-    
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        super.onCreateView(inflater, container, savedInstanceState);
-        mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
-        mImageView = (ImageView)mView.findViewById(R.id.image);
-        return mView;
-    }
-    
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        if (!(activity instanceof FileFragment.ContainerActivity))
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
-        if (savedInstanceState != null) {
-            mFile = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
-            mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
-            
-        }
-        if (mFile == null) {
-            throw new IllegalStateException("Instanced with a NULL OCFile");
-        }
-        if (mAccount == null) {
-            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
-        }
-        if (!mFile.isDown()) {
-            throw new IllegalStateException("There is no local file to preview");
-        }
-    }
-        
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putParcelable(PreviewImageFragment.EXTRA_FILE, mFile);
-        outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
-    }
-    
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONSTART " + mFile.getFileName());
-        if (mFile != null) {
-           BitmapLoader bl = new BitmapLoader(mImageView);
-           bl.execute(new String[]{mFile.getStoragePath()});
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        super.onCreateOptionsMenu(menu, inflater);
-
-        inflater.inflate(R.menu.file_actions_menu, menu);
-        List<Integer> toHide = new ArrayList<Integer>();    
-        
-        MenuItem item = null;
-        toHide.add(R.id.action_cancel_download);
-        toHide.add(R.id.action_cancel_upload);
-        toHide.add(R.id.action_download_file);
-        toHide.add(R.id.action_rename_file);    // by now
-
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
-        }
-        
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.action_open_file_with: {
-                openFile();
-                return true;
-            }
-            case R.id.action_remove_file: {
-                removeFile();
-                return true;
-            }
-            case R.id.action_see_details: {
-                seeDetails();
-                return true;
-            }
-            
-            default:
-                return false;
-        }
-    }
-
-    
-    private void seeDetails() {
-        ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mFile);        
-    }
-
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONRESUME " + mFile.getFileName());
-        /*
-        mDownloadFinishReceiver = new DownloadFinishReceiver();
-        IntentFilter filter = new IntentFilter(
-                FileDownloader.DOWNLOAD_FINISH_MESSAGE);
-        getActivity().registerReceiver(mDownloadFinishReceiver, filter);
-        
-        mUploadFinishReceiver = new UploadFinishReceiver();
-        filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
-        getActivity().registerReceiver(mUploadFinishReceiver, filter);
-        */
-
-    }
-
-
-    @Override
-    public void onPause() {
-        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONPAUSE " + mFile.getFileName());
-        super.onPause();
-        /*
-        if (mVideoPreview.getVisibility() == View.VISIBLE) {
-            mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
-        }*/
-        /*
-        getActivity().unregisterReceiver(mDownloadFinishReceiver);
-        mDownloadFinishReceiver = null;
-        
-        getActivity().unregisterReceiver(mUploadFinishReceiver);
-        mUploadFinishReceiver = null;
-        */
-    }
-
-
-    @Override
-    public void onStop() {
-        super.onStop();
-        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONSTOP " + mFile.getFileName());
-    }
-    
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONDESTROY " + mFile.getFileName());
-        if (mBitmap != null) {
-            mBitmap.recycle();
-        }
-    }
-
-    
-    /**
-     * Opens the previewed image with an external application.
-     * 
-     * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
-     * we should get a list of available apps for MIME tpye in the server and join it with the list of 
-     * available apps for the MIME type known from the file extension, to let the user choose
-     */
-    private void openFile() {
-        String storagePath = mFile.getStoragePath();
-        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
-        try {
-            Intent i = new Intent(Intent.ACTION_VIEW);
-            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
-            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            startActivity(i);
-            
-        } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
-            boolean toastIt = true; 
-            String mimeType = "";
-            try {
-                Intent i = new Intent(Intent.ACTION_VIEW);
-                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
-                if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
-                    if (mimeType != null) {
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
-                    } else {
-                        // desperate try
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
-                    }
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                    startActivity(i);
-                    toastIt = false;
-                }
-                
-            } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
-                
-            } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
-                
-            } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
-                
-            } finally {
-                if (toastIt) {
-                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
-                }
-            }
-            
-        }
-        finish();
-    }
-    
-    
-    /**
-     * Starts a the removal of the previewed file.
-     * 
-     * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
-     * depending upon the user selection in the dialog. 
-     */
-    private void removeFile() {
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{mFile.getFileName()},
-                R.string.confirmation_remove_remote_and_local,
-                R.string.confirmation_remove_local,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
-    }
-
-    
-    /**
-     * Performs the removal of the previewed file, both locally and in the server.
-     */
-    @Override
-    public void onConfirmation(String callerTag) {
-        if (mStorageManager.getFileById(mFile.getFileId()) != null) {   // check that the file is still there;
-            mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
-                                                            true, 
-                                                            mStorageManager);
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
-            
-            getActivity().showDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
-        }
-    }
-    
-    
-    /**
-     * Removes the file from local storage
-     */
-    @Override
-    public void onNeutral(String callerTag) {
-        // TODO this code should be made in a secondary thread,
-        if (mFile.isDown()) {   // checks it is still there
-            File f = new File(mFile.getStoragePath());
-            f.delete();
-            mFile.setStoragePath(null);
-            mStorageManager.saveFile(mFile);
-            finish();
-        }
-    }
-    
-    /**
-     * User cancelled the removal action.
-     */
-    @Override
-    public void onCancel(String callerTag) {
-        // nothing to do here
-    }
-    
-
-    /**
-     * {@inheritDoc}
-     */
-    public OCFile getFile(){
-        return mFile;
-    }
-    
-    /*
-    /**
-     * Use this method to signal this Activity that it shall update its view.
-     * 
-     * @param file : An {@link OCFile}
-     *-/
-    public void updateFileDetails(OCFile file, Account ocAccount) {
-        mFile = file;
-        if (ocAccount != null && ( 
-                mStorageManager == null || 
-                (mAccount != null && !mAccount.equals(ocAccount))
-           )) {
-            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
-        }
-        mAccount = ocAccount;
-        updateFileDetails(false);
-    }
-    */
-    
-
-    private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
-
-        /**
-         * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
-         * 
-         * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
-         */
-        private final WeakReference<ImageView> mImageViewRef;
-        
-        
-        /**
-         * Constructor.
-         * 
-         * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
-         */
-        public BitmapLoader(ImageView imageView) {
-            mImageViewRef = new WeakReference<ImageView>(imageView);
-        }
-        
-        
-        @SuppressWarnings("deprecation")
-        @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20
-               @Override
-        protected Bitmap doInBackground(String... params) {
-            Bitmap result = null;
-            if (params.length != 1) return result;
-            String storagePath = params[0];
-            try {
-                // set desired options that will affect the size of the bitmap
-                BitmapFactory.Options options = new Options();
-                options.inScaled = true;
-                options.inPurgeable = true;
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
-                    options.inPreferQualityOverSpeed = false;
-                }
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
-                    options.inMutable = false;
-                }
-                // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
-                options.inJustDecodeBounds = true;
-                BitmapFactory.decodeFile(storagePath, options);   
-                
-                int width = options.outWidth;
-                int height = options.outHeight;
-                int scale = 1;
-                if (width >= 2048 || height >= 2048) {  
-                    // try to scale down the image to save memory  
-                    scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));
-                    options.inSampleSize = scale;
-                }
-                Display display = getActivity().getWindowManager().getDefaultDisplay();
-                Point size = new Point();
-                int screenwidth;
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
-                    display.getSize(size);
-                    screenwidth = size.x;
-                } else {
-                    screenwidth = display.getWidth();
-                }
-
-                Log.d(TAG, "image width: " + width + ", screen width: " + screenwidth);
-
-                if (width > screenwidth) {
-                    // second try to scale down the image , this time depending upon the screen size; WTF... 
-                    scale = (int) Math.ceil((float)width / screenwidth);
-                    options.inSampleSize = scale;
-                }
-
-                // really load the bitmap
-                options.inJustDecodeBounds = false; // the next decodeFile call will be real
-                result = BitmapFactory.decodeFile(storagePath, options);
-                Log.e(TAG, "loaded width: " + options.outWidth + ", loaded height: " + options.outHeight);
-
-            } catch (OutOfMemoryError e) {
-                result = null;
-                Log.e(TAG, "Out of memory occured for file with size " + storagePath);
-                
-            } catch (NoSuchFieldError e) {
-                result = null;
-                Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);
-                
-            } catch (Throwable t) {
-                result = null;
-                Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);
-            }
-            return result;
-        }
-        
-        @Override
-        protected void onPostExecute(Bitmap result) {
-            if (result != null && mImageViewRef != null) {
-                final ImageView imageView = mImageViewRef.get();
-                imageView.setImageBitmap(result);
-                mBitmap  = result;
-            }
-        }
-        
-    }
-
-    /**
-     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed.
-     * 
-     * @param file      File to test if can be previewed.
-     * @return          'True' if the file can be handled by the fragment.
-     */
-    public static boolean canBePreviewed(OCFile file) {
-        return (file != null && file.isImage());
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation) && operation instanceof RemoveFileOperation) {
-            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-        }
-    }
-    
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        getActivity().dismissDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
-        
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            finish();
-                
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
-            }
-        }
-    }
-
-    /**
-     * Finishes the preview
-     */
-    private void finish() {
-        Activity container = getActivity();
-        container.finish();
-    }
-    
-
-}
diff --git a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java
new file mode 100644 (file)
index 0000000..1e9d108
--- /dev/null
@@ -0,0 +1,340 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013  ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import android.accounts.Account;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.R;
+
+/**
+ *  Used as an utility to preview image files contained in an ownCloud account.
+ *  
+ *  @author David A. Velasco
+ */
+public class PreviewImageActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity, ViewPager.OnPageChangeListener {
+    
+    public static final int DIALOG_SHORT_WAIT = 0;
+
+    public static final String TAG = PreviewImageActivity.class.getSimpleName();
+    
+    public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
+    
+    private OCFile mFile;
+    private OCFile mParentFolder;  
+    private Account mAccount;
+    private DataStorageManager mStorageManager;
+    
+    private ViewPager mViewPager; 
+    private PreviewImagePagerAdapter mPreviewImagePagerAdapter;    
+    
+    private FileDownloaderBinder mDownloaderBinder = null;
+    private ServiceConnection mDownloadConnection, mUploadConnection = null;
+    private FileUploaderBinder mUploaderBinder = null;
+    private OCFile mWaitingToPreview = null;
+    
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
+        mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
+        if (mFile == null) {
+            throw new IllegalStateException("Instanced with a NULL OCFile");
+        }
+        if (mAccount == null) {
+            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+        }
+        if (!mFile.isImage()) {
+            throw new IllegalArgumentException("Non-image file passed as argument");
+        }
+        
+        setContentView(R.layout.preview_image_activity);
+    
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        actionBar.setTitle(mFile.getFileName());
+        
+        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+        mParentFolder = mStorageManager.getFileById(mFile.getParentId());
+        if (mParentFolder == null) {
+            // should not be necessary
+            mParentFolder = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+        }
+
+        createViewPager();
+
+        if (savedInstanceState == null) {
+            mWaitingToPreview = (mFile.isDown())?null:mFile;
+        } else {
+            mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(KEY_WAITING_TO_PREVIEW);
+        }
+        
+        mDownloadConnection = new PreviewImageServiceConnection();
+        bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
+        mUploadConnection = new PreviewImageServiceConnection();
+        bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
+        
+    }
+
+    private void createViewPager() {
+        mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), mParentFolder, mAccount, mStorageManager);
+        mViewPager = (ViewPager) findViewById(R.id.fragmentPager);
+        mViewPager.setAdapter(mPreviewImagePagerAdapter);        
+        mViewPager.setOnPageChangeListener(this);
+    }
+    
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
+    }
+
+
+    /** Defines callbacks for service binding, passed to bindService() */
+    private class PreviewImageServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+                
+            if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+                Log.d(TAG, "Download service connected");
+                mDownloaderBinder = (FileDownloaderBinder) service;
+                    
+            } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+                Log.d(TAG, "Upload service connected");
+                mUploaderBinder = (FileUploaderBinder) service;
+            } else {
+                return;
+            }
+            
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+                Log.d(TAG, "Download service suddenly disconnected");
+                mDownloaderBinder = null;
+            } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+                Log.d(TAG, "Upload service suddenly disconnected");
+                mUploaderBinder = null;
+            }
+        }
+    };    
+    
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mDownloadConnection != null) {
+            unbindService(mDownloadConnection);
+            mDownloadConnection = null;
+        }
+        if (mUploadConnection != null) {
+            unbindService(mUploadConnection);
+            mUploadConnection = null;
+        }
+    }
+    
+    
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean returnValue = false;
+        
+        switch(item.getItemId()){
+        case android.R.id.home:
+            backToDisplayActivity();
+            returnValue = true;
+            break;
+        default:
+               returnValue = super.onOptionsItemSelected(item);
+        }
+        
+        return returnValue;
+    }
+
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+    
+
+    private void backToDisplayActivity() {
+        /*
+        Intent intent = new Intent(this, FileDisplayActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        intent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
+        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        startActivity(intent);
+        */
+        finish();
+    }
+    
+    
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        Dialog dialog = null;
+        switch (id) {
+        case DIALOG_SHORT_WAIT: {
+            ProgressDialog working_dialog = new ProgressDialog(this);
+            working_dialog.setMessage(getResources().getString(
+                    R.string.wait_a_moment));
+            working_dialog.setIndeterminate(true);
+            working_dialog.setCancelable(false);
+            dialog = working_dialog;
+            break;
+        }
+        default:
+            dialog = null;
+        }
+        return dialog;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFileStateChanged() {
+        // nothing to do here!
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FileDownloaderBinder getFileDownloaderBinder() {
+        return mDownloaderBinder;
+    }
+
+
+    @Override
+    public FileUploaderBinder getFileUploaderBinder() {
+        return mUploaderBinder;
+    }
+
+
+    @Override
+    public void showFragmentWithDetails(OCFile file) {
+        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+        showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+        startActivity(showDetailsIntent);
+    }
+
+    
+    private void requestForDownload() {
+        Log.e(TAG, "REQUEST FOR DOWNLOAD : " + mWaitingToPreview.getFileName());
+        if (!mDownloaderBinder.isDownloading(mAccount, mWaitingToPreview)) {
+            Intent i = new Intent(this, FileDownloader.class);
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+            i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview);
+            startService(i);
+        }
+    }
+
+    @Override
+    public void notifySuccessfulDownload(OCFile file, Intent intent, boolean success) {
+        if (success) {
+            if (mWaitingToPreview != null && mWaitingToPreview.equals(file)) {
+                mWaitingToPreview = null;
+                int position = mViewPager.getCurrentItem();
+                mPreviewImagePagerAdapter.updateFile(position, file);
+                Log.e(TAG, "BEFORE NOTIFY DATA SET CHANGED");
+                mPreviewImagePagerAdapter.notifyDataSetChanged();
+                Log.e(TAG, "AFTER NOTIFY DATA SET CHANGED");
+                //Log.e(TAG, "BEFORE INVALIDATE");
+                //mViewPager.postInvalidate();
+                //Log.e(TAG, "AFTER INVALIDATE");
+            }
+        }
+    }
+
+    
+    /**
+     * This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
+     * 
+     *  @param  Position        Position index of the new selected page
+     */
+    @Override
+    public void onPageSelected(int position) {
+        OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); 
+        getSupportActionBar().setTitle(currentFile.getFileName());
+        if (currentFile.isDown()) {
+            mWaitingToPreview = null;
+        } else {
+            mWaitingToPreview = currentFile;
+            requestForDownload();
+            mViewPager.invalidate();
+        }
+    }
+    
+    /**
+     * Called when the scroll state changes. Useful for discovering when the user begins dragging, 
+     * when the pager is automatically settling to the current page, or when it is fully stopped/idle.
+     * 
+     * @param   State       The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
+     */
+    @Override
+    public void onPageScrollStateChanged(int state) {
+    }
+
+    /**
+     * This method will be invoked when the current page is scrolled, either as part of a programmatically 
+     * initiated smooth scroll or a user initiated touch scroll.
+     * 
+     * @param   position                Position index of the first page currently being displayed. 
+     *                                  Page position+1 will be visible if positionOffset is nonzero.
+     *                                  
+     * @param   positionOffset          Value from [0, 1) indicating the offset from the page at position.
+     * @param   positionOffsetPixels    Value in pixels indicating the offset from position. 
+     */
+    @Override
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+    }
+    
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java
new file mode 100644 (file)
index 0000000..4d6ad2d
--- /dev/null
@@ -0,0 +1,603 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc. 
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+
+import android.accounts.Account;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.MimeTypeMap;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.actionbarsherlock.app.SherlockFragment;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+import com.owncloud.android.ui.fragment.FileFragment.ContainerActivity;
+
+import com.owncloud.android.R;
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+
+/**
+ * This fragment shows a preview of a downloaded image.
+ * 
+ * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
+ * 
+ * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
+ * 
+ * @author David A. Velasco
+ */
+public class PreviewImageFragment extends SherlockFragment implements   FileFragment, 
+                                                                        OnRemoteOperationListener, 
+                                                                        ConfirmationDialogFragment.ConfirmationDialogFragmentListener{
+    public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+
+    private View mView;
+    private OCFile mFile;
+    private Account mAccount;
+    private FileDataStorageManager mStorageManager;
+    private ImageView mImageView;
+    public Bitmap mBitmap = null;
+    
+    private Handler mHandler;
+    private RemoteOperation mLastRemoteOperation;
+    
+    private static final String TAG = PreviewImageFragment.class.getSimpleName();
+
+    
+    /**
+     * Creates a fragment to preview an image.
+     * 
+     * When 'imageFile' or 'ocAccount' are null
+     * 
+     * @param imageFile         An {@link OCFile} to preview as an image in the fragment
+     * @param ocAccount         An ownCloud account; needed to start downloads
+     */
+    public PreviewImageFragment(OCFile fileToDetail, Account ocAccount) {
+        mFile = fileToDetail;
+        mAccount = ocAccount;
+        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+    }
+    
+    
+    /**
+     *  Creates an empty fragment for image previews.
+     * 
+     *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+     * 
+     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+     */
+    public PreviewImageFragment() {
+        mFile = null;
+        mAccount = null;
+        mStorageManager = null;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONCREATE " + ((mFile == null)? "(NULL)" : mFile.getFileName()));
+        mHandler = new Handler();
+        setHasOptionsMenu(true);
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        super.onCreateView(inflater, container, savedInstanceState);
+        mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
+        mImageView = (ImageView)mView.findViewById(R.id.image);
+        return mView;
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        if (!(activity instanceof FileFragment.ContainerActivity))
+            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
+        if (savedInstanceState != null) {
+            mFile = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+            mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
+            
+        }
+        if (mFile == null) {
+            throw new IllegalStateException("Instanced with a NULL OCFile");
+        }
+        if (mAccount == null) {
+            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+        }
+        if (!mFile.isDown()) {
+            throw new IllegalStateException("There is no local file to preview");
+        }
+    }
+        
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(PreviewImageFragment.EXTRA_FILE, mFile);
+        outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
+    }
+    
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONSTART " + mFile.getFileName());
+        if (mFile != null) {
+           BitmapLoader bl = new BitmapLoader(mImageView);
+           bl.execute(new String[]{mFile.getStoragePath()});
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+
+        inflater.inflate(R.menu.file_actions_menu, menu);
+        List<Integer> toHide = new ArrayList<Integer>();    
+        
+        MenuItem item = null;
+        toHide.add(R.id.action_cancel_download);
+        toHide.add(R.id.action_cancel_upload);
+        toHide.add(R.id.action_download_file);
+        toHide.add(R.id.action_rename_file);    // by now
+
+        for (int i : toHide) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(false);
+                item.setEnabled(false);
+            }
+        }
+        
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_open_file_with: {
+                openFile();
+                return true;
+            }
+            case R.id.action_remove_file: {
+                removeFile();
+                return true;
+            }
+            case R.id.action_see_details: {
+                seeDetails();
+                return true;
+            }
+            
+            default:
+                return false;
+        }
+    }
+
+    
+    private void seeDetails() {
+        ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mFile);        
+    }
+
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONRESUME " + mFile.getFileName());
+        /*
+        mDownloadFinishReceiver = new DownloadFinishReceiver();
+        IntentFilter filter = new IntentFilter(
+                FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+        getActivity().registerReceiver(mDownloadFinishReceiver, filter);
+        
+        mUploadFinishReceiver = new UploadFinishReceiver();
+        filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+        getActivity().registerReceiver(mUploadFinishReceiver, filter);
+        */
+
+    }
+
+
+    @Override
+    public void onPause() {
+        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONPAUSE " + mFile.getFileName());
+        super.onPause();
+        /*
+        if (mVideoPreview.getVisibility() == View.VISIBLE) {
+            mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
+        }*/
+        /*
+        getActivity().unregisterReceiver(mDownloadFinishReceiver);
+        mDownloadFinishReceiver = null;
+        
+        getActivity().unregisterReceiver(mUploadFinishReceiver);
+        mUploadFinishReceiver = null;
+        */
+    }
+
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONSTOP " + mFile.getFileName());
+    }
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.e(TAG, "PREVIEW_IMAGE_FRAGMENT ONDESTROY " + mFile.getFileName());
+        if (mBitmap != null) {
+            mBitmap.recycle();
+        }
+    }
+
+    
+    /**
+     * Opens the previewed image with an external application.
+     * 
+     * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
+     * we should get a list of available apps for MIME tpye in the server and join it with the list of 
+     * available apps for the MIME type known from the file extension, to let the user choose
+     */
+    private void openFile() {
+        String storagePath = mFile.getStoragePath();
+        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+        try {
+            Intent i = new Intent(Intent.ACTION_VIEW);
+            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            startActivity(i);
+            
+        } catch (Throwable t) {
+            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            boolean toastIt = true; 
+            String mimeType = "";
+            try {
+                Intent i = new Intent(Intent.ACTION_VIEW);
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
+                    if (mimeType != null) {
+                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
+                    } else {
+                        // desperate try
+                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
+                    }
+                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                    startActivity(i);
+                    toastIt = false;
+                }
+                
+            } catch (IndexOutOfBoundsException e) {
+                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                
+            } catch (Throwable th) {
+                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                
+            } finally {
+                if (toastIt) {
+                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                }
+            }
+            
+        }
+        finish();
+    }
+    
+    
+    /**
+     * Starts a the removal of the previewed file.
+     * 
+     * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
+     * depending upon the user selection in the dialog. 
+     */
+    private void removeFile() {
+        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
+                R.string.confirmation_remove_alert,
+                new String[]{mFile.getFileName()},
+                R.string.confirmation_remove_remote_and_local,
+                R.string.confirmation_remove_local,
+                R.string.common_cancel);
+        confDialog.setOnConfirmationListener(this);
+        confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
+    }
+
+    
+    /**
+     * Performs the removal of the previewed file, both locally and in the server.
+     */
+    @Override
+    public void onConfirmation(String callerTag) {
+        if (mStorageManager.getFileById(mFile.getFileId()) != null) {   // check that the file is still there;
+            mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
+                                                            true, 
+                                                            mStorageManager);
+            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
+            mLastRemoteOperation.execute(wc, this, mHandler);
+            
+            getActivity().showDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
+        }
+    }
+    
+    
+    /**
+     * Removes the file from local storage
+     */
+    @Override
+    public void onNeutral(String callerTag) {
+        // TODO this code should be made in a secondary thread,
+        if (mFile.isDown()) {   // checks it is still there
+            File f = new File(mFile.getStoragePath());
+            f.delete();
+            mFile.setStoragePath(null);
+            mStorageManager.saveFile(mFile);
+            finish();
+        }
+    }
+    
+    /**
+     * User cancelled the removal action.
+     */
+    @Override
+    public void onCancel(String callerTag) {
+        // nothing to do here
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public OCFile getFile(){
+        return mFile;
+    }
+    
+    /*
+    /**
+     * Use this method to signal this Activity that it shall update its view.
+     * 
+     * @param file : An {@link OCFile}
+     *-/
+    public void updateFileDetails(OCFile file, Account ocAccount) {
+        mFile = file;
+        if (ocAccount != null && ( 
+                mStorageManager == null || 
+                (mAccount != null && !mAccount.equals(ocAccount))
+           )) {
+            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+        }
+        mAccount = ocAccount;
+        updateFileDetails(false);
+    }
+    */
+    
+
+    private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
+
+        /**
+         * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
+         * 
+         * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+         */
+        private final WeakReference<ImageView> mImageViewRef;
+        
+        
+        /**
+         * Constructor.
+         * 
+         * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
+         */
+        public BitmapLoader(ImageView imageView) {
+            mImageViewRef = new WeakReference<ImageView>(imageView);
+        }
+        
+        
+        @SuppressWarnings("deprecation")
+        @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20
+               @Override
+        protected Bitmap doInBackground(String... params) {
+            Bitmap result = null;
+            if (params.length != 1) return result;
+            String storagePath = params[0];
+            try {
+                // set desired options that will affect the size of the bitmap
+                BitmapFactory.Options options = new Options();
+                options.inScaled = true;
+                options.inPurgeable = true;
+                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+                    options.inPreferQualityOverSpeed = false;
+                }
+                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+                    options.inMutable = false;
+                }
+                // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
+                options.inJustDecodeBounds = true;
+                BitmapFactory.decodeFile(storagePath, options);   
+                
+                int width = options.outWidth;
+                int height = options.outHeight;
+                int scale = 1;
+                if (width >= 2048 || height >= 2048) {  
+                    // try to scale down the image to save memory  
+                    scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));
+                    options.inSampleSize = scale;
+                }
+                Display display = getActivity().getWindowManager().getDefaultDisplay();
+                Point size = new Point();
+                int screenwidth;
+                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
+                    display.getSize(size);
+                    screenwidth = size.x;
+                } else {
+                    screenwidth = display.getWidth();
+                }
+
+                Log.d(TAG, "image width: " + width + ", screen width: " + screenwidth);
+
+                if (width > screenwidth) {
+                    // second try to scale down the image , this time depending upon the screen size; WTF... 
+                    scale = (int) Math.ceil((float)width / screenwidth);
+                    options.inSampleSize = scale;
+                }
+
+                // really load the bitmap
+                options.inJustDecodeBounds = false; // the next decodeFile call will be real
+                result = BitmapFactory.decodeFile(storagePath, options);
+                Log.e(TAG, "loaded width: " + options.outWidth + ", loaded height: " + options.outHeight);
+
+            } catch (OutOfMemoryError e) {
+                result = null;
+                Log.e(TAG, "Out of memory occured for file with size " + storagePath);
+                
+            } catch (NoSuchFieldError e) {
+                result = null;
+                Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);
+                
+            } catch (Throwable t) {
+                result = null;
+                Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);
+            }
+            return result;
+        }
+        
+        @Override
+        protected void onPostExecute(Bitmap result) {
+            if (result != null && mImageViewRef != null) {
+                final ImageView imageView = mImageViewRef.get();
+                imageView.setImageBitmap(result);
+                mBitmap  = result;
+            }
+        }
+        
+    }
+
+    /**
+     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed.
+     * 
+     * @param file      File to test if can be previewed.
+     * @return          'True' if the file can be handled by the fragment.
+     */
+    public static boolean canBePreviewed(OCFile file) {
+        return (file != null && file.isImage());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        if (operation.equals(mLastRemoteOperation) && operation instanceof RemoveFileOperation) {
+            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+        }
+    }
+    
+    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+        getActivity().dismissDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
+        
+        if (result.isSuccess()) {
+            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
+            msg.show();
+            finish();
+                
+        } else {
+            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
+            msg.show();
+            if (result.isSslRecoverableException()) {
+                // TODO show the SSL warning dialog
+            }
+        }
+    }
+
+    /**
+     * Finishes the preview
+     */
+    private void finish() {
+        Activity container = getActivity();
+        container.finish();
+    }
+    
+
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java b/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java
new file mode 100644 (file)
index 0000000..22aa495
--- /dev/null
@@ -0,0 +1,288 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013  ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.PagerAdapter;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.fragment.FileDownloadFragment;
+
+/**
+ * Adapter class that provides Fragment instances  
+ * 
+ * @author David A. Velasco
+ */
+//public class PreviewImagePagerAdapter extends PagerAdapter {
+public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
+    
+    private static final String TAG = PreviewImagePagerAdapter.class.getSimpleName();
+            
+    private Vector<OCFile> mImageFiles;
+    private Account mAccount;
+    private Set<Object> mObsoleteFragments;
+    private DataStorageManager mStorageManager;
+    
+    /*
+    private final FragmentManager mFragmentManager;
+    private FragmentTransaction mCurTransaction = null;
+    private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
+    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
+    private Fragment mCurrentPrimaryItem = null;
+    */
+
+    /**
+     * Constructor.
+     * 
+     * @param fragmentManager   {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter. 
+     * @param parentFolder      Folder where images will be searched for.
+     * @param storageManager    Bridge to database.
+     */
+    public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, DataStorageManager storageManager) {
+        super(fragmentManager);
+
+        if (fragmentManager == null) {
+            throw new IllegalArgumentException("NULL FragmentManager instance");
+        }
+        if (parentFolder == null) {
+            throw new IllegalArgumentException("NULL parent folder");
+        } 
+        if (storageManager == null) {
+            throw new IllegalArgumentException("NULL storage manager");
+        }
+
+        mAccount = account;
+        mStorageManager = storageManager;
+        mImageFiles = mStorageManager.getDirectoryImages(parentFolder); 
+        mObsoleteFragments = new HashSet<Object>();
+    }
+
+    
+    /**
+     * Returns the image files handled by the adapter.
+     * 
+     * @return  A vector with the image files handled by the adapter.
+     */
+    protected OCFile getFileAt(int position) {
+        return mImageFiles.get(position);
+    }
+
+    
+    public Fragment getItem(int i) {
+        Log.e(TAG, "GETTING PAGE " + i);
+        OCFile file = mImageFiles.get(i);
+        Fragment fragment = null;
+        if (file.isDown()) {
+            fragment = new PreviewImageFragment(file, mAccount);
+        } else {
+            fragment = new FileDownloadFragment(file, mAccount);
+        }
+        return fragment;
+    }
+
+    @Override
+    public int getCount() {
+        return mImageFiles.size();
+    }
+
+    @Override
+    public CharSequence getPageTitle(int position) {
+        return mImageFiles.get(position).getFileName();
+    }
+
+    public void updateFile(int position, OCFile file) {
+        mImageFiles.set(position, file);
+        mObsoleteFragments.add(instantiateItem(null, position));
+    }
+    
+    @Override
+    public int getItemPosition(Object object) {
+        Log.e(TAG, "getItemPosition ");
+        if (mObsoleteFragments.contains(object)) {
+            return POSITION_NONE;
+        }
+        return super.getItemPosition(object);
+    }
+    
+    /* *
+     * Called when a change in the shown pages is going to start being made.
+     * 
+     * @param   container   The containing View which is displaying this adapter's page views.
+     * -/
+    @Override
+    public void startUpdate(ViewGroup container) {
+        Log.e(TAG, "** startUpdate");
+    }
+
+    @Override
+    public Object instantiateItem(ViewGroup container, int position) {
+        Log.e(TAG, "** instantiateItem " + position);
+        
+        if (mFragments.size() > position) {
+            Fragment fragment = mFragments.get(position);
+            if (fragment != null) {
+                Log.e(TAG, "** \t returning cached item");
+                return fragment;
+            }
+        }
+
+        if (mCurTransaction == null) {
+            mCurTransaction = mFragmentManager.beginTransaction();
+        }
+
+        Fragment fragment = getItem(position);
+        if (mSavedState.size() > position) {
+            Fragment.SavedState savedState = mSavedState.get(position);
+            if (savedState != null) {
+                // TODO WATCH OUT:
+                // * The Fragment must currently be attached to the FragmentManager.
+                // * A new Fragment created using this saved state must be the same class type as the Fragment it was created from.
+                // * The saved state can not contain dependencies on other fragments -- that is it can't use putFragment(Bundle, String, Fragment) 
+                //   to store a fragment reference                 
+                fragment.setInitialSavedState(savedState);
+            }
+        }
+        while (mFragments.size() <= position) {
+            mFragments.add(null);
+        }
+        fragment.setMenuVisibility(false);
+        mFragments.set(position, fragment);
+        Log.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
+        mCurTransaction.add(container.getId(), fragment);
+
+        return fragment;
+    }
+
+    @Override
+    public void destroyItem(ViewGroup container, int position, Object object) {
+        Log.e(TAG, "** destroyItem " + position);
+        Fragment fragment = (Fragment)object;
+        
+        if (mCurTransaction == null) {
+            mCurTransaction = mFragmentManager.beginTransaction();
+        }
+        Log.e(TAG, "** \t removing fragment at position " + position);
+        while (mSavedState.size() <= position) {
+            mSavedState.add(null);
+        }
+        mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
+        mFragments.set(position, null);
+
+        mCurTransaction.remove(fragment);
+    }
+
+    @Override
+    public void setPrimaryItem(ViewGroup container, int position, Object object) {
+        Fragment fragment = (Fragment)object;
+        if (fragment != mCurrentPrimaryItem) {
+            if (mCurrentPrimaryItem != null) {
+                mCurrentPrimaryItem.setMenuVisibility(false);
+            }
+            if (fragment != null) {
+                fragment.setMenuVisibility(true);
+            }
+            mCurrentPrimaryItem = fragment;
+        }
+    }
+
+    @Override
+    public void finishUpdate(ViewGroup container) {
+        Log.e(TAG, "** finishUpdate (start)");
+        if (mCurTransaction != null) {
+            mCurTransaction.commitAllowingStateLoss();
+            mCurTransaction = null;
+            mFragmentManager.executePendingTransactions();
+        }
+        Log.e(TAG, "** finishUpdate (end)");
+    }
+
+    @Override
+    public boolean isViewFromObject(View view, Object object) {
+        return ((Fragment)object).getView() == view;
+    }
+
+    @Override
+    public Parcelable saveState() {
+        Bundle state = null;
+        if (mSavedState.size() > 0) {
+            state = new Bundle();
+            Fragment.SavedState[] savedStates = new Fragment.SavedState[mSavedState.size()];
+            mSavedState.toArray(savedStates);
+            state.putParcelableArray("states", savedStates);
+        }
+        for (int i=0; i<mFragments.size(); i++) {
+            Fragment fragment = mFragments.get(i);
+            if (fragment != null) {
+                if (state == null) {
+                    state = new Bundle();
+                }
+                String key = "f" + i;
+                mFragmentManager.putFragment(state, key, fragment);
+            }
+        }
+        return state;
+    }
+
+    @Override
+    public void restoreState(Parcelable state, ClassLoader loader) {
+        if (state != null) {
+            Bundle bundle = (Bundle)state;
+            bundle.setClassLoader(loader);
+            Parcelable[] states = bundle.getParcelableArray("states");
+            mSavedState.clear();
+            mFragments.clear();
+            if (states != null) {
+                for (int i=0; i<states.length; i++) {
+                    mSavedState.add((Fragment.SavedState)states[i]);
+                }
+            }
+            Iterable<String> keys = bundle.keySet();
+            for (String key: keys) {
+                if (key.startsWith("f")) {
+                    int index = Integer.parseInt(key.substring(1));
+                    Fragment f = mFragmentManager.getFragment(bundle, key);
+                    if (f != null) {
+                        while (mFragments.size() <= index) {
+                            mFragments.add(null);
+                        }
+                        f.setMenuVisibility(false);
+                        mFragments.set(index, f);
+                    } else {
+                        Log.w(TAG, "Bad fragment at key " + key);
+                    }
+                }
+            }
+        }
+    } */
+    
+}