<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
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
+++ /dev/null
-/* 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) {
- }
-
-}
private DownloadFinishReceiver mDownloadFinishReceiver;
public ProgressListener mProgressListener;
+ private boolean mListening;
private static final String TAG = FileDownloadFragment.class.getSimpleName();
mAccount = null;
mStorageManager = null;
mProgressListener = null;
+ mListening = false;
}
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;
}
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;
@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;
@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());;
}
@Override
public View getView() {
+ if (!mListening) {
+ listenForTransferProgress();
+ }
return super.getView() == null ? mView : super.getView();
}
/**
* 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()) {
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);
}
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);
}
//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);
}
if (downloadWasFine) {
mFile = mStorageManager.getFileByPath(downloadedRemotePath);
}
- mContainerActivity.notifySuccessfulDownload(mFile, intent, downloadWasFine);
+ updateView(false);
getActivity().removeStickyBroadcast(intent);
- updateView();
+ mContainerActivity.notifySuccessfulDownload(mFile, intent, downloadWasFine);
}
}
}
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();
}
}
}
if (mContainerActivity.getFileDownloaderBinder() != null) {
mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
}
- if (mContainerActivity.getFileUploaderBinder() != null) {
- mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
- }
}
}
+++ /dev/null
-/* 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();
- }
-
-
-}
--- /dev/null
+/* 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) {
+ }
+
+}
--- /dev/null
+/* 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();
+ }
+
+
+}
--- /dev/null
+/* 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);
+ }
+ }
+ }
+ }
+ } */
+
+}