From 18a715072c2c12d9779586ec171c7301207a53fd Mon Sep 17 00:00:00 2001 From: zerginator Date: Sun, 10 Mar 2013 20:38:46 +0100 Subject: [PATCH 01/10] moved About App into preferences https://github.com/owncloud/android/issues/57 --- res/menu/menu.xml | 1 - res/values/strings.xml | 3 +- res/xml/preferences.xml | 2 +- .../ui/activity/FileDisplayActivity.java | 45 -- .../android/ui/activity/Preferences.java | 438 ++++++++---------- 5 files changed, 204 insertions(+), 285 deletions(-) diff --git a/res/menu/menu.xml b/res/menu/menu.xml index 9ff7342f0d..68011f45ad 100644 --- a/res/menu/menu.xml +++ b/res/menu/menu.xml @@ -26,5 +26,4 @@ - diff --git a/res/values/strings.xml b/res/values/strings.xml index f518bdab47..45e2a4e333 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -15,7 +15,8 @@ Settings Setup Account There is no account set up on your device. In order to use this App, you need to create one. - %1$s Android App\n\nversion: %2$s + Android App + version: Refresh Upload Content from other apps diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 3b168f54eb..634f84163a 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -33,7 +33,7 @@ android:title="@string/prefs_instant_upload" android:summary="@string/prefs_instant_upload_summary"/> - + diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 46ed65e679..a9fb902da1 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -122,7 +122,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF private static final int DIALOG_SETUP_ACCOUNT = 0; private static final int DIALOG_CREATE_DIR = 1; - private static final int DIALOG_ABOUT_APP = 2; public static final int DIALOG_SHORT_WAIT = 3; private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4; private static final int DIALOG_SSL_VALIDATOR = 5; @@ -136,7 +135,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF private static final String TAG = "FileDisplayActivity"; - private static int[] mMenuIdentifiersToPatch = {R.id.about_app}; @Override public void onCreate(Bundle savedInstanceState) { @@ -320,32 +318,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getSherlock().getMenuInflater(); inflater.inflate(R.menu.menu, menu); - - patchHiddenAccents(menu); - return true; } - /** - * Workaround for this: http://code.google.com/p/android/issues/detail?id=3974 - * - * @param menu Menu to patch - */ - private void patchHiddenAccents(Menu menu) { - for (int i = 0; i < mMenuIdentifiersToPatch.length ; i++) { - MenuItem aboutItem = menu.findItem(mMenuIdentifiersToPatch[i]); - if (aboutItem != null && aboutItem.getIcon() instanceof BitmapDrawable) { - // Clip off the bottom three (density independent) pixels of transparent padding - Bitmap original = ((BitmapDrawable) aboutItem.getIcon()).getBitmap(); - float scale = getResources().getDisplayMetrics().density; - int clippedHeight = (int) (original.getHeight() - (3 * scale)); - Bitmap scaled = Bitmap.createBitmap(original, 0, 0, original.getWidth(), clippedHeight); - aboutItem.setIcon(new BitmapDrawable(getResources(), scaled)); - } - } - } - - @Override public boolean onOptionsItemSelected(MenuItem item) { boolean retval = true; @@ -367,10 +342,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF startActivity(settingsIntent); break; } - case R.id.about_app: { - showDialog(DIALOG_ABOUT_APP); - break; - } case android.R.id.home: { if (mCurrentDir != null && mCurrentDir.getParentId() != 0) { onBackPressed(); @@ -650,22 +621,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF dialog = builder.create(); break; } - case DIALOG_ABOUT_APP: { - builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.about_title)); - PackageInfo pkg; - try { - pkg = getPackageManager().getPackageInfo(getPackageName(), 0); - builder.setMessage(String.format(getString(R.string.about_message), getString(R.string.app_name), pkg.versionName)); - builder.setIcon(android.R.drawable.ic_menu_info_details); - dialog = builder.create(); - } catch (NameNotFoundException e) { - builder = null; - dialog = null; - Log.e(TAG, "Error while showing about dialog", e); - } - break; - } case DIALOG_CREATE_DIR: { builder = new Builder(this); final EditText dirNameInput = new EditText(getBaseContext()); diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index 460c5e0c95..35638c5e75 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -1,237 +1,201 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * 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 . - * - */ -package com.owncloud.android.ui.activity; - -import java.util.Vector; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceManager; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.Preference.OnPreferenceClickListener; -import android.util.Log; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockPreferenceActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuItem; -import com.owncloud.android.OwnCloudSession; -import com.owncloud.android.db.DbHandler; - -import com.owncloud.android.R; - -/** - * An Activity that allows the user to change the application's settings. - * - * @author Bartek Przybylski - * - */ -public class Preferences extends SherlockPreferenceActivity implements - OnPreferenceChangeListener{ - private static final String TAG = "OwnCloudPreferences"; - private final int mNewSession = 47; - private final int mEditSession = 48; - private DbHandler mDbHandler; - private Vector mSessions; - //private Account[] mAccounts; - //private ListPreference mAccountList; - private ListPreference mTrackingUpdateInterval; - private CheckBoxPreference mDeviceTracking; - private CheckBoxPreference pCode; - private int mSelectedMenuItem; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mDbHandler = new DbHandler(getBaseContext()); - mSessions = new Vector(); - addPreferencesFromResource(R.xml.preferences); - //populateAccountList(); - ActionBar actionBar = getSherlock().getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - Preference p = findPreference("manage_account"); - if (p != null) - p.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class); - startActivity(i); - return true; - } - }); - - pCode = (CheckBoxPreference) findPreference("set_pincode"); - - - if (pCode != null){ - - pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - - Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); - i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences"); - i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString()); - - startActivity(i); - - return true; - } - }); - - } - - } - - - @Override - protected void onResume() { - // TODO Auto-generated method stub - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - boolean state = appPrefs.getBoolean("set_pincode", false); - pCode.setChecked(state); - - super.onResume(); - } - - - - /** - * Populates the account selector - *-/ - private void populateAccountList() { - AccountManager accMan = AccountManager.get(this); - mAccounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - mAccountList = (ListPreference) findPreference("select_oc_account"); - mAccountList.setOnPreferenceChangeListener(this); - - // Display the name of the current account if there is any - Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this); - if (defaultAccount != null) { - mAccountList.setSummary(defaultAccount.name); - } - - // Transform accounts into array of string for preferences to use - String[] accNames = new String[mAccounts.length]; - for (int i = 0; i < mAccounts.length; i++) { - Account account = mAccounts[i]; - accNames[i] = account.name; - } - - mAccountList.setEntries(accNames); - mAccountList.setEntryValues(accNames); - }*/ - - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - //MenuInflater inflater = getSherlock().getMenuInflater(); - //inflater.inflate(R.menu.prefs_menu, menu); - return true; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - super.onMenuItemSelected(featureId, item); - Intent intent; - - switch (item.getItemId()) { - //case R.id.addSessionItem: - case 1: - intent = new Intent(this, PreferencesNewSession.class); - startActivityForResult(intent, mNewSession); - break; - case R.id.SessionContextEdit: - intent = new Intent(this, PreferencesNewSession.class); - intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem) - .getEntryId()); - intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem) - .getName()); - intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem) - .getUrl()); - startActivityForResult(intent, mEditSession); - break; - case android.R.id.home: - intent = new Intent(getBaseContext(), FileDisplayActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - break; - default: - Log.w(TAG, "Unknown menu item triggered"); - return false; - } - return true; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onDestroy() { - mDbHandler.close(); - super.onDestroy(); - } - - - - @Override - /** - * Updates various summaries after updates. Also starts and stops - * the - */ - public boolean onPreferenceChange(Preference preference, Object newValue) { - // Update current account summary - /*if (preference.equals(mAccountList)) { - mAccountList.setSummary(newValue.toString()); - } - - // Update tracking interval summary - else*/ if (preference.equals(mTrackingUpdateInterval)) { - String trackingSummary = getResources().getString( - R.string.prefs_trackmydevice_interval_summary); - trackingSummary = String.format(trackingSummary, - newValue.toString()); - mTrackingUpdateInterval.setSummary(trackingSummary); - } - - // Start or stop tracking service - else if (preference.equals(mDeviceTracking)) { - Intent locationServiceIntent = new Intent(); - locationServiceIntent - .setAction("com.owncloud.android.location.LocationLauncher"); - locationServiceIntent.putExtra("TRACKING_SETTING", - (Boolean) newValue); - sendBroadcast(locationServiceIntent); - } - return true; - } - - - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * 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 . + * + */ +package com.owncloud.android.ui.activity; + +import java.util.Vector; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockPreferenceActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.owncloud.android.OwnCloudSession; +import com.owncloud.android.R; +import com.owncloud.android.db.DbHandler; + +/** + * An Activity that allows the user to change the application's settings. + * + * @author Bartek Przybylski + * + */ +public class Preferences extends SherlockPreferenceActivity implements OnPreferenceChangeListener { + + private static final String TAG = "OwnCloudPreferences"; + private final int mNewSession = 47; + private final int mEditSession = 48; + private DbHandler mDbHandler; + private Vector mSessions; + private ListPreference mTrackingUpdateInterval; + private CheckBoxPreference mDeviceTracking; + private CheckBoxPreference pCode; + private Preference pAboutApp; + private int mSelectedMenuItem; + + @SuppressWarnings("deprecation") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mDbHandler = new DbHandler(getBaseContext()); + mSessions = new Vector(); + addPreferencesFromResource(R.xml.preferences); + //populateAccountList(); + ActionBar actionBar = getSherlock().getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + Preference p = findPreference("manage_account"); + if (p != null) + p.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class); + startActivity(i); + return true; + } + }); + + pCode = (CheckBoxPreference) findPreference("set_pincode"); + if (pCode != null){ + pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); + i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences"); + i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString()); + startActivity(i); + return true; + } + }); + + /* About App */ + pAboutApp = (Preference) findPreference("about_app"); + if (pAboutApp != null) { + pAboutApp.setTitle(getString(R.string.app_name)+" "+getString(R.string.about_android)); + PackageInfo pkg; + try { + pkg = getPackageManager().getPackageInfo(getPackageName(), 0); + pAboutApp.setSummary(getString(R.string.about_version)+" "+pkg.versionName); + } catch (NameNotFoundException e) { + Log.e(TAG, "Error while showing about dialog", e); + } + } + } + } + + @Override + protected void onResume() { + SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + boolean state = appPrefs.getBoolean("set_pincode", false); + pCode.setChecked(state); + super.onResume(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + super.onMenuItemSelected(featureId, item); + Intent intent; + + switch (item.getItemId()) { + //case R.id.addSessionItem: + case 1: + intent = new Intent(this, PreferencesNewSession.class); + startActivityForResult(intent, mNewSession); + break; + case R.id.SessionContextEdit: + intent = new Intent(this, PreferencesNewSession.class); + intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem) + .getEntryId()); + intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem) + .getName()); + intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem) + .getUrl()); + startActivityForResult(intent, mEditSession); + break; + case android.R.id.home: + intent = new Intent(getBaseContext(), FileDisplayActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + break; + default: + Log.w(TAG, "Unknown menu item triggered"); + return false; + } + return true; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onDestroy() { + mDbHandler.close(); + super.onDestroy(); + } + + @Override + /** + * Updates various summaries after updates. Also starts and stops + * the + */ + public boolean onPreferenceChange(Preference preference, Object newValue) { + // Update current account summary + /*if (preference.equals(mAccountList)) { + mAccountList.setSummary(newValue.toString()); + } + + // Update tracking interval summary + else*/ if (preference.equals(mTrackingUpdateInterval)) { + String trackingSummary = getResources().getString( + R.string.prefs_trackmydevice_interval_summary); + trackingSummary = String.format(trackingSummary, + newValue.toString()); + mTrackingUpdateInterval.setSummary(trackingSummary); + } + + // Start or stop tracking service + else if (preference.equals(mDeviceTracking)) { + Intent locationServiceIntent = new Intent(); + locationServiceIntent + .setAction("com.owncloud.android.location.LocationLauncher"); + locationServiceIntent.putExtra("TRACKING_SETTING", + (Boolean) newValue); + sendBroadcast(locationServiceIntent); + } + return true; + } +} From 8e36e7cc3e6218ccb80ee2af3eb0a19df24e339f Mon Sep 17 00:00:00 2001 From: zerginator Date: Tue, 12 Mar 2013 07:56:27 +0100 Subject: [PATCH 02/10] This wraps the android.util.logging into Log_OC which , if its enabled in the app, logs the logcat into a file. It also includes the phone information (MODEL, VERSION...) https://github.com/owncloud/android/issues/97 --- res/values/strings.xml | 2 + res/xml/preferences.xml | 7 +- src/com/owncloud/android/Uploader.java | 814 +++---- .../authenticator/AccountAuthenticator.java | 565 ++--- .../datamodel/FileDataStorageManager.java | 23 +- .../owncloud/android/datamodel/OCFile.java | 6 +- src/com/owncloud/android/db/DbHandler.java | 8 +- .../extensions/ExtensionsAvailableDialog.java | 3 +- .../extensions/ExtensionsListActivity.java | 3 +- .../files/BootupBroadcastReceiver.java | 7 +- .../files/InstantUploadBroadcastReceiver.java | 21 +- .../android/files/OwnCloudFileObserver.java | 5 +- .../files/services/FileDownloader.java | 833 +++---- .../files/services/FileObserverService.java | 23 +- .../android/files/services/FileUploader.java | 33 +- .../files/services/InstantUploadService.java | 5 +- .../LocationServiceLauncherReciever.java | 6 +- .../location/LocationUpdateService.java | 5 +- .../network/AdvancedSslSocketFactory.java | 8 +- .../network/AdvancedX509TrustManager.java | 4 +- .../android/network/OwnCloudClientUtils.java | 13 +- .../ChunkedUploadFileOperation.java | 3 +- .../operations/ConnectionCheckOperation.java | 9 +- .../operations/DownloadFileOperation.java | 7 +- .../operations/RemoveFileOperation.java | 5 +- .../operations/RenameFileOperation.java | 7 +- .../operations/SynchronizeFileOperation.java | 5 +- .../SynchronizeFolderOperation.java | 19 +- .../operations/UpdateOCVersionOperation.java | 11 +- .../operations/UploadFileOperation.java | 11 +- .../providers/FileContentProvider.java | 579 ++--- .../android/syncadapter/FileSyncAdapter.java | 741 +++--- .../ui/activity/AccountSelectActivity.java | 3 +- .../ui/activity/AuthenticatorActivity.java | 1219 +++++----- .../ui/activity/ConflictsResolveActivity.java | 3 +- .../ErrorsWhileCopyingHandlerActivity.java | 7 +- .../ui/activity/FileDetailActivity.java | 461 ++-- .../ui/activity/FileDisplayActivity.java | 35 +- .../ui/activity/InstantUploadActivity.java | 27 +- .../android/ui/activity/Preferences.java | 34 +- .../ui/activity/UploadFilesActivity.java | 15 +- .../android/ui/dialog/SslValidatorDialog.java | 5 +- .../fragment/ConfirmationDialogFragment.java | 3 +- .../ui/fragment/FileDetailFragment.java | 2125 +++++++++-------- .../ui/fragment/LocalFileListFragment.java | 21 +- .../ui/fragment/OCFileListFragment.java | 27 +- .../ChunkFromFileChannelRequestEntity.java | 4 +- src/eu/alefzero/webdav/FileRequestEntity.java | 4 +- src/eu/alefzero/webdav/WebdavClient.java | 684 +++--- src/eu/alefzero/webdav/WebdavEntry.java | 4 +- 50 files changed, 4280 insertions(+), 4192 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 45e2a4e333..39c88f990e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -41,6 +41,8 @@ Protect your client Enable instant uploads Instantly upload photos taken by camera + Enable Logging + This is used to log problems URL Username Password diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 634f84163a..c3f9478996 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -33,7 +33,12 @@ android:title="@string/prefs_instant_upload" android:summary="@string/prefs_instant_upload_summary"/> - + + diff --git a/src/com/owncloud/android/Uploader.java b/src/com/owncloud/android/Uploader.java index 6f9dc6ddde..438308904d 100644 --- a/src/com/owncloud/android/Uploader.java +++ b/src/com/owncloud/android/Uploader.java @@ -1,407 +1,407 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * 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 . - * - */ -package com.owncloud.android; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Stack; -import java.util.Vector; - -import com.owncloud.android.authenticator.AccountAuthenticator; -import com.owncloud.android.datamodel.DataStorageManager; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileUploader; -import com.owncloud.android.network.OwnCloudClientUtils; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.ListActivity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Parcelable; -import android.provider.MediaStore.Images.Media; -import android.util.Log; -import android.view.View; -import android.view.Window; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.Button; -import android.widget.EditText; -import android.widget.SimpleAdapter; -import android.widget.Toast; - -import com.owncloud.android.R; -import eu.alefzero.webdav.WebdavClient; - -/** - * This can be used to upload things to an ownCloud instance. - * - * @author Bartek Przybylski - * - */ -public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { - private static final String TAG = "ownCloudUploader"; - - private Account mAccount; - private AccountManager mAccountManager; - private Stack mParents; - private ArrayList mStreamsToUpload; - private boolean mCreateDir; - private String mUploadPath; - private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE }; - private DataStorageManager mStorageManager; - private OCFile mFile; - - private final static int DIALOG_NO_ACCOUNT = 0; - private final static int DIALOG_WAITING = 1; - private final static int DIALOG_NO_STREAM = 2; - private final static int DIALOG_MULTIPLE_ACCOUNT = 3; - //private final static int DIALOG_GET_DIRNAME = 4; - - private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - mParents = new Stack(); - mParents.add(""); - /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { - prepareStreamsToUpload();*/ - if (prepareStreamsToUpload()) { - mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - if (accounts.length == 0) { - Log.i(TAG, "No ownCloud account is available"); - showDialog(DIALOG_NO_ACCOUNT); - } else if (accounts.length > 1) { - Log.i(TAG, "More then one ownCloud is available"); - showDialog(DIALOG_MULTIPLE_ACCOUNT); - } else { - mAccount = accounts[0]; - mStorageManager = new FileDataStorageManager(mAccount, getContentResolver()); - populateDirectoryList(); - } - } else { - showDialog(DIALOG_NO_STREAM); - } - } - - @Override - protected Dialog onCreateDialog(final int id) { - final AlertDialog.Builder builder = new Builder(this); - switch (id) { - case DIALOG_WAITING: - ProgressDialog pDialog = new ProgressDialog(this); - pDialog.setIndeterminate(false); - pDialog.setCancelable(false); - pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading)); - return pDialog; - case DIALOG_NO_ACCOUNT: - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.uploader_wrn_no_account_title); - builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name))); - builder.setCancelable(false); - builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) { - // using string value since in API7 this - // constatn is not defined - // in API7 < this constatant is defined in - // Settings.ADD_ACCOUNT_SETTINGS - // and Settings.EXTRA_AUTHORITIES - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); - } else { - // since in API7 there is no direct call for - // account setup, so we need to - // show our own AccountSetupAcricity, get - // desired results and setup - // everything for ourself - Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class); - startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); - } - } - }); - builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - return builder.create(); - /*case DIALOG_GET_DIRNAME: - final EditText dirName = new EditText(getBaseContext()); - builder.setView(dirName); - builder.setTitle(R.string.uploader_info_dirname); - String pathToUpload; - if (mParents.empty()) { - pathToUpload = "/"; - } else { - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null, - null, null, null); - mCursor.moveToFirst(); - pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) - + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); // TODO don't make this ; use WebdavUtils.encode in the right moment - } - a a = new a(pathToUpload, dirName); - builder.setPositiveButton(R.string.common_ok, a); - builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - return builder.create();*/ - case DIALOG_MULTIPLE_ACCOUNT: - CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; - for (int i = 0; i < ac.length; ++i) { - ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; - } - builder.setTitle(R.string.common_choose_account); - builder.setItems(ac, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; - mStorageManager = new FileDataStorageManager(mAccount, getContentResolver()); - populateDirectoryList(); - } - }); - builder.setCancelable(true); - builder.setOnCancelListener(new OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - dialog.cancel(); - finish(); - } - }); - return builder.create(); - case DIALOG_NO_STREAM: - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.uploader_wrn_no_content_title); - builder.setMessage(R.string.uploader_wrn_no_content_text); - builder.setCancelable(false); - builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - return builder.create(); - default: - throw new IllegalArgumentException("Unknown dialog id: " + id); - } - } - - class a implements OnClickListener { - String mPath; - EditText mDirname; - - public a(String path, EditText dirname) { - mPath = path; - mDirname = dirname; - } - - @Override - public void onClick(DialogInterface dialog, int which) { - Uploader.this.mUploadPath = mPath + mDirname.getText().toString(); - Uploader.this.mCreateDir = true; - uploadFiles(); - } - } - - @Override - public void onBackPressed() { - - if (mParents.size() <= 1) { - super.onBackPressed(); - return; - } else { - mParents.pop(); - populateDirectoryList(); - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - // click on folder in the list - Log.d(TAG, "on item click"); - Vector tmpfiles = mStorageManager.getDirectoryContent(mFile); - if (tmpfiles.size() <= 0) return; - // filter on dirtype - Vector files = new Vector(); - for (OCFile f : tmpfiles) - if (f.isDirectory()) - files.add(f); - if (files.size() < position) { - throw new IndexOutOfBoundsException("Incorrect item selected"); - } - mParents.push(files.get(position).getFileName()); - populateDirectoryList(); - } - - @Override - public void onClick(View v) { - // click on button - switch (v.getId()) { - case R.id.uploader_choose_folder: - mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix - for (String p : mParents) - mUploadPath += p + OCFile.PATH_SEPARATOR; - Log.d(TAG, "Uploading file to dir " + mUploadPath); - - uploadFiles(); - - break; - /*case android.R.id.button1: // dynamic action for create aditional dir - showDialog(DIALOG_GET_DIRNAME); - break;*/ - default: - throw new IllegalArgumentException("Wrong element clicked"); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); - if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { - dismissDialog(DIALOG_NO_ACCOUNT); - if (resultCode == RESULT_CANCELED) { - finish(); - } - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); - if (accounts.length == 0) { - showDialog(DIALOG_NO_ACCOUNT); - } else { - // there is no need for checking for is there more then one - // account at this point - // since account setup can set only one account at time - mAccount = accounts[0]; - populateDirectoryList(); - } - } - } - - private void populateDirectoryList() { - setContentView(R.layout.uploader_layout); - - String full_path = ""; - for (String a : mParents) - full_path += a + "/"; - - Log.d(TAG, "Populating view with content of : " + full_path); - - mFile = mStorageManager.getFileByPath(full_path); - if (mFile != null) { - Vector files = mStorageManager.getDirectoryContent(mFile); - List> data = new LinkedList>(); - for (OCFile f : files) { - HashMap h = new HashMap(); - if (f.isDirectory()) { - h.put("dirname", f.getFileName()); - data.add(h); - } - } - SimpleAdapter sa = new SimpleAdapter(this, - data, - R.layout.uploader_list_item_layout, - new String[] {"dirname"}, - new int[] {R.id.textView1}); - setListAdapter(sa); - Button btn = (Button) findViewById(R.id.uploader_choose_folder); - btn.setOnClickListener(this); - getListView().setOnItemClickListener(this); - } - } - - private boolean prepareStreamsToUpload() { - if (getIntent().getAction().equals(Intent.ACTION_SEND)) { - mStreamsToUpload = new ArrayList(); - mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); - } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); - } - return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null); - } - - public void uploadFiles() { - try { - WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); - - // create last directory in path if necessary - if (mCreateDir) { - wdc.createDirectory(mUploadPath); - } - - String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()]; - - for (int i = 0; i < mStreamsToUpload.size(); ++i) { - Uri uri = (Uri) mStreamsToUpload.get(i); - if (uri.getScheme().equals("content")) { - Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i), - CONTENT_PROJECTION, - null, - null, - null); - - if (!c.moveToFirst()) - continue; - - final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), - data = c.getString(c.getColumnIndex(Media.DATA)); - local[i] = data; - remote[i] = mUploadPath + display_name; - } else if (uri.getScheme().equals("file")) { - final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "")); - local[i] = file.getAbsolutePath(); - remote[i] = mUploadPath + file.getName(); - } - - } - Intent intent = new Intent(getApplicationContext(), FileUploader.class); - intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES); - intent.putExtra(FileUploader.KEY_LOCAL_FILE, local); - intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote); - intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount); - startService(intent); - finish(); - - } catch (SecurityException e) { - String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name)); - Toast.makeText(this, message, Toast.LENGTH_LONG).show(); - } - } - -} +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * 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 . + * + */ +package com.owncloud.android; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; +import java.util.Vector; + +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.network.OwnCloudClientUtils; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.Dialog; +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Parcelable; +import android.provider.MediaStore.Images.Media; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.SimpleAdapter; +import android.widget.Toast; + +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +/** + * This can be used to upload things to an ownCloud instance. + * + * @author Bartek Przybylski + * + */ +public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { + private static final String TAG = "ownCloudUploader"; + + private Account mAccount; + private AccountManager mAccountManager; + private Stack mParents; + private ArrayList mStreamsToUpload; + private boolean mCreateDir; + private String mUploadPath; + private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE }; + private DataStorageManager mStorageManager; + private OCFile mFile; + + private final static int DIALOG_NO_ACCOUNT = 0; + private final static int DIALOG_WAITING = 1; + private final static int DIALOG_NO_STREAM = 2; + private final static int DIALOG_MULTIPLE_ACCOUNT = 3; + //private final static int DIALOG_GET_DIRNAME = 4; + + private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + mParents = new Stack(); + mParents.add(""); + /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { + prepareStreamsToUpload();*/ + if (prepareStreamsToUpload()) { + mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + if (accounts.length == 0) { + Log_OC.i(TAG, "No ownCloud account is available"); + showDialog(DIALOG_NO_ACCOUNT); + } else if (accounts.length > 1) { + Log_OC.i(TAG, "More then one ownCloud is available"); + showDialog(DIALOG_MULTIPLE_ACCOUNT); + } else { + mAccount = accounts[0]; + mStorageManager = new FileDataStorageManager(mAccount, getContentResolver()); + populateDirectoryList(); + } + } else { + showDialog(DIALOG_NO_STREAM); + } + } + + @Override + protected Dialog onCreateDialog(final int id) { + final AlertDialog.Builder builder = new Builder(this); + switch (id) { + case DIALOG_WAITING: + ProgressDialog pDialog = new ProgressDialog(this); + pDialog.setIndeterminate(false); + pDialog.setCancelable(false); + pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading)); + return pDialog; + case DIALOG_NO_ACCOUNT: + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.uploader_wrn_no_account_title); + builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name))); + builder.setCancelable(false); + builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) { + // using string value since in API7 this + // constatn is not defined + // in API7 < this constatant is defined in + // Settings.ADD_ACCOUNT_SETTINGS + // and Settings.EXTRA_AUTHORITIES + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); + } else { + // since in API7 there is no direct call for + // account setup, so we need to + // show our own AccountSetupAcricity, get + // desired results and setup + // everything for ourself + Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class); + startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); + } + } + }); + builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + return builder.create(); + /*case DIALOG_GET_DIRNAME: + final EditText dirName = new EditText(getBaseContext()); + builder.setView(dirName); + builder.setTitle(R.string.uploader_info_dirname); + String pathToUpload; + if (mParents.empty()) { + pathToUpload = "/"; + } else { + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null, + null, null, null); + mCursor.moveToFirst(); + pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); // TODO don't make this ; use WebdavUtils.encode in the right moment + } + a a = new a(pathToUpload, dirName); + builder.setPositiveButton(R.string.common_ok, a); + builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + return builder.create();*/ + case DIALOG_MULTIPLE_ACCOUNT: + CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; + for (int i = 0; i < ac.length; ++i) { + ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; + } + builder.setTitle(R.string.common_choose_account); + builder.setItems(ac, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; + mStorageManager = new FileDataStorageManager(mAccount, getContentResolver()); + populateDirectoryList(); + } + }); + builder.setCancelable(true); + builder.setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + dialog.cancel(); + finish(); + } + }); + return builder.create(); + case DIALOG_NO_STREAM: + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.uploader_wrn_no_content_title); + builder.setMessage(R.string.uploader_wrn_no_content_text); + builder.setCancelable(false); + builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + return builder.create(); + default: + throw new IllegalArgumentException("Unknown dialog id: " + id); + } + } + + class a implements OnClickListener { + String mPath; + EditText mDirname; + + public a(String path, EditText dirname) { + mPath = path; + mDirname = dirname; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + Uploader.this.mUploadPath = mPath + mDirname.getText().toString(); + Uploader.this.mCreateDir = true; + uploadFiles(); + } + } + + @Override + public void onBackPressed() { + + if (mParents.size() <= 1) { + super.onBackPressed(); + return; + } else { + mParents.pop(); + populateDirectoryList(); + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + // click on folder in the list + Log_OC.d(TAG, "on item click"); + Vector tmpfiles = mStorageManager.getDirectoryContent(mFile); + if (tmpfiles.size() <= 0) return; + // filter on dirtype + Vector files = new Vector(); + for (OCFile f : tmpfiles) + if (f.isDirectory()) + files.add(f); + if (files.size() < position) { + throw new IndexOutOfBoundsException("Incorrect item selected"); + } + mParents.push(files.get(position).getFileName()); + populateDirectoryList(); + } + + @Override + public void onClick(View v) { + // click on button + switch (v.getId()) { + case R.id.uploader_choose_folder: + mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix + for (String p : mParents) + mUploadPath += p + OCFile.PATH_SEPARATOR; + Log_OC.d(TAG, "Uploading file to dir " + mUploadPath); + + uploadFiles(); + + break; + /*case android.R.id.button1: // dynamic action for create aditional dir + showDialog(DIALOG_GET_DIRNAME); + break;*/ + default: + throw new IllegalArgumentException("Wrong element clicked"); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); + if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { + dismissDialog(DIALOG_NO_ACCOUNT); + if (resultCode == RESULT_CANCELED) { + finish(); + } + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); + if (accounts.length == 0) { + showDialog(DIALOG_NO_ACCOUNT); + } else { + // there is no need for checking for is there more then one + // account at this point + // since account setup can set only one account at time + mAccount = accounts[0]; + populateDirectoryList(); + } + } + } + + private void populateDirectoryList() { + setContentView(R.layout.uploader_layout); + + String full_path = ""; + for (String a : mParents) + full_path += a + "/"; + + Log_OC.d(TAG, "Populating view with content of : " + full_path); + + mFile = mStorageManager.getFileByPath(full_path); + if (mFile != null) { + Vector files = mStorageManager.getDirectoryContent(mFile); + List> data = new LinkedList>(); + for (OCFile f : files) { + HashMap h = new HashMap(); + if (f.isDirectory()) { + h.put("dirname", f.getFileName()); + data.add(h); + } + } + SimpleAdapter sa = new SimpleAdapter(this, + data, + R.layout.uploader_list_item_layout, + new String[] {"dirname"}, + new int[] {R.id.textView1}); + setListAdapter(sa); + Button btn = (Button) findViewById(R.id.uploader_choose_folder); + btn.setOnClickListener(this); + getListView().setOnItemClickListener(this); + } + } + + private boolean prepareStreamsToUpload() { + if (getIntent().getAction().equals(Intent.ACTION_SEND)) { + mStreamsToUpload = new ArrayList(); + mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); + } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); + } + return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null); + } + + public void uploadFiles() { + try { + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); + + // create last directory in path if necessary + if (mCreateDir) { + wdc.createDirectory(mUploadPath); + } + + String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()]; + + for (int i = 0; i < mStreamsToUpload.size(); ++i) { + Uri uri = (Uri) mStreamsToUpload.get(i); + if (uri.getScheme().equals("content")) { + Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i), + CONTENT_PROJECTION, + null, + null, + null); + + if (!c.moveToFirst()) + continue; + + final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), + data = c.getString(c.getColumnIndex(Media.DATA)); + local[i] = data; + remote[i] = mUploadPath + display_name; + } else if (uri.getScheme().equals("file")) { + final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "")); + local[i] = file.getAbsolutePath(); + remote[i] = mUploadPath + file.getName(); + } + + } + Intent intent = new Intent(getApplicationContext(), FileUploader.class); + intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES); + intent.putExtra(FileUploader.KEY_LOCAL_FILE, local); + intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote); + intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount); + startService(intent); + finish(); + + } catch (SecurityException e) { + String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name)); + Toast.makeText(this, message, Toast.LENGTH_LONG).show(); + } + } + +} diff --git a/src/com/owncloud/android/authenticator/AccountAuthenticator.java b/src/com/owncloud/android/authenticator/AccountAuthenticator.java index 9d8b4ab0f5..d0e99f5d1b 100644 --- a/src/com/owncloud/android/authenticator/AccountAuthenticator.java +++ b/src/com/owncloud/android/authenticator/AccountAuthenticator.java @@ -1,282 +1,283 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * 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 . - * - */ - -package com.owncloud.android.authenticator; - -import com.owncloud.android.ui.activity.AuthenticatorActivity; - -import android.accounts.*; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; - -public class AccountAuthenticator extends AbstractAccountAuthenticator { - /** - * Is used by android system to assign accounts to authenticators. Should be - * used by application and all extensions. - */ - public static final String ACCOUNT_TYPE = "owncloud"; - public static final String AUTH_TOKEN_TYPE = "org.owncloud"; - - public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType"; - public static final String KEY_REQUIRED_FEATURES = "requiredFeatures"; - public static final String KEY_LOGIN_OPTIONS = "loginOptions"; - public static final String KEY_ACCOUNT = "account"; - /** - * Value under this key should handle path to webdav php script. Will be - * removed and usage should be replaced by combining - * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and - * {@link com.owncloud.android.utils.OwnCloudVersion} - * - * @deprecated - */ - public static final String KEY_OC_URL = "oc_url"; - /** - * Version should be 3 numbers separated by dot so it can be parsed by - * {@link com.owncloud.android.utils.OwnCloudVersion} - */ - public static final String KEY_OC_VERSION = "oc_version"; - /** - * Base url should point to owncloud installation without trailing / ie: - * http://server/path or https://owncloud.server - */ - public static final String KEY_OC_BASE_URL = "oc_base_url"; - - private static final String TAG = "AccountAuthenticator"; - private Context mContext; - - public AccountAuthenticator(Context context) { - super(context); - mContext = context; - } - - /** - * {@inheritDoc} - */ - @Override - public Bundle addAccount(AccountAuthenticatorResponse response, - String accountType, String authTokenType, - String[] requiredFeatures, Bundle options) - throws NetworkErrorException { - Log.i(TAG, "Adding account with type " + accountType - + " and auth token " + authTokenType); - try { - validateAccountType(accountType); - } catch (AuthenticatorException e) { - Log.e(TAG, "Failed to validate account type " + accountType + ": " - + e.getMessage()); - e.printStackTrace(); - return e.getFailureBundle(); - } - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - - setIntentFlags(intent); - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - /** - * {@inheritDoc} - */ - @Override - public Bundle confirmCredentials(AccountAuthenticatorResponse response, - Account account, Bundle options) throws NetworkErrorException { - try { - validateAccountType(account.type); - } catch (AuthenticatorException e) { - Log.e(TAG, "Failed to validate account type " + account.type + ": " - + e.getMessage()); - e.printStackTrace(); - return e.getFailureBundle(); - } - Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_ACCOUNT, account); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - - setIntentFlags(intent); - - Bundle resultBundle = new Bundle(); - resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); - return resultBundle; - } - - @Override - public Bundle editProperties(AccountAuthenticatorResponse response, - String accountType) { - return null; - } - - @Override - public Bundle getAuthToken(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle options) - throws NetworkErrorException { - try { - validateAccountType(account.type); - validateAuthTokenType(authTokenType); - } catch (AuthenticatorException e) { - Log.e(TAG, "Failed to validate account type " + account.type + ": " - + e.getMessage()); - e.printStackTrace(); - return e.getFailureBundle(); - } - final AccountManager am = AccountManager.get(mContext); - final String password = am.getPassword(account); - if (password != null) { - final Bundle result = new Bundle(); - result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); - result.putString(AccountManager.KEY_AUTHTOKEN, password); - return result; - } - - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); - - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - @Override - public String getAuthTokenLabel(String authTokenType) { - return null; - } - - @Override - public Bundle hasFeatures(AccountAuthenticatorResponse response, - Account account, String[] features) throws NetworkErrorException { - final Bundle result = new Bundle(); - result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); - return result; - } - - @Override - public Bundle updateCredentials(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle options) - throws NetworkErrorException { - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_ACCOUNT, account); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - setIntentFlags(intent); - - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - @Override - public Bundle getAccountRemovalAllowed( - AccountAuthenticatorResponse response, Account account) - throws NetworkErrorException { - return super.getAccountRemovalAllowed(response, account); - } - - private void setIntentFlags(Intent intent) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.addFlags(Intent.FLAG_FROM_BACKGROUND); - } - - private void validateAccountType(String type) - throws UnsupportedAccountTypeException { - if (!type.equals(ACCOUNT_TYPE)) { - throw new UnsupportedAccountTypeException(); - } - } - - private void validateAuthTokenType(String authTokenType) - throws UnsupportedAuthTokenTypeException { - if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { - throw new UnsupportedAuthTokenTypeException(); - } - } - - public static class AuthenticatorException extends Exception { - private static final long serialVersionUID = 1L; - private Bundle mFailureBundle; - - public AuthenticatorException(int code, String errorMsg) { - mFailureBundle = new Bundle(); - mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code); - mFailureBundle - .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg); - } - - public Bundle getFailureBundle() { - return mFailureBundle; - } - } - - public static class UnsupportedAccountTypeException extends - AuthenticatorException { - private static final long serialVersionUID = 1L; - - public UnsupportedAccountTypeException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, - "Unsupported account type"); - } - } - - public static class UnsupportedAuthTokenTypeException extends - AuthenticatorException { - private static final long serialVersionUID = 1L; - - public UnsupportedAuthTokenTypeException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, - "Unsupported auth token type"); - } - } - - public static class UnsupportedFeaturesException extends - AuthenticatorException { - public static final long serialVersionUID = 1L; - - public UnsupportedFeaturesException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, - "Unsupported features"); - } - } - - public static class AccessDeniedException extends AuthenticatorException { - public AccessDeniedException(int code, String errorMsg) { - super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied"); - } - - private static final long serialVersionUID = 1L; - - } -} +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * 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 . + * + */ + +package com.owncloud.android.authenticator; + +import com.owncloud.android.Log_OC; +import com.owncloud.android.ui.activity.AuthenticatorActivity; + +import android.accounts.*; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +public class AccountAuthenticator extends AbstractAccountAuthenticator { + /** + * Is used by android system to assign accounts to authenticators. Should be + * used by application and all extensions. + */ + public static final String ACCOUNT_TYPE = "owncloud"; + public static final String AUTH_TOKEN_TYPE = "org.owncloud"; + + public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType"; + public static final String KEY_REQUIRED_FEATURES = "requiredFeatures"; + public static final String KEY_LOGIN_OPTIONS = "loginOptions"; + public static final String KEY_ACCOUNT = "account"; + /** + * Value under this key should handle path to webdav php script. Will be + * removed and usage should be replaced by combining + * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and + * {@link com.owncloud.android.utils.OwnCloudVersion} + * + * @deprecated + */ + public static final String KEY_OC_URL = "oc_url"; + /** + * Version should be 3 numbers separated by dot so it can be parsed by + * {@link com.owncloud.android.utils.OwnCloudVersion} + */ + public static final String KEY_OC_VERSION = "oc_version"; + /** + * Base url should point to owncloud installation without trailing / ie: + * http://server/path or https://owncloud.server + */ + public static final String KEY_OC_BASE_URL = "oc_base_url"; + + private static final String TAG = "AccountAuthenticator"; + private Context mContext; + + public AccountAuthenticator(Context context) { + super(context); + mContext = context; + } + + /** + * {@inheritDoc} + */ + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, + String accountType, String authTokenType, + String[] requiredFeatures, Bundle options) + throws NetworkErrorException { + Log_OC.i(TAG, "Adding account with type " + accountType + + " and auth token " + authTokenType); + try { + validateAccountType(accountType); + } catch (AuthenticatorException e) { + Log_OC.e(TAG, "Failed to validate account type " + accountType + ": " + + e.getMessage()); + e.printStackTrace(); + return e.getFailureBundle(); + } + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + + setIntentFlags(intent); + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + /** + * {@inheritDoc} + */ + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, + Account account, Bundle options) throws NetworkErrorException { + try { + validateAccountType(account.type); + } catch (AuthenticatorException e) { + Log_OC.e(TAG, "Failed to validate account type " + account.type + ": " + + e.getMessage()); + e.printStackTrace(); + return e.getFailureBundle(); + } + Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_ACCOUNT, account); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + + setIntentFlags(intent); + + Bundle resultBundle = new Bundle(); + resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); + return resultBundle; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, + String accountType) { + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + try { + validateAccountType(account.type); + validateAuthTokenType(authTokenType); + } catch (AuthenticatorException e) { + Log_OC.e(TAG, "Failed to validate account type " + account.type + ": " + + e.getMessage()); + e.printStackTrace(); + return e.getFailureBundle(); + } + final AccountManager am = AccountManager.get(mContext); + final String password = am.getPassword(account); + if (password != null) { + final Bundle result = new Bundle(); + result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); + result.putString(AccountManager.KEY_AUTHTOKEN, password); + return result; + } + + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); + + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, + Account account, String[] features) throws NetworkErrorException { + final Bundle result = new Bundle(); + result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); + return result; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_ACCOUNT, account); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + setIntentFlags(intent); + + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + @Override + public Bundle getAccountRemovalAllowed( + AccountAuthenticatorResponse response, Account account) + throws NetworkErrorException { + return super.getAccountRemovalAllowed(response, account); + } + + private void setIntentFlags(Intent intent) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.addFlags(Intent.FLAG_FROM_BACKGROUND); + } + + private void validateAccountType(String type) + throws UnsupportedAccountTypeException { + if (!type.equals(ACCOUNT_TYPE)) { + throw new UnsupportedAccountTypeException(); + } + } + + private void validateAuthTokenType(String authTokenType) + throws UnsupportedAuthTokenTypeException { + if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { + throw new UnsupportedAuthTokenTypeException(); + } + } + + public static class AuthenticatorException extends Exception { + private static final long serialVersionUID = 1L; + private Bundle mFailureBundle; + + public AuthenticatorException(int code, String errorMsg) { + mFailureBundle = new Bundle(); + mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code); + mFailureBundle + .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg); + } + + public Bundle getFailureBundle() { + return mFailureBundle; + } + } + + public static class UnsupportedAccountTypeException extends + AuthenticatorException { + private static final long serialVersionUID = 1L; + + public UnsupportedAccountTypeException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "Unsupported account type"); + } + } + + public static class UnsupportedAuthTokenTypeException extends + AuthenticatorException { + private static final long serialVersionUID = 1L; + + public UnsupportedAuthTokenTypeException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "Unsupported auth token type"); + } + } + + public static class UnsupportedFeaturesException extends + AuthenticatorException { + public static final long serialVersionUID = 1L; + + public UnsupportedFeaturesException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "Unsupported features"); + } + } + + public static class AccessDeniedException extends AuthenticatorException { + public AccessDeniedException(int code, String errorMsg) { + super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied"); + } + + private static final long serialVersionUID = 1L; + + } +} diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java index aa914c4739..3d053e6ecd 100644 --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.List; import java.util.Vector; +import com.owncloud.android.Log_OC; import com.owncloud.android.db.ProviderMeta; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; import com.owncloud.android.utils.FileStorageUtils; @@ -156,7 +157,7 @@ public class FileDataStorageManager implements DataStorageManager { cv, ProviderTableMeta._ID + "=?", new String[] { String.valueOf(file.getFileId()) }); } catch (RemoteException e) { - Log.e(TAG, + Log_OC.e(TAG, "Fail to insert insert file to database " + e.getMessage()); } @@ -171,7 +172,7 @@ public class FileDataStorageManager implements DataStorageManager { result_uri = getContentProvider().insert( ProviderTableMeta.CONTENT_URI_FILE, cv); } catch (RemoteException e) { - Log.e(TAG, + Log_OC.e(TAG, "Fail to insert insert file to database " + e.getMessage()); } @@ -256,10 +257,10 @@ public class FileDataStorageManager implements DataStorageManager { } } catch (OperationApplicationException e) { - Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage()); + Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage()); } catch (RemoteException e) { - Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage()); + Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage()); } // update new id in file objects for insertions @@ -269,7 +270,7 @@ public class FileDataStorageManager implements DataStorageManager { if (results[i].uri != null) { newId = Long.parseLong(results[i].uri.getPathSegments().get(1)); files.get(i).setFileId(newId); - //Log.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath()); + //Log_OC.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath()); } } } @@ -321,7 +322,7 @@ public class FileDataStorageManager implements DataStorageManager { ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", new String[] { mAccount.name }, null); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log_OC.e(TAG, e.getMessage()); return ret; } } else { @@ -364,7 +365,7 @@ public class FileDataStorageManager implements DataStorageManager { + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", new String[] { value, mAccount.name }, null); } catch (RemoteException e) { - Log.e(TAG, + Log_OC.e(TAG, "Couldn't determine file existance, assuming non existance: " + e.getMessage()); return false; @@ -394,7 +395,7 @@ public class FileDataStorageManager implements DataStorageManager { + "=?", new String[] { value, mAccount.name }, null); } catch (RemoteException e) { - Log.e(TAG, "Could not get file details: " + e.getMessage()); + Log_OC.e(TAG, "Could not get file details: " + e.getMessage()); c = null; } } @@ -517,7 +518,7 @@ public class FileDataStorageManager implements DataStorageManager { ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?", new String[] { mAccount.name, dir.getRemotePath() + "%" }, null); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log_OC.e(TAG, e.getMessage()); } } else { c = getContentResolver().query(ProviderTableMeta.CONTENT_URI, @@ -558,10 +559,10 @@ public class FileDataStorageManager implements DataStorageManager { } } catch (OperationApplicationException e) { - Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e); + Log_OC.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e); } catch (RemoteException e) { - Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e); + Log_OC.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e); } } diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 668e9917a8..5631854dad 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -21,6 +21,8 @@ package com.owncloud.android.datamodel; import java.io.File; +import com.owncloud.android.Log_OC; + import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -262,7 +264,7 @@ public class OCFile implements Parcelable, Comparable { * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory */ public void setFileName(String name) { - Log.d(TAG, "OCFile name changin from " + mRemotePath); + Log_OC.d(TAG, "OCFile name changin from " + mRemotePath); if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(PATH_SEPARATOR)) { String parent = (new File(getRemotePath())).getParent(); parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR; @@ -270,7 +272,7 @@ public class OCFile implements Parcelable, Comparable { if (isDirectory()) { mRemotePath += PATH_SEPARATOR; } - Log.d(TAG, "OCFile name changed to " + mRemotePath); + Log_OC.d(TAG, "OCFile name changed to " + mRemotePath); } } diff --git a/src/com/owncloud/android/db/DbHandler.java b/src/com/owncloud/android/db/DbHandler.java index 3e4103a6fb..d9ce1d6635 100644 --- a/src/com/owncloud/android/db/DbHandler.java +++ b/src/com/owncloud/android/db/DbHandler.java @@ -17,6 +17,8 @@ */ package com.owncloud.android.db; +import com.owncloud.android.Log_OC; + import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -56,7 +58,7 @@ public class DbHandler { cv.put("account", account); cv.put("attempt", UPLOAD_STATUS_UPLOAD_LATER); long result = mDB.insert(TABLE_INSTANT_UPLOAD, null, cv); - Log.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath); + Log_OC.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath); return result != -1; } @@ -64,7 +66,7 @@ public class DbHandler { ContentValues cv = new ContentValues(); cv.put("attempt", status); int result = mDB.update(TABLE_INSTANT_UPLOAD, cv, "path=?", new String[] { filepath }); - Log.d(TABLE_INSTANT_UPLOAD, "updateFileState returns with: " + result + " for file: " + filepath); + Log_OC.d(TABLE_INSTANT_UPLOAD, "updateFileState returns with: " + result + " for file: " + filepath); return result; } @@ -87,7 +89,7 @@ public class DbHandler { */ public boolean removeIUPendingFile(String localPath) { long result = mDB.delete(TABLE_INSTANT_UPLOAD, "path = ?", new String[] { localPath }); - Log.d(TABLE_INSTANT_UPLOAD, "delete returns with: " + result + " for file: " + localPath); + Log_OC.d(TABLE_INSTANT_UPLOAD, "delete returns with: " + result + " for file: " + localPath); return result != 0; } diff --git a/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java b/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java index ccef3408ae..6b800fd28c 100644 --- a/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java +++ b/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java @@ -19,6 +19,7 @@ package com.owncloud.android.extensions; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; import android.content.Intent; import android.os.Bundle; @@ -62,7 +63,7 @@ public class ExtensionsAvailableDialog extends DialogFragment implements getActivity().finish(); break; default: - Log.e("EAD", "Button with unknown id clicked " + v.getId()); + Log_OC.e("EAD", "Button with unknown id clicked " + v.getId()); } } diff --git a/src/com/owncloud/android/extensions/ExtensionsListActivity.java b/src/com/owncloud/android/extensions/ExtensionsListActivity.java index 5b1672914a..0452109fd1 100644 --- a/src/com/owncloud/android/extensions/ExtensionsListActivity.java +++ b/src/com/owncloud/android/extensions/ExtensionsListActivity.java @@ -28,6 +28,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import com.owncloud.android.Log_OC; import com.owncloud.android.utils.OwnCloudVersion; @@ -81,7 +82,7 @@ public class ExtensionsListActivity extends ListActivity { final JSONArray ar; try { hc.executeMethod(gm); - Log.e("ASD", gm.getResponseBodyAsString() + ""); + Log_OC.e("ASD", gm.getResponseBodyAsString() + ""); ar = new JSONObject(gm.getResponseBodyAsString()) .getJSONArray("apps"); } catch (Exception e) { diff --git a/src/com/owncloud/android/files/BootupBroadcastReceiver.java b/src/com/owncloud/android/files/BootupBroadcastReceiver.java index e322fa5d9a..43ef36715e 100644 --- a/src/com/owncloud/android/files/BootupBroadcastReceiver.java +++ b/src/com/owncloud/android/files/BootupBroadcastReceiver.java @@ -19,6 +19,7 @@ package com.owncloud.android.files; +import com.owncloud.android.Log_OC; import com.owncloud.android.files.services.FileObserverService; import android.content.BroadcastReceiver; @@ -33,15 +34,15 @@ public class BootupBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - Log.wtf(TAG, "Incorrect action sent " + intent.getAction()); + Log_OC.wtf(TAG, "Incorrect action sent " + intent.getAction()); return; } - Log.d(TAG, "Starting file observer service..."); + Log_OC.d(TAG, "Starting file observer service..."); Intent i = new Intent(context, FileObserverService.class); i.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST); context.startService(i); - Log.d(TAG, "DONE"); + Log_OC.d(TAG, "DONE"); } } diff --git a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java index 8fd06f3d60..f6e531dd47 100644 --- a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java +++ b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java @@ -35,6 +35,7 @@ import android.util.Log; import android.webkit.MimeTypeMap; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.db.DbHandler; import com.owncloud.android.files.services.FileUploader; @@ -48,7 +49,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - Log.d(TAG, "Received: " + intent.getAction()); + Log_OC.d(TAG, "Received: " + intent.getAction()); if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) { handleConnectivityAction(context, intent); } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) { @@ -56,7 +57,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { } else if (intent.getAction().equals(FileUploader.UPLOAD_FINISH_MESSAGE)) { handleUploadFinished(context, intent); } else { - Log.e(TAG, "Incorrect intent sent: " + intent.getAction()); + Log_OC.e(TAG, "Incorrect intent sent: " + intent.getAction()); } } @@ -66,7 +67,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { DbHandler db = new DbHandler(context); String localPath = intent.getStringExtra(FileUploader.EXTRA_OLD_FILE_PATH); if (!db.removeIUPendingFile(localPath)) { - Log.w(TAG, "Tried to remove non existing instant upload file " + localPath); + Log_OC.w(TAG, "Tried to remove non existing instant upload file " + localPath); } db.close(); } @@ -74,20 +75,20 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { private void handleNewPhotoAction(Context context, Intent intent) { if (!instantUploadEnabled(context)) { - Log.d(TAG, "Instant upload disabled, abording uploading"); + Log_OC.d(TAG, "Instant upload disabled, abording uploading"); return; } Account account = AccountUtils.getCurrentOwnCloudAccount(context); if (account == null) { - Log.w(TAG, "No owncloud account found for instant upload, aborting"); + Log_OC.w(TAG, "No owncloud account found for instant upload, aborting"); return; } Cursor c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null); if (!c.moveToFirst()) { - Log.e(TAG, "Couldn't resolve given uri: " + intent.getDataString()); + Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString()); return; } @@ -96,7 +97,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { String mime_type = c.getString(c.getColumnIndex(Media.MIME_TYPE)); c.close(); - Log.e(TAG, file_path + ""); + Log_OC.e(TAG, file_path + ""); // same always temporally the picture to upload DbHandler db = new DbHandler(context); @@ -131,7 +132,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { private void handleConnectivityAction(Context context, Intent intent) { if (!instantUploadEnabled(context)) { - Log.d(TAG, "Instant upload disabled, abording uploading"); + Log_OC.d(TAG, "Instant upload disabled, abording uploading"); return; } @@ -156,7 +157,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { f.getName().substring(f.getName().lastIndexOf('.') + 1)); } catch (Throwable e) { - Log.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName()); + Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName()); } if (mimeType == null) mimeType = "application/octet-stream"; @@ -170,7 +171,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { context.startService(i); } else { - Log.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore"); + Log_OC.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore"); } } while (c.moveToNext()); } diff --git a/src/com/owncloud/android/files/OwnCloudFileObserver.java b/src/com/owncloud/android/files/OwnCloudFileObserver.java index 8e1f7363f4..4f46eba3c1 100644 --- a/src/com/owncloud/android/files/OwnCloudFileObserver.java +++ b/src/com/owncloud/android/files/OwnCloudFileObserver.java @@ -21,6 +21,7 @@ package com.owncloud.android.files; import java.io.File; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.network.OwnCloudClientUtils; @@ -71,9 +72,9 @@ public class OwnCloudFileObserver extends FileObserver { @Override public void onEvent(int event, String path) { - Log.d(TAG, "Got file modified with event " + event + " and path " + mPath + ((path != null) ? File.separator + path : "")); + Log_OC.d(TAG, "Got file modified with event " + event + " and path " + mPath + ((path != null) ? File.separator + path : "")); if ((event & mMask) == 0) { - Log.wtf(TAG, "Incorrect event " + event + " sent for file " + mPath + ((path != null) ? File.separator + path : "") + + Log_OC.wtf(TAG, "Incorrect event " + event + " sent for file " + mPath + ((path != null) ? File.separator + path : "") + " with registered for " + mMask + " and original path " + mPath); return; diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index ac70e39a22..a9aa2dc153 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -1,416 +1,417 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * 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 . - * - */ - -package com.owncloud.android.files.services; - -import java.io.File; -import java.util.AbstractList; -import java.util.Iterator; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import eu.alefzero.webdav.OnDatatransferProgressListener; - -import com.owncloud.android.network.OwnCloudClientUtils; -import com.owncloud.android.operations.DownloadFileOperation; -import com.owncloud.android.operations.RemoteOperationResult; -import com.owncloud.android.ui.activity.FileDetailActivity; -import com.owncloud.android.ui.fragment.FileDetailFragment; - -import android.accounts.Account; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Intent; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.util.Log; -import android.widget.RemoteViews; - -import com.owncloud.android.R; -import eu.alefzero.webdav.WebdavClient; - -public class FileDownloader extends Service implements OnDatatransferProgressListener { - - public static final String EXTRA_ACCOUNT = "ACCOUNT"; - public static final String EXTRA_FILE = "FILE"; - - public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; - public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; - public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; - public static final String EXTRA_FILE_PATH = "FILE_PATH"; - public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - - private static final String TAG = "FileDownloader"; - - private Looper mServiceLooper; - private ServiceHandler mServiceHandler; - private IBinder mBinder; - private WebdavClient mDownloadClient = null; - private Account mLastAccount = null; - private FileDataStorageManager mStorageManager; - - private ConcurrentMap mPendingDownloads = new ConcurrentHashMap(); - private DownloadFileOperation mCurrentDownload = null; - - private NotificationManager mNotificationManager; - private Notification mNotification; - private int mLastPercent; - - - /** - * Builds a key for mPendingDownloads from the account and file to download - * - * @param account Account where the file to download is stored - * @param file File to download - */ - private String buildRemoteName(Account account, OCFile file) { - return account.name + file.getRemotePath(); - } - - - /** - * Service initialization - */ - @Override - public void onCreate() { - super.onCreate(); - mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - HandlerThread thread = new HandlerThread("FileDownloaderThread", - Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - mServiceLooper = thread.getLooper(); - mServiceHandler = new ServiceHandler(mServiceLooper, this); - mBinder = new FileDownloaderBinder(); - } - - - /** - * Entry point to add one or several files to the queue of downloads. - * - * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working - * although the caller activity goes away. - */ - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if ( !intent.hasExtra(EXTRA_ACCOUNT) || - !intent.hasExtra(EXTRA_FILE) - /*!intent.hasExtra(EXTRA_FILE_PATH) || - !intent.hasExtra(EXTRA_REMOTE_PATH)*/ - ) { - Log.e(TAG, "Not enough information provided in intent"); - return START_NOT_STICKY; - } - Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); - OCFile file = intent.getParcelableExtra(EXTRA_FILE); - - AbstractList requestedDownloads = new Vector(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection) - String downloadKey = buildRemoteName(account, file); - try { - DownloadFileOperation newDownload = new DownloadFileOperation(account, file); - mPendingDownloads.putIfAbsent(downloadKey, newDownload); - newDownload.addDatatransferProgressListener(this); - requestedDownloads.add(downloadKey); - sendBroadcastNewDownload(newDownload); - - } catch (IllegalArgumentException e) { - Log.e(TAG, "Not enough information provided in intent: " + e.getMessage()); - return START_NOT_STICKY; - } - - if (requestedDownloads.size() > 0) { - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - msg.obj = requestedDownloads; - mServiceHandler.sendMessage(msg); - } - - return START_NOT_STICKY; - } - - - /** - * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. - * - * Implemented to perform cancellation, pause and resume of existing downloads. - */ - @Override - public IBinder onBind(Intent arg0) { - return mBinder; - } - - - /** - * Binder to let client components to perform operations on the queue of downloads. - * - * It provides by itself the available operations. - */ - public class FileDownloaderBinder extends Binder { - - /** - * Cancels a pending or current download of a remote file. - * - * @param account Owncloud account where the remote file is stored. - * @param file A file in the queue of pending downloads - */ - public void cancel(Account account, OCFile file) { - DownloadFileOperation download = null; - synchronized (mPendingDownloads) { - download = mPendingDownloads.remove(buildRemoteName(account, file)); - } - if (download != null) { - download.cancel(); - } - } - - - /** - * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download. - * - * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. - * - * @param account Owncloud account where the remote file is stored. - * @param file A file that could be in the queue of downloads. - */ - public boolean isDownloading(Account account, OCFile file) { - if (account == null || file == null) return false; - String targetKey = buildRemoteName(account, file); - synchronized (mPendingDownloads) { - if (file.isDirectory()) { - // this can be slow if there are many downloads :( - Iterator it = mPendingDownloads.keySet().iterator(); - boolean found = false; - while (it.hasNext() && !found) { - found = it.next().startsWith(targetKey); - } - return found; - } else { - return (mPendingDownloads.containsKey(targetKey)); - } - } - } - } - - - /** - * Download worker. Performs the pending downloads in the order they were requested. - * - * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. - */ - private static class ServiceHandler extends Handler { - // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak - FileDownloader mService; - public ServiceHandler(Looper looper, FileDownloader service) { - super(looper); - if (service == null) - throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); - mService = service; - } - - @Override - public void handleMessage(Message msg) { - @SuppressWarnings("unchecked") - AbstractList requestedDownloads = (AbstractList) msg.obj; - if (msg.obj != null) { - Iterator it = requestedDownloads.iterator(); - while (it.hasNext()) { - mService.downloadFile(it.next()); - } - } - mService.stopSelf(msg.arg1); - } - } - - - - /** - * Core download method: requests a file to download and stores it. - * - * @param downloadKey Key to access the download to perform, contained in mPendingDownloads - */ - private void downloadFile(String downloadKey) { - - synchronized(mPendingDownloads) { - mCurrentDownload = mPendingDownloads.get(downloadKey); - } - - if (mCurrentDownload != null) { - - notifyDownloadStart(mCurrentDownload); - - /// prepare client object to send the request to the ownCloud server - if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) { - mLastAccount = mCurrentDownload.getAccount(); - mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver()); - mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext()); - } - - /// perform the download - RemoteOperationResult downloadResult = null; - try { - downloadResult = mCurrentDownload.execute(mDownloadClient); - if (downloadResult.isSuccess()) { - saveDownloadedFile(); - } - - } finally { - synchronized(mPendingDownloads) { - mPendingDownloads.remove(downloadKey); - } - } - - - /// notify result - notifyDownloadResult(mCurrentDownload, downloadResult); - - sendBroadcastDownloadFinished(mCurrentDownload, downloadResult); - } - } - - - /** - * Updates the OC File after a successful download. - */ - private void saveDownloadedFile() { - OCFile file = mCurrentDownload.getFile(); - long syncDate = System.currentTimeMillis(); - file.setLastSyncDateForProperties(syncDate); - file.setLastSyncDateForData(syncDate); - file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp()); - file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp()); - // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where available - file.setMimetype(mCurrentDownload.getMimeType()); - file.setStoragePath(mCurrentDownload.getSavePath()); - file.setFileLength((new File(mCurrentDownload.getSavePath()).length())); - mStorageManager.saveFile(file); - } - - - /** - * Creates a status notification to show the download progress - * - * @param download Download operation starting. - */ - private void notifyDownloadStart(DownloadFileOperation download) { - /// create status notification with a progress bar - mLastPercent = 0; - mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis()); - mNotification.flags |= Notification.FLAG_ONGOING_EVENT; - mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout); - mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0); - mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName())); - mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); - - /// includes a pending intent in the notification showing the details view of the file - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile()); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount()); - showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0); - - mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); - } - - - /** - * Callback method to update the progress bar in the status notification. - */ - @Override - public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) { - int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer)); - if (percent != mLastPercent) { - mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0); - String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName); - mNotification.contentView.setTextViewText(R.id.status_text, text); - mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); - } - mLastPercent = percent; - } - - - /** - * Callback method to update the progress bar in the status notification (old version) - */ - @Override - public void onTransferProgress(long progressRate) { - // NOTHING TO DO HERE ANYMORE - } - - - /** - * Updates the status notification with the result of a download operation. - * - * @param downloadResult Result of the download operation. - * @param download Finished download operation - */ - private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { - mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); - if (!downloadResult.isCancelled()) { - int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; - int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content; - Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis()); - finalNotification.flags |= Notification.FLAG_AUTO_CANCEL; - // TODO put something smart in the contentIntent below - finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); - finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent); - mNotificationManager.notify(tickerId, finalNotification); - } - } - - - /** - * Sends a broadcast when a download finishes in order to the interested activities can update their view - * - * @param download Finished download operation - * @param downloadResult Result of the download operation - */ - private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) { - Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE); - end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess()); - end.putExtra(ACCOUNT_NAME, download.getAccount().name); - end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); - end.putExtra(EXTRA_FILE_PATH, download.getSavePath()); - sendStickyBroadcast(end); - } - - - /** - * Sends a broadcast when a new download is added to the queue. - * - * @param download Added download operation - */ - private void sendBroadcastNewDownload(DownloadFileOperation download) { - Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE); - /*added.putExtra(ACCOUNT_NAME, download.getAccount().name); - added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());*/ - added.putExtra(EXTRA_FILE_PATH, download.getSavePath()); - sendStickyBroadcast(added); - } - -} +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * 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 . + * + */ + +package com.owncloud.android.files.services; + +import java.io.File; +import java.util.AbstractList; +import java.util.Iterator; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import eu.alefzero.webdav.OnDatatransferProgressListener; + +import com.owncloud.android.network.OwnCloudClientUtils; +import com.owncloud.android.operations.DownloadFileOperation; +import com.owncloud.android.operations.RemoteOperationResult; +import com.owncloud.android.ui.activity.FileDetailActivity; +import com.owncloud.android.ui.fragment.FileDetailFragment; + +import android.accounts.Account; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.util.Log; +import android.widget.RemoteViews; + +import com.owncloud.android.Log_OC; +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +public class FileDownloader extends Service implements OnDatatransferProgressListener { + + public static final String EXTRA_ACCOUNT = "ACCOUNT"; + public static final String EXTRA_FILE = "FILE"; + + public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; + public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; + public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; + public static final String EXTRA_FILE_PATH = "FILE_PATH"; + public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; + public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; + + private static final String TAG = "FileDownloader"; + + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + private IBinder mBinder; + private WebdavClient mDownloadClient = null; + private Account mLastAccount = null; + private FileDataStorageManager mStorageManager; + + private ConcurrentMap mPendingDownloads = new ConcurrentHashMap(); + private DownloadFileOperation mCurrentDownload = null; + + private NotificationManager mNotificationManager; + private Notification mNotification; + private int mLastPercent; + + + /** + * Builds a key for mPendingDownloads from the account and file to download + * + * @param account Account where the file to download is stored + * @param file File to download + */ + private String buildRemoteName(Account account, OCFile file) { + return account.name + file.getRemotePath(); + } + + + /** + * Service initialization + */ + @Override + public void onCreate() { + super.onCreate(); + mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + HandlerThread thread = new HandlerThread("FileDownloaderThread", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper, this); + mBinder = new FileDownloaderBinder(); + } + + + /** + * Entry point to add one or several files to the queue of downloads. + * + * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working + * although the caller activity goes away. + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if ( !intent.hasExtra(EXTRA_ACCOUNT) || + !intent.hasExtra(EXTRA_FILE) + /*!intent.hasExtra(EXTRA_FILE_PATH) || + !intent.hasExtra(EXTRA_REMOTE_PATH)*/ + ) { + Log_OC.e(TAG, "Not enough information provided in intent"); + return START_NOT_STICKY; + } + Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); + OCFile file = intent.getParcelableExtra(EXTRA_FILE); + + AbstractList requestedDownloads = new Vector(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection) + String downloadKey = buildRemoteName(account, file); + try { + DownloadFileOperation newDownload = new DownloadFileOperation(account, file); + mPendingDownloads.putIfAbsent(downloadKey, newDownload); + newDownload.addDatatransferProgressListener(this); + requestedDownloads.add(downloadKey); + sendBroadcastNewDownload(newDownload); + + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); + return START_NOT_STICKY; + } + + if (requestedDownloads.size() > 0) { + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.obj = requestedDownloads; + mServiceHandler.sendMessage(msg); + } + + return START_NOT_STICKY; + } + + + /** + * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. + * + * Implemented to perform cancellation, pause and resume of existing downloads. + */ + @Override + public IBinder onBind(Intent arg0) { + return mBinder; + } + + + /** + * Binder to let client components to perform operations on the queue of downloads. + * + * It provides by itself the available operations. + */ + public class FileDownloaderBinder extends Binder { + + /** + * Cancels a pending or current download of a remote file. + * + * @param account Owncloud account where the remote file is stored. + * @param file A file in the queue of pending downloads + */ + public void cancel(Account account, OCFile file) { + DownloadFileOperation download = null; + synchronized (mPendingDownloads) { + download = mPendingDownloads.remove(buildRemoteName(account, file)); + } + if (download != null) { + download.cancel(); + } + } + + + /** + * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download. + * + * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. + * + * @param account Owncloud account where the remote file is stored. + * @param file A file that could be in the queue of downloads. + */ + public boolean isDownloading(Account account, OCFile file) { + if (account == null || file == null) return false; + String targetKey = buildRemoteName(account, file); + synchronized (mPendingDownloads) { + if (file.isDirectory()) { + // this can be slow if there are many downloads :( + Iterator it = mPendingDownloads.keySet().iterator(); + boolean found = false; + while (it.hasNext() && !found) { + found = it.next().startsWith(targetKey); + } + return found; + } else { + return (mPendingDownloads.containsKey(targetKey)); + } + } + } + } + + + /** + * Download worker. Performs the pending downloads in the order they were requested. + * + * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. + */ + private static class ServiceHandler extends Handler { + // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak + FileDownloader mService; + public ServiceHandler(Looper looper, FileDownloader service) { + super(looper); + if (service == null) + throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); + mService = service; + } + + @Override + public void handleMessage(Message msg) { + @SuppressWarnings("unchecked") + AbstractList requestedDownloads = (AbstractList) msg.obj; + if (msg.obj != null) { + Iterator it = requestedDownloads.iterator(); + while (it.hasNext()) { + mService.downloadFile(it.next()); + } + } + mService.stopSelf(msg.arg1); + } + } + + + + /** + * Core download method: requests a file to download and stores it. + * + * @param downloadKey Key to access the download to perform, contained in mPendingDownloads + */ + private void downloadFile(String downloadKey) { + + synchronized(mPendingDownloads) { + mCurrentDownload = mPendingDownloads.get(downloadKey); + } + + if (mCurrentDownload != null) { + + notifyDownloadStart(mCurrentDownload); + + /// prepare client object to send the request to the ownCloud server + if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) { + mLastAccount = mCurrentDownload.getAccount(); + mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver()); + mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext()); + } + + /// perform the download + RemoteOperationResult downloadResult = null; + try { + downloadResult = mCurrentDownload.execute(mDownloadClient); + if (downloadResult.isSuccess()) { + saveDownloadedFile(); + } + + } finally { + synchronized(mPendingDownloads) { + mPendingDownloads.remove(downloadKey); + } + } + + + /// notify result + notifyDownloadResult(mCurrentDownload, downloadResult); + + sendBroadcastDownloadFinished(mCurrentDownload, downloadResult); + } + } + + + /** + * Updates the OC File after a successful download. + */ + private void saveDownloadedFile() { + OCFile file = mCurrentDownload.getFile(); + long syncDate = System.currentTimeMillis(); + file.setLastSyncDateForProperties(syncDate); + file.setLastSyncDateForData(syncDate); + file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp()); + file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp()); + // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where available + file.setMimetype(mCurrentDownload.getMimeType()); + file.setStoragePath(mCurrentDownload.getSavePath()); + file.setFileLength((new File(mCurrentDownload.getSavePath()).length())); + mStorageManager.saveFile(file); + } + + + /** + * Creates a status notification to show the download progress + * + * @param download Download operation starting. + */ + private void notifyDownloadStart(DownloadFileOperation download) { + /// create status notification with a progress bar + mLastPercent = 0; + mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis()); + mNotification.flags |= Notification.FLAG_ONGOING_EVENT; + mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout); + mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0); + mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName())); + mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); + + /// includes a pending intent in the notification showing the details view of the file + Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile()); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount()); + showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0); + + mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); + } + + + /** + * Callback method to update the progress bar in the status notification. + */ + @Override + public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) { + int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer)); + if (percent != mLastPercent) { + mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0); + String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName); + mNotification.contentView.setTextViewText(R.id.status_text, text); + mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); + } + mLastPercent = percent; + } + + + /** + * Callback method to update the progress bar in the status notification (old version) + */ + @Override + public void onTransferProgress(long progressRate) { + // NOTHING TO DO HERE ANYMORE + } + + + /** + * Updates the status notification with the result of a download operation. + * + * @param downloadResult Result of the download operation. + * @param download Finished download operation + */ + private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { + mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); + if (!downloadResult.isCancelled()) { + int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; + int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content; + Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis()); + finalNotification.flags |= Notification.FLAG_AUTO_CANCEL; + // TODO put something smart in the contentIntent below + finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); + finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent); + mNotificationManager.notify(tickerId, finalNotification); + } + } + + + /** + * Sends a broadcast when a download finishes in order to the interested activities can update their view + * + * @param download Finished download operation + * @param downloadResult Result of the download operation + */ + private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) { + Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE); + end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess()); + end.putExtra(ACCOUNT_NAME, download.getAccount().name); + end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); + end.putExtra(EXTRA_FILE_PATH, download.getSavePath()); + sendStickyBroadcast(end); + } + + + /** + * Sends a broadcast when a new download is added to the queue. + * + * @param download Added download operation + */ + private void sendBroadcastNewDownload(DownloadFileOperation download) { + Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE); + /*added.putExtra(ACCOUNT_NAME, download.getAccount().name); + added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());*/ + added.putExtra(EXTRA_FILE_PATH, download.getSavePath()); + sendStickyBroadcast(added); + } + +} diff --git a/src/com/owncloud/android/files/services/FileObserverService.java b/src/com/owncloud/android/files/services/FileObserverService.java index d4bf24d0fa..635571fb8e 100644 --- a/src/com/owncloud/android/files/services/FileObserverService.java +++ b/src/com/owncloud/android/files/services/FileObserverService.java @@ -23,6 +23,7 @@ import java.io.File; import java.util.HashMap; import java.util.Map; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; @@ -83,7 +84,7 @@ public class FileObserverService extends Service { super.onDestroy(); unregisterReceiver(mDownloadReceiver); mObserversMap = null; // TODO study carefully the life cycle of Services to grant the best possible observance - Log.d(TAG, "Bye, bye"); + Log_OC.d(TAG, "Bye, bye"); } @@ -102,7 +103,7 @@ public class FileObserverService extends Service { } if (!intent.hasExtra(KEY_FILE_CMD)) { - Log.e(TAG, "No KEY_FILE_CMD argument given"); + Log_OC.e(TAG, "No KEY_FILE_CMD argument given"); return Service.START_STICKY; } @@ -119,7 +120,7 @@ public class FileObserverService extends Service { (Account)intent.getParcelableExtra(KEY_CMD_ARG_ACCOUNT)); break; default: - Log.wtf(TAG, "Incorrect key given"); + Log_OC.wtf(TAG, "Incorrect key given"); } return Service.START_STICKY; @@ -166,7 +167,7 @@ public class FileObserverService extends Service { mObserversMap.put(path, observer); if (new File(path).exists()) { observer.startWatching(); - Log.d(TAG, "Started watching file " + path); + Log_OC.d(TAG, "Started watching file " + path); } } while (c.moveToNext()); @@ -189,7 +190,7 @@ public class FileObserverService extends Service { */ private void addObservedFile(OCFile file, Account account) { if (file == null) { - Log.e(TAG, "Trying to add a NULL file to observer"); + Log_OC.e(TAG, "Trying to add a NULL file to observer"); return; } String localPath = file.getStoragePath(); @@ -204,11 +205,11 @@ public class FileObserverService extends Service { getApplicationContext(), OwnCloudFileObserver.CHANGES_ONLY); mObserversMap.put(localPath, observer); - Log.d(TAG, "Observer added for path " + localPath); + Log_OC.d(TAG, "Observer added for path " + localPath); if (file.isDown()) { observer.startWatching(); - Log.d(TAG, "Started watching " + localPath); + Log_OC.d(TAG, "Started watching " + localPath); } // else - the observance can't be started on a file not already down; mDownloadReceiver will get noticed when the download of the file finishes } @@ -229,7 +230,7 @@ public class FileObserverService extends Service { */ private void removeObservedFile(OCFile file, Account account) { if (file == null) { - Log.e(TAG, "Trying to remove a NULL file"); + Log_OC.e(TAG, "Trying to remove a NULL file"); return; } String localPath = file.getStoragePath(); @@ -241,7 +242,7 @@ public class FileObserverService extends Service { if (observer != null) { observer.stopWatching(); mObserversMap.remove(observer); - Log.d(TAG, "Stopped watching " + localPath); + Log_OC.d(TAG, "Stopped watching " + localPath); } } @@ -263,11 +264,11 @@ public class FileObserverService extends Service { if (intent.getAction().equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE) && new File(downloadPath).exists()) { // the download could be successful, or not; in both cases, the file could be down, due to a former download or upload observer.startWatching(); - Log.d(TAG, "Watching again " + downloadPath); + Log_OC.d(TAG, "Watching again " + downloadPath); } else if (intent.getAction().equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) { observer.stopWatching(); - Log.d(TAG, "Disabling observance of " + downloadPath); + Log_OC.d(TAG, "Disabling observance of " + downloadPath); } } } diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index eaaea01043..57ce11ec1e 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -49,6 +49,7 @@ import android.webkit.MimeTypeMap; import android.widget.RemoteViews; import android.widget.Toast; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -147,7 +148,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe @Override public void onCreate() { super.onCreate(); - Log.i(TAG, "mPendingUploads size:" + mPendingUploads.size()); + Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size()); mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); HandlerThread thread = new HandlerThread("FileUploaderThread", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); @@ -167,12 +168,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe public int onStartCommand(Intent intent, int flags, int startId) { if (!intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE) || !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) { - Log.e(TAG, "Not enough information provided in intent"); + Log_OC.e(TAG, "Not enough information provided in intent"); return Service.START_NOT_STICKY; } int uploadType = intent.getIntExtra(KEY_UPLOAD_TYPE, -1); if (uploadType == -1) { - Log.e(TAG, "Incorrect upload type provided"); + Log_OC.e(TAG, "Incorrect upload type provided"); return Service.START_NOT_STICKY; } Account account = intent.getParcelableExtra(KEY_ACCOUNT); @@ -223,20 +224,20 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } if (intent.hasExtra(KEY_FILE) && files == null) { - Log.e(TAG, "Incorrect array for OCFiles provided in upload intent"); + Log_OC.e(TAG, "Incorrect array for OCFiles provided in upload intent"); return Service.START_NOT_STICKY; } else if (!intent.hasExtra(KEY_FILE)) { if (localPaths == null) { - Log.e(TAG, "Incorrect array for local paths provided in upload intent"); + Log_OC.e(TAG, "Incorrect array for local paths provided in upload intent"); return Service.START_NOT_STICKY; } if (remotePaths == null) { - Log.e(TAG, "Incorrect array for remote paths provided in upload intent"); + Log_OC.e(TAG, "Incorrect array for remote paths provided in upload intent"); return Service.START_NOT_STICKY; } if (localPaths.length != remotePaths.length) { - Log.e(TAG, "Different number of remote paths and local paths!"); + Log_OC.e(TAG, "Different number of remote paths and local paths!"); return Service.START_NOT_STICKY; } @@ -275,15 +276,15 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } } catch (IllegalArgumentException e) { - Log.e(TAG, "Not enough information provided in intent: " + e.getMessage()); + Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); return START_NOT_STICKY; } catch (IllegalStateException e) { - Log.e(TAG, "Bad information provided in intent: " + e.getMessage()); + Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage()); return START_NOT_STICKY; } catch (Exception e) { - Log.e(TAG, "Unexpected exception while processing upload intent", e); + Log_OC.e(TAG, "Unexpected exception while processing upload intent", e); return START_NOT_STICKY; } @@ -294,7 +295,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe msg.obj = requestedUploads; mServiceHandler.sendMessage(msg); } - Log.i(TAG, "mPendingUploads size:" + mPendingUploads.size()); + Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size()); return Service.START_NOT_STICKY; } @@ -457,7 +458,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } finally { synchronized (mPendingUploads) { mPendingUploads.remove(uploadKey); - Log.i(TAG, "Remove CurrentUploadItem from pending upload Item Map."); + Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map."); } } @@ -503,12 +504,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } result = new RemoteOperationResult(isMultiStatus, status); - Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + Log_OC.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + Log_OC.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage(), e); } finally { @@ -584,7 +585,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension( remotePath.substring(remotePath.lastIndexOf('.') + 1)); } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath); + Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath); } } if (mimeType == null) { @@ -672,7 +673,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe * @param upload Finished upload operation */ private void notifyUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) { - Log.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode()); + Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode()); if (uploadResult.isCancelled()) { // / cancelled operation -> silent removal of progress notification mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); diff --git a/src/com/owncloud/android/files/services/InstantUploadService.java b/src/com/owncloud/android/files/services/InstantUploadService.java index ae1cb0565a..8ec0a8d0f1 100644 --- a/src/com/owncloud/android/files/services/InstantUploadService.java +++ b/src/com/owncloud/android/files/services/InstantUploadService.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import com.owncloud.android.Log_OC; import com.owncloud.android.network.OwnCloudClientUtils; import eu.alefzero.webdav.WebdavClient; @@ -56,7 +57,7 @@ public class InstantUploadService extends Service { if (intent == null || !intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_DISPLAY_NAME) || !intent.hasExtra(KEY_FILE_PATH) || !intent.hasExtra(KEY_FILE_SIZE) || !intent.hasExtra(KEY_MIME_TYPE)) { - Log.w(TAG, "Not all required information was provided, abording"); + Log_OC.w(TAG, "Not all required information was provided, abording"); return Service.START_NOT_STICKY; } @@ -74,7 +75,7 @@ public class InstantUploadService extends Service { // starting new thread for new download doesnt seems like a good idea // maybe some thread pool or single background thread would be better - Log.d(TAG, "Starting instant upload thread"); + Log_OC.d(TAG, "Starting instant upload thread"); new Thread(mUploaderRunnable).start(); return Service.START_STICKY; diff --git a/src/com/owncloud/android/location/LocationServiceLauncherReciever.java b/src/com/owncloud/android/location/LocationServiceLauncherReciever.java index a2b131f8b2..0803f47c81 100644 --- a/src/com/owncloud/android/location/LocationServiceLauncherReciever.java +++ b/src/com/owncloud/android/location/LocationServiceLauncherReciever.java @@ -18,6 +18,8 @@ */ package com.owncloud.android.location; +import com.owncloud.android.Log_OC; + import android.app.ActivityManager; import android.app.ActivityManager.RunningServiceInfo; import android.content.BroadcastReceiver; @@ -60,10 +62,10 @@ public class LocationServiceLauncherReciever extends BroadcastReceiver { deviceTrackingIntent .setAction("com.owncloud.android.location.LocationUpdateService"); if (!isDeviceTrackingServiceRunning(context) && trackDevice) { - Log.d(TAG, "Starting device tracker service"); + Log_OC.d(TAG, "Starting device tracker service"); context.startService(deviceTrackingIntent); } else if (isDeviceTrackingServiceRunning(context) && !trackDevice) { - Log.d(TAG, "Stopping device tracker service"); + Log_OC.d(TAG, "Stopping device tracker service"); context.stopService(deviceTrackingIntent); } } diff --git a/src/com/owncloud/android/location/LocationUpdateService.java b/src/com/owncloud/android/location/LocationUpdateService.java index 1b6b28a703..c468fbda46 100644 --- a/src/com/owncloud/android/location/LocationUpdateService.java +++ b/src/com/owncloud/android/location/LocationUpdateService.java @@ -31,6 +31,7 @@ import android.preference.PreferenceManager; import android.util.Log; import android.widget.Toast; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; public class LocationUpdateService extends IntentService implements @@ -76,7 +77,7 @@ public class LocationUpdateService extends IntentService implements // If we do shall track the device -> Stop if (!trackDevice) { - Log.d(TAG, "Devicetracking is disabled"); + Log_OC.d(TAG, "Devicetracking is disabled"); stopSelf(); return; } @@ -87,7 +88,7 @@ public class LocationUpdateService extends IntentService implements @Override public void onLocationChanged(Location location) { - Log.d(TAG, "Location changed: " + location); + Log_OC.d(TAG, "Location changed: " + location); } diff --git a/src/com/owncloud/android/network/AdvancedSslSocketFactory.java b/src/com/owncloud/android/network/AdvancedSslSocketFactory.java index c206ca7c80..59a125defd 100644 --- a/src/com/owncloud/android/network/AdvancedSslSocketFactory.java +++ b/src/com/owncloud/android/network/AdvancedSslSocketFactory.java @@ -40,6 +40,8 @@ import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.http.conn.ssl.X509HostnameVerifier; +import com.owncloud.android.Log_OC; + import android.util.Log; /** @@ -104,13 +106,13 @@ public class AdvancedSslSocketFactory implements ProtocolSocketFactory { final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { - Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params); + Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params); if (params == null) { throw new IllegalArgumentException("Parameters may not be null"); } int timeout = params.getConnectionTimeout(); SocketFactory socketfactory = mSslContext.getSocketFactory(); - Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout()); + Log_OC.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout()); Socket socket = socketfactory.createSocket(); SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); SocketAddress remoteaddr = new InetSocketAddress(host, port); @@ -126,7 +128,7 @@ public class AdvancedSslSocketFactory implements ProtocolSocketFactory { */ public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port); + Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port); Socket socket = mSslContext.getSocketFactory().createSocket(host, port); verifyPeerIdentity(host, port, socket); return socket; diff --git a/src/com/owncloud/android/network/AdvancedX509TrustManager.java b/src/com/owncloud/android/network/AdvancedX509TrustManager.java index d3c7924618..671e98b528 100644 --- a/src/com/owncloud/android/network/AdvancedX509TrustManager.java +++ b/src/com/owncloud/android/network/AdvancedX509TrustManager.java @@ -32,6 +32,8 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; +import com.owncloud.android.Log_OC; + import android.util.Log; /** @@ -139,7 +141,7 @@ public class AdvancedX509TrustManager implements X509TrustManager { try { return (mKnownServersKeyStore.getCertificateAlias(cert) != null); } catch (KeyStoreException e) { - Log.d(TAG, "Fail while checking certificate in the known-servers store"); + Log_OC.d(TAG, "Fail while checking certificate in the known-servers store"); return false; } } diff --git a/src/com/owncloud/android/network/OwnCloudClientUtils.java b/src/com/owncloud/android/network/OwnCloudClientUtils.java index 198441306b..bed7aff23a 100644 --- a/src/com/owncloud/android/network/OwnCloudClientUtils.java +++ b/src/com/owncloud/android/network/OwnCloudClientUtils.java @@ -38,6 +38,7 @@ import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier; import org.apache.http.conn.ssl.X509HostnameVerifier; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import eu.alefzero.webdav.WebdavClient; @@ -75,7 +76,7 @@ public class OwnCloudClientUtils { * @return A WebdavClient object ready to be used */ public static WebdavClient createOwnCloudClient (Account account, Context context) { - Log.d(TAG, "Creating WebdavClient associated to " + account.name); + Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name); Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(context, account)); WebdavClient client = createOwnCloudClient(uri, context); @@ -100,7 +101,7 @@ public class OwnCloudClientUtils { * @return A WebdavClient object ready to be used */ public static WebdavClient createOwnCloudClient(Uri uri, String username, String password, Context context) { - Log.d(TAG, "Creating WebdavClient for " + username + "@" + uri); + Log_OC.d(TAG, "Creating WebdavClient for " + username + "@" + uri); WebdavClient client = createOwnCloudClient(uri, context); @@ -118,16 +119,16 @@ public class OwnCloudClientUtils { * @return A WebdavClient object ready to be used */ public static WebdavClient createOwnCloudClient(Uri uri, Context context) { - Log.d(TAG, "Creating WebdavClient for " + uri); + Log_OC.d(TAG, "Creating WebdavClient for " + uri); //allowSelfsignedCertificates(true); try { registerAdvancedSslContext(true, context); } catch (GeneralSecurityException e) { - Log.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in the system will be used for HTTPS connections", e); + Log_OC.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in the system will be used for HTTPS connections", e); } catch (IOException e) { - Log.e(TAG, "The local server truststore could not be read. Default SSL management in the system will be used for HTTPS connections", e); + Log_OC.e(TAG, "The local server truststore could not be read. Default SSL management in the system will be used for HTTPS connections", e); } WebdavClient client = new WebdavClient(getMultiThreadedConnManager()); @@ -205,7 +206,7 @@ public class OwnCloudClientUtils { //mKnownServersStore = KeyStore.getInstance("BKS"); mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType()); File localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME); - Log.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath()); + Log_OC.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath()); if (localTrustStoreFile.exists()) { InputStream in = new FileInputStream(localTrustStoreFile); try { diff --git a/src/com/owncloud/android/operations/ChunkedUploadFileOperation.java b/src/com/owncloud/android/operations/ChunkedUploadFileOperation.java index c01ee46b0a..0e9838e661 100644 --- a/src/com/owncloud/android/operations/ChunkedUploadFileOperation.java +++ b/src/com/owncloud/android/operations/ChunkedUploadFileOperation.java @@ -28,6 +28,7 @@ import java.util.Random; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.PutMethod; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.OCFile; import android.accounts.Account; @@ -74,7 +75,7 @@ public class ChunkedUploadFileOperation extends UploadFileOperation { mPutMethod.setRequestEntity(entity); status = client.executeMethod(mPutMethod); client.exhaustResponse(mPutMethod.getResponseBodyAsStream()); - Log.d(TAG, "Upload of " + getStoragePath() + " to " + getRemotePath() + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status); + Log_OC.d(TAG, "Upload of " + getStoragePath() + " to " + getRemotePath() + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status); if (!isSuccess(status)) break; } diff --git a/src/com/owncloud/android/operations/ConnectionCheckOperation.java b/src/com/owncloud/android/operations/ConnectionCheckOperation.java index f8ede26384..d83de76b30 100644 --- a/src/com/owncloud/android/operations/ConnectionCheckOperation.java +++ b/src/com/owncloud/android/operations/ConnectionCheckOperation.java @@ -24,6 +24,7 @@ import org.json.JSONException; import org.json.JSONObject; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.utils.OwnCloudVersion; import eu.alefzero.webdav.WebdavClient; @@ -96,13 +97,13 @@ public class ConnectionCheckOperation extends RemoteOperation { } if (mLatestResult.isSuccess()) { - Log.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); + Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); } else if (mLatestResult.getException() != null) { - Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); + Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); } else { - Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); + Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); } return retval; @@ -127,7 +128,7 @@ public class ConnectionCheckOperation extends RemoteOperation { client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH)); boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { - Log.d(TAG, "establishing secure connection failed, trying non secure connection"); + Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection"); client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH)); tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH); } diff --git a/src/com/owncloud/android/operations/DownloadFileOperation.java b/src/com/owncloud/android/operations/DownloadFileOperation.java index 75bf9234d2..e84345ca5b 100644 --- a/src/com/owncloud/android/operations/DownloadFileOperation.java +++ b/src/com/owncloud/android/operations/DownloadFileOperation.java @@ -33,6 +33,7 @@ import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.http.HttpStatus; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.operations.RemoteOperation; import com.owncloud.android.operations.RemoteOperationResult; @@ -104,7 +105,7 @@ public class DownloadFileOperation extends RemoteOperation { .getMimeTypeFromExtension( mFile.getRemotePath().substring(mFile.getRemotePath().lastIndexOf('.') + 1)); } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Trying to find out MIME type of a file without extension: " + mFile.getRemotePath()); + Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + mFile.getRemotePath()); } } if (mimeType == null) { @@ -148,11 +149,11 @@ public class DownloadFileOperation extends RemoteOperation { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED); else result = new RemoteOperationResult(isSuccess(status), status); - Log.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage(), e); } return result; diff --git a/src/com/owncloud/android/operations/RemoveFileOperation.java b/src/com/owncloud/android/operations/RemoveFileOperation.java index 80f409779c..4203f6f804 100644 --- a/src/com/owncloud/android/operations/RemoveFileOperation.java +++ b/src/com/owncloud/android/operations/RemoveFileOperation.java @@ -23,6 +23,7 @@ import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; import android.util.Log; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -91,11 +92,11 @@ public class RemoveFileOperation extends RemoteOperation { } delete.getResponseBodyAsString(); // exhaust the response, although not interesting result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status); - Log.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage(), e); } finally { if (delete != null) diff --git a/src/com/owncloud/android/operations/RenameFileOperation.java b/src/com/owncloud/android/operations/RenameFileOperation.java index 41233f18fe..bc2c6e0197 100644 --- a/src/com/owncloud/android/operations/RenameFileOperation.java +++ b/src/com/owncloud/android/operations/RenameFileOperation.java @@ -27,6 +27,7 @@ import org.apache.jackrabbit.webdav.client.methods.DavMethodBase; import android.accounts.Account; import android.util.Log; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; @@ -138,11 +139,11 @@ public class RenameFileOperation extends RemoteOperation { move.getResponseBodyAsString(); // exhaust response, although not interesting result = new RemoteOperationResult(move.succeeded(), status); - Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e); } finally { if (move != null) @@ -206,7 +207,7 @@ public class RenameFileOperation extends RemoteOperation { try { testFile.createNewFile(); // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name } catch (IOException e) { - Log.i(TAG, "Test for validity of name " + mNewName + " in the file system failed"); + Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed"); return false; } boolean result = (testFile.exists() && testFile.isFile()); diff --git a/src/com/owncloud/android/operations/SynchronizeFileOperation.java b/src/com/owncloud/android/operations/SynchronizeFileOperation.java index 606017aa5c..8b1857feef 100644 --- a/src/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.Intent; import android.util.Log; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader; @@ -158,11 +159,11 @@ public class SynchronizeFileOperation extends RemoteOperation { } - Log.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage(), result.getException()); } finally { if (propfind != null) diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java index 977460bfa9..96131a20c6 100644 --- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -37,6 +37,7 @@ import android.accounts.Account; import android.content.Context; import android.util.Log; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; @@ -132,7 +133,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { // code before in FileSyncAdapter.fetchData PropFindMethod query = null; try { - Log.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath); + Log_OC.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath); // remote request query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath)); @@ -209,9 +210,9 @@ public class SynchronizeFolderOperation extends RemoteOperation { } else { mFailsInFavouritesFound++; if (contentsResult.getException() != null) { - Log.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); + Log_OC.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); } else { - Log.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage()); + Log_OC.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage()); } } } // won't let these fails break the synchronization process @@ -225,7 +226,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { for (int i=0; i < mChildren.size(); ) { file = mChildren.get(i); if (file.getLastSyncDateForProperties() != mCurrentSyncTime) { - Log.d(TAG, "removing file: " + file); + Log_OC.d(TAG, "removing file: " + file); mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath))); mChildren.remove(i); } else { @@ -248,12 +249,12 @@ public class SynchronizeFolderOperation extends RemoteOperation { } else { result = new RemoteOperationResult(false, status); } - Log.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException()); } finally { if (query != null) @@ -329,7 +330,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { file.setStoragePath(expectedPath); } catch (Exception e) { - Log.e(TAG, "Exception while copying foreign file " + expectedPath, e); + Log_OC.e(TAG, "Exception while copying foreign file " + expectedPath, e); mForgottenLocalFiles.put(file.getRemotePath(), storagePath); file.setStoragePath(null); @@ -337,12 +338,12 @@ public class SynchronizeFolderOperation extends RemoteOperation { try { if (in != null) in.close(); } catch (Exception e) { - Log.d(TAG, "Weird exception while closing input stream for " + storagePath + " (ignoring)", e); + Log_OC.d(TAG, "Weird exception while closing input stream for " + storagePath + " (ignoring)", e); } try { if (out != null) out.close(); } catch (Exception e) { - Log.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); + Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); } } } diff --git a/src/com/owncloud/android/operations/UpdateOCVersionOperation.java b/src/com/owncloud/android/operations/UpdateOCVersionOperation.java index 08a9c15f87..2316881222 100644 --- a/src/com/owncloud/android/operations/UpdateOCVersionOperation.java +++ b/src/com/owncloud/android/operations/UpdateOCVersionOperation.java @@ -29,6 +29,7 @@ import android.content.Context; import android.util.Log; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.utils.OwnCloudVersion; @@ -76,11 +77,11 @@ public class UpdateOCVersionOperation extends RemoteOperation { OwnCloudVersion ocver = new OwnCloudVersion(json.getString("version")); if (ocver.isVersionValid()) { accountMngr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION, ocver.toString()); - Log.d(TAG, "Got new OC version " + ocver.toString()); + Log_OC.d(TAG, "Got new OC version " + ocver.toString()); result = new RemoteOperationResult(ResultCode.OK); } else { - Log.w(TAG, "Invalid version number received from server: " + json.getString("version")); + Log_OC.w(TAG, "Invalid version number received from server: " + json.getString("version")); result = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION); } } @@ -89,15 +90,15 @@ public class UpdateOCVersionOperation extends RemoteOperation { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } } - Log.i(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage()); } catch (JSONException e) { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - Log.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e); } finally { if (get != null) diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index 2824b6da36..704a88a84a 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -32,6 +32,7 @@ import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.http.HttpStatus; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.operations.RemoteOperation; @@ -214,12 +215,12 @@ public class UploadFileOperation extends RemoteOperation { try { if (in != null) in.close(); } catch (Exception e) { - Log.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e); + Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e); } try { if (out != null) out.close(); } catch (Exception e) { - Log.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); + Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); } } } @@ -282,7 +283,7 @@ public class UploadFileOperation extends RemoteOperation { temporalFile.delete(); } if (result.isSuccess()) { - Log.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()); } else { if (result.getException() != null) { @@ -292,9 +293,9 @@ public class UploadFileOperation extends RemoteOperation { } else if (!localCopyPassed) { complement = " (while copying local file to " + FileStorageUtils.getSavePath(mAccount.name) + ")"; } - Log.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage() + complement, result.getException()); + Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage() + complement, result.getException()); } else { - Log.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()); } } } diff --git a/src/com/owncloud/android/providers/FileContentProvider.java b/src/com/owncloud/android/providers/FileContentProvider.java index 5e54341bb3..aedb5685d7 100644 --- a/src/com/owncloud/android/providers/FileContentProvider.java +++ b/src/com/owncloud/android/providers/FileContentProvider.java @@ -1,289 +1,290 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * 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 . - * - */ - -package com.owncloud.android.providers; - -import java.util.HashMap; - -import com.owncloud.android.db.ProviderMeta; -import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; - - -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; - -/** - * The ContentProvider for the ownCloud App. - * - * @author Bartek Przybylski - * - */ -public class FileContentProvider extends ContentProvider { - - private DataBaseHelper mDbHelper; - - private static HashMap mProjectionMap; - static { - mProjectionMap = new HashMap(); - mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); - mProjectionMap.put(ProviderTableMeta.FILE_PARENT, - ProviderTableMeta.FILE_PARENT); - mProjectionMap.put(ProviderTableMeta.FILE_PATH, - ProviderTableMeta.FILE_PATH); - mProjectionMap.put(ProviderTableMeta.FILE_NAME, - ProviderTableMeta.FILE_NAME); - mProjectionMap.put(ProviderTableMeta.FILE_CREATION, - ProviderTableMeta.FILE_CREATION); - mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, - ProviderTableMeta.FILE_MODIFIED); - mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, - ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA); - mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH, - ProviderTableMeta.FILE_CONTENT_LENGTH); - mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE, - ProviderTableMeta.FILE_CONTENT_TYPE); - mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH, - ProviderTableMeta.FILE_STORAGE_PATH); - mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, - ProviderTableMeta.FILE_LAST_SYNC_DATE); - mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, - ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA); - mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, - ProviderTableMeta.FILE_KEEP_IN_SYNC); - mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, - ProviderTableMeta.FILE_ACCOUNT_OWNER); - } - - private static final int SINGLE_FILE = 1; - private static final int DIRECTORY = 2; - private static final int ROOT_DIRECTORY = 3; - private static final UriMatcher mUriMatcher; - static { - mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); - } - - @Override - public int delete(Uri uri, String where, String[] whereArgs) { - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - int count = 0; - switch (mUriMatcher.match(uri)) { - case SINGLE_FILE: - count = db.delete(ProviderTableMeta.DB_NAME, - ProviderTableMeta._ID - + "=" - + uri.getPathSegments().get(1) - + (!TextUtils.isEmpty(where) ? " AND (" + where - + ")" : ""), whereArgs); - break; - case ROOT_DIRECTORY: - count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); - break; - default: - throw new IllegalArgumentException("Unknown uri: " + uri.toString()); - } - getContext().getContentResolver().notifyChange(uri, null); - return count; - } - - @Override - public String getType(Uri uri) { - switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - return ProviderTableMeta.CONTENT_TYPE; - case SINGLE_FILE: - return ProviderTableMeta.CONTENT_TYPE_ITEM; - default: - throw new IllegalArgumentException("Unknown Uri id." - + uri.toString()); - } - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - if (mUriMatcher.match(uri) != SINGLE_FILE && - mUriMatcher.match(uri) != ROOT_DIRECTORY) { - - throw new IllegalArgumentException("Unknown uri id: " + uri); - } - - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values); - if (rowId > 0) { - Uri insertedFileUri = ContentUris.withAppendedId( - ProviderTableMeta.CONTENT_URI_FILE, rowId); - getContext().getContentResolver().notifyChange(insertedFileUri, - null); - return insertedFileUri; - } - throw new SQLException("ERROR " + uri); - } - - @Override - public boolean onCreate() { - mDbHelper = new DataBaseHelper(getContext()); - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); - - sqlQuery.setTables(ProviderTableMeta.DB_NAME); - sqlQuery.setProjectionMap(mProjectionMap); - - switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - break; - case DIRECTORY: - sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" - + uri.getPathSegments().get(1)); - break; - case SINGLE_FILE: - if (uri.getPathSegments().size() > 1) { - sqlQuery.appendWhere(ProviderTableMeta._ID + "=" - + uri.getPathSegments().get(1)); - } - break; - default: - throw new IllegalArgumentException("Unknown uri id: " + uri); - } - - String order; - if (TextUtils.isEmpty(sortOrder)) { - order = ProviderTableMeta.DEFAULT_SORT_ORDER; - } else { - order = sortOrder; - } - - SQLiteDatabase db = mDbHelper.getReadableDatabase(); - Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, - null, null, order); - - c.setNotificationUri(getContext().getContentResolver(), uri); - - return c; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - return mDbHelper.getWritableDatabase().update( - ProviderTableMeta.DB_NAME, values, selection, selectionArgs); - } - - class DataBaseHelper extends SQLiteOpenHelper { - - public DataBaseHelper(Context context) { - super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION); - - } - - @Override - public void onCreate(SQLiteDatabase db) { - // files table - Log.i("SQL", "Entering in onCreate"); - db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" - + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " - + ProviderTableMeta.FILE_NAME + " TEXT, " - + ProviderTableMeta.FILE_PATH + " TEXT, " - + ProviderTableMeta.FILE_PARENT + " INTEGER, " - + ProviderTableMeta.FILE_CREATION + " INTEGER, " - + ProviderTableMeta.FILE_MODIFIED + " INTEGER, " - + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " - + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " - + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " - + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, " - + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, " - + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, " - + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, " - + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );" - ); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.i("SQL", "Entering in onUpgrade"); - boolean upgraded = false; - if (oldVersion == 1 && newVersion >= 2) { - Log.i("SQL", "Entering in the #1 ADD in onUpgrade"); - db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + - " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + - " DEFAULT 0"); - upgraded = true; - } - if (oldVersion < 3 && newVersion >= 3) { - Log.i("SQL", "Entering in the #2 ADD in onUpgrade"); - db.beginTransaction(); - try { - db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + - " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " + - " DEFAULT 0"); - - // assume there are not local changes pending to upload - db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + - " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + - " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); - - upgraded = true; - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - if (oldVersion < 4 && newVersion >= 4) { - Log.i("SQL", "Entering in the #3 ADD in onUpgrade"); - db.beginTransaction(); - try { - db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + - " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " + - " DEFAULT 0"); - - db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + - " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + - " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); - - upgraded = true; - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - if (!upgraded) - Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); - } - - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * 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 . + * + */ + +package com.owncloud.android.providers; + +import java.util.HashMap; + +import com.owncloud.android.Log_OC; +import com.owncloud.android.db.ProviderMeta; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; + + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +/** + * The ContentProvider for the ownCloud App. + * + * @author Bartek Przybylski + * + */ +public class FileContentProvider extends ContentProvider { + + private DataBaseHelper mDbHelper; + + private static HashMap mProjectionMap; + static { + mProjectionMap = new HashMap(); + mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); + mProjectionMap.put(ProviderTableMeta.FILE_PARENT, + ProviderTableMeta.FILE_PARENT); + mProjectionMap.put(ProviderTableMeta.FILE_PATH, + ProviderTableMeta.FILE_PATH); + mProjectionMap.put(ProviderTableMeta.FILE_NAME, + ProviderTableMeta.FILE_NAME); + mProjectionMap.put(ProviderTableMeta.FILE_CREATION, + ProviderTableMeta.FILE_CREATION); + mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, + ProviderTableMeta.FILE_MODIFIED); + mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA); + mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH, + ProviderTableMeta.FILE_CONTENT_LENGTH); + mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE, + ProviderTableMeta.FILE_CONTENT_TYPE); + mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH, + ProviderTableMeta.FILE_STORAGE_PATH); + mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, + ProviderTableMeta.FILE_LAST_SYNC_DATE); + mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA); + mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, + ProviderTableMeta.FILE_KEEP_IN_SYNC); + mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, + ProviderTableMeta.FILE_ACCOUNT_OWNER); + } + + private static final int SINGLE_FILE = 1; + private static final int DIRECTORY = 2; + private static final int ROOT_DIRECTORY = 3; + private static final UriMatcher mUriMatcher; + static { + mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); + } + + @Override + public int delete(Uri uri, String where, String[] whereArgs) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + int count = 0; + switch (mUriMatcher.match(uri)) { + case SINGLE_FILE: + count = db.delete(ProviderTableMeta.DB_NAME, + ProviderTableMeta._ID + + "=" + + uri.getPathSegments().get(1) + + (!TextUtils.isEmpty(where) ? " AND (" + where + + ")" : ""), whereArgs); + break; + case ROOT_DIRECTORY: + count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); + break; + default: + throw new IllegalArgumentException("Unknown uri: " + uri.toString()); + } + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + @Override + public String getType(Uri uri) { + switch (mUriMatcher.match(uri)) { + case ROOT_DIRECTORY: + return ProviderTableMeta.CONTENT_TYPE; + case SINGLE_FILE: + return ProviderTableMeta.CONTENT_TYPE_ITEM; + default: + throw new IllegalArgumentException("Unknown Uri id." + + uri.toString()); + } + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + if (mUriMatcher.match(uri) != SINGLE_FILE && + mUriMatcher.match(uri) != ROOT_DIRECTORY) { + + throw new IllegalArgumentException("Unknown uri id: " + uri); + } + + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values); + if (rowId > 0) { + Uri insertedFileUri = ContentUris.withAppendedId( + ProviderTableMeta.CONTENT_URI_FILE, rowId); + getContext().getContentResolver().notifyChange(insertedFileUri, + null); + return insertedFileUri; + } + throw new SQLException("ERROR " + uri); + } + + @Override + public boolean onCreate() { + mDbHelper = new DataBaseHelper(getContext()); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); + + sqlQuery.setTables(ProviderTableMeta.DB_NAME); + sqlQuery.setProjectionMap(mProjectionMap); + + switch (mUriMatcher.match(uri)) { + case ROOT_DIRECTORY: + break; + case DIRECTORY: + sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" + + uri.getPathSegments().get(1)); + break; + case SINGLE_FILE: + if (uri.getPathSegments().size() > 1) { + sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + + uri.getPathSegments().get(1)); + } + break; + default: + throw new IllegalArgumentException("Unknown uri id: " + uri); + } + + String order; + if (TextUtils.isEmpty(sortOrder)) { + order = ProviderTableMeta.DEFAULT_SORT_ORDER; + } else { + order = sortOrder; + } + + SQLiteDatabase db = mDbHelper.getReadableDatabase(); + Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, + null, null, order); + + c.setNotificationUri(getContext().getContentResolver(), uri); + + return c; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, + String[] selectionArgs) { + return mDbHelper.getWritableDatabase().update( + ProviderTableMeta.DB_NAME, values, selection, selectionArgs); + } + + class DataBaseHelper extends SQLiteOpenHelper { + + public DataBaseHelper(Context context) { + super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION); + + } + + @Override + public void onCreate(SQLiteDatabase db) { + // files table + Log_OC.i("SQL", "Entering in onCreate"); + db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + + ProviderTableMeta.FILE_NAME + " TEXT, " + + ProviderTableMeta.FILE_PATH + " TEXT, " + + ProviderTableMeta.FILE_PARENT + " INTEGER, " + + ProviderTableMeta.FILE_CREATION + " INTEGER, " + + ProviderTableMeta.FILE_MODIFIED + " INTEGER, " + + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " + + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " + + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, " + + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, " + + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, " + + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, " + + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );" + ); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log_OC.i("SQL", "Entering in onUpgrade"); + boolean upgraded = false; + if (oldVersion == 1 && newVersion >= 2) { + Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade"); + db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + + " DEFAULT 0"); + upgraded = true; + } + if (oldVersion < 3 && newVersion >= 3) { + Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade"); + db.beginTransaction(); + try { + db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " + + " DEFAULT 0"); + + // assume there are not local changes pending to upload + db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + + " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + + " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + if (oldVersion < 4 && newVersion >= 4) { + Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade"); + db.beginTransaction(); + try { + db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " + + " DEFAULT 0"); + + db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + + " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + + " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + if (!upgraded) + Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); + } + + } + +} diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java index 6da3e81d13..3dc80d9183 100644 --- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -1,370 +1,371 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * 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 . - * - */ - -package com.owncloud.android.syncadapter; - -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.jackrabbit.webdav.DavException; - -import com.owncloud.android.R; -import com.owncloud.android.datamodel.DataStorageManager; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.operations.RemoteOperationResult; -import com.owncloud.android.operations.SynchronizeFolderOperation; -import com.owncloud.android.operations.UpdateOCVersionOperation; -import com.owncloud.android.operations.RemoteOperationResult.ResultCode; -import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity; -import android.accounts.Account; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.ContentProviderClient; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.SyncResult; -import android.os.Bundle; -import android.util.Log; - -/** - * SyncAdapter implementation for syncing sample SyncAdapter contacts to the - * platform ContactOperations provider. - * - * @author Bartek Przybylski - */ -public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { - - private final static String TAG = "FileSyncAdapter"; - - /** - * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation - */ - private static final int MAX_FAILED_RESULTS = 3; - - private long mCurrentSyncTime; - private boolean mCancellation; - private boolean mIsManualSync; - private int mFailedResultsCounter; - private RemoteOperationResult mLastFailedResult; - private SyncResult mSyncResult; - private int mConflictsFound; - private int mFailsInFavouritesFound; - private Map mForgottenLocalFiles; - - - public FileSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized void onPerformSync(Account account, Bundle extras, - String authority, ContentProviderClient provider, - SyncResult syncResult) { - - mCancellation = false; - mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); - mFailedResultsCounter = 0; - mLastFailedResult = null; - mConflictsFound = 0; - mFailsInFavouritesFound = 0; - mForgottenLocalFiles = new HashMap(); - mSyncResult = syncResult; - mSyncResult.fullSyncRequested = false; - mSyncResult.delayUntil = 60*60*24; // sync after 24h - - this.setAccount(account); - this.setContentProvider(provider); - this.setStorageManager(new FileDataStorageManager(account, getContentProvider())); - try { - this.initClientForCurrentAccount(); - } catch (UnknownHostException e) { - /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again - mSyncResult.tooManyRetries = true; - notifyFailedSynchronization(); - return; - } - - Log.d(TAG, "Synchronization of ownCloud account " + account.name + " starting"); - sendStickyBroadcast(true, null, null); // message to signal the start of the synchronization to the UI - - try { - updateOCVersion(); - mCurrentSyncTime = System.currentTimeMillis(); - if (!mCancellation) { - fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID); - - } else { - Log.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested"); - } - - - } finally { - // it's important making this although very unexpected errors occur; that's the reason for the finally - - if (mFailedResultsCounter > 0 && mIsManualSync) { - /// don't let the system synchronization manager retries MANUAL synchronizations - // (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account) - mSyncResult.tooManyRetries = true; - - /// notify the user about the failure of MANUAL synchronization - notifyFailedSynchronization(); - - } - if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { - notifyFailsInFavourites(); - } - if (mForgottenLocalFiles.size() > 0) { - notifyForgottenLocalFiles(); - - } - sendStickyBroadcast(false, null, mLastFailedResult); // message to signal the end to the UI - } - - } - - - /** - * Called by system SyncManager when a synchronization is required to be cancelled. - * - * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder - * fetched will be still saved in the database. See onPerformSync implementation. - */ - @Override - public void onSyncCanceled() { - Log.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel"); - mCancellation = true; - super.onSyncCanceled(); - } - - - /** - * Updates the locally stored version value of the ownCloud server - */ - private void updateOCVersion() { - UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext()); - RemoteOperationResult result = update.execute(getClient()); - if (!result.isSuccess()) { - mLastFailedResult = result; - } - } - - - - /** - * Synchronize the properties of files and folders contained in a remote folder given by remotePath. - * - * @param remotePath Remote path to the folder to synchronize. - * @param parentId Database Id of the folder to synchronize. - */ - private void fetchData(String remotePath, long parentId) { - - if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult)) - return; - - // perform folder synchronization - SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( remotePath, - mCurrentSyncTime, - parentId, - getStorageManager(), - getAccount(), - getContext() - ); - RemoteOperationResult result = synchFolderOp.execute(getClient()); - - - // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess - sendStickyBroadcast(true, remotePath, null); - - if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) { - - if (result.getCode() == ResultCode.SYNC_CONFLICT) { - mConflictsFound += synchFolderOp.getConflictsFound(); - mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound(); - } - if (synchFolderOp.getForgottenLocalFiles().size() > 0) { - mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles()); - } - // synchronize children folders - List children = synchFolderOp.getChildren(); - fetchChildren(children); // beware of the 'hidden' recursion here! - - } else { - if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) { - mSyncResult.stats.numAuthExceptions++; - - } else if (result.getException() instanceof DavException) { - mSyncResult.stats.numParseExceptions++; - - } else if (result.getException() instanceof IOException) { - mSyncResult.stats.numIoExceptions++; - } - mFailedResultsCounter++; - mLastFailedResult = result; - } - - } - - /** - * Checks if a failed result should terminate the synchronization process immediately, according to - * OUR OWN POLICY - * - * @param failedResult Remote operation result to check. - * @return 'True' if the result should immediately finish the synchronization - */ - private boolean isFinisher(RemoteOperationResult failedResult) { - if (failedResult != null) { - RemoteOperationResult.ResultCode code = failedResult.getCode(); - return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) || - code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) || - code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) || - code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED)); - } - return false; - } - - /** - * Synchronize data of folders in the list of received files - * - * @param files Files to recursively fetch - */ - private void fetchChildren(List files) { - int i; - for (i=0; i < files.size() && !mCancellation; i++) { - OCFile newFile = files.get(i); - if (newFile.isDirectory()) { - fetchData(newFile.getRemotePath(), newFile.getFileId()); - } - } - if (mCancellation && i 0) { - Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis()); - notification.flags |= Notification.FLAG_AUTO_CANCEL; - // TODO put something smart in the contentIntent below - notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); - notification.setLatestEventInfo(getContext().getApplicationContext(), - getContext().getString(R.string.sync_fail_in_favourites_ticker), - String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), - notification.contentIntent); - ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification); - - } else { - Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis()); - notification.flags |= Notification.FLAG_AUTO_CANCEL; - // TODO put something smart in the contentIntent below - notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); - notification.setLatestEventInfo(getContext().getApplicationContext(), - getContext().getString(R.string.sync_conflicts_in_favourites_ticker), - String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), - notification.contentIntent); - ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification); - } - } - - - /** - * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because - * copying them inside the ownCloud local directory was not possible. - * - * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have - * synchronization problems if a local file is linked to more than one remote file. - * - * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory. - */ - private void notifyForgottenLocalFiles() { - Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis()); - notification.flags |= Notification.FLAG_AUTO_CANCEL; - - /// includes a pending intent in the notification showing a more detailed explanation - Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class); - explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount()); - ArrayList remotePaths = new ArrayList(); - ArrayList localPaths = new ArrayList(); - remotePaths.addAll(mForgottenLocalFiles.keySet()); - localPaths.addAll(mForgottenLocalFiles.values()); - explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths); - explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths); - explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0); - notification.setLatestEventInfo(getContext().getApplicationContext(), - getContext().getString(R.string.sync_foreign_files_forgotten_ticker), - String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), - notification.contentIntent); - ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification); - - } - - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * 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 . + * + */ + +package com.owncloud.android.syncadapter; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.jackrabbit.webdav.DavException; + +import com.owncloud.android.Log_OC; +import com.owncloud.android.R; +import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.operations.RemoteOperationResult; +import com.owncloud.android.operations.SynchronizeFolderOperation; +import com.owncloud.android.operations.UpdateOCVersionOperation; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity; +import android.accounts.Account; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.SyncResult; +import android.os.Bundle; +import android.util.Log; + +/** + * SyncAdapter implementation for syncing sample SyncAdapter contacts to the + * platform ContactOperations provider. + * + * @author Bartek Przybylski + */ +public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { + + private final static String TAG = "FileSyncAdapter"; + + /** + * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation + */ + private static final int MAX_FAILED_RESULTS = 3; + + private long mCurrentSyncTime; + private boolean mCancellation; + private boolean mIsManualSync; + private int mFailedResultsCounter; + private RemoteOperationResult mLastFailedResult; + private SyncResult mSyncResult; + private int mConflictsFound; + private int mFailsInFavouritesFound; + private Map mForgottenLocalFiles; + + + public FileSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void onPerformSync(Account account, Bundle extras, + String authority, ContentProviderClient provider, + SyncResult syncResult) { + + mCancellation = false; + mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); + mFailedResultsCounter = 0; + mLastFailedResult = null; + mConflictsFound = 0; + mFailsInFavouritesFound = 0; + mForgottenLocalFiles = new HashMap(); + mSyncResult = syncResult; + mSyncResult.fullSyncRequested = false; + mSyncResult.delayUntil = 60*60*24; // sync after 24h + + this.setAccount(account); + this.setContentProvider(provider); + this.setStorageManager(new FileDataStorageManager(account, getContentProvider())); + try { + this.initClientForCurrentAccount(); + } catch (UnknownHostException e) { + /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again + mSyncResult.tooManyRetries = true; + notifyFailedSynchronization(); + return; + } + + Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting"); + sendStickyBroadcast(true, null, null); // message to signal the start of the synchronization to the UI + + try { + updateOCVersion(); + mCurrentSyncTime = System.currentTimeMillis(); + if (!mCancellation) { + fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID); + + } else { + Log_OC.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested"); + } + + + } finally { + // it's important making this although very unexpected errors occur; that's the reason for the finally + + if (mFailedResultsCounter > 0 && mIsManualSync) { + /// don't let the system synchronization manager retries MANUAL synchronizations + // (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account) + mSyncResult.tooManyRetries = true; + + /// notify the user about the failure of MANUAL synchronization + notifyFailedSynchronization(); + + } + if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { + notifyFailsInFavourites(); + } + if (mForgottenLocalFiles.size() > 0) { + notifyForgottenLocalFiles(); + + } + sendStickyBroadcast(false, null, mLastFailedResult); // message to signal the end to the UI + } + + } + + + /** + * Called by system SyncManager when a synchronization is required to be cancelled. + * + * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder + * fetched will be still saved in the database. See onPerformSync implementation. + */ + @Override + public void onSyncCanceled() { + Log_OC.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel"); + mCancellation = true; + super.onSyncCanceled(); + } + + + /** + * Updates the locally stored version value of the ownCloud server + */ + private void updateOCVersion() { + UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext()); + RemoteOperationResult result = update.execute(getClient()); + if (!result.isSuccess()) { + mLastFailedResult = result; + } + } + + + + /** + * Synchronize the properties of files and folders contained in a remote folder given by remotePath. + * + * @param remotePath Remote path to the folder to synchronize. + * @param parentId Database Id of the folder to synchronize. + */ + private void fetchData(String remotePath, long parentId) { + + if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult)) + return; + + // perform folder synchronization + SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( remotePath, + mCurrentSyncTime, + parentId, + getStorageManager(), + getAccount(), + getContext() + ); + RemoteOperationResult result = synchFolderOp.execute(getClient()); + + + // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess + sendStickyBroadcast(true, remotePath, null); + + if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) { + + if (result.getCode() == ResultCode.SYNC_CONFLICT) { + mConflictsFound += synchFolderOp.getConflictsFound(); + mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound(); + } + if (synchFolderOp.getForgottenLocalFiles().size() > 0) { + mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles()); + } + // synchronize children folders + List children = synchFolderOp.getChildren(); + fetchChildren(children); // beware of the 'hidden' recursion here! + + } else { + if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) { + mSyncResult.stats.numAuthExceptions++; + + } else if (result.getException() instanceof DavException) { + mSyncResult.stats.numParseExceptions++; + + } else if (result.getException() instanceof IOException) { + mSyncResult.stats.numIoExceptions++; + } + mFailedResultsCounter++; + mLastFailedResult = result; + } + + } + + /** + * Checks if a failed result should terminate the synchronization process immediately, according to + * OUR OWN POLICY + * + * @param failedResult Remote operation result to check. + * @return 'True' if the result should immediately finish the synchronization + */ + private boolean isFinisher(RemoteOperationResult failedResult) { + if (failedResult != null) { + RemoteOperationResult.ResultCode code = failedResult.getCode(); + return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) || + code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) || + code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) || + code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED)); + } + return false; + } + + /** + * Synchronize data of folders in the list of received files + * + * @param files Files to recursively fetch + */ + private void fetchChildren(List files) { + int i; + for (i=0; i < files.size() && !mCancellation; i++) { + OCFile newFile = files.get(i); + if (newFile.isDirectory()) { + fetchData(newFile.getRemotePath(), newFile.getFileId()); + } + } + if (mCancellation && i 0) { + Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis()); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + // TODO put something smart in the contentIntent below + notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_fail_in_favourites_ticker), + String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), + notification.contentIntent); + ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification); + + } else { + Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis()); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + // TODO put something smart in the contentIntent below + notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_conflicts_in_favourites_ticker), + String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), + notification.contentIntent); + ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification); + } + } + + + /** + * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because + * copying them inside the ownCloud local directory was not possible. + * + * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have + * synchronization problems if a local file is linked to more than one remote file. + * + * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory. + */ + private void notifyForgottenLocalFiles() { + Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis()); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + + /// includes a pending intent in the notification showing a more detailed explanation + Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class); + explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount()); + ArrayList remotePaths = new ArrayList(); + ArrayList localPaths = new ArrayList(); + remotePaths.addAll(mForgottenLocalFiles.keySet()); + localPaths.addAll(mForgottenLocalFiles.values()); + explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths); + explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths); + explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_foreign_files_forgotten_ticker), + String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), + notification.contentIntent); + ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification); + + } + + +} diff --git a/src/com/owncloud/android/ui/activity/AccountSelectActivity.java b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java index 31b59d490a..2eca33a943 100644 --- a/src/com/owncloud/android/ui/activity/AccountSelectActivity.java +++ b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java @@ -50,6 +50,7 @@ import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.R; @@ -153,7 +154,7 @@ public class AccountSelectActivity extends SherlockListActivity implements try { map = (HashMap) getListAdapter().getItem(index); } catch (ClassCastException e) { - Log.wtf(TAG, "getitem(index) from list adapter did not return hashmap, bailing out"); + Log_OC.wtf(TAG, "getitem(index) from list adapter did not return hashmap, bailing out"); return false; } diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java index d277040656..2121329a47 100644 --- a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java +++ b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java @@ -1,609 +1,610 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * 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 . - * - */ - -package com.owncloud.android.ui.activity; - -import java.net.MalformedURLException; -import java.net.URL; - -import com.owncloud.android.AccountUtils; -import com.owncloud.android.authenticator.AccountAuthenticator; -import com.owncloud.android.authenticator.AuthenticationRunnable; -import com.owncloud.android.authenticator.OnAuthenticationResultListener; -import com.owncloud.android.authenticator.OnConnectCheckListener; -import com.owncloud.android.ui.dialog.SslValidatorDialog; -import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; -import com.owncloud.android.network.OwnCloudClientUtils; -import com.owncloud.android.operations.ConnectionCheckOperation; -import com.owncloud.android.operations.OnRemoteOperationListener; -import com.owncloud.android.operations.RemoteOperation; -import com.owncloud.android.operations.RemoteOperationResult; - -import android.accounts.Account; -import android.accounts.AccountAuthenticatorActivity; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.ContentResolver; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.text.InputType; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; -import android.view.Window; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.TextView; -import com.owncloud.android.R; - -import eu.alefzero.webdav.WebdavClient; - -/** - * This Activity is used to add an ownCloud account to the App - * - * @author Bartek Przybylski - * - */ -public class AuthenticatorActivity extends AccountAuthenticatorActivity - implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, - OnFocusChangeListener, OnClickListener { - - private static final int DIALOG_LOGIN_PROGRESS = 0; - private static final int DIALOG_SSL_VALIDATOR = 1; - private static final int DIALOG_CERT_NOT_SAVED = 2; - - private static final String TAG = "AuthActivity"; - - private Thread mAuthThread; - private AuthenticationRunnable mAuthRunnable; - //private ConnectionCheckerRunnable mConnChkRunnable = null; - private ConnectionCheckOperation mConnChkRunnable; - private final Handler mHandler = new Handler(); - private String mBaseUrl; - - private static final String STATUS_TEXT = "STATUS_TEXT"; - private static final String STATUS_ICON = "STATUS_ICON"; - private static final String STATUS_CORRECT = "STATUS_CORRECT"; - private static final String IS_SSL_CONN = "IS_SSL_CONN"; - private int mStatusText, mStatusIcon; - private boolean mStatusCorrect, mIsSslConn; - private RemoteOperationResult mLastSslUntrustedServerResult; - - public static final String PARAM_USERNAME = "param_Username"; - public static final String PARAM_HOSTNAME = "param_Hostname"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.account_setup); - ImageView iv = (ImageView) findViewById(R.id.refreshButton); - ImageView iv2 = (ImageView) findViewById(R.id.viewPassword); - TextView tv = (TextView) findViewById(R.id.host_URL); - TextView tv2 = (TextView) findViewById(R.id.account_password); - - if (savedInstanceState != null) { - mStatusIcon = savedInstanceState.getInt(STATUS_ICON); - mStatusText = savedInstanceState.getInt(STATUS_TEXT); - mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT); - mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN); - setResultIconAndText(mStatusIcon, mStatusText); - findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); - if (!mStatusCorrect) - iv.setVisibility(View.VISIBLE); - else - iv.setVisibility(View.INVISIBLE); - - } else { - mStatusText = mStatusIcon = 0; - mStatusCorrect = false; - mIsSslConn = false; - } - iv.setOnClickListener(this); - iv2.setOnClickListener(this); - tv.setOnFocusChangeListener(this); - tv2.setOnFocusChangeListener(this); - - Button b = (Button) findViewById(R.id.account_register); - if (b != null) { - b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name))); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putInt(STATUS_ICON, mStatusIcon); - outState.putInt(STATUS_TEXT, mStatusText); - outState.putBoolean(STATUS_CORRECT, mStatusCorrect); - super.onSaveInstanceState(outState); - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog = null; - switch (id) { - case DIALOG_LOGIN_PROGRESS: { - ProgressDialog working_dialog = new ProgressDialog(this); - working_dialog.setMessage(getResources().getString( - R.string.auth_trying_to_login)); - working_dialog.setIndeterminate(true); - working_dialog.setCancelable(true); - working_dialog - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - Log.i(TAG, "Login canceled"); - if (mAuthThread != null) { - mAuthThread.interrupt(); - finish(); - } - } - }); - dialog = working_dialog; - break; - } - case DIALOG_SSL_VALIDATOR: { - dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this); - break; - } - case DIALOG_CERT_NOT_SAVED: { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved)); - builder.setCancelable(false); - builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - }; - }); - dialog = builder.create(); - break; - } - default: - Log.e(TAG, "Incorrect dialog called with id = " + id); - } - return dialog; - } - - @Override - protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { - switch (id) { - case DIALOG_LOGIN_PROGRESS: - case DIALOG_CERT_NOT_SAVED: - break; - case DIALOG_SSL_VALIDATOR: { - ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult); - break; - } - default: - Log.e(TAG, "Incorrect dialog called with id = " + id); - } - } - - public void onAuthenticationResult(boolean success, String message) { - if (success) { - TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password); - - URL url; - try { - url = new URL(message); - } catch (MalformedURLException e) { - // should never happen - Log.e(getClass().getName(), "Malformed URL: " + message); - return; - } - - String username = username_text.getText().toString().trim(); - String accountName = username + "@" + url.getHost(); - if (url.getPort() >= 0) { - accountName += ":" + url.getPort(); - } - Account account = new Account(accountName, - AccountAuthenticator.ACCOUNT_TYPE); - AccountManager accManager = AccountManager.get(this); - accManager.addAccountExplicitly(account, password_text.getText() - .toString(), null); - - // Add this account as default in the preferences, if there is none - // already - Account defaultAccount = AccountUtils - .getCurrentOwnCloudAccount(this); - if (defaultAccount == null) { - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(this).edit(); - editor.putString("select_oc_account", accountName); - editor.commit(); - } - - final Intent intent = new Intent(); - intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, - AccountAuthenticator.ACCOUNT_TYPE); - intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); - intent.putExtra(AccountManager.KEY_AUTHTOKEN, - AccountAuthenticator.ACCOUNT_TYPE); - intent.putExtra(AccountManager.KEY_USERDATA, username); - - accManager.setUserData(account, - AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable - .getDiscoveredVersion().toString()); - - accManager.setUserData(account, - AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl); - - setAccountAuthenticatorResult(intent.getExtras()); - setResult(RESULT_OK, intent); - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, - // bundle); - ContentResolver.requestSync(account, "org.owncloud", bundle); - - /* - * if - * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion - * .owncloud_v2) >= 0) { Intent i = new Intent(this, - * ExtensionsAvailableActivity.class); startActivity(i); } - */ - - finish(); - } else { - try { - dismissDialog(DIALOG_LOGIN_PROGRESS); - } catch (IllegalArgumentException e) { - // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens - } - TextView tv = (TextView) findViewById(R.id.account_username); - tv.setError(message + " "); // the extra spaces are a workaround for an ugly bug: - // 1. insert wrong credentials and connect - // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field - // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word - // Seen, at least, in Android 2.x devices - } - } - public void onCancelClick(View view) { - setResult(RESULT_CANCELED); - finish(); - } - - public void onOkClick(View view) { - String prefix = ""; - String url = ((TextView) findViewById(R.id.host_URL)).getText() - .toString().trim(); - if (mIsSslConn) { - prefix = "https://"; - } else { - prefix = "http://"; - } - if (url.toLowerCase().startsWith("http://") - || url.toLowerCase().startsWith("https://")) { - prefix = ""; - } - continueConnection(prefix); - } - - public void onRegisterClick(View view) { - Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register))); - setResult(RESULT_CANCELED); - startActivity(register); - } - - private void continueConnection(String prefix) { - String url = ((TextView) findViewById(R.id.host_URL)).getText() - .toString().trim(); - String username = ((TextView) findViewById(R.id.account_username)) - .getText().toString(); - String password = ((TextView) findViewById(R.id.account_password)) - .getText().toString(); - if (url.endsWith("/")) - url = url.substring(0, url.length() - 1); - - URL uri = null; - String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable - .getDiscoveredVersion()); - - if (webdav_path == null) { - onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title)); - return; - } - - try { - mBaseUrl = prefix + url; - String url_str = prefix + url + webdav_path; - uri = new URL(url_str); - } catch (MalformedURLException e) { - // should never happen - onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title)); - return; - } - - showDialog(DIALOG_LOGIN_PROGRESS); - mAuthRunnable = new AuthenticationRunnable(uri, username, password, this); - mAuthRunnable.setOnAuthenticationResultListener(this, mHandler); - mAuthThread = new Thread(mAuthRunnable); - mAuthThread.start(); - } - - @Override - public void onConnectionCheckResult(ResultType type) { - mStatusText = mStatusIcon = 0; - mStatusCorrect = false; - String t_url = ((TextView) findViewById(R.id.host_URL)).getText() - .toString().trim().toLowerCase(); - - switch (type) { - case OK_SSL: - mIsSslConn = true; - mStatusIcon = android.R.drawable.ic_secure; - mStatusText = R.string.auth_secure_connection; - mStatusCorrect = true; - break; - case OK_NO_SSL: - mIsSslConn = false; - mStatusCorrect = true; - if (t_url.startsWith("http://") ) { - mStatusText = R.string.auth_connection_established; - mStatusIcon = R.drawable.ic_ok; - } else { - mStatusText = R.string.auth_nossl_plain_ok_title; - mStatusIcon = android.R.drawable.ic_partial_secure; - } - break; - case BAD_OC_VERSION: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_bad_oc_version_title; - break; - case WRONG_CONNECTION: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_wrong_connection_title; - break; - case TIMEOUT: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_timeout_title; - break; - case INCORRECT_ADDRESS: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_address_title; - break; - case SSL_UNVERIFIED_SERVER: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_ssl_unverified_server_title; - break; - case SSL_INIT_ERROR: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_ssl_general_error_title; - break; - case HOST_NOT_AVAILABLE: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknown_host_title; - break; - case NO_NETWORK_CONNECTION: - mStatusIcon = R.drawable.no_network; - mStatusText = R.string.auth_no_net_conn_title; - break; - case INSTANCE_NOT_CONFIGURED: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_not_configured_title; - break; - case UNKNOWN_ERROR: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknown_error_title; - break; - case FILE_NOT_FOUND: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_path_title; - break; - default: - Log.e(TAG, "Incorrect connection checker result type: " + type); - } - setResultIconAndText(mStatusIcon, mStatusText); - if (!mStatusCorrect) - findViewById(R.id.refreshButton).setVisibility(View.VISIBLE); - else - findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); - findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); - } - - @Override - public void onFocusChange(View view, boolean hasFocus) { - if (view.getId() == R.id.host_URL) { - if (!hasFocus) { - TextView tv = ((TextView) findViewById(R.id.host_URL)); - String uri = tv.getText().toString().trim(); - if (uri.length() != 0) { - setResultIconAndText(R.drawable.progress_small, - R.string.auth_testing_connection); - //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this); - mConnChkRunnable = new ConnectionCheckOperation(uri, this); - //mConnChkRunnable.setListener(this, mHandler); - //mAuthThread = new Thread(mConnChkRunnable); - //mAuthThread.start(); - WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this); - mAuthThread = mConnChkRunnable.execute(client, this, mHandler); - } else { - findViewById(R.id.refreshButton).setVisibility( - View.INVISIBLE); - setResultIconAndText(0, 0); - } - } else { - // avoids that the 'connect' button can be clicked if the test was previously passed - findViewById(R.id.buttonOK).setEnabled(false); - } - } else if (view.getId() == R.id.account_password) { - ImageView iv = (ImageView) findViewById(R.id.viewPassword); - if (hasFocus) { - iv.setVisibility(View.VISIBLE); - } else { - TextView v = (TextView) findViewById(R.id.account_password); - int input_type = InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_PASSWORD; - v.setInputType(input_type); - iv.setVisibility(View.INVISIBLE); - } - } - } - - private void setResultIconAndText(int drawable_id, int text_id) { - ImageView iv = (ImageView) findViewById(R.id.action_indicator); - TextView tv = (TextView) findViewById(R.id.status_text); - - if (drawable_id == 0 && text_id == 0) { - iv.setVisibility(View.INVISIBLE); - tv.setVisibility(View.INVISIBLE); - } else { - iv.setImageResource(drawable_id); - tv.setText(text_id); - iv.setVisibility(View.VISIBLE); - tv.setVisibility(View.VISIBLE); - } - } - - @Override - public void onClick(View v) { - if (v.getId() == R.id.refreshButton) { - onFocusChange(findViewById(R.id.host_URL), false); - } else if (v.getId() == R.id.viewPassword) { - EditText view = (EditText) findViewById(R.id.account_password); - int selectionStart = view.getSelectionStart(); - int selectionEnd = view.getSelectionEnd(); - int input_type = view.getInputType(); - if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) { - input_type = InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_PASSWORD; - } else { - input_type = InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; - } - view.setInputType(input_type); - view.setSelection(selectionStart, selectionEnd); - } - } - - @Override - public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { - if (operation.equals(mConnChkRunnable)) { - - mStatusText = mStatusIcon = 0; - mStatusCorrect = false; - String t_url = ((TextView) findViewById(R.id.host_URL)).getText() - .toString().trim().toLowerCase(); - - switch (result.getCode()) { - case OK_SSL: - mIsSslConn = true; - mStatusIcon = android.R.drawable.ic_secure; - mStatusText = R.string.auth_secure_connection; - mStatusCorrect = true; - break; - - case OK_NO_SSL: - case OK: - mIsSslConn = false; - mStatusCorrect = true; - if (t_url.startsWith("http://") ) { - mStatusText = R.string.auth_connection_established; - mStatusIcon = R.drawable.ic_ok; - } else { - mStatusText = R.string.auth_nossl_plain_ok_title; - mStatusIcon = android.R.drawable.ic_partial_secure; - } - break; - - - case BAD_OC_VERSION: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_bad_oc_version_title; - break; - case WRONG_CONNECTION: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_wrong_connection_title; - break; - case TIMEOUT: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_timeout_title; - break; - case INCORRECT_ADDRESS: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_address_title; - break; - - case SSL_RECOVERABLE_PEER_UNVERIFIED: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_ssl_unverified_server_title; - mLastSslUntrustedServerResult = result; - showDialog(DIALOG_SSL_VALIDATOR); - break; - - case SSL_ERROR: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_ssl_general_error_title; - break; - - case HOST_NOT_AVAILABLE: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknown_host_title; - break; - case NO_NETWORK_CONNECTION: - mStatusIcon = R.drawable.no_network; - mStatusText = R.string.auth_no_net_conn_title; - break; - case INSTANCE_NOT_CONFIGURED: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_not_configured_title; - break; - case FILE_NOT_FOUND: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_path_title; - break; - case UNHANDLED_HTTP_CODE: - case UNKNOWN_ERROR: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknown_error_title; - break; - default: - Log.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode()); - } - setResultIconAndText(mStatusIcon, mStatusText); - if (!mStatusCorrect) - findViewById(R.id.refreshButton).setVisibility(View.VISIBLE); - else - findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); - findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); - } - } - - - public void onSavedCertificate() { - mAuthThread = mConnChkRunnable.retry(this, mHandler); - } - - @Override - public void onFailedSavingCertificate() { - showDialog(DIALOG_CERT_NOT_SAVED); - } - -} +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * 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 . + * + */ + +package com.owncloud.android.ui.activity; + +import java.net.MalformedURLException; +import java.net.URL; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.authenticator.AuthenticationRunnable; +import com.owncloud.android.authenticator.OnAuthenticationResultListener; +import com.owncloud.android.authenticator.OnConnectCheckListener; +import com.owncloud.android.ui.dialog.SslValidatorDialog; +import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; +import com.owncloud.android.network.OwnCloudClientUtils; +import com.owncloud.android.operations.ConnectionCheckOperation; +import com.owncloud.android.operations.OnRemoteOperationListener; +import com.owncloud.android.operations.RemoteOperation; +import com.owncloud.android.operations.RemoteOperationResult; + +import android.accounts.Account; +import android.accounts.AccountAuthenticatorActivity; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.ContentResolver; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.text.InputType; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnFocusChangeListener; +import android.view.Window; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; +import com.owncloud.android.R; + +import eu.alefzero.webdav.WebdavClient; + +/** + * This Activity is used to add an ownCloud account to the App + * + * @author Bartek Przybylski + * + */ +public class AuthenticatorActivity extends AccountAuthenticatorActivity + implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, + OnFocusChangeListener, OnClickListener { + + private static final int DIALOG_LOGIN_PROGRESS = 0; + private static final int DIALOG_SSL_VALIDATOR = 1; + private static final int DIALOG_CERT_NOT_SAVED = 2; + + private static final String TAG = "AuthActivity"; + + private Thread mAuthThread; + private AuthenticationRunnable mAuthRunnable; + //private ConnectionCheckerRunnable mConnChkRunnable = null; + private ConnectionCheckOperation mConnChkRunnable; + private final Handler mHandler = new Handler(); + private String mBaseUrl; + + private static final String STATUS_TEXT = "STATUS_TEXT"; + private static final String STATUS_ICON = "STATUS_ICON"; + private static final String STATUS_CORRECT = "STATUS_CORRECT"; + private static final String IS_SSL_CONN = "IS_SSL_CONN"; + private int mStatusText, mStatusIcon; + private boolean mStatusCorrect, mIsSslConn; + private RemoteOperationResult mLastSslUntrustedServerResult; + + public static final String PARAM_USERNAME = "param_Username"; + public static final String PARAM_HOSTNAME = "param_Hostname"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.account_setup); + ImageView iv = (ImageView) findViewById(R.id.refreshButton); + ImageView iv2 = (ImageView) findViewById(R.id.viewPassword); + TextView tv = (TextView) findViewById(R.id.host_URL); + TextView tv2 = (TextView) findViewById(R.id.account_password); + + if (savedInstanceState != null) { + mStatusIcon = savedInstanceState.getInt(STATUS_ICON); + mStatusText = savedInstanceState.getInt(STATUS_TEXT); + mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT); + mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN); + setResultIconAndText(mStatusIcon, mStatusText); + findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); + if (!mStatusCorrect) + iv.setVisibility(View.VISIBLE); + else + iv.setVisibility(View.INVISIBLE); + + } else { + mStatusText = mStatusIcon = 0; + mStatusCorrect = false; + mIsSslConn = false; + } + iv.setOnClickListener(this); + iv2.setOnClickListener(this); + tv.setOnFocusChangeListener(this); + tv2.setOnFocusChangeListener(this); + + Button b = (Button) findViewById(R.id.account_register); + if (b != null) { + b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name))); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putInt(STATUS_ICON, mStatusIcon); + outState.putInt(STATUS_TEXT, mStatusText); + outState.putBoolean(STATUS_CORRECT, mStatusCorrect); + super.onSaveInstanceState(outState); + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog = null; + switch (id) { + case DIALOG_LOGIN_PROGRESS: { + ProgressDialog working_dialog = new ProgressDialog(this); + working_dialog.setMessage(getResources().getString( + R.string.auth_trying_to_login)); + working_dialog.setIndeterminate(true); + working_dialog.setCancelable(true); + working_dialog + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + Log_OC.i(TAG, "Login canceled"); + if (mAuthThread != null) { + mAuthThread.interrupt(); + finish(); + } + } + }); + dialog = working_dialog; + break; + } + case DIALOG_SSL_VALIDATOR: { + dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this); + break; + } + case DIALOG_CERT_NOT_SAVED: { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved)); + builder.setCancelable(false); + builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + }; + }); + dialog = builder.create(); + break; + } + default: + Log_OC.e(TAG, "Incorrect dialog called with id = " + id); + } + return dialog; + } + + @Override + protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { + switch (id) { + case DIALOG_LOGIN_PROGRESS: + case DIALOG_CERT_NOT_SAVED: + break; + case DIALOG_SSL_VALIDATOR: { + ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult); + break; + } + default: + Log_OC.e(TAG, "Incorrect dialog called with id = " + id); + } + } + + public void onAuthenticationResult(boolean success, String message) { + if (success) { + TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password); + + URL url; + try { + url = new URL(message); + } catch (MalformedURLException e) { + // should never happen + Log_OC.e(getClass().getName(), "Malformed URL: " + message); + return; + } + + String username = username_text.getText().toString().trim(); + String accountName = username + "@" + url.getHost(); + if (url.getPort() >= 0) { + accountName += ":" + url.getPort(); + } + Account account = new Account(accountName, + AccountAuthenticator.ACCOUNT_TYPE); + AccountManager accManager = AccountManager.get(this); + accManager.addAccountExplicitly(account, password_text.getText() + .toString(), null); + + // Add this account as default in the preferences, if there is none + // already + Account defaultAccount = AccountUtils + .getCurrentOwnCloudAccount(this); + if (defaultAccount == null) { + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(this).edit(); + editor.putString("select_oc_account", accountName); + editor.commit(); + } + + final Intent intent = new Intent(); + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, + AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); + intent.putExtra(AccountManager.KEY_AUTHTOKEN, + AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_USERDATA, username); + + accManager.setUserData(account, + AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable + .getDiscoveredVersion().toString()); + + accManager.setUserData(account, + AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl); + + setAccountAuthenticatorResult(intent.getExtras()); + setResult(RESULT_OK, intent); + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, + // bundle); + ContentResolver.requestSync(account, "org.owncloud", bundle); + + /* + * if + * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion + * .owncloud_v2) >= 0) { Intent i = new Intent(this, + * ExtensionsAvailableActivity.class); startActivity(i); } + */ + + finish(); + } else { + try { + dismissDialog(DIALOG_LOGIN_PROGRESS); + } catch (IllegalArgumentException e) { + // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens + } + TextView tv = (TextView) findViewById(R.id.account_username); + tv.setError(message + " "); // the extra spaces are a workaround for an ugly bug: + // 1. insert wrong credentials and connect + // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field + // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word + // Seen, at least, in Android 2.x devices + } + } + public void onCancelClick(View view) { + setResult(RESULT_CANCELED); + finish(); + } + + public void onOkClick(View view) { + String prefix = ""; + String url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString().trim(); + if (mIsSslConn) { + prefix = "https://"; + } else { + prefix = "http://"; + } + if (url.toLowerCase().startsWith("http://") + || url.toLowerCase().startsWith("https://")) { + prefix = ""; + } + continueConnection(prefix); + } + + public void onRegisterClick(View view) { + Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register))); + setResult(RESULT_CANCELED); + startActivity(register); + } + + private void continueConnection(String prefix) { + String url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString().trim(); + String username = ((TextView) findViewById(R.id.account_username)) + .getText().toString(); + String password = ((TextView) findViewById(R.id.account_password)) + .getText().toString(); + if (url.endsWith("/")) + url = url.substring(0, url.length() - 1); + + URL uri = null; + String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable + .getDiscoveredVersion()); + + if (webdav_path == null) { + onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title)); + return; + } + + try { + mBaseUrl = prefix + url; + String url_str = prefix + url + webdav_path; + uri = new URL(url_str); + } catch (MalformedURLException e) { + // should never happen + onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title)); + return; + } + + showDialog(DIALOG_LOGIN_PROGRESS); + mAuthRunnable = new AuthenticationRunnable(uri, username, password, this); + mAuthRunnable.setOnAuthenticationResultListener(this, mHandler); + mAuthThread = new Thread(mAuthRunnable); + mAuthThread.start(); + } + + @Override + public void onConnectionCheckResult(ResultType type) { + mStatusText = mStatusIcon = 0; + mStatusCorrect = false; + String t_url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString().trim().toLowerCase(); + + switch (type) { + case OK_SSL: + mIsSslConn = true; + mStatusIcon = android.R.drawable.ic_secure; + mStatusText = R.string.auth_secure_connection; + mStatusCorrect = true; + break; + case OK_NO_SSL: + mIsSslConn = false; + mStatusCorrect = true; + if (t_url.startsWith("http://") ) { + mStatusText = R.string.auth_connection_established; + mStatusIcon = R.drawable.ic_ok; + } else { + mStatusText = R.string.auth_nossl_plain_ok_title; + mStatusIcon = android.R.drawable.ic_partial_secure; + } + break; + case BAD_OC_VERSION: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_bad_oc_version_title; + break; + case WRONG_CONNECTION: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_wrong_connection_title; + break; + case TIMEOUT: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_timeout_title; + break; + case INCORRECT_ADDRESS: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_address_title; + break; + case SSL_UNVERIFIED_SERVER: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_ssl_unverified_server_title; + break; + case SSL_INIT_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_ssl_general_error_title; + break; + case HOST_NOT_AVAILABLE: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknown_host_title; + break; + case NO_NETWORK_CONNECTION: + mStatusIcon = R.drawable.no_network; + mStatusText = R.string.auth_no_net_conn_title; + break; + case INSTANCE_NOT_CONFIGURED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_not_configured_title; + break; + case UNKNOWN_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknown_error_title; + break; + case FILE_NOT_FOUND: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_path_title; + break; + default: + Log_OC.e(TAG, "Incorrect connection checker result type: " + type); + } + setResultIconAndText(mStatusIcon, mStatusText); + if (!mStatusCorrect) + findViewById(R.id.refreshButton).setVisibility(View.VISIBLE); + else + findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); + findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); + } + + @Override + public void onFocusChange(View view, boolean hasFocus) { + if (view.getId() == R.id.host_URL) { + if (!hasFocus) { + TextView tv = ((TextView) findViewById(R.id.host_URL)); + String uri = tv.getText().toString().trim(); + if (uri.length() != 0) { + setResultIconAndText(R.drawable.progress_small, + R.string.auth_testing_connection); + //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this); + mConnChkRunnable = new ConnectionCheckOperation(uri, this); + //mConnChkRunnable.setListener(this, mHandler); + //mAuthThread = new Thread(mConnChkRunnable); + //mAuthThread.start(); + WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this); + mAuthThread = mConnChkRunnable.execute(client, this, mHandler); + } else { + findViewById(R.id.refreshButton).setVisibility( + View.INVISIBLE); + setResultIconAndText(0, 0); + } + } else { + // avoids that the 'connect' button can be clicked if the test was previously passed + findViewById(R.id.buttonOK).setEnabled(false); + } + } else if (view.getId() == R.id.account_password) { + ImageView iv = (ImageView) findViewById(R.id.viewPassword); + if (hasFocus) { + iv.setVisibility(View.VISIBLE); + } else { + TextView v = (TextView) findViewById(R.id.account_password); + int input_type = InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD; + v.setInputType(input_type); + iv.setVisibility(View.INVISIBLE); + } + } + } + + private void setResultIconAndText(int drawable_id, int text_id) { + ImageView iv = (ImageView) findViewById(R.id.action_indicator); + TextView tv = (TextView) findViewById(R.id.status_text); + + if (drawable_id == 0 && text_id == 0) { + iv.setVisibility(View.INVISIBLE); + tv.setVisibility(View.INVISIBLE); + } else { + iv.setImageResource(drawable_id); + tv.setText(text_id); + iv.setVisibility(View.VISIBLE); + tv.setVisibility(View.VISIBLE); + } + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.refreshButton) { + onFocusChange(findViewById(R.id.host_URL), false); + } else if (v.getId() == R.id.viewPassword) { + EditText view = (EditText) findViewById(R.id.account_password); + int selectionStart = view.getSelectionStart(); + int selectionEnd = view.getSelectionEnd(); + int input_type = view.getInputType(); + if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) { + input_type = InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD; + } else { + input_type = InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; + } + view.setInputType(input_type); + view.setSelection(selectionStart, selectionEnd); + } + } + + @Override + public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { + if (operation.equals(mConnChkRunnable)) { + + mStatusText = mStatusIcon = 0; + mStatusCorrect = false; + String t_url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString().trim().toLowerCase(); + + switch (result.getCode()) { + case OK_SSL: + mIsSslConn = true; + mStatusIcon = android.R.drawable.ic_secure; + mStatusText = R.string.auth_secure_connection; + mStatusCorrect = true; + break; + + case OK_NO_SSL: + case OK: + mIsSslConn = false; + mStatusCorrect = true; + if (t_url.startsWith("http://") ) { + mStatusText = R.string.auth_connection_established; + mStatusIcon = R.drawable.ic_ok; + } else { + mStatusText = R.string.auth_nossl_plain_ok_title; + mStatusIcon = android.R.drawable.ic_partial_secure; + } + break; + + + case BAD_OC_VERSION: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_bad_oc_version_title; + break; + case WRONG_CONNECTION: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_wrong_connection_title; + break; + case TIMEOUT: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_timeout_title; + break; + case INCORRECT_ADDRESS: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_address_title; + break; + + case SSL_RECOVERABLE_PEER_UNVERIFIED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_ssl_unverified_server_title; + mLastSslUntrustedServerResult = result; + showDialog(DIALOG_SSL_VALIDATOR); + break; + + case SSL_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_ssl_general_error_title; + break; + + case HOST_NOT_AVAILABLE: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknown_host_title; + break; + case NO_NETWORK_CONNECTION: + mStatusIcon = R.drawable.no_network; + mStatusText = R.string.auth_no_net_conn_title; + break; + case INSTANCE_NOT_CONFIGURED: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_not_configured_title; + break; + case FILE_NOT_FOUND: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_path_title; + break; + case UNHANDLED_HTTP_CODE: + case UNKNOWN_ERROR: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknown_error_title; + break; + default: + Log_OC.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode()); + } + setResultIconAndText(mStatusIcon, mStatusText); + if (!mStatusCorrect) + findViewById(R.id.refreshButton).setVisibility(View.VISIBLE); + else + findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); + findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); + } + } + + + public void onSavedCertificate() { + mAuthThread = mConnChkRunnable.retry(this, mHandler); + } + + @Override + public void onFailedSavingCertificate() { + showDialog(DIALOG_CERT_NOT_SAVED); + } + +} diff --git a/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java b/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java index 21aaed8f99..3ccc07dc3e 100644 --- a/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java +++ b/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java @@ -20,6 +20,7 @@ package com.owncloud.android.ui.activity; import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.ui.dialog.ConflictsResolveDialog; @@ -79,7 +80,7 @@ public class ConflictsResolveActivity extends SherlockFragmentActivity implement i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE); break; default: - Log.wtf(TAG, "Unhandled conflict decision " + decision); + Log_OC.wtf(TAG, "Unhandled conflict decision " + decision); return; } i.putExtra(FileUploader.KEY_ACCOUNT, mOCAccount); diff --git a/src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java b/src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java index 0522cb8522..dc6a507b23 100644 --- a/src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java +++ b/src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java @@ -41,6 +41,7 @@ import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -182,16 +183,16 @@ public class ErrorsWhileCopyingHandlerActivity extends SherlockFragmentActivity public void onClick(View v) { if (v.getId() == R.id.ok) { /// perform movement operation in background thread - Log.d(TAG, "Clicked MOVE, start movement"); + Log_OC.d(TAG, "Clicked MOVE, start movement"); new MoveFilesTask().execute(); } else if (v.getId() == R.id.cancel) { /// just finish - Log.d(TAG, "Clicked CANCEL, bye"); + Log_OC.d(TAG, "Clicked CANCEL, bye"); finish(); } else { - Log.e(TAG, "Clicked phantom button, id: " + v.getId()); + Log_OC.e(TAG, "Clicked phantom button, id: " + v.getId()); } } diff --git a/src/com/owncloud/android/ui/activity/FileDetailActivity.java b/src/com/owncloud/android/ui/activity/FileDetailActivity.java index cd68c891a3..f08d1605fb 100644 --- a/src/com/owncloud/android/ui/activity/FileDetailActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDetailActivity.java @@ -1,230 +1,231 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * 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 . - * - */ -package com.owncloud.android.ui.activity; - -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.content.res.Configuration; -import android.os.Bundle; -import android.os.IBinder; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.MenuItem; -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.R; - -/** - * This activity displays the details of a file like its name, its size and so - * on. - * - * @author Bartek Przybylski - * - */ -public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity { - - public static final int DIALOG_SHORT_WAIT = 0; - - public static final String TAG = FileDetailActivity.class.getSimpleName(); - - private boolean mConfigurationChangedToLandscape = false; - private FileDownloaderBinder mDownloaderBinder = null; - private ServiceConnection mDownloadConnection, mUploadConnection = null; - private FileUploaderBinder mUploaderBinder = null; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity - Configuration conf = getResources().getConfiguration(); - mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && - (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE - ); - - if (!mConfigurationChangedToLandscape) { - 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); - - setContentView(R.layout.file_activity_details); - - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - - OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); - Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT); - FileDetailFragment mFileDetail = new FileDetailFragment(file, account); - - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG); - ft.commit(); - - } else { - backToDisplayActivity(); // the 'back' won't be effective until this.onStart() and this.onResume() are completed; - } - - - } - - - /** 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(FileDetailActivity.this, FileDownloader.class))) { - Log.d(TAG, "Download service connected"); - mDownloaderBinder = (FileDownloaderBinder) service; - } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) { - Log.d(TAG, "Upload service connected"); - mUploaderBinder = (FileUploaderBinder) service; - } else { - return; - } - FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); - if (fragment != null) - fragment.updateFileDetails(false); // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais()) - } - - @Override - public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) { - Log.d(TAG, "Download service disconnected"); - mDownloaderBinder = null; - } else if (component.equals(new ComponentName(FileDetailActivity.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(); - if (!mConfigurationChangedToLandscape) { - FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); - 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, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE)); - intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT)); - 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; - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * 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 . + * + */ +package com.owncloud.android.ui.activity; + +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.content.res.Configuration; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.MenuItem; +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.Log_OC; +import com.owncloud.android.R; + +/** + * This activity displays the details of a file like its name, its size and so + * on. + * + * @author Bartek Przybylski + * + */ +public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity { + + public static final int DIALOG_SHORT_WAIT = 0; + + public static final String TAG = FileDetailActivity.class.getSimpleName(); + + private boolean mConfigurationChangedToLandscape = false; + private FileDownloaderBinder mDownloaderBinder = null; + private ServiceConnection mDownloadConnection, mUploadConnection = null; + private FileUploaderBinder mUploaderBinder = null; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity + Configuration conf = getResources().getConfiguration(); + mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && + (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE + ); + + if (!mConfigurationChangedToLandscape) { + 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); + + setContentView(R.layout.file_activity_details); + + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + + OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); + Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT); + FileDetailFragment mFileDetail = new FileDetailFragment(file, account); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG); + ft.commit(); + + } else { + backToDisplayActivity(); // the 'back' won't be effective until this.onStart() and this.onResume() are completed; + } + + + } + + + /** 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(FileDetailActivity.this, FileDownloader.class))) { + Log_OC.d(TAG, "Download service connected"); + mDownloaderBinder = (FileDownloaderBinder) service; + } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) { + Log_OC.d(TAG, "Upload service connected"); + mUploaderBinder = (FileUploaderBinder) service; + } else { + return; + } + FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (fragment != null) + fragment.updateFileDetails(false); // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais()) + } + + @Override + public void onServiceDisconnected(ComponentName component) { + if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) { + Log_OC.d(TAG, "Download service disconnected"); + mDownloaderBinder = null; + } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) { + Log_OC.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(); + if (!mConfigurationChangedToLandscape) { + FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + 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, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE)); + intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT)); + 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; + } + +} diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index a9fb902da1..cfdd89bbae 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -66,6 +66,7 @@ import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.Window; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.datamodel.DataStorageManager; @@ -138,7 +139,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF @Override public void onCreate(Bundle savedInstanceState) { - Log.d(getClass().toString(), "onCreate() start"); + Log_OC.d(getClass().toString(), "onCreate() start"); super.onCreate(savedInstanceState); /// Load of parameters from received intent @@ -215,7 +216,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF // show changelog, if needed showChangeLog(); - Log.d(getClass().toString(), "onCreate() end"); + Log_OC.d(getClass().toString(), "onCreate() end"); } @@ -418,7 +419,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF startService(i); } else { - Log.d("FileDisplay", "User clicked on 'Update' with no selection"); + Log_OC.d("FileDisplay", "User clicked on 'Update' with no selection"); Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG); t.show(); return; @@ -440,12 +441,12 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF filepath = filemanagerstring; } catch (Exception e) { - Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e); + Log_OC.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e); e.printStackTrace(); } finally { if (filepath == null) { - Log.e("FileDisplay", "Couldnt resolve path to file"); + Log_OC.e("FileDisplay", "Couldnt resolve path to file"); Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG); t.show(); return; @@ -504,7 +505,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF @Override protected void onSaveInstanceState(Bundle outState) { // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved - Log.d(getClass().toString(), "onSaveInstanceState() start"); + Log_OC.d(getClass().toString(), "onSaveInstanceState() start"); super.onSaveInstanceState(outState); outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir); if (mDualPane) { @@ -516,12 +517,12 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF } } } - Log.d(getClass().toString(), "onSaveInstanceState() end"); + Log_OC.d(getClass().toString(), "onSaveInstanceState() end"); } @Override protected void onResume() { - Log.d(getClass().toString(), "onResume() start"); + Log_OC.d(getClass().toString(), "onResume() start"); super.onResume(); if (AccountUtils.accountsAreSetup(this)) { @@ -558,13 +559,13 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF showDialog(DIALOG_SETUP_ACCOUNT); } - Log.d(getClass().toString(), "onResume() end"); + Log_OC.d(getClass().toString(), "onResume() end"); } @Override protected void onPause() { - Log.d(getClass().toString(), "onPause() start"); + Log_OC.d(getClass().toString(), "onPause() start"); super.onPause(); if (mSyncBroadcastReceiver != null) { unregisterReceiver(mSyncBroadcastReceiver); @@ -582,7 +583,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF dismissDialog(DIALOG_SETUP_ACCOUNT); } - Log.d(getClass().toString(), "onPause() end"); + Log_OC.d(getClass().toString(), "onPause() end"); } @@ -816,7 +817,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF msg.show(); } catch (NotFoundException e) { - Log.e(TAG, "Error while trying to show fail message ", e); + Log_OC.e(TAG, "Error while trying to show fail message ", e); } } }); @@ -859,7 +860,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false); String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME); - Log.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress); + Log_OC.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress); if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { @@ -1052,10 +1053,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF @Override public void onServiceConnected(ComponentName component, IBinder service) { if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { - Log.d(TAG, "Download service connected"); + Log_OC.d(TAG, "Download service connected"); mDownloaderBinder = (FileDownloaderBinder) service; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { - Log.d(TAG, "Upload service connected"); + Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; } else { return; @@ -1074,10 +1075,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { - Log.d(TAG, "Download service disconnected"); + Log_OC.d(TAG, "Download service disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { - Log.d(TAG, "Upload service disconnected"); + Log_OC.d(TAG, "Upload service disconnected"); mUploaderBinder = null; } } diff --git a/src/com/owncloud/android/ui/activity/InstantUploadActivity.java b/src/com/owncloud/android/ui/activity/InstantUploadActivity.java index 4325b8ab75..d5f87e6f4b 100644 --- a/src/com/owncloud/android/ui/activity/InstantUploadActivity.java +++ b/src/com/owncloud/android/ui/activity/InstantUploadActivity.java @@ -42,6 +42,7 @@ import android.widget.LinearLayout; import android.widget.Toast; import com.owncloud.android.AccountUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; import com.owncloud.android.db.DbHandler; import com.owncloud.android.files.InstantUploadBroadcastReceiver; @@ -127,7 +128,7 @@ public class InstantUploadActivity extends Activity { rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx)); rowLayout.addView(getFileButton(imp_path, lastLoadImageIdx)); listView.addView(rowLayout); - Log.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx); + Log_OC.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx); if (lastLoadImageIdx % MAX_LOAD_IMAGES == 0) { break; } @@ -178,12 +179,12 @@ public class InstantUploadActivity extends Activity { private List getCheckboxList() { List list = new ArrayList(); for (int i = 0; i < listView.getChildCount(); i++) { - Log.d(LOG_TAG, "ListView has Childs: " + listView.getChildCount()); + Log_OC.d(LOG_TAG, "ListView has Childs: " + listView.getChildCount()); View childView = listView.getChildAt(i); if (childView != null && childView instanceof ViewGroup) { View checkboxView = getChildViews((ViewGroup) childView); if (checkboxView != null && checkboxView instanceof CheckBox) { - Log.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass()); + Log_OC.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass()); list.add((CheckBox) checkboxView); } } @@ -245,12 +246,12 @@ public class InstantUploadActivity extends Activity { for (CheckBox checkbox : list) { boolean to_retry = checkbox.isChecked(); - Log.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry); + Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry); String img_path = fileList.get(checkbox.getId()); if (to_retry) { final String msg = "Image-Path " + checkbox.getId() + " was checked: " + img_path; - Log.d(LOG_TAG, msg); + Log_OC.d(LOG_TAG, msg); startUpload(img_path); } @@ -282,12 +283,12 @@ public class InstantUploadActivity extends Activity { for (CheckBox checkbox : list) { boolean to_be_delete = checkbox.isChecked(); - Log.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete); + Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete); String img_path = fileList.get(checkbox.getId()); - Log.d(LOG_TAG, "Image-Path " + checkbox.getId() + " was checked: " + img_path); + Log_OC.d(LOG_TAG, "Image-Path " + checkbox.getId() + " was checked: " + img_path); if (to_be_delete) { boolean deleted = dbh.removeIUPendingFile(img_path); - Log.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted); + Log_OC.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted); } @@ -341,7 +342,7 @@ public class InstantUploadActivity extends Activity { // scale and add a thumbnail to the imagebutton int base_scale_size = 32; if (img_path != null) { - Log.d(LOG_TAG, "add " + img_path + " to Image Button"); + Log_OC.d(LOG_TAG, "add " + img_path + " to Image Button"); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeFile(img_path, options); @@ -356,16 +357,16 @@ public class InstantUploadActivity extends Activity { scale++; } - Log.d(LOG_TAG, "scale Imgae with: " + scale); + Log_OC.d(LOG_TAG, "scale Imgae with: " + scale); BitmapFactory.Options options2 = new BitmapFactory.Options(); options2.inSampleSize = scale; bitmap = BitmapFactory.decodeFile(img_path, options2); if (bitmap != null) { - Log.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes()); + Log_OC.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes()); imageButton.setImageBitmap(bitmap); } else { - Log.d(LOG_TAG, "could not load imgage: " + img_path); + Log_OC.d(LOG_TAG, "could not load imgage: " + img_path); } } return imageButton; @@ -409,7 +410,7 @@ public class InstantUploadActivity extends Activity { i.putExtra(com.owncloud.android.files.services.FileUploader.KEY_INSTANT_UPLOAD, true); final String msg = "try to upload file with name :" + filename; - Log.d(LOG_TAG, msg); + Log_OC.d(LOG_TAG, msg); Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text) + filename, Toast.LENGTH_LONG); toast.show(); diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index 35638c5e75..8d27574e56 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -37,6 +37,7 @@ import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockPreferenceActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; +import com.owncloud.android.Log_OC; import com.owncloud.android.OwnCloudSession; import com.owncloud.android.R; import com.owncloud.android.db.DbHandler; @@ -57,9 +58,11 @@ public class Preferences extends SherlockPreferenceActivity implements OnPrefere private ListPreference mTrackingUpdateInterval; private CheckBoxPreference mDeviceTracking; private CheckBoxPreference pCode; + private CheckBoxPreference pLogging; private Preference pAboutApp; private int mSelectedMenuItem; + @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { @@ -103,10 +106,33 @@ public class Preferences extends SherlockPreferenceActivity implements OnPrefere pkg = getPackageManager().getPackageInfo(getPackageName(), 0); pAboutApp.setSummary(getString(R.string.about_version)+" "+pkg.versionName); } catch (NameNotFoundException e) { - Log.e(TAG, "Error while showing about dialog", e); + Log_OC.e(TAG, "Error while showing about dialog", e); } - } - } + } + pLogging = (CheckBoxPreference) findPreference("log_to_file"); + + if (pLogging != null) { + pLogging.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + + String logpath = getApplicationContext().getFilesDir().getAbsolutePath(); + + if(!pLogging.isChecked()) { + Log_OC.d("Debug", "start logging"); + Log_OC.v("PATH", logpath); + Log_OC.startLogging(logpath); + } + else { + Log_OC.d("Debug", "stop logging"); + Log_OC.stopLogging(); + } + return true; + } + }); + + } + } } @Override @@ -150,7 +176,7 @@ public class Preferences extends SherlockPreferenceActivity implements OnPrefere startActivity(intent); break; default: - Log.w(TAG, "Unknown menu item triggered"); + Log_OC.w(TAG, "Unknown menu item triggered"); return false; } return true; diff --git a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java index a6d61d188a..84fdc63805 100644 --- a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -44,6 +44,7 @@ import com.owncloud.android.ui.fragment.LocalFileListFragment; import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; import com.owncloud.android.utils.FileStorageUtils; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; /** @@ -78,7 +79,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements @Override public void onCreate(Bundle savedInstanceState) { - Log.d(TAG, "onCreate() start"); + Log_OC.d(TAG, "onCreate() start"); super.onCreate(savedInstanceState); if(savedInstanceState != null) { @@ -125,7 +126,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements mCurrentDialog = null; } - Log.d(TAG, "onCreate() end"); + Log_OC.d(TAG, "onCreate() end"); } @@ -181,10 +182,10 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements @Override protected void onSaveInstanceState(Bundle outState) { // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved - Log.d(TAG, "onSaveInstanceState() start"); + Log_OC.d(TAG, "onSaveInstanceState() start"); super.onSaveInstanceState(outState); outState.putString(UploadFilesActivity.KEY_DIRECTORY_PATH, mCurrentDir.getAbsolutePath()); - Log.d(TAG, "onSaveInstanceState() end"); + Log_OC.d(TAG, "onSaveInstanceState() end"); } @@ -355,7 +356,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements @Override public void onConfirmation(String callerTag) { - Log.d(TAG, "Positive button in dialog was clicked; dialog tag is " + callerTag); + Log_OC.d(TAG, "Positive button in dialog was clicked; dialog tag is " + callerTag); if (callerTag.equals(QUERY_TO_MOVE_DIALOG_TAG)) { // return the list of selected files to the caller activity (success), signaling that they should be moved to the ownCloud folder, instead of copied Intent data = new Intent(); @@ -370,7 +371,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements @Override public void onNeutral(String callerTag) { - Log.d(TAG, "Phantom neutral button in dialog was clicked; dialog tag is " + callerTag); + Log_OC.d(TAG, "Phantom neutral button in dialog was clicked; dialog tag is " + callerTag); mCurrentDialog.dismiss(); mCurrentDialog = null; } @@ -379,7 +380,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements @Override public void onCancel(String callerTag) { /// nothing to do; don't finish, let the user change the selection - Log.d(TAG, "Negative button in dialog was clicked; dialog tag is " + callerTag); + Log_OC.d(TAG, "Negative button in dialog was clicked; dialog tag is " + callerTag); mCurrentDialog.dismiss(); mCurrentDialog = null; } diff --git a/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java b/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java index 2143e9a9b8..201fd7e1dc 100644 --- a/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java +++ b/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java @@ -38,6 +38,7 @@ import android.view.Window; import android.widget.Button; import android.widget.TextView; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; import com.owncloud.android.network.CertificateCombinedException; import com.owncloud.android.network.OwnCloudClientUtils; @@ -110,13 +111,13 @@ public class SslValidatorDialog extends Dialog { if (mListener != null) mListener.onSavedCertificate(); else - Log.d(TAG, "Nobody there to notify the certificate was saved"); + Log_OC.d(TAG, "Nobody there to notify the certificate was saved"); } catch (Exception e) { dismiss(); if (mListener != null) mListener.onFailedSavingCertificate(); - Log.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); + Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); } } }); diff --git a/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java b/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java index e527d31e15..679b2b9c8e 100644 --- a/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java +++ b/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java @@ -26,6 +26,7 @@ import android.os.Bundle; import android.util.Log; import com.actionbarsherlock.app.SherlockDialogFragment; +import com.owncloud.android.Log_OC; public class ConfirmationDialogFragment extends SherlockDialogFragment { @@ -73,7 +74,7 @@ public class ConfirmationDialogFragment extends SherlockDialogFragment { int negBtn = getArguments().getInt(ARG_NEGATIVE_BTN_RES, -1); if (confirmationTarget == null || resourceId == -1) { - Log.wtf(getTag(), "Calling confirmation dialog without resource or arguments"); + Log_OC.wtf(getTag(), "Calling confirmation dialog without resource or arguments"); return null; } diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java index 2d46a55c8f..88c4889c3a 100644 --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -1,1062 +1,1063 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * 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 . - * - */ -package com.owncloud.android.ui.fragment; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.commons.httpclient.params.HttpConnectionManagerParams; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.protocol.HTTP; -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import org.json.JSONObject; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -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.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.webkit.MimeTypeMap; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import com.actionbarsherlock.app.SherlockFragment; -import com.owncloud.android.AccountUtils; -import com.owncloud.android.DisplayUtils; -import com.owncloud.android.authenticator.AccountAuthenticator; -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.FileObserverService; -import com.owncloud.android.files.services.FileUploader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; -import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; -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.RemoteOperationResult.ResultCode; -import com.owncloud.android.operations.RemoveFileOperation; -import com.owncloud.android.operations.RenameFileOperation; -import com.owncloud.android.operations.SynchronizeFileOperation; -import com.owncloud.android.ui.activity.ConflictsResolveActivity; -import com.owncloud.android.ui.activity.FileDetailActivity; -import com.owncloud.android.ui.activity.FileDisplayActivity; -import com.owncloud.android.ui.activity.TransferServiceGetter; -import com.owncloud.android.ui.dialog.EditNameDialog; -import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener; -import com.owncloud.android.utils.OwnCloudVersion; - -import com.owncloud.android.R; -import eu.alefzero.webdav.WebdavClient; -import eu.alefzero.webdav.WebdavUtils; - -/** - * This Fragment is used to display the details about a file. - * - * @author Bartek Przybylski - * - */ -public class FileDetailFragment extends SherlockFragment implements - OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener { - - public static final String EXTRA_FILE = "FILE"; - public static final String EXTRA_ACCOUNT = "ACCOUNT"; - - private FileDetailFragment.ContainerActivity mContainerActivity; - - private int mLayout; - private View mView; - private OCFile mFile; - private Account mAccount; - private FileDataStorageManager mStorageManager; - private ImageView mPreview; - - private DownloadFinishReceiver mDownloadFinishReceiver; - private UploadFinishReceiver mUploadFinishReceiver; - - private Handler mHandler; - private RemoteOperation mLastRemoteOperation; - private DialogFragment mCurrentDialog; - - private static final String TAG = FileDetailFragment.class.getSimpleName(); - public static final String FTAG = "FileDetails"; - public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT"; - - - /** - * Creates an empty details fragment. - * - * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. - */ - public FileDetailFragment() { - mFile = null; - mAccount = null; - mStorageManager = null; - mLayout = R.layout.file_details_empty; - } - - - /** - * Creates a details fragment. - * - * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before). - * - * @param fileToDetail An {@link OCFile} to show in the fragment - * @param ocAccount An ownCloud account; needed to start downloads - */ - public FileDetailFragment(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 - mLayout = R.layout.file_details_empty; - } - - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mHandler = new Handler(); - } - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - - if (savedInstanceState != null) { - mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE); - mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT); - } - - if(mFile != null && mAccount != null) { - mLayout = R.layout.file_details_fragment; - } - - View view = null; - view = inflater.inflate(mLayout, container, false); - mView = view; - - if (mLayout == R.layout.file_details_fragment) { - mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this); - mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this); - mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this); - mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this); - mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this); - //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this); - mPreview = (ImageView)mView.findViewById(R.id.fdPreview); - } - - updateFileDetails(false); - return view; - } - - - /** - * {@inheritDoc} - */ - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mContainerActivity = (ContainerActivity) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName()); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - if (mAccount != null) { - mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());; - } - } - - - @Override - public void onSaveInstanceState(Bundle outState) { - Log.i(getClass().toString(), "onSaveInstanceState() start"); - super.onSaveInstanceState(outState); - outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile); - outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount); - Log.i(getClass().toString(), "onSaveInstanceState() end"); - } - - - @Override - public void onResume() { - super.onResume(); - - 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); - - mPreview = (ImageView)mView.findViewById(R.id.fdPreview); - } - - @Override - public void onPause() { - super.onPause(); - - getActivity().unregisterReceiver(mDownloadFinishReceiver); - mDownloadFinishReceiver = null; - - getActivity().unregisterReceiver(mUploadFinishReceiver); - mUploadFinishReceiver = null; - - if (mPreview != null) { - mPreview = null; - } - } - - @Override - public View getView() { - return super.getView() == null ? mView : super.getView(); - } - - - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.fdDownloadBtn: { - FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); - FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) { - downloaderBinder.cancel(mAccount, mFile); - if (mFile.isDown()) { - setButtonsForDown(); - } else { - setButtonsForRemote(); - } - - } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) { - uploaderBinder.cancel(mAccount, mFile); - if (!mFile.fileExists()) { - // TODO make something better - if (getActivity() instanceof FileDisplayActivity) { - // double pane - FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment - transaction.commit(); - mContainerActivity.onFileStateChanged(); - } else { - getActivity().finish(); - } - - } else if (mFile.isDown()) { - setButtonsForDown(); - } else { - setButtonsForRemote(); - } - - } else { - mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity()); - WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); - mLastRemoteOperation.execute(wc, this, mHandler); - - // update ui - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference - - } - break; - } - case R.id.fdKeepInSync: { - CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync); - mFile.setKeepInSync(cb.isChecked()); - mStorageManager.saveFile(mFile); - - /// register the OCFile instance in the observer service to monitor local updates; - /// if necessary, the file is download - Intent intent = new Intent(getActivity().getApplicationContext(), - FileObserverService.class); - intent.putExtra(FileObserverService.KEY_FILE_CMD, - (cb.isChecked()? - FileObserverService.CMD_ADD_OBSERVED_FILE: - FileObserverService.CMD_DEL_OBSERVED_FILE)); - intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile); - intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount); - Log.e(TAG, "starting observer service"); - getActivity().startService(intent); - - if (mFile.keepInSync()) { - onClick(getView().findViewById(R.id.fdDownloadBtn)); // force an immediate synchronization - } - break; - } - case R.id.fdRenameBtn: { - EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this); - dialog.show(getFragmentManager(), "nameeditdialog"); - break; - } - case R.id.fdRemoveBtn: { - ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance( - R.string.confirmation_remove_alert, - new String[]{mFile.getFileName()}, - mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote, - mFile.isDown() ? R.string.confirmation_remove_local : -1, - R.string.common_cancel); - confDialog.setOnConfirmationListener(this); - mCurrentDialog = confDialog; - mCurrentDialog.show(getFragmentManager(), FTAG_CONFIRMATION); - break; - } - case R.id.fdOpenBtn: { - 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(); - } - } - - } - break; - } - default: - Log.e(TAG, "Incorrect view clicked!"); - } - - /* else if (v.getId() == R.id.fdShareBtn) { - Thread t = new Thread(new ShareRunnable(mFile.getRemotePath())); - t.start(); - }*/ - } - - - @Override - public void onConfirmation(String callerTag) { - if (callerTag.equals(FTAG_CONFIRMATION)) { - if (mStorageManager.getFileById(mFile.getFileId()) != null) { - mLastRemoteOperation = new RemoveFileOperation( mFile, - true, - mStorageManager); - WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); - mLastRemoteOperation.execute(wc, this, mHandler); - - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - } - } - mCurrentDialog.dismiss(); - mCurrentDialog = null; - } - - @Override - public void onNeutral(String callerTag) { - File f = null; - if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) { - f.delete(); - mFile.setStoragePath(null); - mStorageManager.saveFile(mFile); - updateFileDetails(mFile, mAccount); - } - mCurrentDialog.dismiss(); - mCurrentDialog = null; - } - - @Override - public void onCancel(String callerTag) { - Log.d(TAG, "REMOVAL CANCELED"); - mCurrentDialog.dismiss(); - mCurrentDialog = null; - } - - - /** - * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced. - * - * @return True when the fragment was created with the empty layout. - */ - public boolean isEmpty() { - return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null); - } - - - /** - * Can be used to get the file that is currently being displayed. - * @return The file on the screen. - */ - public OCFile getDisplayedFile(){ - 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); - } - - - /** - * Updates the view with all relevant details about that file. - * - * TODO Remove parameter when the transferring state of files is kept in database. - * - * @param transferring Flag signaling if the file should be considered as downloading or uploading, - * although {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and - * {@link FileUploaderBinder#isUploading(Account, OCFile)} return false. - * - */ - public void updateFileDetails(boolean transferring) { - - if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) { - - // set file details - setFilename(mFile.getFileName()); - setFiletype(mFile.getMimetype()); - setFilesize(mFile.getFileLength()); - if(ocVersionSupportsTimeCreated()){ - setTimeCreated(mFile.getCreationTimestamp()); - } - - setTimeModified(mFile.getModificationTimestamp()); - - CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync); - cb.setChecked(mFile.keepInSync()); - - // configure UI for depending upon local state of the file - //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) { - FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); - FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder(); - if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) { - setButtonsForTransferring(); - - } else if (mFile.isDown()) { - // Update preview - if (mFile.getMimetype().startsWith("image/")) { - BitmapLoader bl = new BitmapLoader(); - bl.execute(new String[]{mFile.getStoragePath()}); - } - - setButtonsForDown(); - - } else { - // TODO load default preview image; when the local file is removed, the preview remains there - setButtonsForRemote(); - } - } - getView().invalidate(); - } - - - /** - * Updates the filename in view - * @param filename to set - */ - private void setFilename(String filename) { - TextView tv = (TextView) getView().findViewById(R.id.fdFilename); - if (tv != null) - tv.setText(filename); - } - - /** - * Updates the MIME type in view - * @param mimetype to set - */ - private void setFiletype(String mimetype) { - TextView tv = (TextView) getView().findViewById(R.id.fdType); - if (tv != null) { - String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);; - tv.setText(printableMimetype); - } - ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon); - if (iv != null) { - iv.setImageResource(DisplayUtils.getResourceId(mimetype)); - } - } - - /** - * Updates the file size in view - * @param filesize in bytes to set - */ - private void setFilesize(long filesize) { - TextView tv = (TextView) getView().findViewById(R.id.fdSize); - if (tv != null) - tv.setText(DisplayUtils.bytesToHumanReadable(filesize)); - } - - /** - * Updates the time that the file was created in view - * @param milliseconds Unix time to set - */ - private void setTimeCreated(long milliseconds){ - TextView tv = (TextView) getView().findViewById(R.id.fdCreated); - TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel); - if(tv != null){ - tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds)); - tv.setVisibility(View.VISIBLE); - tvLabel.setVisibility(View.VISIBLE); - } - } - - /** - * Updates the time that the file was last modified - * @param milliseconds Unix time to set - */ - private void setTimeModified(long milliseconds){ - TextView tv = (TextView) getView().findViewById(R.id.fdModified); - if(tv != null){ - tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds)); - } - } - - /** - * Enables or disables buttons for a file being downloaded - */ - private void setButtonsForTransferring() { - if (!isEmpty()) { - Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn); - downloadButton.setText(R.string.common_cancel); - //downloadButton.setEnabled(false); - - // let's protect the user from himself ;) - ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false); - ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false); - ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false); - getView().findViewById(R.id.fdKeepInSync).setEnabled(false); - } - } - - /** - * Enables or disables buttons for a file locally available - */ - private void setButtonsForDown() { - if (!isEmpty()) { - Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn); - downloadButton.setText(R.string.filedetails_sync_file); - - ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true); - ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); - ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true); - getView().findViewById(R.id.fdKeepInSync).setEnabled(true); - } - } - - /** - * Enables or disables buttons for a file not locally available - */ - private void setButtonsForRemote() { - if (!isEmpty()) { - Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn); - downloadButton.setText(R.string.filedetails_download); - - ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false); - ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); - ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true); - getView().findViewById(R.id.fdKeepInSync).setEnabled(true); - } - } - - - /** - * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return - * the time that the file was created. There is a chance that this will - * be fixed in future versions. Use this method to check if this version of - * ownCloud has this fix. - * @return True, if ownCloud the ownCloud version is supporting creation time - */ - private boolean ocVersionSupportsTimeCreated(){ - /*if(mAccount != null){ - AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE); - OwnCloudVersion ocVersion = new OwnCloudVersion(accManager - .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); - if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) { - return true; - } - }*/ - return false; - } - - - /** - * Interface to implement by any Activity that includes some instance of FileDetailFragment - * - * @author David A. Velasco - */ - public interface ContainerActivity extends TransferServiceGetter { - - /** - * Callback method invoked when the detail fragment wants to notice its container - * activity about a relevant state the file shown by the fragment. - * - * Added to notify to FileDisplayActivity about the need of refresh the files list. - * - * Currently called when: - * - a download is started; - * - a rename is completed; - * - a deletion is completed; - * - the 'inSync' flag is changed; - */ - public void onFileStateChanged(); - - } - - - /** - * Once the file download has finished -> update view - * @author Bartek Przybylski - */ - private class DownloadFinishReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); - - if (!isEmpty() && accountName.equals(mAccount.name)) { - boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); - String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); - if (mFile.getRemotePath().equals(downloadedRemotePath)) { - if (downloadWasFine) { - mFile = mStorageManager.getFileByPath(downloadedRemotePath); - } - updateFileDetails(false); // it updates the buttons; must be called although !downloadWasFine - } - } - } - } - - - /** - * Once the file upload has finished -> update view - * - * Being notified about the finish of an upload is necessary for the next sequence: - * 1. Upload a big file. - * 2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list - * of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. - * 3. Click the file in the list to see its details. - * 4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons. - */ - private class UploadFinishReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); - - if (!isEmpty() && accountName.equals(mAccount.name)) { - boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false); - String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH); - boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH)); - if (mFile.getRemotePath().equals(uploadRemotePath) || - renamedInUpload) { - if (uploadWasFine) { - mFile = mStorageManager.getFileByPath(uploadRemotePath); - } - if (renamedInUpload) { - String newName = (new File(uploadRemotePath)).getName(); - Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG); - msg.show(); - } - getSherlockActivity().removeStickyBroadcast(intent); // not the best place to do this; a small refactorization of BroadcastReceivers should be done - updateFileDetails(false); // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server - } - } - } - } - - - // this is a temporary class for sharing purposes, it need to be replaced in transfer service - @SuppressWarnings("unused") - private class ShareRunnable implements Runnable { - private String mPath; - - public ShareRunnable(String path) { - mPath = path; - } - - public void run() { - AccountManager am = AccountManager.get(getActivity()); - Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity()); - OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); - String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv); - - Log.d("share", "sharing for version " + ocv.toString()); - - if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) { - String APPS_PATH = "/apps/files_sharing/"; - String SHARE_PATH = "ajax/share.php"; - - String SHARED_PATH = "/apps/files_sharing/get.php?token="; - - final String WEBDAV_SCRIPT = "webdav.php"; - final String WEBDAV_FILES_LOCATION = "/files/"; - - WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext()); - HttpConnectionManagerParams params = new HttpConnectionManagerParams(); - params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5); - - //wc.getParams().setParameter("http.protocol.single-cookie-header", true); - //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); - - PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH); - - post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" ); - post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); - List formparams = new ArrayList(); - Log.d("share", mPath+""); - formparams.add(new BasicNameValuePair("sources",mPath)); - formparams.add(new BasicNameValuePair("uid_shared_with", "public")); - formparams.add(new BasicNameValuePair("permissions", "0")); - post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8))); - - int status; - try { - PropFindMethod find = new PropFindMethod(url+"/"); - find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); - Log.d("sharer", ""+ url+"/"); - - for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) { - Log.d("sharer-h", a.getName() + ":"+a.getValue()); - } - - int status2 = wc.executeMethod(find); - - Log.d("sharer", "propstatus "+status2); - - GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/"); - get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); - - status2 = wc.executeMethod(get); - - Log.d("sharer", "getstatus "+status2); - Log.d("sharer", "" + get.getResponseBodyAsString()); - - for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) { - Log.d("sharer", a.getName() + ":"+a.getValue()); - } - - status = wc.executeMethod(post); - for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) { - Log.d("sharer-h", a.getName() + ":"+a.getValue()); - } - for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) { - Log.d("sharer", a.getName() + ":"+a.getValue()); - } - String resp = post.getResponseBodyAsString(); - Log.d("share", ""+post.getURI().toString()); - Log.d("share", "returned status " + status); - Log.d("share", " " +resp); - - if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) { - return; - } - - JSONObject jsonObject = new JSONObject (resp); - String jsonStatus = jsonObject.getString("status"); - if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success"); - - String token = jsonObject.getString("data"); - String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; - Log.d("Actions:shareFile ok", "url: " + uri); - - } catch (Exception e) { - e.printStackTrace(); - } - - } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) { - - } - } - } - - public void onDismiss(EditNameDialog dialog) { - if (dialog.getResult()) { - String newFilename = dialog.getNewFilename(); - Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); - mLastRemoteOperation = new RenameFileOperation( mFile, - mAccount, - newFilename, - new FileDataStorageManager(mAccount, getActivity().getContentResolver())); - WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); - mLastRemoteOperation.execute(wc, this, mHandler); - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - } - } - - - class BitmapLoader extends AsyncTask { - @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 { - - BitmapFactory.Options options = new Options(); - options.inScaled = true; - options.inPurgeable = true; - options.inJustDecodeBounds = 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; - } - - result = BitmapFactory.decodeFile(storagePath, options); - options.inJustDecodeBounds = false; - - int width = options.outWidth; - int height = options.outHeight; - int scale = 1; - if (width >= 2048 || height >= 2048) { - 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.e("ASD", "W " + width + " SW " + screenwidth); - - if (width > screenwidth) { - scale = (int) Math.ceil((float)width / screenwidth); - options.inSampleSize = scale; - } - - result = BitmapFactory.decodeFile(storagePath, options); - - Log.e("ASD", "W " + options.outWidth + " SW " + 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 && mPreview != null) { - mPreview.setImageBitmap(result); - } - } - - } - - /** - * {@inheritDoc} - */ - @Override - public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { - if (operation.equals(mLastRemoteOperation)) { - if (operation instanceof RemoveFileOperation) { - onRemoveFileOperationFinish((RemoveFileOperation)operation, result); - - } else if (operation instanceof RenameFileOperation) { - onRenameFileOperationFinish((RenameFileOperation)operation, result); - - } else if (operation instanceof SynchronizeFileOperation) { - onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result); - } - } - } - - - private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - - if (result.isSuccess()) { - Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG); - msg.show(); - if (inDisplayActivity) { - // double pane - FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment - transaction.commit(); - mContainerActivity.onFileStateChanged(); - } else { - getActivity().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 - } - } - } - - private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) { - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - - if (result.isSuccess()) { - updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount); - mContainerActivity.onFileStateChanged(); - - } else { - if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) { - Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); - msg.show(); - // TODO throw again the new rename dialog - } else { - Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); - msg.show(); - if (result.isSslRecoverableException()) { - // TODO show the SSL warning dialog - } - } - } - } - - private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) { - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - - if (!result.isSuccess()) { - if (result.getCode() == ResultCode.SYNC_CONFLICT) { - Intent i = new Intent(getActivity(), ConflictsResolveActivity.class); - i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile); - i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount); - startActivity(i); - - } else { - Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); - msg.show(); - } - - if (mFile.isDown()) { - setButtonsForDown(); - - } else { - setButtonsForRemote(); - } - - } else { - if (operation.transferWasRequested()) { - mContainerActivity.onFileStateChanged(); // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so - // checking the service to see if the file is downloading results in FALSE - } else { - Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); - msg.show(); - if (mFile.isDown()) { - setButtonsForDown(); - - } else { - setButtonsForRemote(); - } - } - } - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * 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 . + * + */ +package com.owncloud.android.ui.fragment; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.commons.httpclient.params.HttpConnectionManagerParams; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HTTP; +import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; +import org.json.JSONObject; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +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.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.webkit.MimeTypeMap; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.actionbarsherlock.app.SherlockFragment; +import com.owncloud.android.AccountUtils; +import com.owncloud.android.DisplayUtils; +import com.owncloud.android.Log_OC; +import com.owncloud.android.authenticator.AccountAuthenticator; +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.FileObserverService; +import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; +import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +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.RemoteOperationResult.ResultCode; +import com.owncloud.android.operations.RemoveFileOperation; +import com.owncloud.android.operations.RenameFileOperation; +import com.owncloud.android.operations.SynchronizeFileOperation; +import com.owncloud.android.ui.activity.ConflictsResolveActivity; +import com.owncloud.android.ui.activity.FileDetailActivity; +import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.ui.activity.TransferServiceGetter; +import com.owncloud.android.ui.dialog.EditNameDialog; +import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener; +import com.owncloud.android.utils.OwnCloudVersion; + +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; +import eu.alefzero.webdav.WebdavUtils; + +/** + * This Fragment is used to display the details about a file. + * + * @author Bartek Przybylski + * + */ +public class FileDetailFragment extends SherlockFragment implements + OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener { + + public static final String EXTRA_FILE = "FILE"; + public static final String EXTRA_ACCOUNT = "ACCOUNT"; + + private FileDetailFragment.ContainerActivity mContainerActivity; + + private int mLayout; + private View mView; + private OCFile mFile; + private Account mAccount; + private FileDataStorageManager mStorageManager; + private ImageView mPreview; + + private DownloadFinishReceiver mDownloadFinishReceiver; + private UploadFinishReceiver mUploadFinishReceiver; + + private Handler mHandler; + private RemoteOperation mLastRemoteOperation; + private DialogFragment mCurrentDialog; + + private static final String TAG = FileDetailFragment.class.getSimpleName(); + public static final String FTAG = "FileDetails"; + public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT"; + + + /** + * Creates an empty details fragment. + * + * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. + */ + public FileDetailFragment() { + mFile = null; + mAccount = null; + mStorageManager = null; + mLayout = R.layout.file_details_empty; + } + + + /** + * Creates a details fragment. + * + * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before). + * + * @param fileToDetail An {@link OCFile} to show in the fragment + * @param ocAccount An ownCloud account; needed to start downloads + */ + public FileDetailFragment(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 + mLayout = R.layout.file_details_empty; + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mHandler = new Handler(); + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + + if (savedInstanceState != null) { + mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE); + mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT); + } + + if(mFile != null && mAccount != null) { + mLayout = R.layout.file_details_fragment; + } + + View view = null; + view = inflater.inflate(mLayout, container, false); + mView = view; + + if (mLayout == R.layout.file_details_fragment) { + mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this); + mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this); + mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this); + mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this); + mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this); + //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this); + mPreview = (ImageView)mView.findViewById(R.id.fdPreview); + } + + updateFileDetails(false); + return view; + } + + + /** + * {@inheritDoc} + */ + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mContainerActivity = (ContainerActivity) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName()); + } + } + + + /** + * {@inheritDoc} + */ + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (mAccount != null) { + mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());; + } + } + + + @Override + public void onSaveInstanceState(Bundle outState) { + Log_OC.i(getClass().toString(), "onSaveInstanceState() start"); + super.onSaveInstanceState(outState); + outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile); + outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount); + Log_OC.i(getClass().toString(), "onSaveInstanceState() end"); + } + + + @Override + public void onResume() { + super.onResume(); + + 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); + + mPreview = (ImageView)mView.findViewById(R.id.fdPreview); + } + + @Override + public void onPause() { + super.onPause(); + + getActivity().unregisterReceiver(mDownloadFinishReceiver); + mDownloadFinishReceiver = null; + + getActivity().unregisterReceiver(mUploadFinishReceiver); + mUploadFinishReceiver = null; + + if (mPreview != null) { + mPreview = null; + } + } + + @Override + public View getView() { + return super.getView() == null ? mView : super.getView(); + } + + + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.fdDownloadBtn: { + FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); + FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder(); + if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) { + downloaderBinder.cancel(mAccount, mFile); + if (mFile.isDown()) { + setButtonsForDown(); + } else { + setButtonsForRemote(); + } + + } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) { + uploaderBinder.cancel(mAccount, mFile); + if (!mFile.fileExists()) { + // TODO make something better + if (getActivity() instanceof FileDisplayActivity) { + // double pane + FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment + transaction.commit(); + mContainerActivity.onFileStateChanged(); + } else { + getActivity().finish(); + } + + } else if (mFile.isDown()) { + setButtonsForDown(); + } else { + setButtonsForRemote(); + } + + } else { + mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity()); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); + mLastRemoteOperation.execute(wc, this, mHandler); + + // update ui + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference + + } + break; + } + case R.id.fdKeepInSync: { + CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync); + mFile.setKeepInSync(cb.isChecked()); + mStorageManager.saveFile(mFile); + + /// register the OCFile instance in the observer service to monitor local updates; + /// if necessary, the file is download + Intent intent = new Intent(getActivity().getApplicationContext(), + FileObserverService.class); + intent.putExtra(FileObserverService.KEY_FILE_CMD, + (cb.isChecked()? + FileObserverService.CMD_ADD_OBSERVED_FILE: + FileObserverService.CMD_DEL_OBSERVED_FILE)); + intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile); + intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount); + Log_OC.e(TAG, "starting observer service"); + getActivity().startService(intent); + + if (mFile.keepInSync()) { + onClick(getView().findViewById(R.id.fdDownloadBtn)); // force an immediate synchronization + } + break; + } + case R.id.fdRenameBtn: { + EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this); + dialog.show(getFragmentManager(), "nameeditdialog"); + break; + } + case R.id.fdRemoveBtn: { + ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance( + R.string.confirmation_remove_alert, + new String[]{mFile.getFileName()}, + mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote, + mFile.isDown() ? R.string.confirmation_remove_local : -1, + R.string.common_cancel); + confDialog.setOnConfirmationListener(this); + mCurrentDialog = confDialog; + mCurrentDialog.show(getFragmentManager(), FTAG_CONFIRMATION); + break; + } + case R.id.fdOpenBtn: { + 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_OC.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_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath); + + } catch (ActivityNotFoundException e) { + Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension"); + + } catch (Throwable th) { + Log_OC.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(); + } + } + + } + break; + } + default: + Log_OC.e(TAG, "Incorrect view clicked!"); + } + + /* else if (v.getId() == R.id.fdShareBtn) { + Thread t = new Thread(new ShareRunnable(mFile.getRemotePath())); + t.start(); + }*/ + } + + + @Override + public void onConfirmation(String callerTag) { + if (callerTag.equals(FTAG_CONFIRMATION)) { + if (mStorageManager.getFileById(mFile.getFileId()) != null) { + mLastRemoteOperation = new RemoveFileOperation( mFile, + true, + mStorageManager); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); + mLastRemoteOperation.execute(wc, this, mHandler); + + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + } + } + mCurrentDialog.dismiss(); + mCurrentDialog = null; + } + + @Override + public void onNeutral(String callerTag) { + File f = null; + if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) { + f.delete(); + mFile.setStoragePath(null); + mStorageManager.saveFile(mFile); + updateFileDetails(mFile, mAccount); + } + mCurrentDialog.dismiss(); + mCurrentDialog = null; + } + + @Override + public void onCancel(String callerTag) { + Log_OC.d(TAG, "REMOVAL CANCELED"); + mCurrentDialog.dismiss(); + mCurrentDialog = null; + } + + + /** + * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced. + * + * @return True when the fragment was created with the empty layout. + */ + public boolean isEmpty() { + return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null); + } + + + /** + * Can be used to get the file that is currently being displayed. + * @return The file on the screen. + */ + public OCFile getDisplayedFile(){ + 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); + } + + + /** + * Updates the view with all relevant details about that file. + * + * TODO Remove parameter when the transferring state of files is kept in database. + * + * @param transferring Flag signaling if the file should be considered as downloading or uploading, + * although {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and + * {@link FileUploaderBinder#isUploading(Account, OCFile)} return false. + * + */ + public void updateFileDetails(boolean transferring) { + + if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) { + + // set file details + setFilename(mFile.getFileName()); + setFiletype(mFile.getMimetype()); + setFilesize(mFile.getFileLength()); + if(ocVersionSupportsTimeCreated()){ + setTimeCreated(mFile.getCreationTimestamp()); + } + + setTimeModified(mFile.getModificationTimestamp()); + + CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync); + cb.setChecked(mFile.keepInSync()); + + // configure UI for depending upon local state of the file + //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) { + FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); + FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder(); + if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) { + setButtonsForTransferring(); + + } else if (mFile.isDown()) { + // Update preview + if (mFile.getMimetype().startsWith("image/")) { + BitmapLoader bl = new BitmapLoader(); + bl.execute(new String[]{mFile.getStoragePath()}); + } + + setButtonsForDown(); + + } else { + // TODO load default preview image; when the local file is removed, the preview remains there + setButtonsForRemote(); + } + } + getView().invalidate(); + } + + + /** + * Updates the filename in view + * @param filename to set + */ + private void setFilename(String filename) { + TextView tv = (TextView) getView().findViewById(R.id.fdFilename); + if (tv != null) + tv.setText(filename); + } + + /** + * Updates the MIME type in view + * @param mimetype to set + */ + private void setFiletype(String mimetype) { + TextView tv = (TextView) getView().findViewById(R.id.fdType); + if (tv != null) { + String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);; + tv.setText(printableMimetype); + } + ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon); + if (iv != null) { + iv.setImageResource(DisplayUtils.getResourceId(mimetype)); + } + } + + /** + * Updates the file size in view + * @param filesize in bytes to set + */ + private void setFilesize(long filesize) { + TextView tv = (TextView) getView().findViewById(R.id.fdSize); + if (tv != null) + tv.setText(DisplayUtils.bytesToHumanReadable(filesize)); + } + + /** + * Updates the time that the file was created in view + * @param milliseconds Unix time to set + */ + private void setTimeCreated(long milliseconds){ + TextView tv = (TextView) getView().findViewById(R.id.fdCreated); + TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel); + if(tv != null){ + tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds)); + tv.setVisibility(View.VISIBLE); + tvLabel.setVisibility(View.VISIBLE); + } + } + + /** + * Updates the time that the file was last modified + * @param milliseconds Unix time to set + */ + private void setTimeModified(long milliseconds){ + TextView tv = (TextView) getView().findViewById(R.id.fdModified); + if(tv != null){ + tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds)); + } + } + + /** + * Enables or disables buttons for a file being downloaded + */ + private void setButtonsForTransferring() { + if (!isEmpty()) { + Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn); + downloadButton.setText(R.string.common_cancel); + //downloadButton.setEnabled(false); + + // let's protect the user from himself ;) + ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false); + ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false); + ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false); + getView().findViewById(R.id.fdKeepInSync).setEnabled(false); + } + } + + /** + * Enables or disables buttons for a file locally available + */ + private void setButtonsForDown() { + if (!isEmpty()) { + Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn); + downloadButton.setText(R.string.filedetails_sync_file); + + ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true); + ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); + ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true); + getView().findViewById(R.id.fdKeepInSync).setEnabled(true); + } + } + + /** + * Enables or disables buttons for a file not locally available + */ + private void setButtonsForRemote() { + if (!isEmpty()) { + Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn); + downloadButton.setText(R.string.filedetails_download); + + ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false); + ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); + ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true); + getView().findViewById(R.id.fdKeepInSync).setEnabled(true); + } + } + + + /** + * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return + * the time that the file was created. There is a chance that this will + * be fixed in future versions. Use this method to check if this version of + * ownCloud has this fix. + * @return True, if ownCloud the ownCloud version is supporting creation time + */ + private boolean ocVersionSupportsTimeCreated(){ + /*if(mAccount != null){ + AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE); + OwnCloudVersion ocVersion = new OwnCloudVersion(accManager + .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); + if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) { + return true; + } + }*/ + return false; + } + + + /** + * Interface to implement by any Activity that includes some instance of FileDetailFragment + * + * @author David A. Velasco + */ + public interface ContainerActivity extends TransferServiceGetter { + + /** + * Callback method invoked when the detail fragment wants to notice its container + * activity about a relevant state the file shown by the fragment. + * + * Added to notify to FileDisplayActivity about the need of refresh the files list. + * + * Currently called when: + * - a download is started; + * - a rename is completed; + * - a deletion is completed; + * - the 'inSync' flag is changed; + */ + public void onFileStateChanged(); + + } + + + /** + * Once the file download has finished -> update view + * @author Bartek Przybylski + */ + private class DownloadFinishReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); + + if (!isEmpty() && accountName.equals(mAccount.name)) { + boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); + String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + if (mFile.getRemotePath().equals(downloadedRemotePath)) { + if (downloadWasFine) { + mFile = mStorageManager.getFileByPath(downloadedRemotePath); + } + updateFileDetails(false); // it updates the buttons; must be called although !downloadWasFine + } + } + } + } + + + /** + * Once the file upload has finished -> update view + * + * Being notified about the finish of an upload is necessary for the next sequence: + * 1. Upload a big file. + * 2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list + * of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. + * 3. Click the file in the list to see its details. + * 4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons. + */ + private class UploadFinishReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); + + if (!isEmpty() && accountName.equals(mAccount.name)) { + boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false); + String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH); + boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH)); + if (mFile.getRemotePath().equals(uploadRemotePath) || + renamedInUpload) { + if (uploadWasFine) { + mFile = mStorageManager.getFileByPath(uploadRemotePath); + } + if (renamedInUpload) { + String newName = (new File(uploadRemotePath)).getName(); + Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG); + msg.show(); + } + getSherlockActivity().removeStickyBroadcast(intent); // not the best place to do this; a small refactorization of BroadcastReceivers should be done + updateFileDetails(false); // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server + } + } + } + } + + + // this is a temporary class for sharing purposes, it need to be replaced in transfer service + @SuppressWarnings("unused") + private class ShareRunnable implements Runnable { + private String mPath; + + public ShareRunnable(String path) { + mPath = path; + } + + public void run() { + AccountManager am = AccountManager.get(getActivity()); + Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity()); + OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); + String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv); + + Log_OC.d("share", "sharing for version " + ocv.toString()); + + if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) { + String APPS_PATH = "/apps/files_sharing/"; + String SHARE_PATH = "ajax/share.php"; + + String SHARED_PATH = "/apps/files_sharing/get.php?token="; + + final String WEBDAV_SCRIPT = "webdav.php"; + final String WEBDAV_FILES_LOCATION = "/files/"; + + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext()); + HttpConnectionManagerParams params = new HttpConnectionManagerParams(); + params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5); + + //wc.getParams().setParameter("http.protocol.single-cookie-header", true); + //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); + + PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH); + + post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" ); + post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); + List formparams = new ArrayList(); + Log_OC.d("share", mPath+""); + formparams.add(new BasicNameValuePair("sources",mPath)); + formparams.add(new BasicNameValuePair("uid_shared_with", "public")); + formparams.add(new BasicNameValuePair("permissions", "0")); + post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8))); + + int status; + try { + PropFindMethod find = new PropFindMethod(url+"/"); + find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); + Log_OC.d("sharer", ""+ url+"/"); + + for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) { + Log_OC.d("sharer-h", a.getName() + ":"+a.getValue()); + } + + int status2 = wc.executeMethod(find); + + Log_OC.d("sharer", "propstatus "+status2); + + GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/"); + get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); + + status2 = wc.executeMethod(get); + + Log_OC.d("sharer", "getstatus "+status2); + Log_OC.d("sharer", "" + get.getResponseBodyAsString()); + + for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) { + Log_OC.d("sharer", a.getName() + ":"+a.getValue()); + } + + status = wc.executeMethod(post); + for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) { + Log_OC.d("sharer-h", a.getName() + ":"+a.getValue()); + } + for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) { + Log_OC.d("sharer", a.getName() + ":"+a.getValue()); + } + String resp = post.getResponseBodyAsString(); + Log_OC.d("share", ""+post.getURI().toString()); + Log_OC.d("share", "returned status " + status); + Log_OC.d("share", " " +resp); + + if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) { + return; + } + + JSONObject jsonObject = new JSONObject (resp); + String jsonStatus = jsonObject.getString("status"); + if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success"); + + String token = jsonObject.getString("data"); + String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; + Log_OC.d("Actions:shareFile ok", "url: " + uri); + + } catch (Exception e) { + e.printStackTrace(); + } + + } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) { + + } + } + } + + public void onDismiss(EditNameDialog dialog) { + if (dialog.getResult()) { + String newFilename = dialog.getNewFilename(); + Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename); + mLastRemoteOperation = new RenameFileOperation( mFile, + mAccount, + newFilename, + new FileDataStorageManager(mAccount, getActivity().getContentResolver())); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); + mLastRemoteOperation.execute(wc, this, mHandler); + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + } + } + + + class BitmapLoader extends AsyncTask { + @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 { + + BitmapFactory.Options options = new Options(); + options.inScaled = true; + options.inPurgeable = true; + options.inJustDecodeBounds = 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; + } + + result = BitmapFactory.decodeFile(storagePath, options); + options.inJustDecodeBounds = false; + + int width = options.outWidth; + int height = options.outHeight; + int scale = 1; + if (width >= 2048 || height >= 2048) { + 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_OC.e("ASD", "W " + width + " SW " + screenwidth); + + if (width > screenwidth) { + scale = (int) Math.ceil((float)width / screenwidth); + options.inSampleSize = scale; + } + + result = BitmapFactory.decodeFile(storagePath, options); + + Log_OC.e("ASD", "W " + options.outWidth + " SW " + options.outHeight); + + } catch (OutOfMemoryError e) { + result = null; + Log_OC.e(TAG, "Out of memory occured for file with size " + storagePath); + + } catch (NoSuchFieldError e) { + result = null; + Log_OC.e(TAG, "Error from access to unexisting field despite protection " + storagePath); + + } catch (Throwable t) { + result = null; + Log_OC.e(TAG, "Unexpected error while creating image preview " + storagePath, t); + } + return result; + } + @Override + protected void onPostExecute(Bitmap result) { + if (result != null && mPreview != null) { + mPreview.setImageBitmap(result); + } + } + + } + + /** + * {@inheritDoc} + */ + @Override + public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { + if (operation.equals(mLastRemoteOperation)) { + if (operation instanceof RemoveFileOperation) { + onRemoveFileOperationFinish((RemoveFileOperation)operation, result); + + } else if (operation instanceof RenameFileOperation) { + onRenameFileOperationFinish((RenameFileOperation)operation, result); + + } else if (operation instanceof SynchronizeFileOperation) { + onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result); + } + } + } + + + private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + + if (result.isSuccess()) { + Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG); + msg.show(); + if (inDisplayActivity) { + // double pane + FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment + transaction.commit(); + mContainerActivity.onFileStateChanged(); + } else { + getActivity().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 + } + } + } + + private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) { + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + + if (result.isSuccess()) { + updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount); + mContainerActivity.onFileStateChanged(); + + } else { + if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) { + Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); + msg.show(); + // TODO throw again the new rename dialog + } else { + Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); + msg.show(); + if (result.isSslRecoverableException()) { + // TODO show the SSL warning dialog + } + } + } + } + + private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) { + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + + if (!result.isSuccess()) { + if (result.getCode() == ResultCode.SYNC_CONFLICT) { + Intent i = new Intent(getActivity(), ConflictsResolveActivity.class); + i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile); + i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount); + startActivity(i); + + } else { + Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); + msg.show(); + } + + if (mFile.isDown()) { + setButtonsForDown(); + + } else { + setButtonsForRemote(); + } + + } else { + if (operation.transferWasRequested()) { + mContainerActivity.onFileStateChanged(); // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so + // checking the service to see if the file is downloading results in FALSE + } else { + Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); + msg.show(); + if (mFile.isDown()) { + setButtonsForDown(); + + } else { + setButtonsForRemote(); + } + } + } + } + +} diff --git a/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java index 51f78b706d..2b16bd7f6a 100644 --- a/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java @@ -35,6 +35,7 @@ import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; +import com.owncloud.android.Log_OC; import com.owncloud.android.R; /** @@ -76,10 +77,10 @@ public class LocalFileListFragment extends FragmentListView { */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Log.i(TAG, "onCreateView() start"); + Log_OC.i(TAG, "onCreateView() start"); View v = super.onCreateView(inflater, container, savedInstanceState); getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - Log.i(TAG, "onCreateView() end"); + Log_OC.i(TAG, "onCreateView() end"); return v; } @@ -89,30 +90,30 @@ public class LocalFileListFragment extends FragmentListView { */ @Override public void onActivityCreated(Bundle savedInstanceState) { - Log.i(TAG, "onActivityCreated() start"); + Log_OC.i(TAG, "onActivityCreated() start"); super.onCreate(savedInstanceState); mAdapter = new LocalFileListAdapter(mContainerActivity.getInitialDirectory(), getActivity()); setListAdapter(mAdapter); if (savedInstanceState != null) { - Log.i(TAG, "savedInstanceState is not null"); + Log_OC.i(TAG, "savedInstanceState is not null"); int position = savedInstanceState.getInt(SAVED_LIST_POSITION); setReferencePosition(position); } - Log.i(TAG, "onActivityCreated() stop"); + Log_OC.i(TAG, "onActivityCreated() stop"); } @Override public void onSaveInstanceState(Bundle savedInstanceState) { - Log.i(TAG, "onSaveInstanceState() start"); + Log_OC.i(TAG, "onSaveInstanceState() start"); savedInstanceState.putInt(SAVED_LIST_POSITION, getReferencePosition()); - Log.i(TAG, "onSaveInstanceState() stop"); + Log_OC.i(TAG, "onSaveInstanceState() stop"); } @@ -144,7 +145,7 @@ public class LocalFileListFragment extends FragmentListView { } } else { - Log.w(TAG, "Null object in ListAdapter!!"); + Log_OC.w(TAG, "Null object in ListAdapter!!"); } } @@ -203,7 +204,7 @@ public class LocalFileListFragment extends FragmentListView { // if that's not a directory -> List its parent if(!directory.isDirectory()){ - Log.w(TAG, "You see, that is not a directory -> " + directory.toString()); + Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString()); directory = directory.getParentFile(); } @@ -225,7 +226,7 @@ public class LocalFileListFragment extends FragmentListView { String [] result = null; SparseBooleanArray positions = mList.getCheckedItemPositions(); if (positions.size() > 0) { - Log.d(TAG, "Returning " + positions.size() + " selected files"); + Log_OC.d(TAG, "Returning " + positions.size() + " selected files"); result = new String[positions.size()]; for (int i=0; i List its parent if(!directory.isDirectory()){ - Log.w(TAG, "You see, that is not a directory -> " + directory.toString()); + Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString()); directory = storageManager.getFileById(directory.getParentId()); } @@ -475,7 +476,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial public void onDismiss(EditNameDialog dialog) { if (dialog.getResult()) { String newFilename = dialog.getNewFilename(); - Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); + Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename); RemoteOperation operation = new RenameFileOperation(mTargetFile, AccountUtils.getCurrentOwnCloudAccount(getActivity()), newFilename, @@ -528,7 +529,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial @Override public void onCancel(String callerTag) { - Log.d(TAG, "REMOVAL CANCELED"); + Log_OC.d(TAG, "REMOVAL CANCELED"); if (mCurrentDialog != null) { mCurrentDialog.dismiss(); mCurrentDialog = null; diff --git a/src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java b/src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java index d39f8ce7aa..13c11042e1 100644 --- a/src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java +++ b/src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java @@ -30,6 +30,8 @@ import java.util.Set; import org.apache.commons.httpclient.methods.RequestEntity; +import com.owncloud.android.Log_OC; + import eu.alefzero.webdav.OnDatatransferProgressListener; import android.util.Log; @@ -123,7 +125,7 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity { } } catch (IOException io) { - Log.e(TAG, io.getMessage()); + Log_OC.e(TAG, io.getMessage()); throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io); } diff --git a/src/eu/alefzero/webdav/FileRequestEntity.java b/src/eu/alefzero/webdav/FileRequestEntity.java index 3adaa3a885..b6ecae939e 100644 --- a/src/eu/alefzero/webdav/FileRequestEntity.java +++ b/src/eu/alefzero/webdav/FileRequestEntity.java @@ -32,6 +32,8 @@ import java.util.Set; import org.apache.commons.httpclient.methods.RequestEntity; +import com.owncloud.android.Log_OC; + import eu.alefzero.webdav.OnDatatransferProgressListener; import android.util.Log; @@ -110,7 +112,7 @@ public class FileRequestEntity implements RequestEntity { } } catch (IOException io) { - Log.e("FileRequestException", io.getMessage()); + Log_OC.e("FileRequestException", io.getMessage()); throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io); } finally { diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java index 1319a2b0ce..704e14af40 100644 --- a/src/eu/alefzero/webdav/WebdavClient.java +++ b/src/eu/alefzero/webdav/WebdavClient.java @@ -1,341 +1,343 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * 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 . - * - */ -package eu.alefzero.webdav; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.httpclient.Credentials; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpConnectionManager; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpMethodBase; -import org.apache.commons.httpclient.HttpVersion; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.HeadMethod; -import org.apache.commons.httpclient.methods.PutMethod; -import org.apache.commons.httpclient.params.HttpMethodParams; -import org.apache.http.HttpStatus; -import org.apache.http.params.CoreProtocolPNames; -import org.apache.jackrabbit.webdav.client.methods.DavMethod; -import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; -import org.apache.jackrabbit.webdav.client.methods.MkColMethod; - -import android.net.Uri; -import android.util.Log; - -public class WebdavClient extends HttpClient { - private Uri mUri; - private Credentials mCredentials; - final private static String TAG = "WebdavClient"; - private static final String USER_AGENT = "Android-ownCloud"; - - private OnDatatransferProgressListener mDataTransferListener; - static private byte[] sExhaustBuffer = new byte[1024]; - - /** - * Constructor - */ - public WebdavClient(HttpConnectionManager connectionMgr) { - super(connectionMgr); - Log.d(TAG, "Creating WebdavClient"); - getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT); - getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); - } - - public void setCredentials(String username, String password) { - getParams().setAuthenticationPreemptive(true); - getState().setCredentials(AuthScope.ANY, - getCredentials(username, password)); - } - - private Credentials getCredentials(String username, String password) { - if (mCredentials == null) - mCredentials = new UsernamePasswordCredentials(username, password); - return mCredentials; - } - - /** - * Downloads a file in remoteFilepath to the local targetPath. - * - * @param remoteFilepath Path to the file in the remote server, URL DECODED. - * @param targetFile Local path to save the downloaded file. - * @return 'True' when the file is successfully downloaded. - */ - public boolean downloadFile(String remoteFilePath, File targetFile) { - boolean ret = false; - GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath)); - - try { - int status = executeMethod(get); - if (status == HttpStatus.SC_OK) { - targetFile.createNewFile(); - BufferedInputStream bis = new BufferedInputStream( - get.getResponseBodyAsStream()); - FileOutputStream fos = new FileOutputStream(targetFile); - - byte[] bytes = new byte[4096]; - int readResult; - while ((readResult = bis.read(bytes)) != -1) { - if (mDataTransferListener != null) - mDataTransferListener.onTransferProgress(readResult); - fos.write(bytes, 0, readResult); - } - fos.close(); - ret = true; - } else { - exhaustResponse(get.getResponseBodyAsStream()); - } - Log.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":"")); - } catch (Exception e) { - logException(e, "dowloading " + remoteFilePath); - - } finally { - if (!ret && targetFile.exists()) { - targetFile.delete(); - } - get.releaseConnection(); // let the connection available for other methods - } - return ret; - } - - /** - * Deletes a remote file via webdav - * @param remoteFilePath Remote file path of the file to delete, in URL DECODED format. - * @return - */ - public boolean deleteFile(String remoteFilePath) { - boolean ret = false; - DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath)); - try { - int status = executeMethod(delete); - ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT); - exhaustResponse(delete.getResponseBodyAsStream()); - - Log.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status + (!ret?"(FAIL)":"")); - - } catch (Exception e) { - logException(e, "deleting " + remoteFilePath); - - } finally { - delete.releaseConnection(); // let the connection available for other methods - } - return ret; - } - - - public void setDataTransferProgressListener(OnDatatransferProgressListener listener) { - mDataTransferListener = listener; - } - - /** - * Creates or update a file in the remote server with the contents of a local file. - * - * @param localFile Path to the local file to upload. - * @param remoteTarget Remote path to the file to create or update, URL DECODED - * @param contentType MIME type of the file. - * @return Status HTTP code returned by the server. - * @throws IOException When a transport error that could not be recovered occurred while uploading the file to the server. - * @throws HttpException When a violation of the HTTP protocol occurred. - */ - public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException { - int status = -1; - PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget)); - - try { - File f = new File(localFile); - FileRequestEntity entity = new FileRequestEntity(f, contentType); - entity.addOnDatatransferProgressListener(mDataTransferListener); - put.setRequestEntity(entity); - status = executeMethod(put); - - exhaustResponse(put.getResponseBodyAsStream()); - - } finally { - put.releaseConnection(); // let the connection available for other methods - } - return status; - } - - /** - * Tries to log in to the current URI, with the current credentials - * - * @return A {@link HttpStatus}-Code of the result. SC_OK is good. - */ - public int tryToLogin() { - int status = 0; - HeadMethod head = new HeadMethod(mUri.toString()); - try { - status = executeMethod(head); - boolean result = status == HttpStatus.SC_OK; - Log.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":"")); - exhaustResponse(head.getResponseBodyAsStream()); - - } catch (Exception e) { - logException(e, "trying to login at " + mUri.toString()); - - } finally { - head.releaseConnection(); - } - return status; - } - - /** - * Creates a remote directory with the received path. - * - * @param path Path of the directory to create, URL DECODED - * @return 'True' when the directory is successfully created - */ - public boolean createDirectory(String path) { - boolean result = false; - int status = -1; - MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path)); - try { - Log.d(TAG, "Creating directory " + path); - status = executeMethod(mkcol); - Log.d(TAG, "Status returned: " + status); - result = mkcol.succeeded(); - - Log.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":"")); - exhaustResponse(mkcol.getResponseBodyAsStream()); - - } catch (Exception e) { - logException(e, "creating directory " + path); - - } finally { - mkcol.releaseConnection(); // let the connection available for other methods - } - return result; - } - - - /** - * Check if a file exists in the OC server - * - * @return 'true' if the file exists; 'false' it doesn't exist - * @throws Exception When the existence could not be determined - */ - public boolean existsFile(String path) throws IOException, HttpException { - HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path)); - try { - int status = executeMethod(head); - Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":"")); - exhaustResponse(head.getResponseBodyAsStream()); - return (status == HttpStatus.SC_OK); - - } finally { - head.releaseConnection(); // let the connection available for other methods - } - } - - - /** - * Requests the received method with the received timeout (milliseconds). - * - * Executes the method through the inherited HttpClient.executedMethod(method). - * - * Sets the socket and connection timeouts only for the method received. - * - * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default' - * - * @param method HTTP method request. - * @param readTimeout Timeout to set for data reception - * @param conntionTimout Timeout to set for connection establishment - */ - public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException { - int oldSoTimeout = getParams().getSoTimeout(); - int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout(); - try { - if (readTimeout >= 0) { - method.getParams().setSoTimeout(readTimeout); // this should be enough... - getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS - } - if (connectionTimeout >= 0) { - getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); - } - return executeMethod(method); - } finally { - getParams().setSoTimeout(oldSoTimeout); - getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout); - } - } - - /** - * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation. - * - * @param responseBodyAsStream InputStream with the HTTP response to exhaust. - */ - public void exhaustResponse(InputStream responseBodyAsStream) { - if (responseBodyAsStream != null) { - try { - while (responseBodyAsStream.read(sExhaustBuffer) >= 0); - responseBodyAsStream.close(); - - } catch (IOException io) { - Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io); - } - } - } - - - /** - * Logs an exception triggered in a HTTP request. - * - * @param e Caught exception. - * @param doing Suffix to add at the end of the logged message. - */ - private void logException(Exception e, String doing) { - if (e instanceof HttpException) { - Log.e(TAG, "HTTP violation while " + doing, e); - - } else if (e instanceof IOException) { - Log.e(TAG, "Unrecovered transport exception while " + doing, e); - - } else { - Log.e(TAG, "Unexpected exception while " + doing, e); - } - } - - - /** - * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client. - */ - public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { - getParams().setSoTimeout(defaultDataTimeout); - getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); - } - - /** - * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs - * @param uri - */ - public void setBaseUri(Uri uri) { - mUri = uri; - } - - public Uri getBaseUri() { - return mUri; - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * 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 . + * + */ +package eu.alefzero.webdav; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpConnectionManager; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.HttpVersion; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.HeadMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.http.HttpStatus; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.jackrabbit.webdav.client.methods.DavMethod; +import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; +import org.apache.jackrabbit.webdav.client.methods.MkColMethod; + +import com.owncloud.android.Log_OC; + +import android.net.Uri; +import android.util.Log; + +public class WebdavClient extends HttpClient { + private Uri mUri; + private Credentials mCredentials; + final private static String TAG = "WebdavClient"; + private static final String USER_AGENT = "Android-ownCloud"; + + private OnDatatransferProgressListener mDataTransferListener; + static private byte[] sExhaustBuffer = new byte[1024]; + + /** + * Constructor + */ + public WebdavClient(HttpConnectionManager connectionMgr) { + super(connectionMgr); + Log_OC.d(TAG, "Creating WebdavClient"); + getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT); + getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); + } + + public void setCredentials(String username, String password) { + getParams().setAuthenticationPreemptive(true); + getState().setCredentials(AuthScope.ANY, + getCredentials(username, password)); + } + + private Credentials getCredentials(String username, String password) { + if (mCredentials == null) + mCredentials = new UsernamePasswordCredentials(username, password); + return mCredentials; + } + + /** + * Downloads a file in remoteFilepath to the local targetPath. + * + * @param remoteFilepath Path to the file in the remote server, URL DECODED. + * @param targetFile Local path to save the downloaded file. + * @return 'True' when the file is successfully downloaded. + */ + public boolean downloadFile(String remoteFilePath, File targetFile) { + boolean ret = false; + GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath)); + + try { + int status = executeMethod(get); + if (status == HttpStatus.SC_OK) { + targetFile.createNewFile(); + BufferedInputStream bis = new BufferedInputStream( + get.getResponseBodyAsStream()); + FileOutputStream fos = new FileOutputStream(targetFile); + + byte[] bytes = new byte[4096]; + int readResult; + while ((readResult = bis.read(bytes)) != -1) { + if (mDataTransferListener != null) + mDataTransferListener.onTransferProgress(readResult); + fos.write(bytes, 0, readResult); + } + fos.close(); + ret = true; + } else { + exhaustResponse(get.getResponseBodyAsStream()); + } + Log_OC.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":"")); + } catch (Exception e) { + logException(e, "dowloading " + remoteFilePath); + + } finally { + if (!ret && targetFile.exists()) { + targetFile.delete(); + } + get.releaseConnection(); // let the connection available for other methods + } + return ret; + } + + /** + * Deletes a remote file via webdav + * @param remoteFilePath Remote file path of the file to delete, in URL DECODED format. + * @return + */ + public boolean deleteFile(String remoteFilePath) { + boolean ret = false; + DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath)); + try { + int status = executeMethod(delete); + ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT); + exhaustResponse(delete.getResponseBodyAsStream()); + + Log.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status + (!ret?"(FAIL)":"")); + + } catch (Exception e) { + logException(e, "deleting " + remoteFilePath); + + } finally { + delete.releaseConnection(); // let the connection available for other methods + } + return ret; + } + + + public void setDataTransferProgressListener(OnDatatransferProgressListener listener) { + mDataTransferListener = listener; + } + + /** + * Creates or update a file in the remote server with the contents of a local file. + * + * @param localFile Path to the local file to upload. + * @param remoteTarget Remote path to the file to create or update, URL DECODED + * @param contentType MIME type of the file. + * @return Status HTTP code returned by the server. + * @throws IOException When a transport error that could not be recovered occurred while uploading the file to the server. + * @throws HttpException When a violation of the HTTP protocol occurred. + */ + public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException { + int status = -1; + PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget)); + + try { + File f = new File(localFile); + FileRequestEntity entity = new FileRequestEntity(f, contentType); + entity.addOnDatatransferProgressListener(mDataTransferListener); + put.setRequestEntity(entity); + status = executeMethod(put); + + exhaustResponse(put.getResponseBodyAsStream()); + + } finally { + put.releaseConnection(); // let the connection available for other methods + } + return status; + } + + /** + * Tries to log in to the current URI, with the current credentials + * + * @return A {@link HttpStatus}-Code of the result. SC_OK is good. + */ + public int tryToLogin() { + int status = 0; + HeadMethod head = new HeadMethod(mUri.toString()); + try { + status = executeMethod(head); + boolean result = status == HttpStatus.SC_OK; + Log_OC.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":"")); + exhaustResponse(head.getResponseBodyAsStream()); + + } catch (Exception e) { + logException(e, "trying to login at " + mUri.toString()); + + } finally { + head.releaseConnection(); + } + return status; + } + + /** + * Creates a remote directory with the received path. + * + * @param path Path of the directory to create, URL DECODED + * @return 'True' when the directory is successfully created + */ + public boolean createDirectory(String path) { + boolean result = false; + int status = -1; + MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path)); + try { + Log_OC.d(TAG, "Creating directory " + path); + status = executeMethod(mkcol); + Log_OC.d(TAG, "Status returned: " + status); + result = mkcol.succeeded(); + + Log_OC.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":"")); + exhaustResponse(mkcol.getResponseBodyAsStream()); + + } catch (Exception e) { + logException(e, "creating directory " + path); + + } finally { + mkcol.releaseConnection(); // let the connection available for other methods + } + return result; + } + + + /** + * Check if a file exists in the OC server + * + * @return 'true' if the file exists; 'false' it doesn't exist + * @throws Exception When the existence could not be determined + */ + public boolean existsFile(String path) throws IOException, HttpException { + HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path)); + try { + int status = executeMethod(head); + Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":"")); + exhaustResponse(head.getResponseBodyAsStream()); + return (status == HttpStatus.SC_OK); + + } finally { + head.releaseConnection(); // let the connection available for other methods + } + } + + + /** + * Requests the received method with the received timeout (milliseconds). + * + * Executes the method through the inherited HttpClient.executedMethod(method). + * + * Sets the socket and connection timeouts only for the method received. + * + * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default' + * + * @param method HTTP method request. + * @param readTimeout Timeout to set for data reception + * @param conntionTimout Timeout to set for connection establishment + */ + public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException { + int oldSoTimeout = getParams().getSoTimeout(); + int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout(); + try { + if (readTimeout >= 0) { + method.getParams().setSoTimeout(readTimeout); // this should be enough... + getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS + } + if (connectionTimeout >= 0) { + getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); + } + return executeMethod(method); + } finally { + getParams().setSoTimeout(oldSoTimeout); + getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout); + } + } + + /** + * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation. + * + * @param responseBodyAsStream InputStream with the HTTP response to exhaust. + */ + public void exhaustResponse(InputStream responseBodyAsStream) { + if (responseBodyAsStream != null) { + try { + while (responseBodyAsStream.read(sExhaustBuffer) >= 0); + responseBodyAsStream.close(); + + } catch (IOException io) { + Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io); + } + } + } + + + /** + * Logs an exception triggered in a HTTP request. + * + * @param e Caught exception. + * @param doing Suffix to add at the end of the logged message. + */ + private void logException(Exception e, String doing) { + if (e instanceof HttpException) { + Log_OC.e(TAG, "HTTP violation while " + doing, e); + + } else if (e instanceof IOException) { + Log_OC.e(TAG, "Unrecovered transport exception while " + doing, e); + + } else { + Log_OC.e(TAG, "Unexpected exception while " + doing, e); + } + } + + + /** + * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client. + */ + public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { + getParams().setSoTimeout(defaultDataTimeout); + getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); + } + + /** + * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs + * @param uri + */ + public void setBaseUri(Uri uri) { + mUri = uri; + } + + public Uri getBaseUri() { + return mUri; + } + +} diff --git a/src/eu/alefzero/webdav/WebdavEntry.java b/src/eu/alefzero/webdav/WebdavEntry.java index f76ee697a7..b474e2072d 100644 --- a/src/eu/alefzero/webdav/WebdavEntry.java +++ b/src/eu/alefzero/webdav/WebdavEntry.java @@ -24,6 +24,8 @@ import org.apache.jackrabbit.webdav.property.DavProperty; import org.apache.jackrabbit.webdav.property.DavPropertyName; import org.apache.jackrabbit.webdav.property.DavPropertySet; +import com.owncloud.android.Log_OC; + import android.net.Uri; import android.util.Log; @@ -89,7 +91,7 @@ public class WebdavEntry { } } else { - Log.e("WebdavEntry", + Log_OC.e("WebdavEntry", "General fuckup, no status for webdav response"); } } From f256bdee5287ef809d70cb46a9b43c5723be644a Mon Sep 17 00:00:00 2001 From: zerginator Date: Tue, 12 Mar 2013 08:08:04 +0100 Subject: [PATCH 03/10] Log_OC included --- src/com/owncloud/android/Log_OC.java | 125 +++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/com/owncloud/android/Log_OC.java diff --git a/src/com/owncloud/android/Log_OC.java b/src/com/owncloud/android/Log_OC.java new file mode 100644 index 0000000000..f65ed1736c --- /dev/null +++ b/src/com/owncloud/android/Log_OC.java @@ -0,0 +1,125 @@ +package com.owncloud.android; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import android.util.Log; + + +public class Log_OC { + + private static boolean isEnabled = false; + private static File logFile; + private static File folder; + private static BufferedWriter buf; + + public static void i(String TAG, String message){ + // Printing the message to LogCat console + Log.i(TAG, message); + // Write the log message to the file + appendLog(TAG+" : "+message); + } + + public static void d(String TAG, String message){ + Log.d(TAG, message); + appendLog(TAG+" : "+message); + } + public static void d(String TAG, String message, Exception e) { + Log.d(TAG, message, e); + appendLog(TAG+" : "+ message+" Exception : "+e.getStackTrace()); + } + public static void e(String TAG, String message){ + Log.e(TAG, message); + appendLog(TAG+" : "+message); + } + + public static void e(String TAG, String message, Throwable e) { + Log.e(TAG, message, e); + appendLog(TAG+" : "+ message+" Exception : "+e.getStackTrace()); + } + + public static void v(String TAG, String message){ + Log.v(TAG, message); + appendLog(TAG+" : "+message); + } + + public static void w(String TAG, String message) { + Log.w(TAG,message); + appendLog(TAG+" : "+message); + } + + public static void wtf(String TAG, String message) { + Log.wtf(TAG,message); + appendLog(TAG+" : "+message); + } + + public static void startLogging(String logPath) { + + folder = new File(logPath+File.separator+"log"); + logFile = new File(folder+File.separator+"log.txt"); + + if (!folder.exists()) { + folder.mkdirs(); + } + if (logFile.exists()) { + logFile.delete(); + } + try { + logFile.createNewFile(); + buf = new BufferedWriter(new FileWriter(logFile, true)); + isEnabled = true; + appendPhoneInfo(); + }catch (IOException e){ + e.printStackTrace(); + } + } + + public static void stopLogging() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.getDefault()); + String currentDateandTime = sdf.format(new Date()); + if (logFile != null) { + logFile.renameTo(new File(folder+File.separator+"log_"+currentDateandTime)); + isEnabled = false; + try { + buf.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + } + + private static void appendPhoneInfo() { + appendLog("Model : " + android.os.Build.MODEL); + appendLog("Brand : " + android.os.Build.BRAND); + appendLog("Product : " + android.os.Build.PRODUCT); + appendLog("Device : " + android.os.Build.DEVICE); + appendLog("Version-Codename : " + android.os.Build.VERSION.CODENAME); + appendLog("Version-Release : " + android.os.Build.VERSION.RELEASE); + } + + private static void appendLog(String text) { + if (isEnabled) { + try { + buf.append(text); + buf.newLine(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} + + + + + + + + +} From 8e7b972936edd8b538ca87014ce79a49071261d3 Mon Sep 17 00:00:00 2001 From: Thorsten Date: Wed, 13 Mar 2013 00:08:50 +0100 Subject: [PATCH 04/10] dfsf dsfdsfsf --- dsfsd | 1 + 1 file changed, 1 insertion(+) create mode 100644 dsfsd diff --git a/dsfsd b/dsfsd new file mode 100644 index 0000000000..60e011adfb --- /dev/null +++ b/dsfsd @@ -0,0 +1 @@ +git push android syncImprovement From 2371b8579473a1f24b51aad0690119f4f1979f89 Mon Sep 17 00:00:00 2001 From: zerginator Date: Wed, 13 Mar 2013 08:39:04 +0100 Subject: [PATCH 05/10] Deleted unused file --- dsfsd | 1 - 1 file changed, 1 deletion(-) delete mode 100644 dsfsd diff --git a/dsfsd b/dsfsd deleted file mode 100644 index 60e011adfb..0000000000 --- a/dsfsd +++ /dev/null @@ -1 +0,0 @@ -git push android syncImprovement From 5a22c7e79f1a53ccdbae04327e6ac500f3676a67 Mon Sep 17 00:00:00 2001 From: zerginator Date: Sun, 31 Mar 2013 22:43:46 +0200 Subject: [PATCH 06/10] Cleaned stuff , add a history delete button and renamed Log2EmailActivity in LogHistoryActivity --- AndroidManifest.xml | 333 +++++++++--------- res/layout/log_item.xml | 19 + res/layout/log_send_file.xml | 34 ++ res/values/strings.xml | 8 +- res/xml/preferences.xml | 14 +- src/com/owncloud/android/Log_OC.java | 12 +- src/com/owncloud/android/db/DbHandler.java | 2 +- .../ui/activity/LogHistoryActivity.java | 119 +++++++ .../android/ui/activity/Preferences.java | 19 +- .../android/ui/adapter/LogListAdapter.java | 54 +++ 10 files changed, 434 insertions(+), 180 deletions(-) create mode 100644 res/layout/log_item.xml create mode 100644 res/layout/log_send_file.xml create mode 100644 src/com/owncloud/android/ui/activity/LogHistoryActivity.java create mode 100644 src/com/owncloud/android/ui/adapter/LogListAdapter.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 14be678ed4..a6f4b5bc24 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,166 +1,167 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/log_item.xml b/res/layout/log_item.xml new file mode 100644 index 0000000000..d9326ffaba --- /dev/null +++ b/res/layout/log_item.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/log_send_file.xml b/res/layout/log_send_file.xml new file mode 100644 index 0000000000..ddeac6929b --- /dev/null +++ b/res/layout/log_send_file.xml @@ -0,0 +1,34 @@ + + + + + + + + + +