<string name="prefs_pincode_summary">Protect your client</string>
<string name="prefs_instant_upload">Enable instant uploads</string>
<string name="prefs_instant_upload_summary">Instantly upload photos taken by camera</string>
+ <string name="prefs_log_title">Enable Logging</string>
+ <string name="prefs_log_summary">This is used to log problems</string>
<string name="auth_host_url">URL</string>
<string name="auth_username">Username</string>
<string name="auth_password">Password</string>
android:title="@string/prefs_instant_upload"
android:summary="@string/prefs_instant_upload_summary"/>
<CheckBoxPreference android:dependency="instant_uploading" android:disableDependentsState="true" android:title="@string/instant_upload_on_wifi" android:key="instant_upload_on_wifi"/>
- <Preference android:id="@+id/about_app" android:title="@string/about_title" android:key="about_app" />
+ <Preference android:id="@+id/about_app"
+ android:title="@string/about_title"
+ android:key="about_app" />
+ <CheckBoxPreference android:key="log_to_file"
+ android:title="@string/prefs_log_title"
+ android:summary="@string/prefs_log_summary"/>
</PreferenceCategory>
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package com.owncloud.android;\r
-\r
-import java.io.File;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Stack;\r
-import java.util.Vector;\r
-\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
-import com.owncloud.android.datamodel.DataStorageManager;\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.files.services.FileUploader;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.AlertDialog.Builder;\r
-import android.app.Dialog;\r
-import android.app.ListActivity;\r
-import android.app.ProgressDialog;\r
-import android.content.Context;\r
-import android.content.DialogInterface;\r
-import android.content.DialogInterface.OnCancelListener;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.content.Intent;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Parcelable;\r
-import android.provider.MediaStore.Images.Media;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.Window;\r
-import android.widget.AdapterView;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.SimpleAdapter;\r
-import android.widget.Toast;\r
-\r
-import com.owncloud.android.R;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * This can be used to upload things to an ownCloud instance.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
- private static final String TAG = "ownCloudUploader";\r
-\r
- private Account mAccount;\r
- private AccountManager mAccountManager;\r
- private Stack<String> mParents;\r
- private ArrayList<Parcelable> mStreamsToUpload;\r
- private boolean mCreateDir;\r
- private String mUploadPath;\r
- private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };\r
- private DataStorageManager mStorageManager;\r
- private OCFile mFile;\r
-\r
- private final static int DIALOG_NO_ACCOUNT = 0;\r
- private final static int DIALOG_WAITING = 1;\r
- private final static int DIALOG_NO_STREAM = 2;\r
- private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
- //private final static int DIALOG_GET_DIRNAME = 4;\r
-\r
- private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
- mParents = new Stack<String>();\r
- mParents.add("");\r
- /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
- prepareStreamsToUpload();*/\r
- if (prepareStreamsToUpload()) {\r
- mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);\r
- Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
- if (accounts.length == 0) {\r
- Log.i(TAG, "No ownCloud account is available");\r
- showDialog(DIALOG_NO_ACCOUNT);\r
- } else if (accounts.length > 1) {\r
- Log.i(TAG, "More then one ownCloud is available");\r
- showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
- } else {\r
- mAccount = accounts[0];\r
- mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
- populateDirectoryList();\r
- }\r
- } else {\r
- showDialog(DIALOG_NO_STREAM);\r
- }\r
- }\r
- \r
- @Override\r
- protected Dialog onCreateDialog(final int id) {\r
- final AlertDialog.Builder builder = new Builder(this);\r
- switch (id) {\r
- case DIALOG_WAITING:\r
- ProgressDialog pDialog = new ProgressDialog(this);\r
- pDialog.setIndeterminate(false);\r
- pDialog.setCancelable(false);\r
- pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
- return pDialog;\r
- case DIALOG_NO_ACCOUNT:\r
- builder.setIcon(android.R.drawable.ic_dialog_alert);\r
- builder.setTitle(R.string.uploader_wrn_no_account_title);\r
- builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
- // using string value since in API7 this\r
- // constatn is not defined\r
- // in API7 < this constatant is defined in\r
- // Settings.ADD_ACCOUNT_SETTINGS\r
- // and Settings.EXTRA_AUTHORITIES\r
- Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
- intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
- startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
- } else {\r
- // since in API7 there is no direct call for\r
- // account setup, so we need to\r
- // show our own AccountSetupAcricity, get\r
- // desired results and setup\r
- // everything for ourself\r
- Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
- startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
- }\r
- }\r
- });\r
- builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- /*case DIALOG_GET_DIRNAME:\r
- final EditText dirName = new EditText(getBaseContext());\r
- builder.setView(dirName);\r
- builder.setTitle(R.string.uploader_info_dirname);\r
- String pathToUpload;\r
- if (mParents.empty()) {\r
- pathToUpload = "/";\r
- } else {\r
- mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,\r
- null, null, null);\r
- mCursor.moveToFirst();\r
- pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))\r
- + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); // TODO don't make this ; use WebdavUtils.encode in the right moment\r
- }\r
- a a = new a(pathToUpload, dirName);\r
- builder.setPositiveButton(R.string.common_ok, a);\r
- builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- dialog.cancel();\r
- }\r
- });\r
- return builder.create();*/\r
- case DIALOG_MULTIPLE_ACCOUNT:\r
- CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
- for (int i = 0; i < ac.length; ++i) {\r
- ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
- }\r
- builder.setTitle(R.string.common_choose_account);\r
- builder.setItems(ac, new OnClickListener() {\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
- mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
- populateDirectoryList();\r
- }\r
- });\r
- builder.setCancelable(true);\r
- builder.setOnCancelListener(new OnCancelListener() {\r
- @Override\r
- public void onCancel(DialogInterface dialog) {\r
- dialog.cancel();\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- case DIALOG_NO_STREAM:\r
- builder.setIcon(android.R.drawable.ic_dialog_alert);\r
- builder.setTitle(R.string.uploader_wrn_no_content_title);\r
- builder.setMessage(R.string.uploader_wrn_no_content_text);\r
- builder.setCancelable(false);\r
- builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- default:\r
- throw new IllegalArgumentException("Unknown dialog id: " + id);\r
- }\r
- }\r
-\r
- class a implements OnClickListener {\r
- String mPath;\r
- EditText mDirname;\r
-\r
- public a(String path, EditText dirname) {\r
- mPath = path; \r
- mDirname = dirname;\r
- }\r
-\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- Uploader.this.mUploadPath = mPath + mDirname.getText().toString();\r
- Uploader.this.mCreateDir = true;\r
- uploadFiles();\r
- }\r
- }\r
-\r
- @Override\r
- public void onBackPressed() {\r
-\r
- if (mParents.size() <= 1) {\r
- super.onBackPressed();\r
- return;\r
- } else {\r
- mParents.pop();\r
- populateDirectoryList();\r
- }\r
- }\r
-\r
- @Override\r
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
- // click on folder in the list\r
- Log.d(TAG, "on item click");\r
- Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);\r
- if (tmpfiles.size() <= 0) return;\r
- // filter on dirtype\r
- Vector<OCFile> files = new Vector<OCFile>();\r
- for (OCFile f : tmpfiles)\r
- if (f.isDirectory())\r
- files.add(f);\r
- if (files.size() < position) {\r
- throw new IndexOutOfBoundsException("Incorrect item selected");\r
- }\r
- mParents.push(files.get(position).getFileName());\r
- populateDirectoryList();\r
- }\r
-\r
- @Override\r
- public void onClick(View v) {\r
- // click on button\r
- switch (v.getId()) {\r
- case R.id.uploader_choose_folder:\r
- mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix\r
- for (String p : mParents)\r
- mUploadPath += p + OCFile.PATH_SEPARATOR;\r
- Log.d(TAG, "Uploading file to dir " + mUploadPath);\r
-\r
- uploadFiles();\r
-\r
- break;\r
- /*case android.R.id.button1: // dynamic action for create aditional dir\r
- showDialog(DIALOG_GET_DIRNAME);\r
- break;*/\r
- default:\r
- throw new IllegalArgumentException("Wrong element clicked");\r
- }\r
- }\r
-\r
- @Override\r
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
- super.onActivityResult(requestCode, resultCode, data);\r
- Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
- if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
- dismissDialog(DIALOG_NO_ACCOUNT);\r
- if (resultCode == RESULT_CANCELED) {\r
- finish();\r
- }\r
- Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
- if (accounts.length == 0) {\r
- showDialog(DIALOG_NO_ACCOUNT);\r
- } else {\r
- // there is no need for checking for is there more then one\r
- // account at this point\r
- // since account setup can set only one account at time\r
- mAccount = accounts[0];\r
- populateDirectoryList();\r
- }\r
- }\r
- }\r
-\r
- private void populateDirectoryList() {\r
- setContentView(R.layout.uploader_layout);\r
-\r
- String full_path = "";\r
- for (String a : mParents)\r
- full_path += a + "/";\r
- \r
- Log.d(TAG, "Populating view with content of : " + full_path);\r
- \r
- mFile = mStorageManager.getFileByPath(full_path);\r
- if (mFile != null) {\r
- Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);\r
- List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();\r
- for (OCFile f : files) {\r
- HashMap<String, Object> h = new HashMap<String, Object>();\r
- if (f.isDirectory()) {\r
- h.put("dirname", f.getFileName());\r
- data.add(h);\r
- }\r
- }\r
- SimpleAdapter sa = new SimpleAdapter(this,\r
- data,\r
- R.layout.uploader_list_item_layout,\r
- new String[] {"dirname"},\r
- new int[] {R.id.textView1});\r
- setListAdapter(sa);\r
- Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
- btn.setOnClickListener(this);\r
- getListView().setOnItemClickListener(this);\r
- }\r
- }\r
-\r
- private boolean prepareStreamsToUpload() {\r
- if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
- mStreamsToUpload = new ArrayList<Parcelable>();\r
- mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
- } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
- mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
- }\r
- return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);\r
- }\r
-\r
- public void uploadFiles() {\r
- try {\r
- WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
-\r
- // create last directory in path if necessary\r
- if (mCreateDir) {\r
- wdc.createDirectory(mUploadPath);\r
- }\r
-\r
- String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
-\r
- for (int i = 0; i < mStreamsToUpload.size(); ++i) {\r
- Uri uri = (Uri) mStreamsToUpload.get(i);\r
- if (uri.getScheme().equals("content")) {\r
- Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),\r
- CONTENT_PROJECTION,\r
- null,\r
- null,\r
- null);\r
-\r
- if (!c.moveToFirst())\r
- continue;\r
-\r
- final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
- data = c.getString(c.getColumnIndex(Media.DATA));\r
- local[i] = data;\r
- remote[i] = mUploadPath + display_name;\r
- } else if (uri.getScheme().equals("file")) {\r
- final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));\r
- local[i] = file.getAbsolutePath();\r
- remote[i] = mUploadPath + file.getName();\r
- }\r
-\r
- }\r
- Intent intent = new Intent(getApplicationContext(), FileUploader.class);\r
- intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
- intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);\r
- intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);\r
- intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);\r
- startService(intent);\r
- finish();\r
- \r
- } catch (SecurityException e) {\r
- String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));\r
- Toast.makeText(this, message, Toast.LENGTH_LONG).show(); \r
- }\r
- }\r
-\r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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<String> mParents;
+ private ArrayList<Parcelable> 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<String>();
+ 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<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);
+ if (tmpfiles.size() <= 0) return;
+ // filter on dirtype
+ Vector<OCFile> files = new Vector<OCFile>();
+ 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<OCFile> files = mStorageManager.getDirectoryContent(mFile);
+ List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
+ for (OCFile f : files) {
+ HashMap<String, Object> h = new HashMap<String, Object>();
+ 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<Parcelable>();
+ 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\r
- * Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.authenticator;\r
-\r
-import com.owncloud.android.ui.activity.AuthenticatorActivity;\r
-\r
-import android.accounts.*;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-\r
-public class AccountAuthenticator extends AbstractAccountAuthenticator {\r
- /**\r
- * Is used by android system to assign accounts to authenticators. Should be\r
- * used by application and all extensions.\r
- */\r
- public static final String ACCOUNT_TYPE = "owncloud";\r
- public static final String AUTH_TOKEN_TYPE = "org.owncloud";\r
-\r
- public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";\r
- public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";\r
- public static final String KEY_LOGIN_OPTIONS = "loginOptions";\r
- public static final String KEY_ACCOUNT = "account";\r
- /**\r
- * Value under this key should handle path to webdav php script. Will be\r
- * removed and usage should be replaced by combining\r
- * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and\r
- * {@link com.owncloud.android.utils.OwnCloudVersion}\r
- * \r
- * @deprecated\r
- */\r
- public static final String KEY_OC_URL = "oc_url";\r
- /**\r
- * Version should be 3 numbers separated by dot so it can be parsed by\r
- * {@link com.owncloud.android.utils.OwnCloudVersion}\r
- */\r
- public static final String KEY_OC_VERSION = "oc_version";\r
- /**\r
- * Base url should point to owncloud installation without trailing / ie:\r
- * http://server/path or https://owncloud.server\r
- */\r
- public static final String KEY_OC_BASE_URL = "oc_base_url";\r
-\r
- private static final String TAG = "AccountAuthenticator";\r
- private Context mContext;\r
-\r
- public AccountAuthenticator(Context context) {\r
- super(context);\r
- mContext = context;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public Bundle addAccount(AccountAuthenticatorResponse response,\r
- String accountType, String authTokenType,\r
- String[] requiredFeatures, Bundle options)\r
- throws NetworkErrorException {\r
- Log.i(TAG, "Adding account with type " + accountType\r
- + " and auth token " + authTokenType);\r
- try {\r
- validateAccountType(accountType);\r
- } catch (AuthenticatorException e) {\r
- Log.e(TAG, "Failed to validate account type " + accountType + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
- intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
- setIntentFlags(intent);\r
- final Bundle bundle = new Bundle();\r
- bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return bundle;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
- Account account, Bundle options) throws NetworkErrorException {\r
- try {\r
- validateAccountType(account.type);\r
- } catch (AuthenticatorException e) {\r
- Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_ACCOUNT, account);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
- setIntentFlags(intent);\r
-\r
- Bundle resultBundle = new Bundle();\r
- resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return resultBundle;\r
- }\r
-\r
- @Override\r
- public Bundle editProperties(AccountAuthenticatorResponse response,\r
- String accountType) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public Bundle getAuthToken(AccountAuthenticatorResponse response,\r
- Account account, String authTokenType, Bundle options)\r
- throws NetworkErrorException {\r
- try {\r
- validateAccountType(account.type);\r
- validateAuthTokenType(authTokenType);\r
- } catch (AuthenticatorException e) {\r
- Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- final AccountManager am = AccountManager.get(mContext);\r
- final String password = am.getPassword(account);\r
- if (password != null) {\r
- final Bundle result = new Bundle();\r
- result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
- result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);\r
- result.putString(AccountManager.KEY_AUTHTOKEN, password);\r
- return result;\r
- }\r
-\r
- final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
- intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);\r
-\r
- final Bundle bundle = new Bundle();\r
- bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return bundle;\r
- }\r
-\r
- @Override\r
- public String getAuthTokenLabel(String authTokenType) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public Bundle hasFeatures(AccountAuthenticatorResponse response,\r
- Account account, String[] features) throws NetworkErrorException {\r
- final Bundle result = new Bundle();\r
- result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);\r
- return result;\r
- }\r
-\r
- @Override\r
- public Bundle updateCredentials(AccountAuthenticatorResponse response,\r
- Account account, String authTokenType, Bundle options)\r
- throws NetworkErrorException {\r
- final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_ACCOUNT, account);\r
- intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
- setIntentFlags(intent);\r
-\r
- final Bundle bundle = new Bundle();\r
- bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return bundle;\r
- }\r
-\r
- @Override\r
- public Bundle getAccountRemovalAllowed(\r
- AccountAuthenticatorResponse response, Account account)\r
- throws NetworkErrorException {\r
- return super.getAccountRemovalAllowed(response, account);\r
- }\r
-\r
- private void setIntentFlags(Intent intent) {\r
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
- intent.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
- }\r
-\r
- private void validateAccountType(String type)\r
- throws UnsupportedAccountTypeException {\r
- if (!type.equals(ACCOUNT_TYPE)) {\r
- throw new UnsupportedAccountTypeException();\r
- }\r
- }\r
-\r
- private void validateAuthTokenType(String authTokenType)\r
- throws UnsupportedAuthTokenTypeException {\r
- if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {\r
- throw new UnsupportedAuthTokenTypeException();\r
- }\r
- }\r
-\r
- public static class AuthenticatorException extends Exception {\r
- private static final long serialVersionUID = 1L;\r
- private Bundle mFailureBundle;\r
-\r
- public AuthenticatorException(int code, String errorMsg) {\r
- mFailureBundle = new Bundle();\r
- mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
- mFailureBundle\r
- .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
- }\r
-\r
- public Bundle getFailureBundle() {\r
- return mFailureBundle;\r
- }\r
- }\r
-\r
- public static class UnsupportedAccountTypeException extends\r
- AuthenticatorException {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedAccountTypeException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported account type");\r
- }\r
- }\r
-\r
- public static class UnsupportedAuthTokenTypeException extends\r
- AuthenticatorException {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedAuthTokenTypeException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported auth token type");\r
- }\r
- }\r
-\r
- public static class UnsupportedFeaturesException extends\r
- AuthenticatorException {\r
- public static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedFeaturesException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported features");\r
- }\r
- }\r
-\r
- public static class AccessDeniedException extends AuthenticatorException {\r
- public AccessDeniedException(int code, String errorMsg) {\r
- super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
- }\r
-\r
- private static final long serialVersionUID = 1L;\r
-\r
- }\r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+
+ }
+}
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;
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());
}
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());
}
}
} 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
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());
}
}
}
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 {
+ 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;
+ "=?", 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;
}
}
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,
}
} 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);
}
}
import java.io.File;
+import com.owncloud.android.Log_OC;
+
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
* 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;
if (isDirectory()) {
mRemotePath += PATH_SEPARATOR;
}
- Log.d(TAG, "OCFile name changed to " + mRemotePath);
+ Log_OC.d(TAG, "OCFile name changed to " + mRemotePath);
}
}
*/
package com.owncloud.android.db;
+import com.owncloud.android.Log_OC;
+
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
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;
}
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;
}
*/
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;
}
package com.owncloud.android.extensions;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
import android.content.Intent;
import android.os.Bundle;
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());
}
}
import org.json.JSONException;
import org.json.JSONObject;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.utils.OwnCloudVersion;
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) {
package com.owncloud.android.files;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.files.services.FileObserverService;
import android.content.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");
}
}
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;
@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)) {
} 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());
}
}
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();
}
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;
}
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);
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;
}
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";
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());
}
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;
@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;
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.files.services;\r
-\r
-import java.io.File;\r
-import java.util.AbstractList;\r
-import java.util.Iterator;\r
-import java.util.Vector;\r
-import java.util.concurrent.ConcurrentHashMap;\r
-import java.util.concurrent.ConcurrentMap;\r
-\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import eu.alefzero.webdav.OnDatatransferProgressListener;\r
-\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-import com.owncloud.android.operations.DownloadFileOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-import com.owncloud.android.ui.activity.FileDetailActivity;\r
-import com.owncloud.android.ui.fragment.FileDetailFragment;\r
-\r
-import android.accounts.Account;\r
-import android.app.Notification;\r
-import android.app.NotificationManager;\r
-import android.app.PendingIntent;\r
-import android.app.Service;\r
-import android.content.Intent;\r
-import android.os.Binder;\r
-import android.os.Handler;\r
-import android.os.HandlerThread;\r
-import android.os.IBinder;\r
-import android.os.Looper;\r
-import android.os.Message;\r
-import android.os.Process;\r
-import android.util.Log;\r
-import android.widget.RemoteViews;\r
-\r
-import com.owncloud.android.R;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-public class FileDownloader extends Service implements OnDatatransferProgressListener {\r
- \r
- public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
- public static final String EXTRA_FILE = "FILE";\r
- \r
- public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";\r
- public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";\r
- public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; \r
- public static final String EXTRA_FILE_PATH = "FILE_PATH";\r
- public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";\r
- public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
- \r
- private static final String TAG = "FileDownloader";\r
-\r
- private Looper mServiceLooper;\r
- private ServiceHandler mServiceHandler;\r
- private IBinder mBinder;\r
- private WebdavClient mDownloadClient = null;\r
- private Account mLastAccount = null;\r
- private FileDataStorageManager mStorageManager;\r
- \r
- private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();\r
- private DownloadFileOperation mCurrentDownload = null;\r
- \r
- private NotificationManager mNotificationManager;\r
- private Notification mNotification;\r
- private int mLastPercent;\r
- \r
- \r
- /**\r
- * Builds a key for mPendingDownloads from the account and file to download\r
- * \r
- * @param account Account where the file to download is stored\r
- * @param file File to download\r
- */\r
- private String buildRemoteName(Account account, OCFile file) {\r
- return account.name + file.getRemotePath();\r
- }\r
-\r
- \r
- /**\r
- * Service initialization\r
- */\r
- @Override\r
- public void onCreate() {\r
- super.onCreate();\r
- mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);\r
- HandlerThread thread = new HandlerThread("FileDownloaderThread",\r
- Process.THREAD_PRIORITY_BACKGROUND);\r
- thread.start();\r
- mServiceLooper = thread.getLooper();\r
- mServiceHandler = new ServiceHandler(mServiceLooper, this);\r
- mBinder = new FileDownloaderBinder();\r
- }\r
-\r
- \r
- /**\r
- * Entry point to add one or several files to the queue of downloads.\r
- * \r
- * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working \r
- * although the caller activity goes away.\r
- */\r
- @Override\r
- public int onStartCommand(Intent intent, int flags, int startId) {\r
- if ( !intent.hasExtra(EXTRA_ACCOUNT) ||\r
- !intent.hasExtra(EXTRA_FILE)\r
- /*!intent.hasExtra(EXTRA_FILE_PATH) ||\r
- !intent.hasExtra(EXTRA_REMOTE_PATH)*/\r
- ) {\r
- Log.e(TAG, "Not enough information provided in intent");\r
- return START_NOT_STICKY;\r
- }\r
- Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);\r
- OCFile file = intent.getParcelableExtra(EXTRA_FILE);\r
- \r
- AbstractList<String> requestedDownloads = new Vector<String>(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection)\r
- String downloadKey = buildRemoteName(account, file);\r
- try {\r
- DownloadFileOperation newDownload = new DownloadFileOperation(account, file); \r
- mPendingDownloads.putIfAbsent(downloadKey, newDownload);\r
- newDownload.addDatatransferProgressListener(this);\r
- requestedDownloads.add(downloadKey);\r
- sendBroadcastNewDownload(newDownload);\r
- \r
- } catch (IllegalArgumentException e) {\r
- Log.e(TAG, "Not enough information provided in intent: " + e.getMessage());\r
- return START_NOT_STICKY;\r
- }\r
- \r
- if (requestedDownloads.size() > 0) {\r
- Message msg = mServiceHandler.obtainMessage();\r
- msg.arg1 = startId;\r
- msg.obj = requestedDownloads;\r
- mServiceHandler.sendMessage(msg);\r
- }\r
-\r
- return START_NOT_STICKY;\r
- }\r
- \r
- \r
- /**\r
- * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. \r
- * \r
- * Implemented to perform cancellation, pause and resume of existing downloads.\r
- */\r
- @Override\r
- public IBinder onBind(Intent arg0) {\r
- return mBinder;\r
- }\r
-\r
- \r
- /**\r
- * Binder to let client components to perform operations on the queue of downloads.\r
- * \r
- * It provides by itself the available operations.\r
- */\r
- public class FileDownloaderBinder extends Binder {\r
- \r
- /**\r
- * Cancels a pending or current download of a remote file.\r
- * \r
- * @param account Owncloud account where the remote file is stored.\r
- * @param file A file in the queue of pending downloads\r
- */\r
- public void cancel(Account account, OCFile file) {\r
- DownloadFileOperation download = null;\r
- synchronized (mPendingDownloads) {\r
- download = mPendingDownloads.remove(buildRemoteName(account, file));\r
- }\r
- if (download != null) {\r
- download.cancel();\r
- }\r
- }\r
- \r
- \r
- /**\r
- * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.\r
- * \r
- * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. \r
- * \r
- * @param account Owncloud account where the remote file is stored.\r
- * @param file A file that could be in the queue of downloads.\r
- */\r
- public boolean isDownloading(Account account, OCFile file) {\r
- if (account == null || file == null) return false;\r
- String targetKey = buildRemoteName(account, file);\r
- synchronized (mPendingDownloads) {\r
- if (file.isDirectory()) {\r
- // this can be slow if there are many downloads :(\r
- Iterator<String> it = mPendingDownloads.keySet().iterator();\r
- boolean found = false;\r
- while (it.hasNext() && !found) {\r
- found = it.next().startsWith(targetKey);\r
- }\r
- return found;\r
- } else {\r
- return (mPendingDownloads.containsKey(targetKey));\r
- }\r
- }\r
- }\r
- }\r
- \r
- \r
- /** \r
- * Download worker. Performs the pending downloads in the order they were requested. \r
- * \r
- * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. \r
- */\r
- private static class ServiceHandler extends Handler {\r
- // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak\r
- FileDownloader mService;\r
- public ServiceHandler(Looper looper, FileDownloader service) {\r
- super(looper);\r
- if (service == null)\r
- throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");\r
- mService = service;\r
- }\r
-\r
- @Override\r
- public void handleMessage(Message msg) {\r
- @SuppressWarnings("unchecked")\r
- AbstractList<String> requestedDownloads = (AbstractList<String>) msg.obj;\r
- if (msg.obj != null) {\r
- Iterator<String> it = requestedDownloads.iterator();\r
- while (it.hasNext()) {\r
- mService.downloadFile(it.next());\r
- }\r
- }\r
- mService.stopSelf(msg.arg1);\r
- }\r
- }\r
- \r
- \r
-\r
- /**\r
- * Core download method: requests a file to download and stores it.\r
- * \r
- * @param downloadKey Key to access the download to perform, contained in mPendingDownloads \r
- */\r
- private void downloadFile(String downloadKey) {\r
- \r
- synchronized(mPendingDownloads) {\r
- mCurrentDownload = mPendingDownloads.get(downloadKey);\r
- }\r
- \r
- if (mCurrentDownload != null) {\r
- \r
- notifyDownloadStart(mCurrentDownload);\r
-\r
- /// prepare client object to send the request to the ownCloud server\r
- if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {\r
- mLastAccount = mCurrentDownload.getAccount();\r
- mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());\r
- mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());\r
- }\r
-\r
- /// perform the download\r
- RemoteOperationResult downloadResult = null;\r
- try {\r
- downloadResult = mCurrentDownload.execute(mDownloadClient);\r
- if (downloadResult.isSuccess()) {\r
- saveDownloadedFile();\r
- }\r
- \r
- } finally {\r
- synchronized(mPendingDownloads) {\r
- mPendingDownloads.remove(downloadKey);\r
- }\r
- }\r
-\r
- \r
- /// notify result\r
- notifyDownloadResult(mCurrentDownload, downloadResult);\r
- \r
- sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Updates the OC File after a successful download.\r
- */\r
- private void saveDownloadedFile() {\r
- OCFile file = mCurrentDownload.getFile();\r
- long syncDate = System.currentTimeMillis();\r
- file.setLastSyncDateForProperties(syncDate);\r
- file.setLastSyncDateForData(syncDate);\r
- file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());\r
- file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());\r
- // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where available\r
- file.setMimetype(mCurrentDownload.getMimeType());\r
- file.setStoragePath(mCurrentDownload.getSavePath());\r
- file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));\r
- mStorageManager.saveFile(file);\r
- }\r
-\r
-\r
- /**\r
- * Creates a status notification to show the download progress\r
- * \r
- * @param download Download operation starting.\r
- */\r
- private void notifyDownloadStart(DownloadFileOperation download) {\r
- /// create status notification with a progress bar\r
- mLastPercent = 0;\r
- mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());\r
- mNotification.flags |= Notification.FLAG_ONGOING_EVENT;\r
- mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);\r
- mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0);\r
- mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()));\r
- mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);\r
- \r
- /// includes a pending intent in the notification showing the details view of the file\r
- Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
- showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());\r
- showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());\r
- showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
- mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);\r
- \r
- mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
- }\r
-\r
- \r
- /**\r
- * Callback method to update the progress bar in the status notification.\r
- */\r
- @Override\r
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {\r
- int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));\r
- if (percent != mLastPercent) {\r
- mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0);\r
- String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);\r
- mNotification.contentView.setTextViewText(R.id.status_text, text);\r
- mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
- }\r
- mLastPercent = percent;\r
- }\r
- \r
- \r
- /**\r
- * Callback method to update the progress bar in the status notification (old version)\r
- */\r
- @Override\r
- public void onTransferProgress(long progressRate) {\r
- // NOTHING TO DO HERE ANYMORE\r
- }\r
- \r
-\r
- /**\r
- * Updates the status notification with the result of a download operation.\r
- * \r
- * @param downloadResult Result of the download operation.\r
- * @param download Finished download operation\r
- */\r
- private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
- mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);\r
- if (!downloadResult.isCancelled()) {\r
- int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;\r
- int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;\r
- Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());\r
- finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;\r
- // TODO put something smart in the contentIntent below\r
- finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
- finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);\r
- mNotificationManager.notify(tickerId, finalNotification);\r
- }\r
- }\r
- \r
- \r
- /**\r
- * Sends a broadcast when a download finishes in order to the interested activities can update their view\r
- * \r
- * @param download Finished download operation\r
- * @param downloadResult Result of the download operation\r
- */\r
- private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
- Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);\r
- end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());\r
- end.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
- end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());\r
- end.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
- sendStickyBroadcast(end);\r
- }\r
- \r
- \r
- /**\r
- * Sends a broadcast when a new download is added to the queue.\r
- * \r
- * @param download Added download operation\r
- */\r
- private void sendBroadcastNewDownload(DownloadFileOperation download) {\r
- Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);\r
- /*added.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
- added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());*/\r
- added.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
- sendStickyBroadcast(added);\r
- }\r
-\r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();
+ 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<String> requestedDownloads = new Vector<String>(); // 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<String> 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<String> requestedDownloads = (AbstractList<String>) msg.obj;
+ if (msg.obj != null) {
+ Iterator<String> 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);
+ }
+
+}
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;
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");
}
}
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;
}
(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;
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());
*/
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();
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
}
*/
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();
if (observer != null) {
observer.stopWatching();
mObserversMap.remove(observer);
- Log.d(TAG, "Stopped watching " + localPath);
+ Log_OC.d(TAG, "Stopped watching " + localPath);
}
}
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);
}
}
}
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;
@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();
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);
}
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;
}
}
} 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;
}
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;
}
} 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.");
}
}
}
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 {
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) {
* @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);
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;
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;
}
// 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;
*/
package com.owncloud.android.location;
+import com.owncloud.android.Log_OC;
+
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.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);
}
}
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
// 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;
}
@Override
public void onLocationChanged(Location location) {
- Log.d(TAG, "Location changed: " + location);
+ Log_OC.d(TAG, "Location changed: " + location);
}
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
+import com.owncloud.android.Log_OC;
+
import android.util.Log;
/**
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);
*/
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;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+import com.owncloud.android.Log_OC;
+
import android.util.Log;
/**
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;
}
}
import org.apache.http.conn.ssl.X509HostnameVerifier;
import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
import eu.alefzero.webdav.WebdavClient;
* @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);
* @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);
* @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());
//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 {
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;
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;
}
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;
}
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;
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);
}
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;
.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) {
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;
import android.util.Log;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.DataStorageManager;
import com.owncloud.android.datamodel.OCFile;
}
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)
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;
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)
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());
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;
}
- 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)
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;
// 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));
} 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
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 {
} 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)
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);
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);
}
}
}
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;
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);
}
}
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)
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;
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);
}
}
}
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) {
} 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());
}
}
}
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.providers;\r
-\r
-import java.util.HashMap;\r
-\r
-import com.owncloud.android.db.ProviderMeta;\r
-import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
-\r
-\r
-import android.content.ContentProvider;\r
-import android.content.ContentUris;\r
-import android.content.ContentValues;\r
-import android.content.Context;\r
-import android.content.UriMatcher;\r
-import android.database.Cursor;\r
-import android.database.SQLException;\r
-import android.database.sqlite.SQLiteDatabase;\r
-import android.database.sqlite.SQLiteOpenHelper;\r
-import android.database.sqlite.SQLiteQueryBuilder;\r
-import android.net.Uri;\r
-import android.text.TextUtils;\r
-import android.util.Log;\r
-\r
-/**\r
- * The ContentProvider for the ownCloud App.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileContentProvider extends ContentProvider {\r
-\r
- private DataBaseHelper mDbHelper;\r
-\r
- private static HashMap<String, String> mProjectionMap;\r
- static {\r
- mProjectionMap = new HashMap<String, String>();\r
- mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);\r
- mProjectionMap.put(ProviderTableMeta.FILE_PARENT,\r
- ProviderTableMeta.FILE_PARENT);\r
- mProjectionMap.put(ProviderTableMeta.FILE_PATH,\r
- ProviderTableMeta.FILE_PATH);\r
- mProjectionMap.put(ProviderTableMeta.FILE_NAME,\r
- ProviderTableMeta.FILE_NAME);\r
- mProjectionMap.put(ProviderTableMeta.FILE_CREATION,\r
- ProviderTableMeta.FILE_CREATION);\r
- mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,\r
- ProviderTableMeta.FILE_MODIFIED);\r
- mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,\r
- ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);\r
- mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,\r
- ProviderTableMeta.FILE_CONTENT_LENGTH);\r
- mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,\r
- ProviderTableMeta.FILE_CONTENT_TYPE);\r
- mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,\r
- ProviderTableMeta.FILE_STORAGE_PATH);\r
- mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,\r
- ProviderTableMeta.FILE_LAST_SYNC_DATE);\r
- mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,\r
- ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);\r
- mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,\r
- ProviderTableMeta.FILE_KEEP_IN_SYNC);\r
- mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,\r
- ProviderTableMeta.FILE_ACCOUNT_OWNER);\r
- }\r
-\r
- private static final int SINGLE_FILE = 1;\r
- private static final int DIRECTORY = 2;\r
- private static final int ROOT_DIRECTORY = 3;\r
- private static final UriMatcher mUriMatcher;\r
- static {\r
- mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);\r
- }\r
-\r
- @Override\r
- public int delete(Uri uri, String where, String[] whereArgs) {\r
- SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
- int count = 0;\r
- switch (mUriMatcher.match(uri)) {\r
- case SINGLE_FILE:\r
- count = db.delete(ProviderTableMeta.DB_NAME,\r
- ProviderTableMeta._ID\r
- + "="\r
- + uri.getPathSegments().get(1)\r
- + (!TextUtils.isEmpty(where) ? " AND (" + where\r
- + ")" : ""), whereArgs);\r
- break;\r
- case ROOT_DIRECTORY:\r
- count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);\r
- break;\r
- default:\r
- throw new IllegalArgumentException("Unknown uri: " + uri.toString());\r
- }\r
- getContext().getContentResolver().notifyChange(uri, null);\r
- return count;\r
- }\r
-\r
- @Override\r
- public String getType(Uri uri) {\r
- switch (mUriMatcher.match(uri)) {\r
- case ROOT_DIRECTORY:\r
- return ProviderTableMeta.CONTENT_TYPE;\r
- case SINGLE_FILE:\r
- return ProviderTableMeta.CONTENT_TYPE_ITEM;\r
- default:\r
- throw new IllegalArgumentException("Unknown Uri id."\r
- + uri.toString());\r
- }\r
- }\r
-\r
- @Override\r
- public Uri insert(Uri uri, ContentValues values) {\r
- if (mUriMatcher.match(uri) != SINGLE_FILE &&\r
- mUriMatcher.match(uri) != ROOT_DIRECTORY) {\r
- \r
- throw new IllegalArgumentException("Unknown uri id: " + uri);\r
- }\r
-\r
- SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
- long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);\r
- if (rowId > 0) {\r
- Uri insertedFileUri = ContentUris.withAppendedId(\r
- ProviderTableMeta.CONTENT_URI_FILE, rowId);\r
- getContext().getContentResolver().notifyChange(insertedFileUri,\r
- null);\r
- return insertedFileUri;\r
- }\r
- throw new SQLException("ERROR " + uri);\r
- }\r
-\r
- @Override\r
- public boolean onCreate() {\r
- mDbHelper = new DataBaseHelper(getContext());\r
- return true;\r
- }\r
-\r
- @Override\r
- public Cursor query(Uri uri, String[] projection, String selection,\r
- String[] selectionArgs, String sortOrder) {\r
- SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();\r
-\r
- sqlQuery.setTables(ProviderTableMeta.DB_NAME);\r
- sqlQuery.setProjectionMap(mProjectionMap);\r
-\r
- switch (mUriMatcher.match(uri)) {\r
- case ROOT_DIRECTORY:\r
- break;\r
- case DIRECTORY:\r
- sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="\r
- + uri.getPathSegments().get(1));\r
- break;\r
- case SINGLE_FILE:\r
- if (uri.getPathSegments().size() > 1) {\r
- sqlQuery.appendWhere(ProviderTableMeta._ID + "="\r
- + uri.getPathSegments().get(1));\r
- }\r
- break;\r
- default:\r
- throw new IllegalArgumentException("Unknown uri id: " + uri);\r
- }\r
-\r
- String order;\r
- if (TextUtils.isEmpty(sortOrder)) {\r
- order = ProviderTableMeta.DEFAULT_SORT_ORDER;\r
- } else {\r
- order = sortOrder;\r
- }\r
-\r
- SQLiteDatabase db = mDbHelper.getReadableDatabase();\r
- Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,\r
- null, null, order);\r
-\r
- c.setNotificationUri(getContext().getContentResolver(), uri);\r
-\r
- return c;\r
- }\r
-\r
- @Override\r
- public int update(Uri uri, ContentValues values, String selection,\r
- String[] selectionArgs) {\r
- return mDbHelper.getWritableDatabase().update(\r
- ProviderTableMeta.DB_NAME, values, selection, selectionArgs);\r
- }\r
-\r
- class DataBaseHelper extends SQLiteOpenHelper {\r
-\r
- public DataBaseHelper(Context context) {\r
- super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);\r
-\r
- }\r
-\r
- @Override\r
- public void onCreate(SQLiteDatabase db) {\r
- // files table\r
- Log.i("SQL", "Entering in onCreate");\r
- db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("\r
- + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "\r
- + ProviderTableMeta.FILE_NAME + " TEXT, "\r
- + ProviderTableMeta.FILE_PATH + " TEXT, "\r
- + ProviderTableMeta.FILE_PARENT + " INTEGER, "\r
- + ProviderTableMeta.FILE_CREATION + " INTEGER, "\r
- + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "\r
- + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "\r
- + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "\r
- + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "\r
- + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "\r
- + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "\r
- + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "\r
- + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "\r
- + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );"\r
- );\r
- }\r
-\r
- @Override\r
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
- Log.i("SQL", "Entering in onUpgrade");\r
- boolean upgraded = false; \r
- if (oldVersion == 1 && newVersion >= 2) {\r
- Log.i("SQL", "Entering in the #1 ADD in onUpgrade");\r
- db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
- " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +\r
- " DEFAULT 0");\r
- upgraded = true;\r
- }\r
- if (oldVersion < 3 && newVersion >= 3) {\r
- Log.i("SQL", "Entering in the #2 ADD in onUpgrade");\r
- db.beginTransaction();\r
- try {\r
- db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
- " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " +\r
- " DEFAULT 0");\r
- \r
- // assume there are not local changes pending to upload\r
- db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + \r
- " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + \r
- " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");\r
- \r
- upgraded = true;\r
- db.setTransactionSuccessful();\r
- } finally {\r
- db.endTransaction();\r
- }\r
- }\r
- if (oldVersion < 4 && newVersion >= 4) {\r
- Log.i("SQL", "Entering in the #3 ADD in onUpgrade");\r
- db.beginTransaction();\r
- try {\r
- db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
- " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " +\r
- " DEFAULT 0");\r
- \r
- db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + \r
- " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + \r
- " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");\r
- \r
- upgraded = true;\r
- db.setTransactionSuccessful();\r
- } finally {\r
- db.endTransaction();\r
- }\r
- }\r
- if (!upgraded)\r
- Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);\r
- }\r
-\r
- }\r
-\r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<String, String> mProjectionMap;
+ static {
+ mProjectionMap = new HashMap<String, String>();
+ 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);
+ }
+
+ }
+
+}
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.syncadapter;\r
-\r
-import java.io.IOException;\r
-import java.net.UnknownHostException;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-\r
-import org.apache.jackrabbit.webdav.DavException;\r
-\r
-import com.owncloud.android.R;\r
-import com.owncloud.android.datamodel.DataStorageManager;\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-import com.owncloud.android.operations.SynchronizeFolderOperation;\r
-import com.owncloud.android.operations.UpdateOCVersionOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
-import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;\r
-import android.accounts.Account;\r
-import android.app.Notification;\r
-import android.app.NotificationManager;\r
-import android.app.PendingIntent;\r
-import android.content.ContentProviderClient;\r
-import android.content.ContentResolver;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.SyncResult;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-\r
-/**\r
- * SyncAdapter implementation for syncing sample SyncAdapter contacts to the\r
- * platform ContactOperations provider.\r
- * \r
- * @author Bartek Przybylski\r
- */\r
-public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {\r
-\r
- private final static String TAG = "FileSyncAdapter";\r
-\r
- /** \r
- * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation\r
- */\r
- private static final int MAX_FAILED_RESULTS = 3; \r
- \r
- private long mCurrentSyncTime;\r
- private boolean mCancellation;\r
- private boolean mIsManualSync;\r
- private int mFailedResultsCounter; \r
- private RemoteOperationResult mLastFailedResult;\r
- private SyncResult mSyncResult;\r
- private int mConflictsFound;\r
- private int mFailsInFavouritesFound;\r
- private Map<String, String> mForgottenLocalFiles;\r
-\r
- \r
- public FileSyncAdapter(Context context, boolean autoInitialize) {\r
- super(context, autoInitialize);\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public synchronized void onPerformSync(Account account, Bundle extras,\r
- String authority, ContentProviderClient provider,\r
- SyncResult syncResult) {\r
-\r
- mCancellation = false;\r
- mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);\r
- mFailedResultsCounter = 0;\r
- mLastFailedResult = null;\r
- mConflictsFound = 0;\r
- mFailsInFavouritesFound = 0;\r
- mForgottenLocalFiles = new HashMap<String, String>();\r
- mSyncResult = syncResult;\r
- mSyncResult.fullSyncRequested = false;\r
- mSyncResult.delayUntil = 60*60*24; // sync after 24h\r
-\r
- this.setAccount(account);\r
- this.setContentProvider(provider);\r
- this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));\r
- try {\r
- this.initClientForCurrentAccount();\r
- } catch (UnknownHostException e) {\r
- /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again\r
- mSyncResult.tooManyRetries = true;\r
- notifyFailedSynchronization();\r
- return;\r
- }\r
- \r
- Log.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");\r
- sendStickyBroadcast(true, null, null); // message to signal the start of the synchronization to the UI\r
- \r
- try {\r
- updateOCVersion();\r
- mCurrentSyncTime = System.currentTimeMillis();\r
- if (!mCancellation) {\r
- fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID);\r
- \r
- } else {\r
- Log.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested");\r
- }\r
- \r
- \r
- } finally {\r
- // it's important making this although very unexpected errors occur; that's the reason for the finally\r
- \r
- if (mFailedResultsCounter > 0 && mIsManualSync) {\r
- /// don't let the system synchronization manager retries MANUAL synchronizations\r
- // (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)\r
- mSyncResult.tooManyRetries = true;\r
- \r
- /// notify the user about the failure of MANUAL synchronization\r
- notifyFailedSynchronization();\r
- \r
- }\r
- if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {\r
- notifyFailsInFavourites();\r
- }\r
- if (mForgottenLocalFiles.size() > 0) {\r
- notifyForgottenLocalFiles();\r
- \r
- }\r
- sendStickyBroadcast(false, null, mLastFailedResult); // message to signal the end to the UI\r
- }\r
- \r
- }\r
-\r
- \r
- /**\r
- * Called by system SyncManager when a synchronization is required to be cancelled.\r
- * \r
- * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder\r
- * fetched will be still saved in the database. See onPerformSync implementation.\r
- */\r
- @Override\r
- public void onSyncCanceled() {\r
- Log.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel");\r
- mCancellation = true;\r
- super.onSyncCanceled();\r
- }\r
- \r
- \r
- /**\r
- * Updates the locally stored version value of the ownCloud server\r
- */\r
- private void updateOCVersion() {\r
- UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext());\r
- RemoteOperationResult result = update.execute(getClient());\r
- if (!result.isSuccess()) {\r
- mLastFailedResult = result; \r
- }\r
- }\r
-\r
- \r
- \r
- /**\r
- * Synchronize the properties of files and folders contained in a remote folder given by remotePath.\r
- * \r
- * @param remotePath Remote path to the folder to synchronize.\r
- * @param parentId Database Id of the folder to synchronize.\r
- */\r
- private void fetchData(String remotePath, long parentId) {\r
- \r
- if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))\r
- return;\r
- \r
- // perform folder synchronization\r
- SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( remotePath, \r
- mCurrentSyncTime, \r
- parentId, \r
- getStorageManager(), \r
- getAccount(), \r
- getContext()\r
- );\r
- RemoteOperationResult result = synchFolderOp.execute(getClient());\r
- \r
- \r
- // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess\r
- sendStickyBroadcast(true, remotePath, null);\r
- \r
- if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {\r
- \r
- if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
- mConflictsFound += synchFolderOp.getConflictsFound();\r
- mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound();\r
- }\r
- if (synchFolderOp.getForgottenLocalFiles().size() > 0) {\r
- mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles());\r
- }\r
- // synchronize children folders \r
- List<OCFile> children = synchFolderOp.getChildren();\r
- fetchChildren(children); // beware of the 'hidden' recursion here!\r
- \r
- } else {\r
- if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) {\r
- mSyncResult.stats.numAuthExceptions++;\r
- \r
- } else if (result.getException() instanceof DavException) {\r
- mSyncResult.stats.numParseExceptions++;\r
- \r
- } else if (result.getException() instanceof IOException) { \r
- mSyncResult.stats.numIoExceptions++;\r
- }\r
- mFailedResultsCounter++;\r
- mLastFailedResult = result;\r
- }\r
- \r
- }\r
-\r
- /**\r
- * Checks if a failed result should terminate the synchronization process immediately, according to\r
- * OUR OWN POLICY\r
- * \r
- * @param failedResult Remote operation result to check.\r
- * @return 'True' if the result should immediately finish the synchronization\r
- */\r
- private boolean isFinisher(RemoteOperationResult failedResult) {\r
- if (failedResult != null) {\r
- RemoteOperationResult.ResultCode code = failedResult.getCode();\r
- return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) ||\r
- code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) ||\r
- code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) ||\r
- code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED));\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Synchronize data of folders in the list of received files\r
- * \r
- * @param files Files to recursively fetch \r
- */\r
- private void fetchChildren(List<OCFile> files) {\r
- int i;\r
- for (i=0; i < files.size() && !mCancellation; i++) {\r
- OCFile newFile = files.get(i);\r
- if (newFile.isDirectory()) {\r
- fetchData(newFile.getRemotePath(), newFile.getFileId());\r
- }\r
- }\r
- if (mCancellation && i <files.size()) Log.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " because cancelation request");\r
- }\r
-\r
- \r
- /**\r
- * Sends a message to any application component interested in the progress of the synchronization.\r
- * \r
- * @param inProgress 'True' when the synchronization progress is not finished.\r
- * @param dirRemotePath Remote path of a folder that was just synchronized (with or without success)\r
- */\r
- private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {\r
- Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
- i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
- i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
- if (dirRemotePath != null) {\r
- i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
- }\r
- if (result != null) {\r
- i.putExtra(FileSyncService.SYNC_RESULT, result);\r
- }\r
- getContext().sendStickyBroadcast(i);\r
- }\r
-\r
- \r
- \r
- /**\r
- * Notifies the user about a failed synchronization through the status notification bar \r
- */\r
- private void notifyFailedSynchronization() {\r
- Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());\r
- notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
- // TODO put something smart in the contentIntent below\r
- notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
- notification.setLatestEventInfo(getContext().getApplicationContext(), \r
- getContext().getString(R.string.sync_fail_ticker), \r
- String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), \r
- notification.contentIntent);\r
- ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);\r
- }\r
-\r
-\r
- /**\r
- * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.\r
- * \r
- * By now, we won't consider a failed synchronization.\r
- */\r
- private void notifyFailsInFavourites() {\r
- if (mFailedResultsCounter > 0) {\r
- Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis());\r
- notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
- // TODO put something smart in the contentIntent below\r
- notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
- notification.setLatestEventInfo(getContext().getApplicationContext(), \r
- getContext().getString(R.string.sync_fail_in_favourites_ticker), \r
- String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), \r
- notification.contentIntent);\r
- ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification);\r
- \r
- } else {\r
- Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis());\r
- notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
- // TODO put something smart in the contentIntent below\r
- notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
- notification.setLatestEventInfo(getContext().getApplicationContext(), \r
- getContext().getString(R.string.sync_conflicts_in_favourites_ticker), \r
- String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), \r
- notification.contentIntent);\r
- ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);\r
- } \r
- }\r
-\r
- \r
- /**\r
- * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because \r
- * copying them inside the ownCloud local directory was not possible.\r
- * \r
- * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have \r
- * synchronization problems if a local file is linked to more than one remote file.\r
- * \r
- * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.\r
- */\r
- private void notifyForgottenLocalFiles() {\r
- Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis());\r
- notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-\r
- /// includes a pending intent in the notification showing a more detailed explanation\r
- Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);\r
- explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());\r
- ArrayList<String> remotePaths = new ArrayList<String>();\r
- ArrayList<String> localPaths = new ArrayList<String>();\r
- remotePaths.addAll(mForgottenLocalFiles.keySet());\r
- localPaths.addAll(mForgottenLocalFiles.values());\r
- explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths);\r
- explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths); \r
- explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
- \r
- notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0);\r
- notification.setLatestEventInfo(getContext().getApplicationContext(), \r
- getContext().getString(R.string.sync_foreign_files_forgotten_ticker), \r
- String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), \r
- notification.contentIntent);\r
- ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification);\r
- \r
- }\r
- \r
- \r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<String, String> 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<String, String>();
+ 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<OCFile> 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<OCFile> 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 <files.size()) Log_OC.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " because cancelation request");
+ }
+
+
+ /**
+ * Sends a message to any application component interested in the progress of the synchronization.
+ *
+ * @param inProgress 'True' when the synchronization progress is not finished.
+ * @param dirRemotePath Remote path of a folder that was just synchronized (with or without success)
+ */
+ private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {
+ Intent i = new Intent(FileSyncService.SYNC_MESSAGE);
+ i.putExtra(FileSyncService.IN_PROGRESS, inProgress);
+ i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);
+ if (dirRemotePath != null) {
+ i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);
+ }
+ if (result != null) {
+ i.putExtra(FileSyncService.SYNC_RESULT, result);
+ }
+ getContext().sendStickyBroadcast(i);
+ }
+
+
+
+ /**
+ * Notifies the user about a failed synchronization through the status notification bar
+ */
+ private void notifyFailedSynchronization() {
+ Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_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_ticker),
+ String.format(getContext().getString(R.string.sync_fail_content), getAccount().name),
+ notification.contentIntent);
+ ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);
+ }
+
+
+ /**
+ * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.
+ *
+ * By now, we won't consider a failed synchronization.
+ */
+ private void notifyFailsInFavourites() {
+ if (mFailedResultsCounter > 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<String> remotePaths = new ArrayList<String>();
+ ArrayList<String> localPaths = new ArrayList<String>();
+ 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);
+
+ }
+
+
+}
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;
try {
map = (HashMap<String, String>) 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;
}
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.ui.activity;\r
-\r
-import java.net.MalformedURLException;\r
-import java.net.URL;\r
-\r
-import com.owncloud.android.AccountUtils;\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
-import com.owncloud.android.authenticator.AuthenticationRunnable;\r
-import com.owncloud.android.authenticator.OnAuthenticationResultListener;\r
-import com.owncloud.android.authenticator.OnConnectCheckListener;\r
-import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-import com.owncloud.android.operations.ConnectionCheckOperation;\r
-import com.owncloud.android.operations.OnRemoteOperationListener;\r
-import com.owncloud.android.operations.RemoteOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountAuthenticatorActivity;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.ContentResolver;\r
-import android.content.DialogInterface;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.preference.PreferenceManager;\r
-import android.text.InputType;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.View.OnFocusChangeListener;\r
-import android.view.Window;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import com.owncloud.android.R;\r
-\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * This Activity is used to add an ownCloud account to the App\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
- implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, \r
- OnFocusChangeListener, OnClickListener {\r
-\r
- private static final int DIALOG_LOGIN_PROGRESS = 0;\r
- private static final int DIALOG_SSL_VALIDATOR = 1;\r
- private static final int DIALOG_CERT_NOT_SAVED = 2;\r
-\r
- private static final String TAG = "AuthActivity";\r
-\r
- private Thread mAuthThread;\r
- private AuthenticationRunnable mAuthRunnable;\r
- //private ConnectionCheckerRunnable mConnChkRunnable = null;\r
- private ConnectionCheckOperation mConnChkRunnable;\r
- private final Handler mHandler = new Handler();\r
- private String mBaseUrl;\r
- \r
- private static final String STATUS_TEXT = "STATUS_TEXT";\r
- private static final String STATUS_ICON = "STATUS_ICON";\r
- private static final String STATUS_CORRECT = "STATUS_CORRECT";\r
- private static final String IS_SSL_CONN = "IS_SSL_CONN";\r
- private int mStatusText, mStatusIcon;\r
- private boolean mStatusCorrect, mIsSslConn;\r
- private RemoteOperationResult mLastSslUntrustedServerResult;\r
-\r
- public static final String PARAM_USERNAME = "param_Username";\r
- public static final String PARAM_HOSTNAME = "param_Hostname";\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
- setContentView(R.layout.account_setup);\r
- ImageView iv = (ImageView) findViewById(R.id.refreshButton);\r
- ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);\r
- TextView tv = (TextView) findViewById(R.id.host_URL);\r
- TextView tv2 = (TextView) findViewById(R.id.account_password);\r
-\r
- if (savedInstanceState != null) {\r
- mStatusIcon = savedInstanceState.getInt(STATUS_ICON);\r
- mStatusText = savedInstanceState.getInt(STATUS_TEXT);\r
- mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);\r
- mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);\r
- setResultIconAndText(mStatusIcon, mStatusText);\r
- findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
- if (!mStatusCorrect)\r
- iv.setVisibility(View.VISIBLE);\r
- else\r
- iv.setVisibility(View.INVISIBLE);\r
-\r
- } else {\r
- mStatusText = mStatusIcon = 0;\r
- mStatusCorrect = false;\r
- mIsSslConn = false;\r
- }\r
- iv.setOnClickListener(this);\r
- iv2.setOnClickListener(this);\r
- tv.setOnFocusChangeListener(this);\r
- tv2.setOnFocusChangeListener(this);\r
-\r
- Button b = (Button) findViewById(R.id.account_register);\r
- if (b != null) {\r
- b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
- }\r
- }\r
-\r
- @Override\r
- protected void onSaveInstanceState(Bundle outState) {\r
- outState.putInt(STATUS_ICON, mStatusIcon);\r
- outState.putInt(STATUS_TEXT, mStatusText);\r
- outState.putBoolean(STATUS_CORRECT, mStatusCorrect);\r
- super.onSaveInstanceState(outState);\r
- }\r
-\r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog = null;\r
- switch (id) {\r
- case DIALOG_LOGIN_PROGRESS: {\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(getResources().getString(\r
- R.string.auth_trying_to_login));\r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(true);\r
- working_dialog\r
- .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
- @Override\r
- public void onCancel(DialogInterface dialog) {\r
- Log.i(TAG, "Login canceled");\r
- if (mAuthThread != null) {\r
- mAuthThread.interrupt();\r
- finish();\r
- }\r
- }\r
- });\r
- dialog = working_dialog;\r
- break;\r
- }\r
- case DIALOG_SSL_VALIDATOR: {\r
- dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
- break;\r
- }\r
- case DIALOG_CERT_NOT_SAVED: {\r
- AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
- builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- dialog.dismiss();\r
- };\r
- });\r
- dialog = builder.create();\r
- break;\r
- }\r
- default:\r
- Log.e(TAG, "Incorrect dialog called with id = " + id);\r
- }\r
- return dialog;\r
- }\r
-\r
- @Override\r
- protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
- switch (id) {\r
- case DIALOG_LOGIN_PROGRESS:\r
- case DIALOG_CERT_NOT_SAVED:\r
- break;\r
- case DIALOG_SSL_VALIDATOR: {\r
- ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
- break;\r
- }\r
- default:\r
- Log.e(TAG, "Incorrect dialog called with id = " + id);\r
- }\r
- }\r
-\r
- public void onAuthenticationResult(boolean success, String message) {\r
- if (success) {\r
- TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);\r
-\r
- URL url;\r
- try {\r
- url = new URL(message);\r
- } catch (MalformedURLException e) {\r
- // should never happen\r
- Log.e(getClass().getName(), "Malformed URL: " + message);\r
- return;\r
- }\r
-\r
- String username = username_text.getText().toString().trim();\r
- String accountName = username + "@" + url.getHost();\r
- if (url.getPort() >= 0) {\r
- accountName += ":" + url.getPort();\r
- }\r
- Account account = new Account(accountName,\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- AccountManager accManager = AccountManager.get(this);\r
- accManager.addAccountExplicitly(account, password_text.getText()\r
- .toString(), null);\r
-\r
- // Add this account as default in the preferences, if there is none\r
- // already\r
- Account defaultAccount = AccountUtils\r
- .getCurrentOwnCloudAccount(this);\r
- if (defaultAccount == null) {\r
- SharedPreferences.Editor editor = PreferenceManager\r
- .getDefaultSharedPreferences(this).edit();\r
- editor.putString("select_oc_account", accountName);\r
- editor.commit();\r
- }\r
-\r
- final Intent intent = new Intent();\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
- intent.putExtra(AccountManager.KEY_AUTHTOKEN,\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- intent.putExtra(AccountManager.KEY_USERDATA, username);\r
-\r
- accManager.setUserData(account,\r
- AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable\r
- .getDiscoveredVersion().toString());\r
- \r
- accManager.setUserData(account,\r
- AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);\r
-\r
- setAccountAuthenticatorResult(intent.getExtras());\r
- setResult(RESULT_OK, intent);\r
- Bundle bundle = new Bundle();\r
- bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
- //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,\r
- // bundle);\r
- ContentResolver.requestSync(account, "org.owncloud", bundle);\r
-\r
- /*\r
- * if\r
- * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion\r
- * .owncloud_v2) >= 0) { Intent i = new Intent(this,\r
- * ExtensionsAvailableActivity.class); startActivity(i); }\r
- */\r
-\r
- finish();\r
- } else {\r
- try {\r
- dismissDialog(DIALOG_LOGIN_PROGRESS);\r
- } catch (IllegalArgumentException e) {\r
- // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
- }\r
- TextView tv = (TextView) findViewById(R.id.account_username);\r
- tv.setError(message + " "); // the extra spaces are a workaround for an ugly bug: \r
- // 1. insert wrong credentials and connect\r
- // 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\r
- // 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\r
- // Seen, at least, in Android 2.x devices\r
- }\r
- }\r
- public void onCancelClick(View view) {\r
- setResult(RESULT_CANCELED);\r
- finish();\r
- }\r
- \r
- public void onOkClick(View view) {\r
- String prefix = "";\r
- String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString().trim();\r
- if (mIsSslConn) {\r
- prefix = "https://";\r
- } else {\r
- prefix = "http://";\r
- }\r
- if (url.toLowerCase().startsWith("http://")\r
- || url.toLowerCase().startsWith("https://")) {\r
- prefix = "";\r
- }\r
- continueConnection(prefix);\r
- }\r
- \r
- public void onRegisterClick(View view) {\r
- Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));\r
- setResult(RESULT_CANCELED);\r
- startActivity(register);\r
- }\r
-\r
- private void continueConnection(String prefix) {\r
- String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString().trim();\r
- String username = ((TextView) findViewById(R.id.account_username))\r
- .getText().toString();\r
- String password = ((TextView) findViewById(R.id.account_password))\r
- .getText().toString();\r
- if (url.endsWith("/"))\r
- url = url.substring(0, url.length() - 1);\r
-\r
- URL uri = null;\r
- String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable\r
- .getDiscoveredVersion());\r
- \r
- if (webdav_path == null) {\r
- onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title));\r
- return;\r
- }\r
- \r
- try {\r
- mBaseUrl = prefix + url;\r
- String url_str = prefix + url + webdav_path;\r
- uri = new URL(url_str);\r
- } catch (MalformedURLException e) {\r
- // should never happen\r
- onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title));\r
- return;\r
- }\r
-\r
- showDialog(DIALOG_LOGIN_PROGRESS);\r
- mAuthRunnable = new AuthenticationRunnable(uri, username, password, this);\r
- mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);\r
- mAuthThread = new Thread(mAuthRunnable);\r
- mAuthThread.start();\r
- }\r
-\r
- @Override\r
- public void onConnectionCheckResult(ResultType type) {\r
- mStatusText = mStatusIcon = 0;\r
- mStatusCorrect = false;\r
- String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString().trim().toLowerCase();\r
-\r
- switch (type) {\r
- case OK_SSL:\r
- mIsSslConn = true;\r
- mStatusIcon = android.R.drawable.ic_secure;\r
- mStatusText = R.string.auth_secure_connection;\r
- mStatusCorrect = true;\r
- break;\r
- case OK_NO_SSL:\r
- mIsSslConn = false;\r
- mStatusCorrect = true;\r
- if (t_url.startsWith("http://") ) {\r
- mStatusText = R.string.auth_connection_established;\r
- mStatusIcon = R.drawable.ic_ok;\r
- } else {\r
- mStatusText = R.string.auth_nossl_plain_ok_title;\r
- mStatusIcon = android.R.drawable.ic_partial_secure;\r
- }\r
- break;\r
- case BAD_OC_VERSION:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_bad_oc_version_title;\r
- break;\r
- case WRONG_CONNECTION:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_wrong_connection_title;\r
- break;\r
- case TIMEOUT:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_timeout_title;\r
- break;\r
- case INCORRECT_ADDRESS:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_incorrect_address_title;\r
- break;\r
- case SSL_UNVERIFIED_SERVER:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_ssl_unverified_server_title;\r
- break;\r
- case SSL_INIT_ERROR:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_ssl_general_error_title;\r
- break;\r
- case HOST_NOT_AVAILABLE:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_unknown_host_title;\r
- break;\r
- case NO_NETWORK_CONNECTION:\r
- mStatusIcon = R.drawable.no_network;\r
- mStatusText = R.string.auth_no_net_conn_title;\r
- break;\r
- case INSTANCE_NOT_CONFIGURED:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_not_configured_title;\r
- break;\r
- case UNKNOWN_ERROR:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_unknown_error_title;\r
- break;\r
- case FILE_NOT_FOUND:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_incorrect_path_title;\r
- break;\r
- default:\r
- Log.e(TAG, "Incorrect connection checker result type: " + type);\r
- }\r
- setResultIconAndText(mStatusIcon, mStatusText);\r
- if (!mStatusCorrect)\r
- findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
- else\r
- findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
- findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
- }\r
-\r
- @Override\r
- public void onFocusChange(View view, boolean hasFocus) {\r
- if (view.getId() == R.id.host_URL) {\r
- if (!hasFocus) {\r
- TextView tv = ((TextView) findViewById(R.id.host_URL));\r
- String uri = tv.getText().toString().trim();\r
- if (uri.length() != 0) {\r
- setResultIconAndText(R.drawable.progress_small,\r
- R.string.auth_testing_connection);\r
- //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);\r
- mConnChkRunnable = new ConnectionCheckOperation(uri, this);\r
- //mConnChkRunnable.setListener(this, mHandler);\r
- //mAuthThread = new Thread(mConnChkRunnable);\r
- //mAuthThread.start();\r
- WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
- mAuthThread = mConnChkRunnable.execute(client, this, mHandler);\r
- } else {\r
- findViewById(R.id.refreshButton).setVisibility(\r
- View.INVISIBLE);\r
- setResultIconAndText(0, 0);\r
- }\r
- } else {\r
- // avoids that the 'connect' button can be clicked if the test was previously passed\r
- findViewById(R.id.buttonOK).setEnabled(false); \r
- }\r
- } else if (view.getId() == R.id.account_password) {\r
- ImageView iv = (ImageView) findViewById(R.id.viewPassword);\r
- if (hasFocus) {\r
- iv.setVisibility(View.VISIBLE);\r
- } else {\r
- TextView v = (TextView) findViewById(R.id.account_password);\r
- int input_type = InputType.TYPE_CLASS_TEXT\r
- | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
- v.setInputType(input_type);\r
- iv.setVisibility(View.INVISIBLE);\r
- }\r
- }\r
- }\r
-\r
- private void setResultIconAndText(int drawable_id, int text_id) {\r
- ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
- TextView tv = (TextView) findViewById(R.id.status_text);\r
-\r
- if (drawable_id == 0 && text_id == 0) {\r
- iv.setVisibility(View.INVISIBLE);\r
- tv.setVisibility(View.INVISIBLE);\r
- } else {\r
- iv.setImageResource(drawable_id);\r
- tv.setText(text_id);\r
- iv.setVisibility(View.VISIBLE);\r
- tv.setVisibility(View.VISIBLE);\r
- }\r
- }\r
-\r
- @Override\r
- public void onClick(View v) {\r
- if (v.getId() == R.id.refreshButton) {\r
- onFocusChange(findViewById(R.id.host_URL), false);\r
- } else if (v.getId() == R.id.viewPassword) {\r
- EditText view = (EditText) findViewById(R.id.account_password);\r
- int selectionStart = view.getSelectionStart();\r
- int selectionEnd = view.getSelectionEnd();\r
- int input_type = view.getInputType();\r
- if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {\r
- input_type = InputType.TYPE_CLASS_TEXT\r
- | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
- } else {\r
- input_type = InputType.TYPE_CLASS_TEXT\r
- | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
- }\r
- view.setInputType(input_type);\r
- view.setSelection(selectionStart, selectionEnd);\r
- }\r
- }\r
-\r
- @Override\r
- public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
- if (operation.equals(mConnChkRunnable)) {\r
- \r
- mStatusText = mStatusIcon = 0;\r
- mStatusCorrect = false;\r
- String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString().trim().toLowerCase();\r
- \r
- switch (result.getCode()) {\r
- case OK_SSL:\r
- mIsSslConn = true;\r
- mStatusIcon = android.R.drawable.ic_secure;\r
- mStatusText = R.string.auth_secure_connection;\r
- mStatusCorrect = true;\r
- break;\r
- \r
- case OK_NO_SSL:\r
- case OK:\r
- mIsSslConn = false;\r
- mStatusCorrect = true;\r
- if (t_url.startsWith("http://") ) {\r
- mStatusText = R.string.auth_connection_established;\r
- mStatusIcon = R.drawable.ic_ok;\r
- } else {\r
- mStatusText = R.string.auth_nossl_plain_ok_title;\r
- mStatusIcon = android.R.drawable.ic_partial_secure;\r
- }\r
- break;\r
- \r
- \r
- case BAD_OC_VERSION:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_bad_oc_version_title;\r
- break;\r
- case WRONG_CONNECTION:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_wrong_connection_title;\r
- break;\r
- case TIMEOUT:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_timeout_title;\r
- break;\r
- case INCORRECT_ADDRESS:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_incorrect_address_title;\r
- break;\r
- \r
- case SSL_RECOVERABLE_PEER_UNVERIFIED:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_ssl_unverified_server_title;\r
- mLastSslUntrustedServerResult = result;\r
- showDialog(DIALOG_SSL_VALIDATOR); \r
- break;\r
- \r
- case SSL_ERROR:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_ssl_general_error_title;\r
- break;\r
- \r
- case HOST_NOT_AVAILABLE:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_unknown_host_title;\r
- break;\r
- case NO_NETWORK_CONNECTION:\r
- mStatusIcon = R.drawable.no_network;\r
- mStatusText = R.string.auth_no_net_conn_title;\r
- break;\r
- case INSTANCE_NOT_CONFIGURED:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_not_configured_title;\r
- break;\r
- case FILE_NOT_FOUND:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_incorrect_path_title;\r
- break;\r
- case UNHANDLED_HTTP_CODE:\r
- case UNKNOWN_ERROR:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_unknown_error_title;\r
- break;\r
- default:\r
- Log.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode());\r
- }\r
- setResultIconAndText(mStatusIcon, mStatusText);\r
- if (!mStatusCorrect)\r
- findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
- else\r
- findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
- findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
- }\r
- }\r
-\r
- \r
- public void onSavedCertificate() {\r
- mAuthThread = mConnChkRunnable.retry(this, mHandler); \r
- }\r
-\r
- @Override\r
- public void onFailedSavingCertificate() {\r
- showDialog(DIALOG_CERT_NOT_SAVED);\r
- }\r
- \r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+
+}
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;
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);
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;
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());
}
}
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package com.owncloud.android.ui.activity;\r
-\r
-import android.accounts.Account;\r
-import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.ComponentName;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.ServiceConnection;\r
-import android.content.res.Configuration;\r
-import android.os.Bundle;\r
-import android.os.IBinder;\r
-import android.support.v4.app.FragmentTransaction;\r
-import android.util.Log;\r
-\r
-import com.actionbarsherlock.app.ActionBar;\r
-import com.actionbarsherlock.app.SherlockFragmentActivity;\r
-import com.actionbarsherlock.view.MenuItem;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.files.services.FileDownloader;\r
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
-import com.owncloud.android.files.services.FileUploader;\r
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
-import com.owncloud.android.ui.fragment.FileDetailFragment;\r
-\r
-import com.owncloud.android.R;\r
-\r
-/**\r
- * This activity displays the details of a file like its name, its size and so\r
- * on.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity {\r
- \r
- public static final int DIALOG_SHORT_WAIT = 0;\r
-\r
- public static final String TAG = FileDetailActivity.class.getSimpleName();\r
- \r
- private boolean mConfigurationChangedToLandscape = false;\r
- private FileDownloaderBinder mDownloaderBinder = null;\r
- private ServiceConnection mDownloadConnection, mUploadConnection = null;\r
- private FileUploaderBinder mUploaderBinder = null;\r
-\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
-\r
- // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity \r
- Configuration conf = getResources().getConfiguration();\r
- mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && \r
- (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE\r
- );\r
-\r
- if (!mConfigurationChangedToLandscape) {\r
- mDownloadConnection = new DetailsServiceConnection();\r
- bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);\r
- mUploadConnection = new DetailsServiceConnection();\r
- bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);\r
- \r
- setContentView(R.layout.file_activity_details);\r
- \r
- ActionBar actionBar = getSupportActionBar();\r
- actionBar.setDisplayHomeAsUpEnabled(true);\r
-\r
- OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
- Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
- FileDetailFragment mFileDetail = new FileDetailFragment(file, account);\r
- \r
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
- ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG);\r
- ft.commit();\r
- \r
- } else {\r
- backToDisplayActivity(); // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
- }\r
- \r
- \r
- }\r
- \r
- \r
- /** Defines callbacks for service binding, passed to bindService() */\r
- private class DetailsServiceConnection implements ServiceConnection {\r
-\r
- @Override\r
- public void onServiceConnected(ComponentName component, IBinder service) {\r
- if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
- Log.d(TAG, "Download service connected");\r
- mDownloaderBinder = (FileDownloaderBinder) service;\r
- } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
- Log.d(TAG, "Upload service connected");\r
- mUploaderBinder = (FileUploaderBinder) service;\r
- } else {\r
- return;\r
- }\r
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
- if (fragment != null)\r
- fragment.updateFileDetails(false); // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
- }\r
-\r
- @Override\r
- public void onServiceDisconnected(ComponentName component) {\r
- if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
- Log.d(TAG, "Download service disconnected");\r
- mDownloaderBinder = null;\r
- } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
- Log.d(TAG, "Upload service disconnected");\r
- mUploaderBinder = null;\r
- }\r
- }\r
- }; \r
- \r
-\r
- @Override\r
- public void onDestroy() {\r
- super.onDestroy();\r
- if (mDownloadConnection != null) {\r
- unbindService(mDownloadConnection);\r
- mDownloadConnection = null;\r
- }\r
- if (mUploadConnection != null) {\r
- unbindService(mUploadConnection);\r
- mUploadConnection = null;\r
- }\r
- }\r
- \r
- \r
- @Override\r
- public boolean onOptionsItemSelected(MenuItem item) {\r
- boolean returnValue = false;\r
- \r
- switch(item.getItemId()){\r
- case android.R.id.home:\r
- backToDisplayActivity();\r
- returnValue = true;\r
- break;\r
- default:\r
- returnValue = super.onOptionsItemSelected(item);\r
- }\r
- \r
- return returnValue;\r
- }\r
-\r
-\r
-\r
- @Override\r
- protected void onResume() {\r
- \r
- super.onResume();\r
- if (!mConfigurationChangedToLandscape) { \r
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
- fragment.updateFileDetails(false);\r
- }\r
- }\r
- \r
-\r
- private void backToDisplayActivity() {\r
- Intent intent = new Intent(this, FileDisplayActivity.class);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
- intent.putExtra(FileDetailFragment.EXTRA_FILE, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE));\r
- intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT));\r
- startActivity(intent);\r
- finish();\r
- }\r
- \r
- \r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog = null;\r
- switch (id) {\r
- case DIALOG_SHORT_WAIT: {\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(getResources().getString(\r
- R.string.wait_a_moment));\r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(false);\r
- dialog = working_dialog;\r
- break;\r
- }\r
- default:\r
- dialog = null;\r
- }\r
- return dialog;\r
- }\r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onFileStateChanged() {\r
- // nothing to do here!\r
- }\r
-\r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public FileDownloaderBinder getFileDownloaderBinder() {\r
- return mDownloaderBinder;\r
- }\r
-\r
-\r
- @Override\r
- public FileUploaderBinder getFileUploaderBinder() {\r
- return mUploaderBinder;\r
- }\r
- \r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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;
+ }
+
+}
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;
@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
// show changelog, if needed
showChangeLog();
- Log.d(getClass().toString(), "onCreate() end");
+ Log_OC.d(getClass().toString(), "onCreate() end");
}
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;
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;
@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) {
}
}
}
- 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)) {
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);
dismissDialog(DIALOG_SETUP_ACCOUNT);
}
- Log.d(getClass().toString(), "onPause() end");
+ Log_OC.d(getClass().toString(), "onPause() end");
}
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);
}
}
});
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)) {
@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;
@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;
}
}
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;
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;
}
private List<CheckBox> getCheckboxList() {
List<CheckBox> list = new ArrayList<CheckBox>();
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);
}
}
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);
}
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);
}
// 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);
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;
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();
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;
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) {
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
startActivity(intent);
break;
default:
- Log.w(TAG, "Unknown menu item triggered");
+ Log_OC.w(TAG, "Unknown menu item triggered");
return false;
}
return true;
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;
/**
@Override
public void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate() start");
+ Log_OC.d(TAG, "onCreate() start");
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
mCurrentDialog = null;
}
- Log.d(TAG, "onCreate() end");
+ Log_OC.d(TAG, "onCreate() end");
}
@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");
}
@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();
@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;
}
@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;
}
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;
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);
}
}
});
import android.util.Log;
import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.Log_OC;
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;
}
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package com.owncloud.android.ui.fragment;\r
-\r
-import java.io.File;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.apache.commons.httpclient.methods.GetMethod;\r
-import org.apache.commons.httpclient.methods.PostMethod;\r
-import org.apache.commons.httpclient.methods.StringRequestEntity;\r
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;\r
-import org.apache.http.HttpStatus;\r
-import org.apache.http.NameValuePair;\r
-import org.apache.http.client.utils.URLEncodedUtils;\r
-import org.apache.http.message.BasicNameValuePair;\r
-import org.apache.http.protocol.HTTP;\r
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
-import org.json.JSONObject;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.annotation.SuppressLint;\r
-import android.app.Activity;\r
-import android.content.ActivityNotFoundException;\r
-import android.content.BroadcastReceiver;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.IntentFilter;\r
-import android.graphics.Bitmap;\r
-import android.graphics.BitmapFactory;\r
-import android.graphics.BitmapFactory.Options;\r
-import android.graphics.Point;\r
-import android.net.Uri;\r
-import android.os.AsyncTask;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.support.v4.app.DialogFragment;\r
-import android.support.v4.app.FragmentTransaction;\r
-import android.util.Log;\r
-import android.view.Display;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.ViewGroup;\r
-import android.webkit.MimeTypeMap;\r
-import android.widget.Button;\r
-import android.widget.CheckBox;\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import android.widget.Toast;\r
-\r
-import com.actionbarsherlock.app.SherlockFragment;\r
-import com.owncloud.android.AccountUtils;\r
-import com.owncloud.android.DisplayUtils;\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.files.services.FileDownloader;\r
-import com.owncloud.android.files.services.FileObserverService;\r
-import com.owncloud.android.files.services.FileUploader;\r
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-import com.owncloud.android.operations.OnRemoteOperationListener;\r
-import com.owncloud.android.operations.RemoteOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
-import com.owncloud.android.operations.RemoveFileOperation;\r
-import com.owncloud.android.operations.RenameFileOperation;\r
-import com.owncloud.android.operations.SynchronizeFileOperation;\r
-import com.owncloud.android.ui.activity.ConflictsResolveActivity;\r
-import com.owncloud.android.ui.activity.FileDetailActivity;\r
-import com.owncloud.android.ui.activity.FileDisplayActivity;\r
-import com.owncloud.android.ui.activity.TransferServiceGetter;\r
-import com.owncloud.android.ui.dialog.EditNameDialog;\r
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;\r
-import com.owncloud.android.utils.OwnCloudVersion;\r
-\r
-import com.owncloud.android.R;\r
-import eu.alefzero.webdav.WebdavClient;\r
-import eu.alefzero.webdav.WebdavUtils;\r
-\r
-/**\r
- * This Fragment is used to display the details about a file.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileDetailFragment extends SherlockFragment implements\r
- OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener {\r
-\r
- public static final String EXTRA_FILE = "FILE";\r
- public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
-\r
- private FileDetailFragment.ContainerActivity mContainerActivity;\r
- \r
- private int mLayout;\r
- private View mView;\r
- private OCFile mFile;\r
- private Account mAccount;\r
- private FileDataStorageManager mStorageManager;\r
- private ImageView mPreview;\r
- \r
- private DownloadFinishReceiver mDownloadFinishReceiver;\r
- private UploadFinishReceiver mUploadFinishReceiver;\r
- \r
- private Handler mHandler;\r
- private RemoteOperation mLastRemoteOperation;\r
- private DialogFragment mCurrentDialog;\r
-\r
- private static final String TAG = FileDetailFragment.class.getSimpleName();\r
- public static final String FTAG = "FileDetails"; \r
- public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
-\r
- \r
- /**\r
- * Creates an empty details fragment.\r
- * \r
- * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. \r
- */\r
- public FileDetailFragment() {\r
- mFile = null;\r
- mAccount = null;\r
- mStorageManager = null;\r
- mLayout = R.layout.file_details_empty;\r
- }\r
- \r
- \r
- /**\r
- * Creates a details fragment.\r
- * \r
- * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).\r
- * \r
- * @param fileToDetail An {@link OCFile} to show in the fragment\r
- * @param ocAccount An ownCloud account; needed to start downloads\r
- */\r
- public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {\r
- mFile = fileToDetail;\r
- mAccount = ocAccount;\r
- mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment \r
- mLayout = R.layout.file_details_empty;\r
- }\r
- \r
- \r
- @Override\r
- public void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- mHandler = new Handler();\r
- }\r
- \r
-\r
- @Override\r
- public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
- Bundle savedInstanceState) {\r
- super.onCreateView(inflater, container, savedInstanceState);\r
- \r
- if (savedInstanceState != null) {\r
- mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
- mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);\r
- }\r
- \r
- if(mFile != null && mAccount != null) {\r
- mLayout = R.layout.file_details_fragment;\r
- }\r
- \r
- View view = null;\r
- view = inflater.inflate(mLayout, container, false);\r
- mView = view;\r
- \r
- if (mLayout == R.layout.file_details_fragment) {\r
- mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);\r
- mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);\r
- mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);\r
- mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);\r
- mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);\r
- //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);\r
- mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
- }\r
- \r
- updateFileDetails(false);\r
- return view;\r
- }\r
- \r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onAttach(Activity activity) {\r
- super.onAttach(activity);\r
- try {\r
- mContainerActivity = (ContainerActivity) activity;\r
- } catch (ClassCastException e) {\r
- throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());\r
- }\r
- }\r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onActivityCreated(Bundle savedInstanceState) {\r
- super.onActivityCreated(savedInstanceState);\r
- if (mAccount != null) {\r
- mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;\r
- }\r
- }\r
- \r
-\r
- @Override\r
- public void onSaveInstanceState(Bundle outState) {\r
- Log.i(getClass().toString(), "onSaveInstanceState() start");\r
- super.onSaveInstanceState(outState);\r
- outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);\r
- outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
- Log.i(getClass().toString(), "onSaveInstanceState() end");\r
- }\r
-\r
- \r
- @Override\r
- public void onResume() {\r
- super.onResume();\r
- \r
- mDownloadFinishReceiver = new DownloadFinishReceiver();\r
- IntentFilter filter = new IntentFilter(\r
- FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
- getActivity().registerReceiver(mDownloadFinishReceiver, filter);\r
- \r
- mUploadFinishReceiver = new UploadFinishReceiver();\r
- filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
- getActivity().registerReceiver(mUploadFinishReceiver, filter);\r
- \r
- mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
- }\r
-\r
- @Override\r
- public void onPause() {\r
- super.onPause();\r
- \r
- getActivity().unregisterReceiver(mDownloadFinishReceiver);\r
- mDownloadFinishReceiver = null;\r
- \r
- getActivity().unregisterReceiver(mUploadFinishReceiver);\r
- mUploadFinishReceiver = null;\r
- \r
- if (mPreview != null) {\r
- mPreview = null;\r
- }\r
- }\r
-\r
- @Override\r
- public View getView() {\r
- return super.getView() == null ? mView : super.getView();\r
- }\r
-\r
- \r
- \r
- @Override\r
- public void onClick(View v) {\r
- switch (v.getId()) {\r
- case R.id.fdDownloadBtn: {\r
- FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
- FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
- if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
- downloaderBinder.cancel(mAccount, mFile);\r
- if (mFile.isDown()) {\r
- setButtonsForDown();\r
- } else {\r
- setButtonsForRemote();\r
- }\r
-\r
- } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {\r
- uploaderBinder.cancel(mAccount, mFile);\r
- if (!mFile.fileExists()) {\r
- // TODO make something better\r
- if (getActivity() instanceof FileDisplayActivity) {\r
- // double pane\r
- FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
- transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment\r
- transaction.commit();\r
- mContainerActivity.onFileStateChanged();\r
- } else {\r
- getActivity().finish();\r
- }\r
- \r
- } else if (mFile.isDown()) {\r
- setButtonsForDown();\r
- } else {\r
- setButtonsForRemote();\r
- }\r
- \r
- } else {\r
- mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());\r
- WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
- mLastRemoteOperation.execute(wc, this, mHandler);\r
- \r
- // update ui \r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference\r
- \r
- }\r
- break;\r
- }\r
- case R.id.fdKeepInSync: {\r
- CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);\r
- mFile.setKeepInSync(cb.isChecked());\r
- mStorageManager.saveFile(mFile);\r
- \r
- /// register the OCFile instance in the observer service to monitor local updates;\r
- /// if necessary, the file is download \r
- Intent intent = new Intent(getActivity().getApplicationContext(),\r
- FileObserverService.class);\r
- intent.putExtra(FileObserverService.KEY_FILE_CMD,\r
- (cb.isChecked()?\r
- FileObserverService.CMD_ADD_OBSERVED_FILE:\r
- FileObserverService.CMD_DEL_OBSERVED_FILE));\r
- intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);\r
- intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);\r
- Log.e(TAG, "starting observer service");\r
- getActivity().startService(intent);\r
- \r
- if (mFile.keepInSync()) {\r
- onClick(getView().findViewById(R.id.fdDownloadBtn)); // force an immediate synchronization\r
- }\r
- break;\r
- }\r
- case R.id.fdRenameBtn: {\r
- EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this);\r
- dialog.show(getFragmentManager(), "nameeditdialog");\r
- break;\r
- } \r
- case R.id.fdRemoveBtn: {\r
- ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(\r
- R.string.confirmation_remove_alert,\r
- new String[]{mFile.getFileName()},\r
- mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,\r
- mFile.isDown() ? R.string.confirmation_remove_local : -1,\r
- R.string.common_cancel);\r
- confDialog.setOnConfirmationListener(this);\r
- mCurrentDialog = confDialog;\r
- mCurrentDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
- break;\r
- }\r
- case R.id.fdOpenBtn: {\r
- String storagePath = mFile.getStoragePath();\r
- String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
- try {\r
- Intent i = new Intent(Intent.ACTION_VIEW);\r
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
- i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
- startActivity(i);\r
- \r
- } catch (Throwable t) {\r
- Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
- boolean toastIt = true; \r
- String mimeType = "";\r
- try {\r
- Intent i = new Intent(Intent.ACTION_VIEW);\r
- mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
- if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
- if (mimeType != null) {\r
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
- } else {\r
- // desperate try\r
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
- }\r
- i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
- startActivity(i);\r
- toastIt = false;\r
- }\r
- \r
- } catch (IndexOutOfBoundsException e) {\r
- Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
- \r
- } catch (ActivityNotFoundException e) {\r
- Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
- \r
- } catch (Throwable th) {\r
- Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
- \r
- } finally {\r
- if (toastIt) {\r
- Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
- }\r
- }\r
- \r
- }\r
- break;\r
- }\r
- default:\r
- Log.e(TAG, "Incorrect view clicked!");\r
- }\r
- \r
- /* else if (v.getId() == R.id.fdShareBtn) {\r
- Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));\r
- t.start();\r
- }*/\r
- }\r
- \r
- \r
- @Override\r
- public void onConfirmation(String callerTag) {\r
- if (callerTag.equals(FTAG_CONFIRMATION)) {\r
- if (mStorageManager.getFileById(mFile.getFileId()) != null) {\r
- mLastRemoteOperation = new RemoveFileOperation( mFile, \r
- true, \r
- mStorageManager);\r
- WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
- mLastRemoteOperation.execute(wc, this, mHandler);\r
- \r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- }\r
- }\r
- mCurrentDialog.dismiss();\r
- mCurrentDialog = null;\r
- }\r
- \r
- @Override\r
- public void onNeutral(String callerTag) {\r
- File f = null;\r
- if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {\r
- f.delete();\r
- mFile.setStoragePath(null);\r
- mStorageManager.saveFile(mFile);\r
- updateFileDetails(mFile, mAccount);\r
- }\r
- mCurrentDialog.dismiss();\r
- mCurrentDialog = null;\r
- }\r
- \r
- @Override\r
- public void onCancel(String callerTag) {\r
- Log.d(TAG, "REMOVAL CANCELED");\r
- mCurrentDialog.dismiss();\r
- mCurrentDialog = null;\r
- }\r
- \r
- \r
- /**\r
- * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.\r
- * \r
- * @return True when the fragment was created with the empty layout.\r
- */\r
- public boolean isEmpty() {\r
- return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null);\r
- }\r
-\r
- \r
- /**\r
- * Can be used to get the file that is currently being displayed.\r
- * @return The file on the screen.\r
- */\r
- public OCFile getDisplayedFile(){\r
- return mFile;\r
- }\r
- \r
- /**\r
- * Use this method to signal this Activity that it shall update its view.\r
- * \r
- * @param file : An {@link OCFile}\r
- */\r
- public void updateFileDetails(OCFile file, Account ocAccount) {\r
- mFile = file;\r
- if (ocAccount != null && ( \r
- mStorageManager == null || \r
- (mAccount != null && !mAccount.equals(ocAccount))\r
- )) {\r
- mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
- }\r
- mAccount = ocAccount;\r
- updateFileDetails(false);\r
- }\r
- \r
-\r
- /**\r
- * Updates the view with all relevant details about that file.\r
- *\r
- * TODO Remove parameter when the transferring state of files is kept in database. \r
- * \r
- * @param transferring Flag signaling if the file should be considered as downloading or uploading, \r
- * although {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and \r
- * {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.\r
- * \r
- */\r
- public void updateFileDetails(boolean transferring) {\r
-\r
- if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
- \r
- // set file details\r
- setFilename(mFile.getFileName());\r
- setFiletype(mFile.getMimetype());\r
- setFilesize(mFile.getFileLength());\r
- if(ocVersionSupportsTimeCreated()){\r
- setTimeCreated(mFile.getCreationTimestamp());\r
- }\r
- \r
- setTimeModified(mFile.getModificationTimestamp());\r
- \r
- CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);\r
- cb.setChecked(mFile.keepInSync());\r
-\r
- // configure UI for depending upon local state of the file\r
- //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
- FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
- FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
- if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
- setButtonsForTransferring();\r
- \r
- } else if (mFile.isDown()) {\r
- // Update preview\r
- if (mFile.getMimetype().startsWith("image/")) {\r
- BitmapLoader bl = new BitmapLoader();\r
- bl.execute(new String[]{mFile.getStoragePath()});\r
- }\r
- \r
- setButtonsForDown();\r
- \r
- } else {\r
- // TODO load default preview image; when the local file is removed, the preview remains there\r
- setButtonsForRemote();\r
- }\r
- }\r
- getView().invalidate();\r
- }\r
- \r
- \r
- /**\r
- * Updates the filename in view\r
- * @param filename to set\r
- */\r
- private void setFilename(String filename) {\r
- TextView tv = (TextView) getView().findViewById(R.id.fdFilename);\r
- if (tv != null)\r
- tv.setText(filename);\r
- }\r
-\r
- /**\r
- * Updates the MIME type in view\r
- * @param mimetype to set\r
- */\r
- private void setFiletype(String mimetype) {\r
- TextView tv = (TextView) getView().findViewById(R.id.fdType);\r
- if (tv != null) {\r
- String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);; \r
- tv.setText(printableMimetype);\r
- }\r
- ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);\r
- if (iv != null) {\r
- iv.setImageResource(DisplayUtils.getResourceId(mimetype));\r
- }\r
- }\r
-\r
- /**\r
- * Updates the file size in view\r
- * @param filesize in bytes to set\r
- */\r
- private void setFilesize(long filesize) {\r
- TextView tv = (TextView) getView().findViewById(R.id.fdSize);\r
- if (tv != null)\r
- tv.setText(DisplayUtils.bytesToHumanReadable(filesize));\r
- }\r
- \r
- /**\r
- * Updates the time that the file was created in view\r
- * @param milliseconds Unix time to set\r
- */\r
- private void setTimeCreated(long milliseconds){\r
- TextView tv = (TextView) getView().findViewById(R.id.fdCreated);\r
- TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);\r
- if(tv != null){\r
- tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
- tv.setVisibility(View.VISIBLE);\r
- tvLabel.setVisibility(View.VISIBLE);\r
- }\r
- }\r
- \r
- /**\r
- * Updates the time that the file was last modified\r
- * @param milliseconds Unix time to set\r
- */\r
- private void setTimeModified(long milliseconds){\r
- TextView tv = (TextView) getView().findViewById(R.id.fdModified);\r
- if(tv != null){\r
- tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
- }\r
- }\r
- \r
- /**\r
- * Enables or disables buttons for a file being downloaded\r
- */\r
- private void setButtonsForTransferring() {\r
- if (!isEmpty()) {\r
- Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
- downloadButton.setText(R.string.common_cancel);\r
- //downloadButton.setEnabled(false);\r
- \r
- // let's protect the user from himself ;)\r
- ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
- ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);\r
- ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);\r
- getView().findViewById(R.id.fdKeepInSync).setEnabled(false);\r
- }\r
- }\r
- \r
- /**\r
- * Enables or disables buttons for a file locally available \r
- */\r
- private void setButtonsForDown() {\r
- if (!isEmpty()) {\r
- Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
- downloadButton.setText(R.string.filedetails_sync_file);\r
- \r
- ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
- ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
- ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
- getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
- }\r
- }\r
-\r
- /**\r
- * Enables or disables buttons for a file not locally available \r
- */\r
- private void setButtonsForRemote() {\r
- if (!isEmpty()) {\r
- Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
- downloadButton.setText(R.string.filedetails_download);\r
- \r
- ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
- ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
- ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
- getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
- }\r
- }\r
- \r
-\r
- /**\r
- * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return\r
- * the time that the file was created. There is a chance that this will\r
- * be fixed in future versions. Use this method to check if this version of\r
- * ownCloud has this fix.\r
- * @return True, if ownCloud the ownCloud version is supporting creation time\r
- */\r
- private boolean ocVersionSupportsTimeCreated(){\r
- /*if(mAccount != null){\r
- AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);\r
- OwnCloudVersion ocVersion = new OwnCloudVersion(accManager\r
- .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
- if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {\r
- return true;\r
- }\r
- }*/\r
- return false;\r
- }\r
- \r
- \r
- /**\r
- * Interface to implement by any Activity that includes some instance of FileDetailFragment\r
- * \r
- * @author David A. Velasco\r
- */\r
- public interface ContainerActivity extends TransferServiceGetter {\r
-\r
- /**\r
- * Callback method invoked when the detail fragment wants to notice its container \r
- * activity about a relevant state the file shown by the fragment.\r
- * \r
- * Added to notify to FileDisplayActivity about the need of refresh the files list. \r
- * \r
- * Currently called when:\r
- * - a download is started;\r
- * - a rename is completed;\r
- * - a deletion is completed;\r
- * - the 'inSync' flag is changed;\r
- */\r
- public void onFileStateChanged();\r
- \r
- }\r
- \r
-\r
- /**\r
- * Once the file download has finished -> update view\r
- * @author Bartek Przybylski\r
- */\r
- private class DownloadFinishReceiver extends BroadcastReceiver {\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-\r
- if (!isEmpty() && accountName.equals(mAccount.name)) {\r
- boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);\r
- String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
- if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
- if (downloadWasFine) {\r
- mFile = mStorageManager.getFileByPath(downloadedRemotePath);\r
- }\r
- updateFileDetails(false); // it updates the buttons; must be called although !downloadWasFine\r
- }\r
- }\r
- }\r
- }\r
- \r
- \r
- /**\r
- * Once the file upload has finished -> update view\r
- * \r
- * Being notified about the finish of an upload is necessary for the next sequence:\r
- * 1. Upload a big file.\r
- * 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\r
- * of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. \r
- * 3. Click the file in the list to see its details.\r
- * 4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.\r
- */\r
- private class UploadFinishReceiver extends BroadcastReceiver {\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
-\r
- if (!isEmpty() && accountName.equals(mAccount.name)) {\r
- boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
- String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
- boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));\r
- if (mFile.getRemotePath().equals(uploadRemotePath) ||\r
- renamedInUpload) {\r
- if (uploadWasFine) {\r
- mFile = mStorageManager.getFileByPath(uploadRemotePath);\r
- }\r
- if (renamedInUpload) {\r
- String newName = (new File(uploadRemotePath)).getName();\r
- Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);\r
- msg.show();\r
- }\r
- getSherlockActivity().removeStickyBroadcast(intent); // not the best place to do this; a small refactorization of BroadcastReceivers should be done\r
- updateFileDetails(false); // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
- }\r
- }\r
- }\r
- }\r
- \r
-\r
- // this is a temporary class for sharing purposes, it need to be replaced in transfer service\r
- @SuppressWarnings("unused")\r
- private class ShareRunnable implements Runnable {\r
- private String mPath;\r
-\r
- public ShareRunnable(String path) {\r
- mPath = path;\r
- }\r
- \r
- public void run() {\r
- AccountManager am = AccountManager.get(getActivity());\r
- Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());\r
- OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));\r
- String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);\r
-\r
- Log.d("share", "sharing for version " + ocv.toString());\r
-\r
- if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {\r
- String APPS_PATH = "/apps/files_sharing/";\r
- String SHARE_PATH = "ajax/share.php";\r
-\r
- String SHARED_PATH = "/apps/files_sharing/get.php?token=";\r
- \r
- final String WEBDAV_SCRIPT = "webdav.php";\r
- final String WEBDAV_FILES_LOCATION = "/files/";\r
- \r
- WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());\r
- HttpConnectionManagerParams params = new HttpConnectionManagerParams();\r
- params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);\r
-\r
- //wc.getParams().setParameter("http.protocol.single-cookie-header", true);\r
- //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);\r
-\r
- PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);\r
-\r
- post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );\r
- post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
- List<NameValuePair> formparams = new ArrayList<NameValuePair>();\r
- Log.d("share", mPath+"");\r
- formparams.add(new BasicNameValuePair("sources",mPath));\r
- formparams.add(new BasicNameValuePair("uid_shared_with", "public"));\r
- formparams.add(new BasicNameValuePair("permissions", "0"));\r
- post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));\r
-\r
- int status;\r
- try {\r
- PropFindMethod find = new PropFindMethod(url+"/");\r
- find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
- Log.d("sharer", ""+ url+"/");\r
- \r
- for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {\r
- Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
- }\r
- \r
- int status2 = wc.executeMethod(find);\r
-\r
- Log.d("sharer", "propstatus "+status2);\r
- \r
- GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");\r
- get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
- \r
- status2 = wc.executeMethod(get);\r
-\r
- Log.d("sharer", "getstatus "+status2);\r
- Log.d("sharer", "" + get.getResponseBodyAsString());\r
- \r
- for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {\r
- Log.d("sharer", a.getName() + ":"+a.getValue());\r
- }\r
-\r
- status = wc.executeMethod(post);\r
- for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {\r
- Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
- }\r
- for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {\r
- Log.d("sharer", a.getName() + ":"+a.getValue());\r
- }\r
- String resp = post.getResponseBodyAsString();\r
- Log.d("share", ""+post.getURI().toString());\r
- Log.d("share", "returned status " + status);\r
- Log.d("share", " " +resp);\r
- \r
- if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {\r
- return;\r
- }\r
-\r
- JSONObject jsonObject = new JSONObject (resp);\r
- String jsonStatus = jsonObject.getString("status");\r
- if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");\r
- \r
- String token = jsonObject.getString("data");\r
- String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; \r
- Log.d("Actions:shareFile ok", "url: " + uri); \r
- \r
- } catch (Exception e) {\r
- e.printStackTrace();\r
- }\r
- \r
- } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {\r
- \r
- }\r
- }\r
- }\r
- \r
- public void onDismiss(EditNameDialog dialog) {\r
- if (dialog.getResult()) {\r
- String newFilename = dialog.getNewFilename();\r
- Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
- mLastRemoteOperation = new RenameFileOperation( mFile, \r
- mAccount, \r
- newFilename, \r
- new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
- WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
- mLastRemoteOperation.execute(wc, this, mHandler);\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- }\r
- }\r
- \r
- \r
- class BitmapLoader extends AsyncTask<String, Void, Bitmap> {\r
- @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20\r
- @Override\r
- protected Bitmap doInBackground(String... params) {\r
- Bitmap result = null;\r
- if (params.length != 1) return result;\r
- String storagePath = params[0];\r
- try {\r
-\r
- BitmapFactory.Options options = new Options();\r
- options.inScaled = true;\r
- options.inPurgeable = true;\r
- options.inJustDecodeBounds = true;\r
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {\r
- options.inPreferQualityOverSpeed = false;\r
- }\r
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {\r
- options.inMutable = false;\r
- }\r
-\r
- result = BitmapFactory.decodeFile(storagePath, options);\r
- options.inJustDecodeBounds = false;\r
-\r
- int width = options.outWidth;\r
- int height = options.outHeight;\r
- int scale = 1;\r
- if (width >= 2048 || height >= 2048) {\r
- scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));\r
- options.inSampleSize = scale;\r
- }\r
- Display display = getActivity().getWindowManager().getDefaultDisplay();\r
- Point size = new Point();\r
- int screenwidth;\r
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {\r
- display.getSize(size);\r
- screenwidth = size.x;\r
- } else {\r
- screenwidth = display.getWidth();\r
- }\r
-\r
- Log.e("ASD", "W " + width + " SW " + screenwidth);\r
-\r
- if (width > screenwidth) {\r
- scale = (int) Math.ceil((float)width / screenwidth);\r
- options.inSampleSize = scale;\r
- }\r
-\r
- result = BitmapFactory.decodeFile(storagePath, options);\r
-\r
- Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight);\r
-\r
- } catch (OutOfMemoryError e) {\r
- result = null;\r
- Log.e(TAG, "Out of memory occured for file with size " + storagePath);\r
- \r
- } catch (NoSuchFieldError e) {\r
- result = null;\r
- Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);\r
- \r
- } catch (Throwable t) {\r
- result = null;\r
- Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);\r
- }\r
- return result;\r
- }\r
- @Override\r
- protected void onPostExecute(Bitmap result) {\r
- if (result != null && mPreview != null) {\r
- mPreview.setImageBitmap(result);\r
- }\r
- }\r
- \r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
- if (operation.equals(mLastRemoteOperation)) {\r
- if (operation instanceof RemoveFileOperation) {\r
- onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
- \r
- } else if (operation instanceof RenameFileOperation) {\r
- onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
- \r
- } else if (operation instanceof SynchronizeFileOperation) {\r
- onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
- }\r
- }\r
- }\r
- \r
- \r
- private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- \r
- if (result.isSuccess()) {\r
- Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);\r
- msg.show();\r
- if (inDisplayActivity) {\r
- // double pane\r
- FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
- transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
- transaction.commit();\r
- mContainerActivity.onFileStateChanged();\r
- } else {\r
- getActivity().finish();\r
- }\r
- \r
- } else {\r
- Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- if (result.isSslRecoverableException()) {\r
- // TODO show the SSL warning dialog\r
- }\r
- }\r
- }\r
- \r
- private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- \r
- if (result.isSuccess()) {\r
- updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);\r
- mContainerActivity.onFileStateChanged();\r
- \r
- } else {\r
- if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {\r
- Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- // TODO throw again the new rename dialog\r
- } else {\r
- Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- if (result.isSslRecoverableException()) {\r
- // TODO show the SSL warning dialog\r
- }\r
- }\r
- }\r
- }\r
- \r
- private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-\r
- if (!result.isSuccess()) {\r
- if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
- Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);\r
- i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile);\r
- i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);\r
- startActivity(i);\r
- \r
- } else {\r
- Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- }\r
- \r
- if (mFile.isDown()) {\r
- setButtonsForDown();\r
- \r
- } else {\r
- setButtonsForRemote();\r
- }\r
- \r
- } else {\r
- if (operation.transferWasRequested()) {\r
- mContainerActivity.onFileStateChanged(); // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so \r
- // checking the service to see if the file is downloading results in FALSE\r
- } else {\r
- Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- if (mFile.isDown()) {\r
- setButtonsForDown();\r
- \r
- } else {\r
- setButtonsForRemote();\r
- }\r
- }\r
- }\r
- }\r
-\r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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<NameValuePair> formparams = new ArrayList<NameValuePair>();
+ 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<String, Void, Bitmap> {
+ @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();
+ }
+ }
+ }
+ }
+
+}
import android.widget.ImageView;
import android.widget.ListView;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
/**
*/
@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;
}
*/
@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");
}
}
} else {
- Log.w(TAG, "Null object in ListAdapter!!");
+ Log_OC.w(TAG, "Null object in ListAdapter!!");
}
}
// 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();
}
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<positions.size(); i++) {
result[i] = ((File) mList.getItemAtPosition(positions.keyAt(i))).getAbsolutePath();
import java.util.List;
import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.DataStorageManager;
import com.owncloud.android.datamodel.OCFile;
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
- Log.i(TAG, "onActivityCreated() start");
+ Log_OC.i(TAG, "onActivityCreated() start");
super.onActivityCreated(savedInstanceState);
mAdapter = new FileListListAdapter(mContainerActivity.getInitialDirectory(), mContainerActivity.getStorageManager(), getActivity(), mContainerActivity);
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);
}
mHandler = new Handler();
- 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");
}
}
} else {
- Log.d(TAG, "Null object in ListAdapter!!");
+ Log_OC.d(TAG, "Null object in ListAdapter!!");
}
}
startActivity(i);
} catch (Throwable t) {
- Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mTargetFile.getMimetype());
+ Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mTargetFile.getMimetype());
boolean toastIt = true;
String mimeType = "";
try {
}
} catch (IndexOutOfBoundsException e) {
- Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+ Log_OC.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");
+ Log_OC.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);
+ Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
} finally {
if (toastIt) {
// 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 = storageManager.getFileById(directory.getParentId());
}
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,
@Override
public void onCancel(String callerTag) {
- Log.d(TAG, "REMOVAL CANCELED");
+ Log_OC.d(TAG, "REMOVAL CANCELED");
if (mCurrentDialog != null) {
mCurrentDialog.dismiss();
mCurrentDialog = null;
import org.apache.commons.httpclient.methods.RequestEntity;
+import com.owncloud.android.Log_OC;
+
import eu.alefzero.webdav.OnDatatransferProgressListener;
import android.util.Log;
}
} 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);
}
import org.apache.commons.httpclient.methods.RequestEntity;
+import com.owncloud.android.Log_OC;
+
import eu.alefzero.webdav.OnDatatransferProgressListener;
import android.util.Log;
}
} 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 {
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.webdav;\r
-\r
-import java.io.BufferedInputStream;\r
-import java.io.File;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-\r
-import org.apache.commons.httpclient.Credentials;\r
-import org.apache.commons.httpclient.HttpClient;\r
-import org.apache.commons.httpclient.HttpConnectionManager;\r
-import org.apache.commons.httpclient.HttpException;\r
-import org.apache.commons.httpclient.HttpMethodBase;\r
-import org.apache.commons.httpclient.HttpVersion;\r
-import org.apache.commons.httpclient.UsernamePasswordCredentials;\r
-import org.apache.commons.httpclient.auth.AuthScope;\r
-import org.apache.commons.httpclient.methods.GetMethod;\r
-import org.apache.commons.httpclient.methods.HeadMethod;\r
-import org.apache.commons.httpclient.methods.PutMethod;\r
-import org.apache.commons.httpclient.params.HttpMethodParams;\r
-import org.apache.http.HttpStatus;\r
-import org.apache.http.params.CoreProtocolPNames;\r
-import org.apache.jackrabbit.webdav.client.methods.DavMethod;\r
-import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
-import org.apache.jackrabbit.webdav.client.methods.MkColMethod;\r
-\r
-import android.net.Uri;\r
-import android.util.Log;\r
-\r
-public class WebdavClient extends HttpClient {\r
- private Uri mUri;\r
- private Credentials mCredentials;\r
- final private static String TAG = "WebdavClient";\r
- private static final String USER_AGENT = "Android-ownCloud";\r
- \r
- private OnDatatransferProgressListener mDataTransferListener;\r
- static private byte[] sExhaustBuffer = new byte[1024];\r
- \r
- /**\r
- * Constructor\r
- */\r
- public WebdavClient(HttpConnectionManager connectionMgr) {\r
- super(connectionMgr);\r
- Log.d(TAG, "Creating WebdavClient");\r
- getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);\r
- getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);\r
- }\r
-\r
- public void setCredentials(String username, String password) {\r
- getParams().setAuthenticationPreemptive(true);\r
- getState().setCredentials(AuthScope.ANY,\r
- getCredentials(username, password));\r
- }\r
-\r
- private Credentials getCredentials(String username, String password) {\r
- if (mCredentials == null)\r
- mCredentials = new UsernamePasswordCredentials(username, password);\r
- return mCredentials;\r
- }\r
- \r
- /**\r
- * Downloads a file in remoteFilepath to the local targetPath.\r
- * \r
- * @param remoteFilepath Path to the file in the remote server, URL DECODED. \r
- * @param targetFile Local path to save the downloaded file.\r
- * @return 'True' when the file is successfully downloaded.\r
- */\r
- public boolean downloadFile(String remoteFilePath, File targetFile) {\r
- boolean ret = false;\r
- GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));\r
-\r
- try {\r
- int status = executeMethod(get);\r
- if (status == HttpStatus.SC_OK) {\r
- targetFile.createNewFile();\r
- BufferedInputStream bis = new BufferedInputStream(\r
- get.getResponseBodyAsStream());\r
- FileOutputStream fos = new FileOutputStream(targetFile);\r
-\r
- byte[] bytes = new byte[4096];\r
- int readResult;\r
- while ((readResult = bis.read(bytes)) != -1) {\r
- if (mDataTransferListener != null)\r
- mDataTransferListener.onTransferProgress(readResult);\r
- fos.write(bytes, 0, readResult);\r
- }\r
- fos.close();\r
- ret = true;\r
- } else {\r
- exhaustResponse(get.getResponseBodyAsStream());\r
- }\r
- Log.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));\r
- } catch (Exception e) {\r
- logException(e, "dowloading " + remoteFilePath);\r
- \r
- } finally {\r
- if (!ret && targetFile.exists()) {\r
- targetFile.delete();\r
- }\r
- get.releaseConnection(); // let the connection available for other methods\r
- }\r
- return ret;\r
- }\r
- \r
- /**\r
- * Deletes a remote file via webdav\r
- * @param remoteFilePath Remote file path of the file to delete, in URL DECODED format.\r
- * @return\r
- */\r
- public boolean deleteFile(String remoteFilePath) {\r
- boolean ret = false;\r
- DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));\r
- try {\r
- int status = executeMethod(delete);\r
- ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);\r
- exhaustResponse(delete.getResponseBodyAsStream());\r
- \r
- Log.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status + (!ret?"(FAIL)":""));\r
- \r
- } catch (Exception e) {\r
- logException(e, "deleting " + remoteFilePath);\r
- \r
- } finally {\r
- delete.releaseConnection(); // let the connection available for other methods\r
- }\r
- return ret;\r
- }\r
-\r
- \r
- public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {\r
- mDataTransferListener = listener;\r
- }\r
- \r
- /**\r
- * Creates or update a file in the remote server with the contents of a local file.\r
- * \r
- * @param localFile Path to the local file to upload.\r
- * @param remoteTarget Remote path to the file to create or update, URL DECODED\r
- * @param contentType MIME type of the file.\r
- * @return Status HTTP code returned by the server.\r
- * @throws IOException When a transport error that could not be recovered occurred while uploading the file to the server.\r
- * @throws HttpException When a violation of the HTTP protocol occurred. \r
- */\r
- public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {\r
- int status = -1;\r
- PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));\r
- \r
- try {\r
- File f = new File(localFile);\r
- FileRequestEntity entity = new FileRequestEntity(f, contentType);\r
- entity.addOnDatatransferProgressListener(mDataTransferListener);\r
- put.setRequestEntity(entity);\r
- status = executeMethod(put);\r
- \r
- exhaustResponse(put.getResponseBodyAsStream());\r
- \r
- } finally {\r
- put.releaseConnection(); // let the connection available for other methods\r
- }\r
- return status;\r
- }\r
- \r
- /**\r
- * Tries to log in to the current URI, with the current credentials\r
- * \r
- * @return A {@link HttpStatus}-Code of the result. SC_OK is good.\r
- */\r
- public int tryToLogin() {\r
- int status = 0;\r
- HeadMethod head = new HeadMethod(mUri.toString());\r
- try {\r
- status = executeMethod(head);\r
- boolean result = status == HttpStatus.SC_OK;\r
- Log.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));\r
- exhaustResponse(head.getResponseBodyAsStream());\r
- \r
- } catch (Exception e) {\r
- logException(e, "trying to login at " + mUri.toString());\r
- \r
- } finally {\r
- head.releaseConnection();\r
- }\r
- return status;\r
- }\r
-\r
- /**\r
- * Creates a remote directory with the received path.\r
- * \r
- * @param path Path of the directory to create, URL DECODED\r
- * @return 'True' when the directory is successfully created\r
- */\r
- public boolean createDirectory(String path) {\r
- boolean result = false;\r
- int status = -1;\r
- MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path));\r
- try {\r
- Log.d(TAG, "Creating directory " + path);\r
- status = executeMethod(mkcol);\r
- Log.d(TAG, "Status returned: " + status);\r
- result = mkcol.succeeded();\r
- \r
- Log.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":""));\r
- exhaustResponse(mkcol.getResponseBodyAsStream());\r
- \r
- } catch (Exception e) {\r
- logException(e, "creating directory " + path);\r
- \r
- } finally {\r
- mkcol.releaseConnection(); // let the connection available for other methods\r
- }\r
- return result;\r
- }\r
- \r
- \r
- /**\r
- * Check if a file exists in the OC server\r
- * \r
- * @return 'true' if the file exists; 'false' it doesn't exist\r
- * @throws Exception When the existence could not be determined\r
- */\r
- public boolean existsFile(String path) throws IOException, HttpException {\r
- HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));\r
- try {\r
- int status = executeMethod(head);\r
- Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));\r
- exhaustResponse(head.getResponseBodyAsStream());\r
- return (status == HttpStatus.SC_OK);\r
- \r
- } finally {\r
- head.releaseConnection(); // let the connection available for other methods\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Requests the received method with the received timeout (milliseconds).\r
- * \r
- * Executes the method through the inherited HttpClient.executedMethod(method).\r
- * \r
- * Sets the socket and connection timeouts only for the method received.\r
- * \r
- * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'\r
- * \r
- * @param method HTTP method request.\r
- * @param readTimeout Timeout to set for data reception\r
- * @param conntionTimout Timeout to set for connection establishment\r
- */\r
- public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {\r
- int oldSoTimeout = getParams().getSoTimeout();\r
- int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();\r
- try {\r
- if (readTimeout >= 0) { \r
- method.getParams().setSoTimeout(readTimeout); // this should be enough...\r
- getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS\r
- }\r
- if (connectionTimeout >= 0) {\r
- getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);\r
- }\r
- return executeMethod(method);\r
- } finally {\r
- getParams().setSoTimeout(oldSoTimeout);\r
- getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);\r
- }\r
- }\r
-\r
- /**\r
- * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.\r
- * \r
- * @param responseBodyAsStream InputStream with the HTTP response to exhaust.\r
- */\r
- public void exhaustResponse(InputStream responseBodyAsStream) {\r
- if (responseBodyAsStream != null) {\r
- try {\r
- while (responseBodyAsStream.read(sExhaustBuffer) >= 0);\r
- responseBodyAsStream.close();\r
- \r
- } catch (IOException io) {\r
- Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);\r
- }\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Logs an exception triggered in a HTTP request. \r
- * \r
- * @param e Caught exception.\r
- * @param doing Suffix to add at the end of the logged message.\r
- */\r
- private void logException(Exception e, String doing) {\r
- if (e instanceof HttpException) {\r
- Log.e(TAG, "HTTP violation while " + doing, e);\r
-\r
- } else if (e instanceof IOException) {\r
- Log.e(TAG, "Unrecovered transport exception while " + doing, e);\r
-\r
- } else {\r
- Log.e(TAG, "Unexpected exception while " + doing, e);\r
- }\r
- }\r
-\r
- \r
- /**\r
- * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.\r
- */\r
- public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {\r
- getParams().setSoTimeout(defaultDataTimeout);\r
- getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);\r
- }\r
-\r
- /**\r
- * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs\r
- * @param uri\r
- */\r
- public void setBaseUri(Uri uri) {\r
- mUri = uri;\r
- }\r
-\r
- public Uri getBaseUri() {\r
- return mUri;\r
- }\r
-\r
-}\r
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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;
+ }
+
+}
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;
}
} else {
- Log.e("WebdavEntry",
+ Log_OC.e("WebdavEntry",
"General fuckup, no status for webdav response");
}
}