From: Bartek Przybylski Date: Tue, 31 Jul 2012 15:43:37 +0000 (+0200) Subject: moving from eu.alefzero.eu to com.owncloud.android X-Git-Tag: oc-android-1.4.3~219 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/a4ba6170ea7696e085b07adfef73eeb8b77cb8e2 moving from eu.alefzero.eu to com.owncloud.android --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 53a199dd..a75fbfbf 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . --> - @@ -123,11 +123,6 @@ - - - - - diff --git a/res/layout-land/account_setup.xml b/res/layout-land/account_setup.xml index 1420234d..1a452ddf 100644 --- a/res/layout-land/account_setup.xml +++ b/res/layout-land/account_setup.xml @@ -17,7 +17,7 @@ along with this program. If not, see . --> - \ No newline at end of file + diff --git a/res/layout-large-land/files.xml b/res/layout-large-land/files.xml index 32d86b0a..13d16f99 100644 --- a/res/layout-large-land/files.xml +++ b/res/layout-large-land/files.xml @@ -32,7 +32,7 @@ android:id="@+id/fileList" android:layout_width="fill_parent" android:layout_height="fill_parent" - class="eu.alefzero.owncloud.ui.fragment.FileListFragment" > + class="com.owncloud.android.ui.fragment.FileListFragment" > @@ -46,4 +46,4 @@ - \ No newline at end of file + diff --git a/res/layout/account_setup.xml b/res/layout/account_setup.xml index 65e1cd9f..5f128722 100644 --- a/res/layout/account_setup.xml +++ b/res/layout/account_setup.xml @@ -17,7 +17,7 @@ along with this program. If not, see . --> - \ No newline at end of file + diff --git a/res/layout/files.xml b/res/layout/files.xml index 9f868cab..78f8daf0 100644 --- a/res/layout/files.xml +++ b/res/layout/files.xml @@ -27,9 +27,9 @@ android:id="@+id/fileList" android:layout_width="fill_parent" android:layout_height="fill_parent" - class="eu.alefzero.owncloud.ui.fragment.FileListFragment" > + class="com.owncloud.android.ui.fragment.FileListFragment" > - \ No newline at end of file + diff --git a/res/layout/pincodelock.xml b/res/layout/pincodelock.xml index 61645fed..a02ca267 100644 --- a/res/layout/pincodelock.xml +++ b/res/layout/pincodelock.xml @@ -16,7 +16,7 @@ along with this program. If not, see . --> - \ No newline at end of file + diff --git a/src/com/owncloud/android/AccountUtils.java b/src/com/owncloud/android/AccountUtils.java new file mode 100644 index 00000000..9c487939 --- /dev/null +++ b/src/com/owncloud/android/AccountUtils.java @@ -0,0 +1,109 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android; + +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.utils.OwnCloudVersion; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +public class AccountUtils { + public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; + public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; + public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav"; + public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php"; + public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php"; + public static final String STATUS_PATH = "/status.php"; + + /** + * Can be used to get the currently selected ownCloud account in the + * preferences + * + * @param context The current appContext + * @return The current account or first available, if none is available, + * then null. + */ + public static Account getCurrentOwnCloudAccount(Context context) { + Account[] ocAccounts = AccountManager.get(context).getAccountsByType( + AccountAuthenticator.ACCOUNT_TYPE); + Account defaultAccount = null; + + SharedPreferences appPreferences = PreferenceManager + .getDefaultSharedPreferences(context); + String accountName = appPreferences + .getString("select_oc_account", null); + + if (accountName != null) { + for (Account account : ocAccounts) { + if (account.name.equals(accountName)) { + defaultAccount = account; + break; + } + } + } else if (ocAccounts.length != 0) { + // we at least need to take first account as fallback + defaultAccount = ocAccounts[0]; + } + + return defaultAccount; + } + + + + /** + * Checks, whether or not there are any ownCloud accounts setup. + * + * @return true, if there is at least one account. + */ + public static boolean accountsAreSetup(Context context) { + AccountManager accMan = AccountManager.get(context); + Account[] accounts = accMan + .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + return accounts.length > 0; + } + + + public static void setCurrentOwnCloudAccount(Context context, String name) { + SharedPreferences.Editor appPrefs = PreferenceManager + .getDefaultSharedPreferences(context).edit(); + appPrefs.putString("select_oc_account", name); + appPrefs.commit(); + } + + /** + * + * @param version version of owncloud + * @return webdav path for given OC version, null if OC version unknown + */ + public static String getWebdavPath(OwnCloudVersion version) { + if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0) + return WEBDAV_PATH_4_0; + if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0 + || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0) + return WEBDAV_PATH_2_0; + if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0) + return WEBDAV_PATH_1_2; + return null; + } + +} diff --git a/src/com/owncloud/android/CrashHandler.java b/src/com/owncloud/android/CrashHandler.java new file mode 100644 index 00000000..e2ceb10b --- /dev/null +++ b/src/com/owncloud/android/CrashHandler.java @@ -0,0 +1,154 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.LinkedList; +import java.util.List; + +import com.owncloud.android.authenticator.AccountAuthenticator; + + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.net.ConnectivityManager; +import android.os.Environment; +import android.util.Log; + +public class CrashHandler implements UncaughtExceptionHandler { + + public static final String KEY_CRASH_FILENAME = "KEY_CRASH_FILENAME"; + + private Context mContext; + private static final String TAG = "CrashHandler"; + private static final String crash_filename_template = "crash"; + private static List TAGS; + private UncaughtExceptionHandler defaultUEH; + + // TODO: create base activity which will register for crashlog tag automaticly + static { + TAGS = new LinkedList(); + TAGS.add("AccountAuthenticator"); + TAGS.add("AccountAuthenticator"); + TAGS.add("ConnectionCheckerRunnable"); + TAGS.add("EasySSLSocketFactory"); + TAGS.add("FileDataStorageManager"); + TAGS.add("PhotoTakenBroadcastReceiver"); + TAGS.add("InstantUploadService"); + TAGS.add("FileDownloader"); + TAGS.add("FileUploader"); + TAGS.add("LocationUpdateService"); + TAGS.add("FileSyncAdapter"); + TAGS.add("AuthActivity"); + TAGS.add("OwnCloudPreferences"); + TAGS.add("FileDetailFragment"); + TAGS.add("FileListFragment"); + TAGS.add("ownCloudUploader"); + TAGS.add("WebdavClient"); + } + + public CrashHandler(Context context) { + mContext = context; + defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); + } + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + final Writer writer = new StringWriter(); + final PrintWriter printwriter = new PrintWriter(writer); + ex.printStackTrace(printwriter); + final String startrace = writer.toString(); + printwriter.close(); + File ocdir = new File(Environment.getExternalStorageDirectory().getAbsoluteFile(), "owncloud"); + ocdir.mkdirs(); + + String crash_filename = crash_filename_template + System.currentTimeMillis() + ".txt"; + File crashfile = new File(ocdir, crash_filename); + try { + PackageInfo pi = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); + ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + String header = String.format("Model: %s, SDK: %d, Current net: %s AppVersion: %s\n\n", + android.os.Build.MODEL, + android.os.Build.VERSION.SDK_INT, + cm.getActiveNetworkInfo() != null ? cm.getActiveNetworkInfo().getTypeName() : "NONE", + pi.versionName); + Account account = AccountUtils.getCurrentOwnCloudAccount(mContext); + AccountManager am = AccountManager.get(mContext); + String header2 = String.format("Account: %s, OCUrl: %s, OCVersion: %s\n\n", + account.name, + am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL), + am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); + + crashfile.createNewFile(); + FileWriter fw = new FileWriter(crashfile); + fw.write(header); + fw.write(header2); + fw.write(startrace); + fw.write("\n\n"); + + String logcat = "logcat -d *:S "; + + for (String s : TAGS) + logcat += s + ":V "; + + Process process = Runtime.getRuntime().exec(logcat); + BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); + String logline; + while ((logline = br.readLine()) != null) + fw.write(logline+"\n"); + + br.close(); + fw.close(); + + Intent dataintent = new Intent(mContext, CrashlogSendActivity.class); + dataintent.putExtra(KEY_CRASH_FILENAME, crashfile.getAbsolutePath()); + PendingIntent intent; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + intent = PendingIntent.getActivity(mContext.getApplicationContext(), 0, dataintent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + } else { + intent = PendingIntent.getActivity(mContext.getApplicationContext(), 0, dataintent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + } + AlarmManager mngr = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + if (mngr == null) { + Log.e(TAG, "Couldn't retrieve alarm manager!"); + defaultUEH.uncaughtException(thread, ex); + return; + } + mngr.set(AlarmManager.RTC, System.currentTimeMillis(), intent); + System.exit(2); + } catch (Exception e1) { + Log.e(TAG, "Crash handler failed!"); + Log.e(TAG, e1.toString()); + defaultUEH.uncaughtException(thread, ex); + return; + } + } +} diff --git a/src/com/owncloud/android/CrashlogSendActivity.java b/src/com/owncloud/android/CrashlogSendActivity.java new file mode 100644 index 00000000..7f4074fc --- /dev/null +++ b/src/com/owncloud/android/CrashlogSendActivity.java @@ -0,0 +1,112 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android; + +import java.io.File; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.util.Log; + +import com.actionbarsherlock.app.SherlockActivity; + +import com.owncloud.android.R; + +public class CrashlogSendActivity extends SherlockActivity implements OnClickListener, OnCancelListener { + + private static final String TAG = "CrashlogSendActivity"; + private static final String CRASHLOG_SUBMIT_URL = "http://alefzero.eu/a/crashlog/"; + private static final int DIALOG_SUBMIT = 5; + + private String mLogFilename; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mLogFilename = getIntent().getStringExtra(CrashHandler.KEY_CRASH_FILENAME); + if (mLogFilename == null) { + Log.wtf(TAG, "No file crashlog path given!"); + finish(); + return; + } + Log.i(TAG, "crashlog file path " + mLogFilename); + + showDialog(DIALOG_SUBMIT); + } + + + @Override + protected Dialog onCreateDialog(int id) { + if (id == DIALOG_SUBMIT) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.crashlog_message); + builder.setNegativeButton(R.string.crashlog_dont_send_report, this); + builder.setPositiveButton(R.string.crashlog_send_report, this); + builder.setCancelable(true); + builder.setOnCancelListener(this); + return builder.create(); + } + return super.onCreateDialog(id); + } + + + @Override + public void onClick(DialogInterface dialog, final int which) { + new Thread(new Runnable() { + + @Override + public void run() { + // TODO Auto-generated method stub + File file = new File(mLogFilename); + if (which == Dialog.BUTTON_POSITIVE) { + try { + HttpClient client = new HttpClient(); + PostMethod post = new PostMethod(CRASHLOG_SUBMIT_URL); + Part[] parts = {new FilePart("crashfile", file)}; + post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams())); + client.executeMethod(post); + post.releaseConnection(); + } catch (Exception e) { + e.printStackTrace(); + } + } + file.delete(); + finish(); + } + }).start(); + } + + + @Override + public void onCancel(DialogInterface dialog) { + new File(mLogFilename).delete(); + finish(); + } + +} diff --git a/src/com/owncloud/android/DisplayUtils.java b/src/com/owncloud/android/DisplayUtils.java new file mode 100644 index 00000000..a9cfe1dc --- /dev/null +++ b/src/com/owncloud/android/DisplayUtils.java @@ -0,0 +1,117 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android; + +import java.util.Date; +import java.util.HashMap; + +/** + * A helper class for some string operations. + * + * @author Bartek Przybylski + * + */ +public class DisplayUtils { + + private static final String[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; + + private static HashMap mimeType2HUmanReadable; + static { + mimeType2HUmanReadable = new HashMap(); + // images + mimeType2HUmanReadable.put("image/jpeg", "JPEG image"); + mimeType2HUmanReadable.put("image/jpg", "JPEG image"); + mimeType2HUmanReadable.put("image/png", "PNG image"); + mimeType2HUmanReadable.put("image/bmp", "Bitmap image"); + mimeType2HUmanReadable.put("image/gif", "GIF image"); + mimeType2HUmanReadable.put("image/svg+xml", "JPEG image"); + mimeType2HUmanReadable.put("image/tiff", "TIFF image"); + // music + mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file"); + mimeType2HUmanReadable.put("application/ogg", "OGG music file"); + + } + + /** + * Converts the file size in bytes to human readable output. + * + * @param bytes Input file size + * @return Like something readable like "12 MB" + */ + public static String bytesToHumanReadable(long bytes) { + double result = bytes; + int attachedsuff = 0; + while (result > 1024 && attachedsuff < suffixes.length) { + result /= 1024.; + attachedsuff++; + } + result = ((int) (result * 100)) / 100.; + return result + " " + suffixes[attachedsuff]; + } + + /** + * Removes special HTML entities from a string + * + * @param s Input string + * @return A cleaned version of the string + */ + public static String HtmlDecode(String s) { + /* + * TODO: Perhaps we should use something more proven like: + * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29 + */ + + String ret = ""; + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '%') { + ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16); + i += 2; + } else { + ret += s.charAt(i); + } + } + return ret; + } + + /** + * Converts MIME types like "image/jpg" to more end user friendly output + * like "JPG image". + * + * @param mimetype MIME type to convert + * @return A human friendly version of the MIME type + */ + public static String convertMIMEtoPrettyPrint(String mimetype) { + if (mimeType2HUmanReadable.containsKey(mimetype)) { + return mimeType2HUmanReadable.get(mimetype); + } + if (mimetype.split("/").length >= 2) + return mimetype.split("/")[1].toUpperCase() + " file"; + return "Unknown type"; + } + + /** + * Converts Unix time to human readable format + * @param miliseconds that have passed since 01/01/1970 + * @return The human readable time for the users locale + */ + public static String unixTimeToHumanReadable(long milliseconds) { + Date date = new Date(milliseconds); + return date.toLocaleString(); + } +} diff --git a/src/com/owncloud/android/OwnCloudSession.java b/src/com/owncloud/android/OwnCloudSession.java new file mode 100644 index 00000000..67f9b8e1 --- /dev/null +++ b/src/com/owncloud/android/OwnCloudSession.java @@ -0,0 +1,56 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android; + +/** + * Represents a session to an ownCloud instance + * + * @author Bartek Przybylski + * + */ +public class OwnCloudSession { + private String mSessionName; + private String mSessionUrl; + private int mEntryId; + + public OwnCloudSession(String name, String url, int entryId) { + mSessionName = name; + mSessionUrl = url; + mEntryId = entryId; + } + + public void setName(String name) { + mSessionName = name; + } + + public String getName() { + return mSessionName; + } + + public void setUrl(String url) { + mSessionUrl = url; + } + + public String getUrl() { + return mSessionUrl; + } + + public int getEntryId() { + return mEntryId; + } +} diff --git a/src/com/owncloud/android/Uploader.java b/src/com/owncloud/android/Uploader.java new file mode 100644 index 00000000..718911d3 --- /dev/null +++ b/src/com/owncloud/android/Uploader.java @@ -0,0 +1,415 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +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 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 com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +/** + * This can be used to upload things to an ownCloud instance. + * + * @author Bartek Przybylski + * + */ +public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { + private static final String TAG = "ownCloudUploader"; + + private Account mAccount; + private AccountManager mAccountManager; + private Stack mParents; + private ArrayList mStreamsToUpload; + private boolean mCreateDir; + private String mUploadPath; + private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE }; + private DataStorageManager mStorageManager; + private OCFile mFile; + + private final static int DIALOG_NO_ACCOUNT = 0; + private final static int DIALOG_WAITING = 1; + private final static int DIALOG_NO_STREAM = 2; + private final static int DIALOG_MULTIPLE_ACCOUNT = 3; + private final static int DIALOG_GET_DIRNAME = 4; + + private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + mParents = new Stack(); + mParents.add(""); + if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { + prepareStreamsToUpload(); + mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + if (accounts.length == 0) { + Log.i(TAG, "No ownCloud account is available"); + showDialog(DIALOG_NO_ACCOUNT); + } else if (accounts.length > 1) { + Log.i(TAG, "More then one ownCloud is available"); + showDialog(DIALOG_MULTIPLE_ACCOUNT); + } else { + mAccount = accounts[0]; + setContentView(R.layout.uploader_layout); + 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(R.string.uploader_wrn_no_account_text); + builder.setCancelable(false); + builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { + 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() { + 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() { + 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() { + public void onCancel(DialogInterface dialog) { + dialog.cancel(); + 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; + } + + 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(); + } + } + + public void onItemClick(AdapterView parent, View view, int position, long id) { + // click on folder in the list + Log.d(TAG, "on item click"); + Vector tmpfiles = mStorageManager.getDirectoryContent(mFile); + if (tmpfiles == null) return; + // filter on dirtype + Vector files = new Vector(); + for (OCFile f : tmpfiles) + if (f.isDirectory()) + files.add(f); + if (files.size() < position) { + throw new IndexOutOfBoundsException("Incorrect item selected"); + } + mParents.push(files.get(position).getFileName()); + populateDirectoryList(); + } + + public void onClick(View v) { + // click on button + switch (v.getId()) { + case R.id.uploader_choose_folder: + mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix + for (String p : mParents) + mUploadPath += p + OCFile.PATH_SEPARATOR; + Log.d(TAG, "Uploading file to dir " + mUploadPath); + + uploadFiles(); + + break; + case android.R.id.button1: // dynamic action for create aditional dir + showDialog(DIALOG_GET_DIRNAME); + break; + default: + throw new IllegalArgumentException("Wrong element clicked"); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); + if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { + dismissDialog(DIALOG_NO_ACCOUNT); + if (resultCode == RESULT_CANCELED) { + finish(); + } + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); + if (accounts.length == 0) { + showDialog(DIALOG_NO_ACCOUNT); + } else { + // there is no need for checking for is there more then one + // account at this point + // since account setup can set only one account at time + mAccount = accounts[0]; + populateDirectoryList(); + } + } + } + + private void populateDirectoryList() { + setContentView(R.layout.uploader_layout); + + String full_path = ""; + for (String a : mParents) + full_path += a + "/"; + + Log.d(TAG, "Populating view with content of : " + full_path); + + mFile = mStorageManager.getFileByPath(full_path); + if (mFile != null) { + Vector files = mStorageManager.getDirectoryContent(mFile); + if (files != null) { + List> data = new LinkedList>(); + for (OCFile f : files) { + HashMap h = new HashMap(); + if (f.isDirectory()) { + h.put("dirname", f.getFileName()); + data.add(h); + } + } + SimpleAdapter sa = new SimpleAdapter(this, + data, + R.layout.uploader_list_item_layout, + new String[] {"dirname"}, + new int[] {R.id.textView1}); + setListAdapter(sa); + Button btn = (Button) findViewById(R.id.uploader_choose_folder); + btn.setOnClickListener(this); + getListView().setOnItemClickListener(this); + } + } + /* + mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, null, ProviderTableMeta.FILE_NAME + + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", new String[] { "/", mAccount.name }, null); + + if (mCursor.moveToFirst()) { + mCursor = managedQuery( + ProviderMeta.ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_CONTENT_TYPE + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + + ProviderTableMeta.FILE_PARENT + "=?", + new String[] { "DIR", mAccount.name, + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)) }, null); + + ListView lv = getListView(); + lv.setOnItemClickListener(this); + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, mCursor, + new String[] { ProviderTableMeta.FILE_NAME }, new int[] { R.id.textView1 }); + setListAdapter(sca); + Button btn = (Button) findViewById(R.id.uploader_choose_folder); + btn.setOnClickListener(this); + /* + * disable this until new server interaction service wont be created + * // insert create new directory for multiple items uploading if + * (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + * Button createDirBtn = new Button(this); + * createDirBtn.setId(android.R.id.button1); + * createDirBtn.setText(R.string.uploader_btn_create_dir_text); + * createDirBtn.setOnClickListener(this); ((LinearLayout) + * findViewById(R.id.linearLayout1)).addView( createDirBtn, + * LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); } + * + }*/ + } + + private void prepareStreamsToUpload() { + if (getIntent().getAction().equals(Intent.ACTION_SEND)) { + mStreamsToUpload = new ArrayList(); + mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); + } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); + } else { + // unknow action inserted + throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction()); + } + } + + public void uploadFiles() { + WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); + wdc.allowSelfsignedCertificates(); + + // create last directory in path if nessesary + 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(); + } + +} diff --git a/src/com/owncloud/android/authenticator/AccountAuthenticator.java b/src/com/owncloud/android/authenticator/AccountAuthenticator.java new file mode 100644 index 00000000..543b0df5 --- /dev/null +++ b/src/com/owncloud/android/authenticator/AccountAuthenticator.java @@ -0,0 +1,281 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.authenticator; + +import com.owncloud.android.ui.activity.AuthenticatorActivity; + +import android.accounts.*; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +public class AccountAuthenticator extends AbstractAccountAuthenticator { + /** + * Is used by android system to assign accounts to authenticators. Should be + * used by application and all extensions. + */ + public static final String ACCOUNT_TYPE = "owncloud"; + public static final String AUTH_TOKEN_TYPE = "org.owncloud"; + + public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType"; + public static final String KEY_REQUIRED_FEATURES = "requiredFeatures"; + public static final String KEY_LOGIN_OPTIONS = "loginOptions"; + public static final String KEY_ACCOUNT = "account"; + /** + * Value under this key should handle path to webdav php script. Will be + * removed and usage should be replaced by combining + * {@link eu.alefzero.owncloud.authenticator.KEY_OC_BASE_URL} and + * {@link com.owncloud.android.utils.OwnCloudVersion} + * + * @deprecated + */ + public static final String KEY_OC_URL = "oc_url"; + /** + * Version should be 3 numbers separated by dot so it can be parsed by + * {@link com.owncloud.android.utils.OwnCloudVersion} + */ + public static final String KEY_OC_VERSION = "oc_version"; + /** + * Base url should point to owncloud installation without trailing / ie: + * http://server/path or https://owncloud.server + */ + public static final String KEY_OC_BASE_URL = "oc_base_url"; + + private static final String TAG = "AccountAuthenticator"; + private Context mContext; + + public AccountAuthenticator(Context context) { + super(context); + mContext = context; + } + + /** + * {@inheritDoc} + */ + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, + String accountType, String authTokenType, + String[] requiredFeatures, Bundle options) + throws NetworkErrorException { + Log.i(TAG, "Adding account with type " + accountType + + " and auth token " + authTokenType); + try { + validateAccountType(accountType); + } catch (AuthenticatorException e) { + Log.e(TAG, "Failed to validate account type " + accountType + ": " + + e.getMessage()); + e.printStackTrace(); + return e.getFailureBundle(); + } + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + + setIntentFlags(intent); + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + /** + * {@inheritDoc} + */ + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, + Account account, Bundle options) throws NetworkErrorException { + try { + validateAccountType(account.type); + } catch (AuthenticatorException e) { + Log.e(TAG, "Failed to validate account type " + account.type + ": " + + e.getMessage()); + e.printStackTrace(); + return e.getFailureBundle(); + } + Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_ACCOUNT, account); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + + setIntentFlags(intent); + + Bundle resultBundle = new Bundle(); + resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); + return resultBundle; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, + String accountType) { + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + try { + validateAccountType(account.type); + validateAuthTokenType(authTokenType); + } catch (AuthenticatorException e) { + Log.e(TAG, "Failed to validate account type " + account.type + ": " + + e.getMessage()); + e.printStackTrace(); + return e.getFailureBundle(); + } + final AccountManager am = AccountManager.get(mContext); + final String password = am.getPassword(account); + if (password != null) { + final Bundle result = new Bundle(); + result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); + result.putString(AccountManager.KEY_AUTHTOKEN, password); + return result; + } + + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); + + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, + Account account, String[] features) throws NetworkErrorException { + final Bundle result = new Bundle(); + result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); + return result; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, + response); + intent.putExtra(KEY_ACCOUNT, account); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + setIntentFlags(intent); + + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + @Override + public Bundle getAccountRemovalAllowed( + AccountAuthenticatorResponse response, Account account) + throws NetworkErrorException { + return super.getAccountRemovalAllowed(response, account); + } + + private void setIntentFlags(Intent intent) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.addFlags(Intent.FLAG_FROM_BACKGROUND); + } + + private void validateAccountType(String type) + throws UnsupportedAccountTypeException { + if (!type.equals(ACCOUNT_TYPE)) { + throw new UnsupportedAccountTypeException(); + } + } + + private void validateAuthTokenType(String authTokenType) + throws UnsupportedAuthTokenTypeException { + if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { + throw new UnsupportedAuthTokenTypeException(); + } + } + + public static class AuthenticatorException extends Exception { + private static final long serialVersionUID = 1L; + private Bundle mFailureBundle; + + public AuthenticatorException(int code, String errorMsg) { + mFailureBundle = new Bundle(); + mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code); + mFailureBundle + .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg); + } + + public Bundle getFailureBundle() { + return mFailureBundle; + } + } + + public static class UnsupportedAccountTypeException extends + AuthenticatorException { + private static final long serialVersionUID = 1L; + + public UnsupportedAccountTypeException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "Unsupported account type"); + } + } + + public static class UnsupportedAuthTokenTypeException extends + AuthenticatorException { + private static final long serialVersionUID = 1L; + + public UnsupportedAuthTokenTypeException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "Unsupported auth token type"); + } + } + + public static class UnsupportedFeaturesException extends + AuthenticatorException { + public static final long serialVersionUID = 1L; + + public UnsupportedFeaturesException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "Unsupported features"); + } + } + + public static class AccessDeniedException extends AuthenticatorException { + public AccessDeniedException(int code, String errorMsg) { + super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied"); + } + + private static final long serialVersionUID = 1L; + + } +} diff --git a/src/com/owncloud/android/authenticator/AccountAuthenticatorService.java b/src/com/owncloud/android/authenticator/AccountAuthenticatorService.java new file mode 100644 index 00000000..e11b03a4 --- /dev/null +++ b/src/com/owncloud/android/authenticator/AccountAuthenticatorService.java @@ -0,0 +1,41 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.authenticator; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class AccountAuthenticatorService extends Service { + + private AccountAuthenticator mAuthenticator; + static final public String ACCOUNT_TYPE = "owncloud"; + + @Override + public void onCreate() { + super.onCreate(); + mAuthenticator = new AccountAuthenticator(this); + } + + @Override + public IBinder onBind(Intent intent) { + return mAuthenticator.getIBinder(); + } + +} diff --git a/src/com/owncloud/android/authenticator/AuthenticationRunnable.java b/src/com/owncloud/android/authenticator/AuthenticationRunnable.java new file mode 100644 index 00000000..dba32819 --- /dev/null +++ b/src/com/owncloud/android/authenticator/AuthenticationRunnable.java @@ -0,0 +1,81 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.authenticator; + +import java.net.URL; + +import org.apache.commons.httpclient.HttpStatus; + +import eu.alefzero.webdav.WebdavClient; + +import android.net.Uri; +import android.os.Handler; + +public class AuthenticationRunnable implements Runnable { + + private OnAuthenticationResultListener mListener; + private Handler mHandler; + private URL mUrl; + private String mUsername; + private String mPassword; + + public AuthenticationRunnable(URL url, String username, String password) { + mListener = null; + mUrl = url; + mUsername = username; + mPassword = password; + } + + public void setOnAuthenticationResultListener( + OnAuthenticationResultListener listener, Handler handler) { + mListener = listener; + mHandler = handler; + } + + @Override + public void run() { + Uri uri; + uri = Uri.parse(mUrl.toString()); + int login_result = WebdavClient.tryToLogin(uri, mUsername, mPassword); + switch (login_result) { + case HttpStatus.SC_OK: + postResult(true, uri.toString()); + break; + case HttpStatus.SC_UNAUTHORIZED: + postResult(false, "Invalid login or/and password"); + break; + case HttpStatus.SC_NOT_FOUND: + postResult(false, "Wrong path given"); + break; + default: + postResult(false, "Internal server error, code: " + login_result); + } + } + + private void postResult(final boolean success, final String message) { + if (mHandler != null && mListener != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onAuthenticationResult(success, message); + } + }); + } + } +} diff --git a/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java b/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java new file mode 100644 index 00000000..d1d10706 --- /dev/null +++ b/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java @@ -0,0 +1,170 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.authenticator; + +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLHandshakeException; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.GetMethod; +import org.json.JSONException; +import org.json.JSONObject; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.OnConnectCheckListener.ResultType; +import com.owncloud.android.utils.OwnCloudVersion; + +import eu.alefzero.webdav.WebdavClient; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Uri; +import android.os.Handler; +import android.util.Log; + +public class ConnectionCheckerRunnable implements Runnable { + + /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs. */ + public static final int TRY_CONNECTION_TIMEOUT = 5000; + + private static final String TAG = "ConnectionCheckerRunnable"; + private OnConnectCheckListener mListener; + private String mUrl; + private Handler mHandler; + private ResultType mLatestResult; + private Context mContext; + private OwnCloudVersion mOCVersion; + + public void setListener(OnConnectCheckListener listener, Handler handler) { + mListener = listener; + mHandler = handler; + } + + public ConnectionCheckerRunnable(String url, Context context) { + mListener = null; + mHandler = null; + mUrl = url; + mContext = context; + mOCVersion = null; + } + + @Override + public void run() { + + if (!isOnline()) { + postResult(ResultType.NO_NETWORK_CONNECTION); + return; + } + if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) { + mLatestResult = (mUrl.startsWith("https://"))? ResultType.OK_SSL : ResultType.OK_NO_SSL; + tryConnection(Uri.parse(mUrl + AccountUtils.STATUS_PATH)); + postResult(mLatestResult); + } else { + Uri uri = Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH); + if (tryConnection(uri)) { + postResult(ResultType.OK_SSL); + return; + } + Log.d(TAG, + "establishing secure connection failed, trying non secure connection"); + uri = Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH); + + if (tryConnection(uri)) { + postResult(ResultType.OK_NO_SSL); + return; + } + postResult(mLatestResult); + } + } + + public OwnCloudVersion getDiscoveredVersion() { + return mOCVersion; + } + + private boolean tryConnection(Uri uri) { + WebdavClient wc = new WebdavClient(); + wc.allowSelfsignedCertificates(); + GetMethod get = new GetMethod(uri.toString()); + boolean retval = false; + try { + int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT); + switch (status) { + case HttpStatus.SC_OK: { + String response = get.getResponseBodyAsString(); + JSONObject json = new JSONObject(response); + if (!json.getBoolean("installed")) { + mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; + break; + } + mOCVersion = new OwnCloudVersion(json.getString("version")); + if (!mOCVersion.isVersionValid()) + break; + retval = true; + break; + } + case HttpStatus.SC_NOT_FOUND: + mLatestResult = ResultType.FILE_NOT_FOUND; + break; + case HttpStatus.SC_INTERNAL_SERVER_ERROR: + mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; + break; + default: + mLatestResult = ResultType.UNKNOWN_ERROR; + Log.e(TAG, "Not handled status received from server: " + status); + } + + } catch (Exception e) { + if (e instanceof UnknownHostException + || e instanceof ConnectException + || e instanceof SocketTimeoutException) { + mLatestResult = ResultType.HOST_NOT_AVAILABLE; + } else if (e instanceof JSONException) { + mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; + } else if (e instanceof SSLHandshakeException) { + mLatestResult = ResultType.SSL_INIT_ERROR; + } else { + mLatestResult = ResultType.UNKNOWN_ERROR; + } + e.printStackTrace(); + } + + return retval; + } + + private boolean isOnline() { + ConnectivityManager cm = (ConnectivityManager) mContext + .getSystemService(Context.CONNECTIVITY_SERVICE); + return cm != null && cm.getActiveNetworkInfo() != null + && cm.getActiveNetworkInfo().isConnectedOrConnecting(); + } + + private void postResult(final ResultType result) { + if (mHandler != null && mListener != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onConnectionCheckResult(result); + } + }); + } + } + +} diff --git a/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java b/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java new file mode 100644 index 00000000..0a3f8bee --- /dev/null +++ b/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java @@ -0,0 +1,221 @@ +/* + * $HeadURL$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package com.owncloud.android.authenticator; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; + +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.HttpClientError; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; + +import android.util.Log; + +/** + *

+ * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s that + * accept self-signed certificates. + *

+ *

+ * This socket factory SHOULD NOT be used for productive systems due to security + * reasons, unless it is a concious decision and you are perfectly aware of + * security implications of accepting self-signed certificates + *

+ * + *

+ * Example of using custom protocol socket factory for a specific host: + * + *

+ * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(),
+ *         443);
+ * 
+ * URI uri = new URI("https://localhost/", true);
+ * // use relative url only
+ * GetMethod httpget = new GetMethod(uri.getPathQuery());
+ * HostConfiguration hc = new HostConfiguration();
+ * hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
+ * HttpClient client = new HttpClient();
+ * client.executeMethod(hc, httpget);
+ * 
+ * + *

+ *

+ * Example of using custom protocol socket factory per default instead of the + * standard one: + * + *

+ * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(),
+ *         443);
+ * Protocol.registerProtocol("https", easyhttps);
+ * 
+ * HttpClient client = new HttpClient();
+ * GetMethod httpget = new GetMethod("https://localhost/");
+ * client.executeMethod(httpget);
+ * 
+ * + *

+ * + * @author Oleg Kalnichevski + * + *

+ * DISCLAIMER: HttpClient developers DO NOT actively support this + * component. The component is provided as a reference material, which + * may be inappropriate for use without additional customization. + *

+ */ + +public class EasySSLSocketFactory implements ProtocolSocketFactory { + + private static final String TAG = "EasySSLSocketFactory"; + private SSLContext sslcontext = null; + + /** + * Constructor for EasySSLProtocolSocketFactory. + */ + public EasySSLSocketFactory() { + super(); + } + + private static SSLContext createEasySSLContext() { + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[] { new EasyX509TrustManager( + null) }, null); + return context; + } catch (Exception er) { + Log.e(TAG, er.getMessage() + ""); + throw new HttpClientError(er.toString()); + } + } + + private SSLContext getSSLContext() { + if (this.sslcontext == null) { + this.sslcontext = createEasySSLContext(); + } + return this.sslcontext; + } + + /** + * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) + */ + public Socket createSocket(String host, int port, InetAddress clientHost, + int clientPort) throws IOException, UnknownHostException { + + return getSSLContext().getSocketFactory().createSocket(host, port, + clientHost, clientPort); + } + + /** + * Attempts to get a new socket connection to the given host within the + * given time limit. + *

+ * To circumvent the limitations of older JREs that do not support connect + * timeout a controller thread is executed. The controller thread attempts + * to create a new socket within the given limit of time. If socket + * constructor does not return until the timeout expires, the controller + * terminates and throws an {@link ConnectTimeoutException} + *

+ * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort the port on the local machine + * @param params {@link HttpConnectionParams Http connection parameters} + * + * @return Socket a new socket + * + * @throws IOException if an I/O error occurs while creating the socket + * @throws UnknownHostException if the IP address of the host cannot be + * determined + */ + public Socket createSocket(final String host, final int port, + final InetAddress localAddress, final int localPort, + final HttpConnectionParams params) throws IOException, + UnknownHostException, ConnectTimeoutException { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + SocketFactory socketfactory = getSSLContext().getSocketFactory(); + if (timeout == 0) { + Socket socket = socketfactory.createSocket(host, port, localAddress, + localPort); + socket.setSoTimeout(params.getSoTimeout()); + return socket; + } else { + Socket socket = socketfactory.createSocket(); + SocketAddress localaddr = new InetSocketAddress(localAddress, + localPort); + SocketAddress remoteaddr = new InetSocketAddress(host, port); + socket.setSoTimeout(params.getSoTimeout()); + socket.bind(localaddr); + socket.connect(remoteaddr, timeout); + return socket; + } + } + + /** + * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) + */ + public Socket createSocket(String host, int port) throws IOException, + UnknownHostException { + return getSSLContext().getSocketFactory().createSocket(host, port); + } + + /** + * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) + */ + public Socket createSocket(Socket socket, String host, int port, + boolean autoClose) throws IOException, UnknownHostException { + return getSSLContext().getSocketFactory().createSocket(socket, host, + port, autoClose); + } + + public boolean equals(Object obj) { + return ((obj != null) && obj.getClass().equals( + EasySSLSocketFactory.class)); + } + + public int hashCode() { + return EasySSLSocketFactory.class.hashCode(); + } + +} \ No newline at end of file diff --git a/src/com/owncloud/android/authenticator/EasyX509TrustManager.java b/src/com/owncloud/android/authenticator/EasyX509TrustManager.java new file mode 100644 index 00000000..0c7b0834 --- /dev/null +++ b/src/com/owncloud/android/authenticator/EasyX509TrustManager.java @@ -0,0 +1,88 @@ +package com.owncloud.android.authenticator; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +/** + * @author olamy + * @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse + * $ + * @since 1.2.3 + */ +public class EasyX509TrustManager implements X509TrustManager { + + private X509TrustManager standardTrustManager = null; + + /** + * Constructor for EasyX509TrustManager. + */ + public EasyX509TrustManager(KeyStore keystore) + throws NoSuchAlgorithmException, KeyStoreException { + super(); + TrustManagerFactory factory = TrustManagerFactory + .getInstance(TrustManagerFactory.getDefaultAlgorithm()); + factory.init(keystore); + TrustManager[] trustmanagers = factory.getTrustManagers(); + if (trustmanagers.length == 0) { + throw new NoSuchAlgorithmException("no trust manager found"); + } + this.standardTrustManager = (X509TrustManager) trustmanagers[0]; + } + + /** + * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[], + * String authType) + */ + public void checkClientTrusted(X509Certificate[] certificates, + String authType) throws CertificateException { + standardTrustManager.checkClientTrusted(certificates, authType); + } + + /** + * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], + * String authType) + */ + public void checkServerTrusted(X509Certificate[] certificates, + String authType) throws CertificateException { + if ((certificates != null) && (certificates.length == 1)) { + certificates[0].checkValidity(); + } else { + // standardTrustManager.checkServerTrusted( certificates, authType + // ); + } + } + + /** + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + public X509Certificate[] getAcceptedIssuers() { + return this.standardTrustManager.getAcceptedIssuers(); + } + +} \ No newline at end of file diff --git a/src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java b/src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java new file mode 100644 index 00000000..11cbdceb --- /dev/null +++ b/src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java @@ -0,0 +1,7 @@ +package com.owncloud.android.authenticator; + +public interface OnAuthenticationResultListener { + + public void onAuthenticationResult(boolean success, String message); + +} diff --git a/src/com/owncloud/android/authenticator/OnConnectCheckListener.java b/src/com/owncloud/android/authenticator/OnConnectCheckListener.java new file mode 100644 index 00000000..bca71ae7 --- /dev/null +++ b/src/com/owncloud/android/authenticator/OnConnectCheckListener.java @@ -0,0 +1,11 @@ +package com.owncloud.android.authenticator; + +public interface OnConnectCheckListener { + + enum ResultType { + OK_SSL, OK_NO_SSL, SSL_INIT_ERROR, HOST_NOT_AVAILABLE, TIMEOUT, NO_NETWORK_CONNECTION, INORRECT_ADDRESS, INSTANCE_NOT_CONFIGURED, FILE_NOT_FOUND, UNKNOWN_ERROR + } + + public void onConnectionCheckResult(ResultType type); + +} diff --git a/src/com/owncloud/android/datamodel/DataStorageManager.java b/src/com/owncloud/android/datamodel/DataStorageManager.java new file mode 100644 index 00000000..a73ab66c --- /dev/null +++ b/src/com/owncloud/android/datamodel/DataStorageManager.java @@ -0,0 +1,41 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.datamodel; + +import java.util.List; +import java.util.Vector; + +public interface DataStorageManager { + + public OCFile getFileByPath(String path); + + public OCFile getFileById(long id); + + public boolean fileExists(String path); + + public boolean fileExists(long id); + + public boolean saveFile(OCFile file); + + public void saveFiles(List files); + + public Vector getDirectoryContent(OCFile f); + + public void removeFile(OCFile file); +} diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java new file mode 100644 index 00000000..49a88c36 --- /dev/null +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -0,0 +1,422 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.datamodel; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import com.owncloud.android.db.ProviderMeta; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; +import com.owncloud.android.files.services.FileDownloader; + +import android.accounts.Account; +import android.content.ContentProviderClient; +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.os.RemoteException; +import android.util.Log; + +public class FileDataStorageManager implements DataStorageManager { + + private ContentResolver mContentResolver; + private ContentProviderClient mContentProvider; + private Account mAccount; + + private static String TAG = "FileDataStorageManager"; + + public FileDataStorageManager(Account account, ContentResolver cr) { + mContentProvider = null; + mContentResolver = cr; + mAccount = account; + } + + public FileDataStorageManager(Account account, ContentProviderClient cp) { + mContentProvider = cp; + mContentResolver = null; + mAccount = account; + } + + @Override + public OCFile getFileByPath(String path) { + Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path); + OCFile file = null; + if (c.moveToFirst()) { + file = createFileInstance(c); + } + c.close(); + return file; + } + + @Override + public OCFile getFileById(long id) { + Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id)); + OCFile file = null; + if (c.moveToFirst()) { + file = createFileInstance(c); + } + c.close(); + return file; + } + + @Override + public boolean fileExists(long id) { + return fileExists(ProviderTableMeta._ID, String.valueOf(id)); + } + + @Override + public boolean fileExists(String path) { + return fileExists(ProviderTableMeta.FILE_PATH, path); + } + + @Override + public boolean saveFile(OCFile file) { + boolean overriden = false; + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp()); + cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp()); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); + cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); + if (file.getParentId() != 0) + cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); + cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); + if (!file.isDirectory()) + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); + cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate()); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); + + if (fileExists(file.getRemotePath())) { + OCFile oldFile = getFileByPath(file.getRemotePath()); + if (file.getStoragePath() == null && oldFile.getStoragePath() != null) + file.setStoragePath(oldFile.getStoragePath()); + if (!file.isDirectory()); + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); + file.setFileId(oldFile.getFileId()); + + overriden = true; + if (getContentResolver() != null) { + getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, + ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(file.getFileId()) }); + } else { + try { + getContentProvider().update(ProviderTableMeta.CONTENT_URI, + cv, ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(file.getFileId()) }); + } catch (RemoteException e) { + Log.e(TAG, + "Fail to insert insert file to database " + + e.getMessage()); + } + } + } else { + Uri result_uri = null; + if (getContentResolver() != null) { + result_uri = getContentResolver().insert( + ProviderTableMeta.CONTENT_URI_FILE, cv); + } else { + try { + result_uri = getContentProvider().insert( + ProviderTableMeta.CONTENT_URI_FILE, cv); + } catch (RemoteException e) { + Log.e(TAG, + "Fail to insert insert file to database " + + e.getMessage()); + } + } + if (result_uri != null) { + long new_id = Long.parseLong(result_uri.getPathSegments() + .get(1)); + file.setFileId(new_id); + } + } + + if (file.isDirectory() && file.needsUpdatingWhileSaving()) + for (OCFile f : getDirectoryContent(file)) + saveFile(f); + + return overriden; + } + + + @Override + public void saveFiles(List files) { + + Iterator filesIt = files.iterator(); + ArrayList operations = new ArrayList(files.size()); + OCFile file = null; + + // prepare operations to perform + while (filesIt.hasNext()) { + file = filesIt.next(); + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp()); + cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp()); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); + cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); + if (file.getParentId() != 0) + cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); + cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); + if (!file.isDirectory()) + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); + cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate()); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); + + if (fileExists(file.getRemotePath())) { + OCFile tmpfile = getFileByPath(file.getRemotePath()); + file.setStoragePath(tmpfile.getStoragePath()); + if (!file.isDirectory()); + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); + file.setFileId(tmpfile.getFileId()); + + operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). + withValues(cv). + withSelection( ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(file.getFileId()) }) + .build()); + + } else { + operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build()); + } + } + + // apply operations in batch + ContentProviderResult[] results = null; + try { + if (getContentResolver() != null) { + results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations); + + } else { + results = getContentProvider().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log.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()); + } + + // update new id in file objects for insertions + if (results != null) { + long newId; + for (int i=0; i getDirectoryContent(OCFile f) { + if (f != null && f.isDirectory() && f.getFileId() != -1) { + Vector ret = new Vector(); + + Uri req_uri = Uri.withAppendedPath( + ProviderTableMeta.CONTENT_URI_DIR, + String.valueOf(f.getFileId())); + Cursor c = null; + + if (getContentProvider() != null) { + try { + c = getContentProvider().query(req_uri, null, + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[] { mAccount.name }, null); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage()); + return ret; + } + } else { + c = getContentResolver().query(req_uri, null, + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[] { mAccount.name }, null); + } + + if (c.moveToFirst()) { + do { + OCFile child = createFileInstance(c); + ret.add(child); + } while (c.moveToNext()); + } + + c.close(); + + Collections.sort(ret); + + return ret; + } + return null; + } + + private boolean fileExists(String cmp_key, String value) { + Cursor c; + if (getContentResolver() != null) { + c = getContentResolver() + .query(ProviderTableMeta.CONTENT_URI, + null, + cmp_key + "=? AND " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + + "=?", + new String[] { value, mAccount.name }, null); + } else { + try { + c = getContentProvider().query( + ProviderTableMeta.CONTENT_URI, + null, + cmp_key + "=? AND " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[] { value, mAccount.name }, null); + } catch (RemoteException e) { + Log.e(TAG, + "Couldn't determine file existance, assuming non existance: " + + e.getMessage()); + return false; + } + } + boolean retval = c.moveToFirst(); + c.close(); + return retval; + } + + private Cursor getCursorForValue(String key, String value) { + Cursor c = null; + if (getContentResolver() != null) { + c = getContentResolver() + .query(ProviderTableMeta.CONTENT_URI, + null, + key + "=? AND " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + + "=?", + new String[] { value, mAccount.name }, null); + } else { + try { + c = getContentProvider().query( + ProviderTableMeta.CONTENT_URI, + null, + key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + + "=?", new String[] { value, mAccount.name }, + null); + } catch (RemoteException e) { + Log.e(TAG, "Could not get file details: " + e.getMessage()); + c = null; + } + } + return c; + } + + private OCFile createFileInstance(Cursor c) { + OCFile file = null; + if (c != null) { + file = new OCFile(c.getString(c + .getColumnIndex(ProviderTableMeta.FILE_PATH))); + file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID))); + file.setParentId(c.getLong(c + .getColumnIndex(ProviderTableMeta.FILE_PARENT))); + file.setMimetype(c.getString(c + .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE))); + if (!file.isDirectory()) { + file.setStoragePath(c.getString(c + .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))); + if (file.getStoragePath() == null) { + // try to find existing file and bind it with current account + File f = new File(FileDownloader.getSavePath(mAccount.name) + file.getRemotePath()); + if (f.exists()) + file.setStoragePath(f.getAbsolutePath()); + } + } + file.setFileLength(c.getLong(c + .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH))); + file.setCreationTimestamp(c.getLong(c + .getColumnIndex(ProviderTableMeta.FILE_CREATION))); + file.setModificationTimestamp(c.getLong(c + .getColumnIndex(ProviderTableMeta.FILE_MODIFIED))); + file.setLastSyncDate(c.getLong(c + .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE))); + file.setKeepInSync(c.getInt( + c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); + } + return file; + } + + public void removeFile(OCFile file) { + Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId()); + if (getContentProvider() != null) { + try { + getContentProvider().delete(file_uri, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", + new String[]{mAccount.name}); + } catch (RemoteException e) { + e.printStackTrace(); + } + } else { + getContentResolver().delete(file_uri, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", + new String[]{mAccount.name}); + } + if (file.isDown()) { + new File(file.getStoragePath()).delete(); + } + } + +} diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java new file mode 100644 index 00000000..f50a86fc --- /dev/null +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -0,0 +1,382 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.datamodel; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; + +import com.owncloud.android.files.services.FileDownloader; + + +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +public class OCFile implements Parcelable, Comparable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public OCFile createFromParcel(Parcel source) { + return new OCFile(source); + } + + @Override + public OCFile[] newArray(int size) { + return new OCFile[size]; + } + }; + + public static final String PATH_SEPARATOR = "/"; + + private long mId; + private long mParentId; + private long mLength; + private long mCreationTimestamp; + private long mModifiedTimestamp; + private String mRemotePath; + private String mLocalPath; + private String mMimeType; + private boolean mNeedsUpdating; + private long mLastSyncDate; + private boolean mKeepInSync; + + /** + * Create new {@link OCFile} with given path. + * + * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'. + * + * @param path The remote path of the file. + */ + public OCFile(String path) { + resetData(); + mNeedsUpdating = false; + if (path == null || path.length() <= 0 || !path.startsWith(PATH_SEPARATOR)) { + throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path); + } + mRemotePath = path; + } + + /** + * Reconstruct from parcel + * + * @param source The source parcel + */ + private OCFile(Parcel source) { + mId = source.readLong(); + mParentId = source.readLong(); + mLength = source.readLong(); + mCreationTimestamp = source.readLong(); + mModifiedTimestamp = source.readLong(); + mRemotePath = source.readString(); + mLocalPath = source.readString(); + mMimeType = source.readString(); + mNeedsUpdating = source.readInt() == 0; + mKeepInSync = source.readInt() == 1; + mLastSyncDate = source.readLong(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mId); + dest.writeLong(mParentId); + dest.writeLong(mLength); + dest.writeLong(mCreationTimestamp); + dest.writeLong(mModifiedTimestamp); + dest.writeString(mRemotePath); + dest.writeString(mLocalPath); + dest.writeString(mMimeType); + dest.writeInt(mNeedsUpdating ? 1 : 0); + dest.writeInt(mKeepInSync ? 1 : 0); + dest.writeLong(mLastSyncDate); + } + + /** + * Gets the ID of the file + * + * @return the file ID + */ + public long getFileId() { + return mId; + } + + /** + * Returns the remote path of the file on ownCloud + * + * @return The remote path to the file + */ + public String getRemotePath() { + return mRemotePath; + } + + /** + * Can be used to check, whether or not this file exists in the database + * already + * + * @return true, if the file exists in the database + */ + public boolean fileExists() { + return mId != -1; + } + + /** + * Use this to find out if this file is a Directory + * + * @return true if it is a directory + */ + public boolean isDirectory() { + return mMimeType != null && mMimeType.equals("DIR"); + } + + /** + * Use this to check if this file is available locally + * + * @return true if it is + */ + public boolean isDown() { + if (mLocalPath != null && mLocalPath.length() > 0) { + File file = new File(mLocalPath); + return (file.exists()); + } + return false; + } + + /** + * The path, where the file is stored locally + * + * @return The local path to the file + */ + public String getStoragePath() { + return mLocalPath; + } + + /** + * Can be used to set the path where the file is stored + * + * @param storage_path to set + */ + public void setStoragePath(String storage_path) { + mLocalPath = storage_path; + } + + /** + * Get a UNIX timestamp of the file creation time + * + * @return A UNIX timestamp of the time that file was created + */ + public long getCreationTimestamp() { + return mCreationTimestamp; + } + + /** + * Set a UNIX timestamp of the time the file was created + * + * @param creation_timestamp to set + */ + public void setCreationTimestamp(long creation_timestamp) { + mCreationTimestamp = creation_timestamp; + } + + /** + * Get a UNIX timestamp of the file modification time + * + * @return A UNIX timestamp of the modification time + */ + public long getModificationTimestamp() { + return mModifiedTimestamp; + } + + /** + * Set a UNIX timestamp of the time the time the file was modified. + * + * @param modification_timestamp to set + */ + public void setModificationTimestamp(long modification_timestamp) { + mModifiedTimestamp = modification_timestamp; + } + + /** + * Returns the filename and "/" for the root directory + * + * @return The name of the file + */ + public String getFileName() { + File f = new File(getRemotePath()); + return f.getName().length() == 0 ? "/" : f.getName(); + } + + /** + * Can be used to get the Mimetype + * + * @return the Mimetype as a String + */ + public String getMimetype() { + return mMimeType; + } + + /** + * Adds a file to this directory. If this file is not a directory, an + * exception gets thrown. + * + * @param file to add + * @throws IllegalStateException if you try to add a something and this is + * not a directory + */ + public void addFile(OCFile file) throws IllegalStateException { + if (isDirectory()) { + file.mParentId = mId; + mNeedsUpdating = true; + return; + } + throw new IllegalStateException( + "This is not a directory where you can add stuff to!"); + } + + /** + * Used internally. Reset all file properties + */ + private void resetData() { + mId = -1; + mRemotePath = null; + mParentId = 0; + mLocalPath = null; + mMimeType = null; + mLength = 0; + mCreationTimestamp = 0; + mModifiedTimestamp = 0; + mLastSyncDate = 0; + mKeepInSync = false; + mNeedsUpdating = false; + } + + /** + * Sets the ID of the file + * + * @param file_id to set + */ + public void setFileId(long file_id) { + mId = file_id; + } + + /** + * Sets the Mime-Type of the + * + * @param mimetype to set + */ + public void setMimetype(String mimetype) { + mMimeType = mimetype; + } + + /** + * Sets the ID of the parent folder + * + * @param parent_id to set + */ + public void setParentId(long parent_id) { + mParentId = parent_id; + } + + /** + * Sets the file size in bytes + * + * @param file_len to set + */ + public void setFileLength(long file_len) { + mLength = file_len; + } + + /** + * Returns the size of the file in bytes + * + * @return The filesize in bytes + */ + public long getFileLength() { + return mLength; + } + + /** + * Returns the ID of the parent Folder + * + * @return The ID + */ + public long getParentId() { + return mParentId; + } + + /** + * Check, if this file needs updating + * + * @return + */ + public boolean needsUpdatingWhileSaving() { + return mNeedsUpdating; + } + + public long getLastSyncDate() { + return mLastSyncDate; + } + + public void setLastSyncDate(long lastSyncDate) { + mLastSyncDate = lastSyncDate; + } + + public void setKeepInSync(boolean keepInSync) { + mKeepInSync = keepInSync; + } + + public boolean keepInSync() { + return mKeepInSync; + } + + @Override + public int describeContents() { + return this.hashCode(); + } + + @Override + public int compareTo(OCFile another) { + if (isDirectory() && another.isDirectory()) { + return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase()); + } else if (isDirectory()) { + return -1; + } else if (another.isDirectory()) { + return 1; + } + return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase()); + } + + public boolean equals(Object o) { + if(o instanceof OCFile){ + OCFile that = (OCFile) o; + if(that != null){ + return this.mId == that.mId; + } + } + + return false; + } + + @Override + public String toString() { + String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s]"; + asString = String.format(asString, new Long(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, new Long(mParentId), new Boolean(mKeepInSync)); + return asString; + } + +} diff --git a/src/com/owncloud/android/db/DbHandler.java b/src/com/owncloud/android/db/DbHandler.java new file mode 100644 index 00000000..61d56557 --- /dev/null +++ b/src/com/owncloud/android/db/DbHandler.java @@ -0,0 +1,87 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.db; + +import java.util.Vector; + +import com.owncloud.android.OwnCloudSession; + + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +/** + * Custom database helper for ownCloud + * + * @author Bartek Przybylski + * + */ +public class DbHandler { + private SQLiteDatabase mDB; + private OpenerHepler mHelper; + private final String mDatabaseName = "ownCloud"; + private final String TABLE_SESSIONS = "sessions"; + private final int mDatabaseVersion = 1; + + private final String TABLE_INSTANT_UPLOAD = "instant_upload"; + + public DbHandler(Context context) { + mHelper = new OpenerHepler(context); + mDB = mHelper.getWritableDatabase(); + } + + public void close() { + mDB.close(); + } + + public boolean putFileForLater(String filepath, String account) { + ContentValues cv = new ContentValues(); + cv.put("path", filepath); + cv.put("account", account); + return mDB.insert(TABLE_INSTANT_UPLOAD, null, cv) != -1; + } + + public Cursor getAwaitingFiles() { + return mDB.query(TABLE_INSTANT_UPLOAD, null, null, null, null, null, null); + } + + public void clearFiles() { + mDB.delete(TABLE_INSTANT_UPLOAD, null, null); + } + + private class OpenerHepler extends SQLiteOpenHelper { + public OpenerHepler(Context context) { + super(context, mDatabaseName, null, mDatabaseVersion); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " (" + + " _id INTEGET PRIMARY KEY, " + + " path TEXT," + + " account TEXT);"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + } + } +} diff --git a/src/com/owncloud/android/db/ProviderMeta.java b/src/com/owncloud/android/db/ProviderMeta.java new file mode 100644 index 00000000..c7f86b63 --- /dev/null +++ b/src/com/owncloud/android/db/ProviderMeta.java @@ -0,0 +1,67 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.db; + +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * Meta-Class that holds various static field information + * + * @author Bartek Przybylski + * + */ +public class ProviderMeta { + + public static final String AUTHORITY_FILES = "org.owncloud"; + public static final String DB_FILE = "owncloud.db"; + public static final String DB_NAME = "filelist"; + public static final int DB_VERSION = 2; + + private ProviderMeta() { + } + + static public class ProviderTableMeta implements BaseColumns { + public static final String DB_NAME = "filelist"; + public static final Uri CONTENT_URI = Uri.parse("content://" + + AUTHORITY_FILES + "/"); + public static final Uri CONTENT_URI_FILE = Uri.parse("content://" + + AUTHORITY_FILES + "/file"); + public static final Uri CONTENT_URI_DIR = Uri.parse("content://" + + AUTHORITY_FILES + "/dir"); + + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file"; + public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file"; + + public static final String FILE_PARENT = "parent"; + public static final String FILE_NAME = "filename"; + public static final String FILE_CREATION = "created"; + public static final String FILE_MODIFIED = "modified"; + public static final String FILE_CONTENT_LENGTH = "content_length"; + public static final String FILE_CONTENT_TYPE = "content_type"; + public static final String FILE_STORAGE_PATH = "media_path"; + public static final String FILE_PATH = "path"; + public static final String FILE_ACCOUNT_OWNER = "file_owner"; + public static final String FILE_LAST_SYNC_DATE = "last_sync_date"; + public static final String FILE_KEEP_IN_SYNC = "keep_in_sync"; + + public static final String DEFAULT_SORT_ORDER = FILE_NAME + + " collate nocase asc"; + + } +} diff --git a/src/com/owncloud/android/extensions/ExtensionsAvailableActivity.java b/src/com/owncloud/android/extensions/ExtensionsAvailableActivity.java new file mode 100644 index 00000000..e389fd33 --- /dev/null +++ b/src/com/owncloud/android/extensions/ExtensionsAvailableActivity.java @@ -0,0 +1,17 @@ +package com.owncloud.android.extensions; + +import android.os.Bundle; +import android.support.v4.app.FragmentManager; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +public class ExtensionsAvailableActivity extends SherlockFragmentActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + FragmentManager fm = getSupportFragmentManager(); + ExtensionsAvailableDialog ead = new ExtensionsAvailableDialog(); + ead.show(fm, "extensions_available_dialog"); + } +} diff --git a/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java b/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java new file mode 100644 index 00000000..55483fa2 --- /dev/null +++ b/src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java @@ -0,0 +1,50 @@ +package com.owncloud.android.extensions; + +import com.owncloud.android.R; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.View.OnClickListener; +import android.widget.Button; + +public class ExtensionsAvailableDialog extends DialogFragment implements + OnClickListener { + + public ExtensionsAvailableDialog() { + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.extensions_available_dialog, + container); + Button btnYes = (Button) view.findViewById(R.id.buttonYes); + Button btnNo = (Button) view.findViewById(R.id.buttonNo); + btnYes.setOnClickListener(this); + btnNo.setOnClickListener(this); + getDialog().setTitle(R.string.extensions_avail_title); + return view; + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.buttonYes: { + Intent i = new Intent(getActivity(), ExtensionsListActivity.class); + startActivity(i); + getActivity().finish(); + } + break; + case R.id.buttonNo: + getActivity().finish(); + break; + default: + Log.e("EAD", "Button with unknown id clicked " + v.getId()); + } + } + +} diff --git a/src/com/owncloud/android/extensions/ExtensionsListActivity.java b/src/com/owncloud/android/extensions/ExtensionsListActivity.java new file mode 100644 index 00000000..44aa819c --- /dev/null +++ b/src/com/owncloud/android/extensions/ExtensionsListActivity.java @@ -0,0 +1,134 @@ +package com.owncloud.android.extensions; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Vector; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.methods.GetMethod; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import com.owncloud.android.utils.OwnCloudVersion; + + +import android.R; +import android.app.Activity; +import android.app.ListActivity; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.widget.SimpleAdapter; + +public class ExtensionsListActivity extends ListActivity { + + private static final String packages_url = "http://alefzero.eu/a/packages.php"; + + private Thread mGetterThread; + private final Handler mHandler = new Handler(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mGetterThread = new Thread(new JsonGetter()); + mGetterThread.start(); + } + + public void done(JSONArray a) { + LinkedList> ll = new LinkedList>(); + for (int i = 0; i < a.length(); ++i) { + try { + ExtensionApplicationEntry ela = new ExtensionApplicationEntry( + ((JSONObject) a.get(i))); + HashMap ss = new HashMap(); + ss.put("NAME", ela.getName()); + ss.put("DESC", ela.getDescription()); + ll.add(ss); + } catch (JSONException e) { + e.printStackTrace(); + } + } + setListAdapter(new SimpleAdapter(this, ll, R.layout.simple_list_item_2, + new String[] { "NAME", "DESC" }, new int[] { + android.R.id.text1, android.R.id.text2 })); + + } + + private class JsonGetter implements Runnable { + + @Override + public void run() { + HttpClient hc = new HttpClient(); + GetMethod gm = new GetMethod(packages_url); + final JSONArray ar; + try { + hc.executeMethod(gm); + Log.e("ASD", gm.getResponseBodyAsString() + ""); + ar = new JSONObject(gm.getResponseBodyAsString()) + .getJSONArray("apps"); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + mHandler.post(new Runnable() { + @Override + public void run() { + done(ar); + } + }); + + } + + } + + private class ExtensionApplicationEntry { + private static final String APP_NAME = "name"; + private static final String APP_VERSION = "version"; + private static final String APP_DESC = "description"; + private static final String APP_ICON = "icon"; + private static final String APP_URL = "download"; + private static final String APP_PLAYID = "play_id"; + + private String mName, mDescription, mIcon, mDownload, mPlayId; + private OwnCloudVersion mVersion; + + public ExtensionApplicationEntry(JSONObject appentry) { + try { + mName = appentry.getString(APP_NAME); + mDescription = appentry.getString(APP_DESC); + mIcon = appentry.getString(APP_ICON); + mDownload = appentry.getString(APP_URL); + mPlayId = appentry.getString(APP_PLAYID); + mVersion = new OwnCloudVersion(appentry.getString(APP_VERSION)); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public String getName() { + return mName; + } + + public String getDescription() { + return mDescription; + } + + public String getIcon() { + return mIcon; + } + + public String getDownload() { + return mDownload; + } + + public String getPlayId() { + return mPlayId; + } + + public OwnCloudVersion getVersion() { + return mVersion; + } + } +} diff --git a/src/com/owncloud/android/files/PhotoTakenBroadcastReceiver.java b/src/com/owncloud/android/files/PhotoTakenBroadcastReceiver.java new file mode 100644 index 00000000..ec313b6a --- /dev/null +++ b/src/com/owncloud/android/files/PhotoTakenBroadcastReceiver.java @@ -0,0 +1,151 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.files; + +import java.io.File; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.db.DbHandler; +import com.owncloud.android.files.services.InstantUploadService; + +import com.owncloud.android.R; +import android.accounts.Account; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.preference.Preference; +import android.preference.PreferenceManager; +import android.provider.MediaStore.Images.Media; +import android.util.Log; +import android.webkit.MimeTypeMap; + +public class PhotoTakenBroadcastReceiver extends BroadcastReceiver { + + private static String TAG = "PhotoTakenBroadcastReceiver"; + private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE }; + + private static String NEW_PHOTO_ACTION = "com.android.camera.NEW_PICTURE"; + + @Override + public void onReceive(Context context, Intent intent) { + if (!PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_uploading", false)) { + Log.d(TAG, "Instant upload disabled, abording uploading"); + return; + } + if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) { + handleConnectivityAction(context, intent); + } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) { + handleNewPhontoAction(context, intent); + } else { + Log.e(TAG, "Incorrect intent sent: " + intent.getAction()); + } + } + + private void handleNewPhontoAction(Context context, Intent intent) { + Account account = AccountUtils.getCurrentOwnCloudAccount(context); + if (account == null) { + Log.w(TAG, "No owncloud account found for instant upload, abording"); + return; + } + + Cursor c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null); + + if (!c.moveToFirst()) { + Log.e(TAG, "Couldn't resolve given uri!"); + return; + } + + String file_path = c.getString(c.getColumnIndex(Media.DATA)); + String file_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)); + String mime_type = c.getString(c.getColumnIndex(Media.MIME_TYPE)); + long file_size = c.getLong(c.getColumnIndex(Media.SIZE)); + + c.close(); + + if (!isOnline(context)) { + DbHandler db = new DbHandler(context); + db.putFileForLater(file_path, account.name); + db.close(); + return; + } + + Intent upload_intent = new Intent(context, InstantUploadService.class); + upload_intent.putExtra(InstantUploadService.KEY_ACCOUNT, account); + upload_intent.putExtra(InstantUploadService.KEY_FILE_PATH, file_path); + upload_intent.putExtra(InstantUploadService.KEY_DISPLAY_NAME, file_name); + upload_intent.putExtra(InstantUploadService.KEY_FILE_SIZE, file_size); + upload_intent.putExtra(InstantUploadService.KEY_MIME_TYPE, mime_type); + + context.startService(upload_intent); + } + + private void handleConnectivityAction(Context context, Intent intent) { + if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY) || + isOnline(context)) { + DbHandler db = new DbHandler(context); + Cursor c = db.getAwaitingFiles(); + if (c.moveToFirst()) { + do { + String account_name = c.getString(c.getColumnIndex("account")); + String file_path = c.getString(c.getColumnIndex("path")); + File f = new File(file_path); + if (f.exists()) { + Intent upload_intent = new Intent(context, InstantUploadService.class); + Account account = new Account(account_name, AccountAuthenticator.ACCOUNT_TYPE); + + String mimeType = null; + try { + mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension( + f.getName().substring(f.getName().lastIndexOf('.') + 1)); + + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName()); + } + if (mimeType == null) + mimeType = "application/octet-stream"; + + upload_intent.putExtra(InstantUploadService.KEY_ACCOUNT, account); + upload_intent.putExtra(InstantUploadService.KEY_FILE_PATH, file_path); + upload_intent.putExtra(InstantUploadService.KEY_DISPLAY_NAME, f.getName()); + upload_intent.putExtra(InstantUploadService.KEY_FILE_SIZE, f.length()); + upload_intent.putExtra(InstantUploadService.KEY_MIME_TYPE, mimeType); + + context.startService(upload_intent); + } else { + Log.w(TAG, "Instant upload file " + f.getName() + " dont exist anymore"); + } + } while(c.moveToNext()); + c.close(); + } + db.clearFiles(); + db.close(); + } + + } + + private boolean isOnline(Context context) { + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected(); + } + +} diff --git a/src/com/owncloud/android/files/interfaces/OnDatatransferProgressListener.java b/src/com/owncloud/android/files/interfaces/OnDatatransferProgressListener.java new file mode 100644 index 00000000..f3ae82bb --- /dev/null +++ b/src/com/owncloud/android/files/interfaces/OnDatatransferProgressListener.java @@ -0,0 +1,6 @@ +package com.owncloud.android.files.interfaces; + +public interface OnDatatransferProgressListener { + void transferProgress(long progressRate); + +} diff --git a/src/com/owncloud/android/files/managers/OCNotificationManager.java b/src/com/owncloud/android/files/managers/OCNotificationManager.java new file mode 100644 index 00000000..851a8f88 --- /dev/null +++ b/src/com/owncloud/android/files/managers/OCNotificationManager.java @@ -0,0 +1,154 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.files.managers; + +import java.util.HashMap; +import java.util.Map; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.widget.RemoteViews; + +import com.owncloud.android.R; + +public class OCNotificationManager { + + enum NotificationType { + NOTIFICATION_SIMPLE, + NOTIFICATION_PROGRESS + } + + static public class NotificationData { + private String mText, mSubtitle; + private int mPercent; + private boolean mOngoing; + + public NotificationData(String text, String subtitle, boolean ongoing) { + this(text, subtitle, -1, ongoing); + } + + public NotificationData(int percent, boolean ongoing) { + this(null, null, percent, ongoing); + } + + public NotificationData(String text, int percent, boolean ongoing) { + this(text, null, percent, ongoing); + } + + public NotificationData(String text, String subtitle, int percent, boolean ongoing) { + mText = text; + mPercent = percent; + mSubtitle = subtitle; + mOngoing = ongoing; + } + + public String getText() { return mText; } + public int getPercent() { return mPercent; } + public String getSubtitle() { return mSubtitle; } + public boolean getOngoing() { return mOngoing; } + } + + static private OCNotificationManager mInstance = null; + + private class NotificationTypePair { + public Notification mNotificaiton; + public NotificationType mType; + public NotificationTypePair(Notification n, NotificationType type) { + mNotificaiton = n; + mType = type; + } + } + + private Context mContext; + private Map mNotificationMap; + private int mNotificationCounter; + NotificationManager mNM; + + static OCNotificationManager getInstance(Context context) { + if (mInstance == null) + mInstance = new OCNotificationManager(context); + return mInstance; + } + + OCNotificationManager(Context context) { + mContext = context; + mNotificationMap = new HashMap(); + mNM = (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationCounter = 0; + } + + public int postNotification(NotificationType type, NotificationData data) { + mNotificationCounter++; + Notification notification = null; + + switch (type) { + case NOTIFICATION_SIMPLE: + notification = new Notification(R.drawable.icon, data.getText(), System.currentTimeMillis()); + break; + case NOTIFICATION_PROGRESS: + notification = new Notification(); + notification.contentView = new RemoteViews(mContext.getPackageName(), R.layout.progressbar_layout); + notification.contentView.setTextViewText(R.id.status_text, + data.getText()); + notification.contentView.setImageViewResource(R.id.status_icon, + R.id.icon); + notification.contentView.setProgressBar(R.id.status_progress, + 100, + data.getPercent(), + false); + break; + default: + return -1; + } + if (data.getOngoing()) { + notification.flags |= notification.flags | Notification.FLAG_ONGOING_EVENT; + } + + mNotificationMap.put(mNotificationCounter, new NotificationTypePair(notification, type)); + return mNotificationCounter; + } + + public boolean updateNotification(int notification_id, NotificationData data) { + if (!mNotificationMap.containsKey(notification_id)) { + return false; + } + NotificationTypePair pair = mNotificationMap.get(notification_id); + switch (pair.mType) { + case NOTIFICATION_PROGRESS: + pair.mNotificaiton.contentView.setProgressBar(R.id.status_text, + 100, + data.getPercent(), + false); + return true; + case NOTIFICATION_SIMPLE: + pair.mNotificaiton = new Notification(R.drawable.icon, + data.getText(), System.currentTimeMillis()); + mNM.notify(notification_id, pair.mNotificaiton); + return true; + default: + return false; + } + } + + public void discardNotification(int notification_id) { + mNM.cancel(notification_id); + mNotificationMap.remove(notification_id); + } +} diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java new file mode 100644 index 00000000..4aafcceb --- /dev/null +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -0,0 +1,253 @@ +package com.owncloud.android.files.services; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; +import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.ContentValues; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.util.Log; +import android.widget.RemoteViews; +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +public class FileDownloader extends Service implements OnDatatransferProgressListener { + public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; + public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; + public static final String EXTRA_ACCOUNT = "ACCOUNT"; + public static final String EXTRA_FILE_PATH = "FILE_PATH"; + public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; + public static final String EXTRA_FILE_SIZE = "FILE_SIZE"; + public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; + + private static final String TAG = "FileDownloader"; + + private NotificationManager mNotificationMngr; + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + private Account mAccount; + private String mFilePath; + private String mRemotePath; + private int mLastPercent; + private long mTotalDownloadSize; + private long mCurrentDownloadSize; + private Notification mNotification; + + /** + * Static map with the files being download and the path to the temporal file were are download + */ + private static Map mDownloadsInProgress = Collections.synchronizedMap(new HashMap()); + + /** + * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading + */ + public static boolean isDownloading(Account account, String remotePath) { + return (mDownloadsInProgress.get(buildRemoteName(account.name, remotePath)) != null); + } + + /** + * Builds a key for mDownloadsInProgress from the accountName and remotePath + */ + private static String buildRemoteName(String accountName, String remotePath) { + return accountName + remotePath; + } + + + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + downloadFile(); + stopSelf(msg.arg1); + } + } + + public static final String getSavePath(String accountName) { + File sdCard = Environment.getExternalStorageDirectory(); + return sdCard.getAbsolutePath() + "/owncloud/" + Uri.encode(accountName, "@"); + // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B + } + + public static final String getTemporalPath(String accountName) { + File sdCard = Environment.getExternalStorageDirectory(); + return sdCard.getAbsolutePath() + "/owncloud/tmp/" + Uri.encode(accountName, "@"); + // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B + } + + @Override + public void onCreate() { + super.onCreate(); + mNotificationMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + HandlerThread thread = new HandlerThread("FileDownladerThread", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if ( !intent.hasExtra(EXTRA_ACCOUNT) || + !intent.hasExtra(EXTRA_FILE_PATH) || + !intent.hasExtra(EXTRA_REMOTE_PATH) + ) { + Log.e(TAG, "Not enough information provided in intent"); + return START_NOT_STICKY; + } + mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT); + mFilePath = intent.getStringExtra(EXTRA_FILE_PATH); + mRemotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); + mTotalDownloadSize = intent.getLongExtra(EXTRA_FILE_SIZE, -1); + mCurrentDownloadSize = mLastPercent = 0; + + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + return START_NOT_STICKY; + } + + /** + * Core download method: requests the file to download and stores it. + */ + private void downloadFile() { + boolean downloadResult = false; + + /// prepare client object to send the request to the ownCloud server + AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); + WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); + String username = mAccount.name.split("@")[0]; + String password = null; + try { + password = am.blockingGetAuthToken(mAccount, + AccountAuthenticator.AUTH_TOKEN_TYPE, true); + } catch (Exception e) { + Log.e(TAG, "Access to account credentials failed", e); + sendFinalBroadcast(downloadResult, null); + return; + } + wdc.setCredentials(username, password); + wdc.allowSelfsignedCertificates(); + wdc.setDataTransferProgressListener(this); + + + /// download will be in a temporal file + File tmpFile = new File(getTemporalPath(mAccount.name) + mFilePath); + + /// create status notification to show the download progress + 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, mTotalDownloadSize == -1); + mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, tmpFile.getName())); + mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); + // TODO put something smart in the contentIntent below + mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); + mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification); + + + /// perform the download + tmpFile.getParentFile().mkdirs(); + mDownloadsInProgress.put(buildRemoteName(mAccount.name, mRemotePath), tmpFile.getAbsolutePath()); + File newFile = null; + try { + if (wdc.downloadFile(mRemotePath, tmpFile)) { + newFile = new File(getSavePath(mAccount.name) + mFilePath); + newFile.getParentFile().mkdirs(); + boolean moved = tmpFile.renameTo(newFile); + + if (moved) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, newFile.getAbsolutePath()); + getContentResolver().update( + ProviderTableMeta.CONTENT_URI, + cv, + ProviderTableMeta.FILE_NAME + "=? AND " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[] { + mFilePath.substring(mFilePath.lastIndexOf('/') + 1), + mAccount.name }); + downloadResult = true; + } + } + } finally { + mDownloadsInProgress.remove(buildRemoteName(mAccount.name, mRemotePath)); + } + + + /// notify result + mNotificationMngr.cancel(R.string.downloader_download_in_progress_ticker); + int tickerId = (downloadResult) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; + int contentId = (downloadResult) ? 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(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); + finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), tmpFile.getName()), finalNotification.contentIntent); + mNotificationMngr.notify(tickerId, finalNotification); + + sendFinalBroadcast(downloadResult, (downloadResult)?newFile.getAbsolutePath():null); + } + + /** + * Callback method to update the progress bar in the status notification. + */ + @Override + public void transferProgress(long progressRate) { + mCurrentDownloadSize += progressRate; + int percent = (int)(100.0*((double)mCurrentDownloadSize)/((double)mTotalDownloadSize)); + if (percent != mLastPercent) { + mNotification.contentView.setProgressBar(R.id.status_progress, 100, (int)(100*mCurrentDownloadSize/mTotalDownloadSize), mTotalDownloadSize == -1); + mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), percent, new File(mFilePath).getName())); + mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification); + } + + mLastPercent = percent; + } + + + /** + * Sends a broadcast in order to the interested activities can update their view + * + * @param downloadResult 'True' if the download was successful + * @param newFilePath Absolute path to the download file + */ + private void sendFinalBroadcast(boolean downloadResult, String newFilePath) { + Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE); + end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult); + end.putExtra(ACCOUNT_NAME, mAccount.name); + end.putExtra(EXTRA_REMOTE_PATH, mRemotePath); + if (downloadResult) { + end.putExtra(EXTRA_FILE_PATH, newFilePath); + } + sendBroadcast(end); + } + +} diff --git a/src/com/owncloud/android/files/services/FileOperation.java b/src/com/owncloud/android/files/services/FileOperation.java new file mode 100644 index 00000000..bdb76cd3 --- /dev/null +++ b/src/com/owncloud/android/files/services/FileOperation.java @@ -0,0 +1,54 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.files.services; + +import java.io.File; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.datamodel.OCFile; + +import android.accounts.Account; +import android.content.Context; +import eu.alefzero.webdav.WebdavClient; + +public class FileOperation { + + Context mContext; + + public FileOperation(Context contex){ + this.mContext = contex; + } + + /** + * Deletes a file from ownCloud - locally and remote. + * @param file The file to delete + * @return True on success, otherwise false + */ + public boolean delete(OCFile file){ + + Account account = AccountUtils.getCurrentOwnCloudAccount(mContext); + WebdavClient client = new WebdavClient(account, mContext); + if(client.deleteFile(file.getRemotePath())){ + File localFile = new File(file.getStoragePath()); + return localFile.delete(); + } + + return false; + } + +} diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java new file mode 100644 index 00000000..34d795b1 --- /dev/null +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -0,0 +1,327 @@ +package com.owncloud.android.files.services; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; + +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.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.webkit.MimeTypeMap; +import android.widget.RemoteViews; +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +public class FileUploader extends Service implements OnDatatransferProgressListener { + + public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH"; + public static final String EXTRA_PARENT_DIR_ID = "PARENT_DIR_ID"; + public static final String EXTRA_UPLOAD_RESULT = "RESULT"; + public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; + public static final String EXTRA_FILE_PATH = "FILE_PATH"; + + public static final String KEY_LOCAL_FILE = "LOCAL_FILE"; + public static final String KEY_REMOTE_FILE = "REMOTE_FILE"; + public static final String KEY_ACCOUNT = "ACCOUNT"; + public static final String KEY_UPLOAD_TYPE = "UPLOAD_TYPE"; + public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; + + public static final int UPLOAD_SINGLE_FILE = 0; + public static final int UPLOAD_MULTIPLE_FILES = 1; + + private static final String TAG = "FileUploader"; + + private NotificationManager mNotificationManager; + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + private Account mAccount; + private String[] mLocalPaths, mRemotePaths; + private int mUploadType; + private Notification mNotification; + private long mTotalDataToSend, mSendData; + private int mCurrentIndexUpload, mPreviousPercent; + private int mSuccessCounter; + + /** + * Static map with the files being download and the path to the temporal file were are download + */ + private static Map mUploadsInProgress = Collections.synchronizedMap(new HashMap()); + + /** + * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading + */ + public static boolean isUploading(Account account, String remotePath) { + return (mUploadsInProgress.get(buildRemoteName(account.name, remotePath)) != null); + } + + /** + * Builds a key for mUplaodsInProgress from the accountName and remotePath + */ + private static String buildRemoteName(String accountName, String remotePath) { + return accountName + remotePath; + } + + + + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + uploadFile(); + stopSelf(msg.arg1); + } + } + + @Override + public void onCreate() { + super.onCreate(); + mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + HandlerThread thread = new HandlerThread("FileUploaderThread", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (!intent.hasExtra(KEY_ACCOUNT) && !intent.hasExtra(KEY_UPLOAD_TYPE)) { + Log.e(TAG, "Not enough information provided in intent"); + return Service.START_NOT_STICKY; + } + mAccount = intent.getParcelableExtra(KEY_ACCOUNT); + mUploadType = intent.getIntExtra(KEY_UPLOAD_TYPE, -1); + if (mUploadType == -1) { + Log.e(TAG, "Incorrect upload type provided"); + return Service.START_NOT_STICKY; + } + if (mUploadType == UPLOAD_SINGLE_FILE) { + mLocalPaths = new String[] { intent.getStringExtra(KEY_LOCAL_FILE) }; + mRemotePaths = new String[] { intent + .getStringExtra(KEY_REMOTE_FILE) }; + } else { // mUploadType == UPLOAD_MULTIPLE_FILES + mLocalPaths = intent.getStringArrayExtra(KEY_LOCAL_FILE); + mRemotePaths = intent.getStringArrayExtra(KEY_REMOTE_FILE); + } + + if (mLocalPaths.length != mRemotePaths.length) { + Log.e(TAG, "Different number of remote paths and local paths!"); + return Service.START_NOT_STICKY; + } + + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + return Service.START_NOT_STICKY; + } + + + /** + * Core upload method: sends the file(s) to upload + */ + public void uploadFile() { + FileDataStorageManager storageManager = new FileDataStorageManager(mAccount, getContentResolver()); + + mTotalDataToSend = mSendData = mPreviousPercent = 0; + + /// prepare client object to send the request to the ownCloud server + WebdavClient wc = new WebdavClient(mAccount, getApplicationContext()); + wc.allowSelfsignedCertificates(); + wc.setDataTransferProgressListener(this); + + /// create status notification to show the upload progress + mNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker), System.currentTimeMillis()); + mNotification.flags |= Notification.FLAG_ONGOING_EVENT; + RemoteViews oldContentView = mNotification.contentView; + mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout); + mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false); + mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); + // dvelasco ; contentIntent MUST be assigned to avoid app crashes in versions previous to Android 4.x ; + // BUT an empty Intent is not a very elegant solution; something smart should happen when a user 'clicks' on an upload in the notification bar + mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); + mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); + + + /// perform the upload + File [] localFiles = new File[mLocalPaths.length]; + for (int i = 0; i < mLocalPaths.length; ++i) { + localFiles[i] = new File(mLocalPaths[i]); + mTotalDataToSend += localFiles[i].length(); + } + Log.d(TAG, "Will upload " + mTotalDataToSend + " bytes, with " + mLocalPaths.length + " files"); + mSuccessCounter = 0; + for (int i = 0; i < mLocalPaths.length; ++i) { + String mimeType = null; + try { + mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension( + mLocalPaths[i].substring(mLocalPaths[i] + .lastIndexOf('.') + 1)); + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Trying to find out MIME type of a file without extension: " + mLocalPaths[i]); + } + if (mimeType == null) + mimeType = "application/octet-stream"; + mCurrentIndexUpload = i; + long parentDirId = -1; + boolean uploadResult = false; + String availablePath = getAvailableRemotePath(wc, mRemotePaths[i]); + try { + File f = new File(mRemotePaths[i]); + parentDirId = storageManager.getFileByPath(f.getParent().endsWith("/")?f.getParent():f.getParent()+"/").getFileId(); + if(availablePath != null) { + mRemotePaths[i] = availablePath; + mUploadsInProgress.put(buildRemoteName(mAccount.name, mRemotePaths[i]), mLocalPaths[i]); + if (wc.putFile(mLocalPaths[i], mRemotePaths[i], mimeType)) { + OCFile new_file = new OCFile(mRemotePaths[i]); + new_file.setMimetype(mimeType); + new_file.setFileLength(localFiles[i].length()); + new_file.setModificationTimestamp(System.currentTimeMillis()); + new_file.setLastSyncDate(0); + new_file.setStoragePath(mLocalPaths[i]); + new_file.setParentId(parentDirId); + storageManager.saveFile(new_file); + mSuccessCounter++; + uploadResult = true; + } + } + } finally { + mUploadsInProgress.remove(buildRemoteName(mAccount.name, mRemotePaths[i])); + + /// notify upload (or fail) of EACH file to activities interested + Intent end = new Intent(UPLOAD_FINISH_MESSAGE); + end.putExtra(EXTRA_PARENT_DIR_ID, parentDirId); + end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult); + end.putExtra(EXTRA_REMOTE_PATH, mRemotePaths[i]); + end.putExtra(EXTRA_FILE_PATH, mLocalPaths[i]); + end.putExtra(ACCOUNT_NAME, mAccount.name); + sendBroadcast(end); + } + + } + + /// notify final result + if (mSuccessCounter == mLocalPaths.length) { // success + //Notification finalNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_succeeded_ticker), System.currentTimeMillis()); + mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove the ongoing flag + mNotification.flags |= Notification.FLAG_AUTO_CANCEL; + mNotification.contentView = oldContentView; + // TODO put something smart in the contentIntent below + mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); + if (mLocalPaths.length == 1) { + mNotification.setLatestEventInfo( getApplicationContext(), + getString(R.string.uploader_upload_succeeded_ticker), + String.format(getString(R.string.uploader_upload_succeeded_content_single), localFiles[0].getName()), + mNotification.contentIntent); + } else { + mNotification.setLatestEventInfo( getApplicationContext(), + getString(R.string.uploader_upload_succeeded_ticker), + String.format(getString(R.string.uploader_upload_succeeded_content_multiple), mSuccessCounter), + mNotification.contentIntent); + } + mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); // NOT AN ERROR; uploader_upload_in_progress_ticker is the target, not a new notification + + } else { + mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); + Notification finalNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis()); + finalNotification.flags |= Notification.FLAG_AUTO_CANCEL; + // TODO put something smart in the contentIntent below + finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); + if (mLocalPaths.length == 1) { + finalNotification.setLatestEventInfo( getApplicationContext(), + getString(R.string.uploader_upload_failed_ticker), + String.format(getString(R.string.uploader_upload_failed_content_single), localFiles[0].getName()), + finalNotification.contentIntent); + } else { + finalNotification.setLatestEventInfo( getApplicationContext(), + getString(R.string.uploader_upload_failed_ticker), + String.format(getString(R.string.uploader_upload_failed_content_multiple), mSuccessCounter, mLocalPaths.length), + finalNotification.contentIntent); + } + mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification); + } + + } + + /** + * Checks if remotePath does not exist in the server and returns it, or adds a suffix to it in order to avoid the server + * file is overwritten. + * + * @param string + * @return + */ + private String getAvailableRemotePath(WebdavClient wc, String remotePath) { + Boolean check = wc.existsFile(remotePath); + if (check == null) { // null means fail + return null; + } else if (!check) { + return remotePath; + } + + int pos = remotePath.lastIndexOf("."); + String suffix = ""; + String extension = ""; + if (pos >= 0) { + extension = remotePath.substring(pos+1); + remotePath = remotePath.substring(0, pos); + } + int count = 2; + while (check != null && check) { + suffix = " (" + count + ")"; + if (pos >= 0) + check = wc.existsFile(remotePath + suffix + "." + extension); + else + check = wc.existsFile(remotePath + suffix); + count++; + } + if (check == null) { + return null; + } else if (pos >=0) { + return remotePath + suffix + "." + extension; + } else { + return remotePath + suffix; + } + } + + + /** + * Callback method to update the progress bar in the status notification. + */ + @Override + public void transferProgress(long progressRate) { + mSendData += progressRate; + int percent = (int)(100*((double)mSendData)/((double)mTotalDataToSend)); + if (percent != mPreviousPercent) { + String text = String.format(getString(R.string.uploader_upload_in_progress_content), percent, new File(mLocalPaths[mCurrentIndexUpload]).getName()); + mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, false); + mNotification.contentView.setTextViewText(R.id.status_text, text); + mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); + } + mPreviousPercent = percent; + } +} diff --git a/src/com/owncloud/android/files/services/InstantUploadService.java b/src/com/owncloud/android/files/services/InstantUploadService.java new file mode 100644 index 00000000..0324f592 --- /dev/null +++ b/src/com/owncloud/android/files/services/InstantUploadService.java @@ -0,0 +1,162 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.files.services; + +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.httpclient.HttpException; +import org.apache.jackrabbit.webdav.client.methods.MkColMethod; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.utils.OwnCloudVersion; + +import eu.alefzero.webdav.WebdavClient; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Service; +import android.content.Intent; +import android.net.Uri; +import android.os.IBinder; +import android.util.Log; + +public class InstantUploadService extends Service { + + public static String KEY_FILE_PATH = "KEY_FILEPATH"; + public static String KEY_FILE_SIZE = "KEY_FILESIZE"; + public static String KEY_MIME_TYPE = "KEY_MIMETYPE"; + public static String KEY_DISPLAY_NAME = "KEY_FILENAME"; + public static String KEY_ACCOUNT = "KEY_ACCOUNT"; + + private static String TAG = "InstantUploadService"; + private static String INSTANT_UPLOAD_DIR = "/InstantUpload"; + private UploaderRunnable mUploaderRunnable; + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + 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"); + return Service.START_NOT_STICKY; + } + + if (mUploaderRunnable == null) { + mUploaderRunnable = new UploaderRunnable(); + } + + String filename = intent.getStringExtra(KEY_DISPLAY_NAME); + String filepath = intent.getStringExtra(KEY_FILE_PATH); + String mimetype = intent.getStringExtra(KEY_MIME_TYPE); + Account account = intent.getParcelableExtra(KEY_ACCOUNT); + long filesize = intent.getLongExtra(KEY_FILE_SIZE, -1); + + mUploaderRunnable.addElementToQueue(filename, filepath, mimetype, filesize, account); + + // 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"); + new Thread(mUploaderRunnable).start(); + + return Service.START_STICKY; + } + + private class UploaderRunnable implements Runnable { + + Object mLock; + List> mHashMapList; + + public UploaderRunnable() { + mHashMapList = new LinkedList>(); + mLock = new Object(); + } + + public void addElementToQueue(String filename, + String filepath, + String mimetype, + long length, + Account account) { + HashMap new_map = new HashMap(); + new_map.put(KEY_ACCOUNT, account); + new_map.put(KEY_DISPLAY_NAME, filename); + new_map.put(KEY_FILE_PATH, filepath); + new_map.put(KEY_MIME_TYPE, mimetype); + new_map.put(KEY_FILE_SIZE, length); + + synchronized (mLock) { + mHashMapList.add(new_map); + } + } + + private HashMap getFirstObject() { + synchronized (mLock) { + if (mHashMapList.size() == 0) + return null; + HashMap ret = mHashMapList.get(0); + mHashMapList.remove(0); + return ret; + } + } + + public void run() { + HashMap working_map; + AccountManager am = AccountManager.get(getApplicationContext()); + + while ((working_map = getFirstObject()) != null) { + Account account = (Account) working_map.get(KEY_ACCOUNT); + String username = account.name.substring(0, account.name.lastIndexOf('@')); + String password = am.getPassword(account); + String filename = (String) working_map.get(KEY_DISPLAY_NAME); + String filepath = (String) working_map.get(KEY_FILE_PATH); + String mimetype = (String) working_map.get(KEY_MIME_TYPE); + + String oc_base_url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); + String oc_version = am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION); + OwnCloudVersion ocv = new OwnCloudVersion(oc_version); + String webdav_path = AccountUtils.getWebdavPath(ocv); + WebdavClient wdc = new WebdavClient(account, getApplicationContext()); + wdc.allowSelfsignedCertificates(); + wdc.setCredentials(username, password); + + MkColMethod mkcol = new MkColMethod(oc_base_url+webdav_path+INSTANT_UPLOAD_DIR); + int status = 0; + try { + status = wdc.executeMethod(mkcol); + Log.e(TAG, "mkcol returned " + status); + wdc.putFile(filepath, INSTANT_UPLOAD_DIR + "/" + filename, mimetype); + } catch (HttpException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/src/com/owncloud/android/files/services/OnUploadCompletedListener.java b/src/com/owncloud/android/files/services/OnUploadCompletedListener.java new file mode 100644 index 00000000..80917ddf --- /dev/null +++ b/src/com/owncloud/android/files/services/OnUploadCompletedListener.java @@ -0,0 +1,8 @@ +package com.owncloud.android.files.services; + +public interface OnUploadCompletedListener extends Runnable { + + public boolean getUploadResult(); + + public void setUploadResult(boolean result); +} diff --git a/src/com/owncloud/android/location/LocationServiceLauncherReciever.java b/src/com/owncloud/android/location/LocationServiceLauncherReciever.java new file mode 100644 index 00000000..19efd7ea --- /dev/null +++ b/src/com/owncloud/android/location/LocationServiceLauncherReciever.java @@ -0,0 +1,87 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.location; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Log; + +public class LocationServiceLauncherReciever extends BroadcastReceiver { + + private final String TAG = getClass().getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + Intent deviceTrackingIntent = new Intent(); + deviceTrackingIntent + .setAction("eu.alefzero.owncloud.location.LocationUpdateService"); + SharedPreferences preferences = PreferenceManager + .getDefaultSharedPreferences(context); + boolean trackDevice = preferences.getBoolean("enable_devicetracking", + true); + + // Used in Preferences activity so that tracking is disabled or + // reenabled + if (intent.hasExtra("TRACKING_SETTING")) { + trackDevice = intent.getBooleanExtra("TRACKING_SETTING", true); + } + + startOrStopDeviceTracking(context, trackDevice); + } + + /** + * Used internally. Starts or stops the device tracking service + * + * @param trackDevice true to start the service, false to stop it + */ + private void startOrStopDeviceTracking(Context context, boolean trackDevice) { + Intent deviceTrackingIntent = new Intent(); + deviceTrackingIntent + .setAction("eu.alefzero.owncloud.location.LocationUpdateService"); + if (!isDeviceTrackingServiceRunning(context) && trackDevice) { + Log.d(TAG, "Starting device tracker service"); + context.startService(deviceTrackingIntent); + } else if (isDeviceTrackingServiceRunning(context) && !trackDevice) { + Log.d(TAG, "Stopping device tracker service"); + context.stopService(deviceTrackingIntent); + } + } + + /** + * Checks to see whether or not the LocationUpdateService is running + * + * @return true, if it is. Otherwise false + */ + private boolean isDeviceTrackingServiceRunning(Context context) { + ActivityManager manager = (ActivityManager) context + .getSystemService(Context.ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager + .getRunningServices(Integer.MAX_VALUE)) { + if (getClass().getName().equals(service.service.getClassName())) { + return true; + } + } + return false; + } + +} diff --git a/src/com/owncloud/android/location/LocationUpdateService.java b/src/com/owncloud/android/location/LocationUpdateService.java new file mode 100644 index 00000000..6e3dfb83 --- /dev/null +++ b/src/com/owncloud/android/location/LocationUpdateService.java @@ -0,0 +1,110 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.location; + +import android.app.IntentService; +import android.content.Intent; +import android.content.SharedPreferences; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.location.LocationProvider; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.widget.Toast; + +import com.owncloud.android.R; + +public class LocationUpdateService extends IntentService implements + LocationListener { + + public static final String TAG = "LocationUpdateService"; + + private LocationManager mLocationManager; + private LocationProvider mLocationProvider; + private SharedPreferences mPreferences; + + public LocationUpdateService() { + super(TAG); + } + + @Override + protected void onHandleIntent(Intent intent) { + mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); + // Determine, how we can track the device + Criteria criteria = new Criteria(); + criteria.setAccuracy(Criteria.ACCURACY_FINE); + criteria.setPowerRequirement(Criteria.POWER_LOW); + mLocationProvider = mLocationManager.getProvider(mLocationManager + .getBestProvider(criteria, true)); + + // Notify user if there is no way to track the device + if (mLocationProvider == null) { + Toast.makeText(this, + R.string.location_no_provider, + Toast.LENGTH_LONG); + stopSelf(); + return; + } + + // Get preferences for device tracking + mPreferences = PreferenceManager.getDefaultSharedPreferences(this); + boolean trackDevice = mPreferences.getBoolean("enable_devicetracking", + true); + int updateIntervall = Integer.parseInt(mPreferences.getString( + "devicetracking_update_intervall", "30")) * 60 * 1000; + int distanceBetweenLocationChecks = 50; + + // If we do shall track the device -> Stop + if (!trackDevice) { + Log.d(TAG, "Devicetracking is disabled"); + stopSelf(); + return; + } + + mLocationManager.requestLocationUpdates(mLocationProvider.getName(), + updateIntervall, distanceBetweenLocationChecks, this); + } + + @Override + public void onLocationChanged(Location location) { + Log.d(TAG, "Location changed: " + location); + + } + + @Override + public void onProviderDisabled(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onProviderEnabled(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onStatusChanged(String arg0, int arg1, Bundle arg2) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/com/owncloud/android/providers/FileContentProvider.java b/src/com/owncloud/android/providers/FileContentProvider.java new file mode 100644 index 00000000..6605d89b --- /dev/null +++ b/src/com/owncloud/android/providers/FileContentProvider.java @@ -0,0 +1,238 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.providers; + +import java.util.HashMap; + +import com.owncloud.android.db.ProviderMeta; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; + + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +/** + * The ContentProvider for the ownCloud App. + * + * @author Bartek Przybylski + * + */ +public class FileContentProvider extends ContentProvider { + + private DataBaseHelper mDbHelper; + + private static HashMap mProjectionMap; + static { + mProjectionMap = new HashMap(); + mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); + mProjectionMap.put(ProviderTableMeta.FILE_PARENT, + ProviderTableMeta.FILE_PARENT); + mProjectionMap.put(ProviderTableMeta.FILE_PATH, + ProviderTableMeta.FILE_PATH); + mProjectionMap.put(ProviderTableMeta.FILE_NAME, + ProviderTableMeta.FILE_NAME); + mProjectionMap.put(ProviderTableMeta.FILE_CREATION, + ProviderTableMeta.FILE_CREATION); + mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, + ProviderTableMeta.FILE_MODIFIED); + mProjectionMap.put(ProviderTableMeta.FILE_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_KEEP_IN_SYNC, + ProviderTableMeta.FILE_KEEP_IN_SYNC); + } + + private static final int SINGLE_FILE = 1; + private static final int DIRECTORY = 2; + private static final int ROOT_DIRECTORY = 3; + private static final UriMatcher mUriMatcher; + static { + mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); + } + + @Override + public int delete(Uri uri, String where, String[] whereArgs) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + int count = 0; + switch (mUriMatcher.match(uri)) { + case SINGLE_FILE: + count = db.delete(ProviderTableMeta.DB_NAME, + ProviderTableMeta._ID + + "=" + + uri.getPathSegments().get(1) + + (!TextUtils.isEmpty(where) ? " AND (" + where + + ")" : ""), whereArgs); + break; + case ROOT_DIRECTORY: + count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); + break; + default: + throw new IllegalArgumentException("Unknown uri: " + uri.toString()); + } + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + @Override + public String getType(Uri uri) { + switch (mUriMatcher.match(uri)) { + case ROOT_DIRECTORY: + return ProviderTableMeta.CONTENT_TYPE; + case SINGLE_FILE: + return ProviderTableMeta.CONTENT_TYPE_ITEM; + default: + throw new IllegalArgumentException("Unknown Uri id." + + uri.toString()); + } + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + if (mUriMatcher.match(uri) != SINGLE_FILE && + mUriMatcher.match(uri) != ROOT_DIRECTORY) { + + throw new IllegalArgumentException("Unknown uri id: " + uri); + } + + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values); + if (rowId > 0) { + Uri insertedFileUri = ContentUris.withAppendedId( + ProviderTableMeta.CONTENT_URI_FILE, rowId); + getContext().getContentResolver().notifyChange(insertedFileUri, + null); + return insertedFileUri; + } + throw new SQLException("ERROR " + uri); + } + + @Override + public boolean onCreate() { + mDbHelper = new DataBaseHelper(getContext()); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); + + sqlQuery.setTables(ProviderTableMeta.DB_NAME); + sqlQuery.setProjectionMap(mProjectionMap); + + switch (mUriMatcher.match(uri)) { + case ROOT_DIRECTORY: + break; + case DIRECTORY: + sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" + + uri.getPathSegments().get(1)); + break; + case SINGLE_FILE: + if (uri.getPathSegments().size() > 1) { + sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + + uri.getPathSegments().get(1)); + } + break; + default: + throw new IllegalArgumentException("Unknown uri id: " + uri); + } + + String order; + if (TextUtils.isEmpty(sortOrder)) { + order = ProviderTableMeta.DEFAULT_SORT_ORDER; + } else { + order = sortOrder; + } + + SQLiteDatabase db = mDbHelper.getReadableDatabase(); + Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, + null, null, order); + + c.setNotificationUri(getContext().getContentResolver(), uri); + + return c; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, + String[] selectionArgs) { + return mDbHelper.getWritableDatabase().update( + ProviderTableMeta.DB_NAME, values, selection, selectionArgs); + } + + class DataBaseHelper extends SQLiteOpenHelper { + + public DataBaseHelper(Context context) { + super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION); + + } + + @Override + public void onCreate(SQLiteDatabase db) { + // files table + Log.i("SQL", "Entering in onCreate"); + db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + + ProviderTableMeta.FILE_NAME + " TEXT, " + + ProviderTableMeta.FILE_PATH + " TEXT, " + + ProviderTableMeta.FILE_PARENT + " INTEGER, " + + ProviderTableMeta.FILE_CREATION + " INTEGER, " + + ProviderTableMeta.FILE_MODIFIED + " INTEGER, " + + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " + + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " + + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, " + + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, " + + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER );"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.i("SQL", "Entering in onUpgrade"); + if (oldVersion == 1 && newVersion >= 2) { + Log.i("SQL", "Entering in the ADD in onUpgrade"); + db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + + " DEFAULT 0"); + } else Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); + } + + } + +} diff --git a/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java b/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java new file mode 100644 index 00000000..e8b1fcb2 --- /dev/null +++ b/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java @@ -0,0 +1,164 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.syncadapter; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.Date; + +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.protocol.HttpContext; + +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.datamodel.DataStorageManager; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.Context; +import android.net.Uri; +import eu.alefzero.webdav.WebdavClient; + +/** + * Base SyncAdapter for OwnCloud Designed to be subclassed for the concrete + * SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc.. + * + * @author sassman + * + */ +public abstract class AbstractOwnCloudSyncAdapter extends + AbstractThreadedSyncAdapter { + + private AccountManager accountManager; + private Account account; + private ContentProviderClient contentProvider; + private Date lastUpdated; + private DataStorageManager mStoreManager; + + private WebdavClient mClient = null; + + public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + this.setAccountManager(AccountManager.get(context)); + } + + public AccountManager getAccountManager() { + return accountManager; + } + + public void setAccountManager(AccountManager accountManager) { + this.accountManager = accountManager; + } + + public Account getAccount() { + return account; + } + + public void setAccount(Account account) { + this.account = account; + } + + public ContentProviderClient getContentProvider() { + return contentProvider; + } + + public void setContentProvider(ContentProviderClient contentProvider) { + this.contentProvider = contentProvider; + } + + public Date getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public void setStorageManager(DataStorageManager storage_manager) { + mStoreManager = storage_manager; + } + + public DataStorageManager getStorageManager() { + return mStoreManager; + } + + protected ConnectionKeepAliveStrategy getKeepAliveStrategy() { + return new ConnectionKeepAliveStrategy() { + public long getKeepAliveDuration(HttpResponse response, + HttpContext context) { + // Change keep alive straategy basing on response: ie + // forbidden/not found/etc + // should have keep alive 0 + // default return: 5s + int statusCode = response.getStatusLine().getStatusCode(); + + // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed + // out + if ((statusCode >= 400 && statusCode <= 418) + || (statusCode >= 421 && statusCode <= 426) + || (statusCode >= 500 && statusCode <= 510) + || statusCode == 118) { + return 0; + } + + return 5 * 1000; + } + }; + } + + protected HttpResponse fireRawRequest(HttpRequest query) + throws ClientProtocolException, OperationCanceledException, + AuthenticatorException, IOException { + /* + * BasicHttpContext httpContext = new BasicHttpContext(); BasicScheme + * basicAuth = new BasicScheme(); + * httpContext.setAttribute("preemptive-auth", basicAuth); + * + * HttpResponse response = getClient().execute(mHost, query, + * httpContext); + */ + return null; + } + + protected Uri getUri() { + return Uri.parse(this.getAccountManager().getUserData(getAccount(), + AccountAuthenticator.KEY_OC_URL)); + } + + protected WebdavClient getClient() throws OperationCanceledException, + AuthenticatorException, IOException { + if (mClient == null) { + if (this.getAccountManager().getUserData(getAccount(), + AccountAuthenticator.KEY_OC_URL) == null) { + throw new UnknownHostException(); + } + mClient = new WebdavClient(account, getContext()); + mClient.allowSelfsignedCertificates(); + // mHost = mClient.getTargetHost(); + } + + return mClient; + } +} \ No newline at end of file diff --git a/src/com/owncloud/android/syncadapter/ContactSyncAdapter.java b/src/com/owncloud/android/syncadapter/ContactSyncAdapter.java new file mode 100644 index 00000000..2508dcd6 --- /dev/null +++ b/src/com/owncloud/android/syncadapter/ContactSyncAdapter.java @@ -0,0 +1,107 @@ +package com.owncloud.android.syncadapter; + +import java.io.FileInputStream; +import java.io.IOException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ByteArrayEntity; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.db.ProviderMeta; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.ContentProviderClient; +import android.content.Context; +import android.content.SyncResult; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract; +import android.util.Log; + +public class ContactSyncAdapter extends AbstractOwnCloudSyncAdapter { + private String mAddrBookUri; + + public ContactSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + mAddrBookUri = null; + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, + ContentProviderClient provider, SyncResult syncResult) { + setAccount(account); + setContentProvider(provider); + Cursor c = getLocalContacts(false); + if (c.moveToFirst()) { + do { + String lookup = c.getString(c + .getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); + String a = getAddressBookUri(); + String uri = a + lookup + ".vcf"; + FileInputStream f; + try { + f = getContactVcard(lookup); + HttpPut query = new HttpPut(uri); + byte[] b = new byte[f.available()]; + f.read(b); + query.setEntity(new ByteArrayEntity(b)); + HttpResponse response = fireRawRequest(query); + } catch (IOException e) { + e.printStackTrace(); + return; + } catch (OperationCanceledException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (AuthenticatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } while (c.moveToNext()); + // } while (c.moveToNext()); + } + + } + + private String getAddressBookUri() { + if (mAddrBookUri != null) + return mAddrBookUri; + + AccountManager am = getAccountManager(); + String uri = am.getUserData(getAccount(), + AccountAuthenticator.KEY_OC_URL).replace( + AccountUtils.WEBDAV_PATH_2_0, AccountUtils.CARDDAV_PATH_2_0); + uri += "/addressbooks/" + + getAccount().name.substring(0, + getAccount().name.lastIndexOf('@')) + "/default/"; + mAddrBookUri = uri; + return uri; + } + + private FileInputStream getContactVcard(String lookupKey) + throws IOException { + Uri uri = Uri.withAppendedPath( + ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey); + AssetFileDescriptor fd = getContext().getContentResolver() + .openAssetFileDescriptor(uri, "r"); + return fd.createInputStream(); + } + + private Cursor getLocalContacts(boolean include_hidden_contacts) { + return getContext().getContentResolver().query( + ContactsContract.Contacts.CONTENT_URI, + new String[] { ContactsContract.Contacts._ID, + ContactsContract.Contacts.LOOKUP_KEY }, + ContactsContract.Contacts.IN_VISIBLE_GROUP + " = ?", + new String[] { (include_hidden_contacts ? "0" : "1") }, + ContactsContract.Contacts._ID + " DESC"); + } + +} diff --git a/src/com/owncloud/android/syncadapter/ContactSyncService.java b/src/com/owncloud/android/syncadapter/ContactSyncService.java new file mode 100644 index 00000000..3016c851 --- /dev/null +++ b/src/com/owncloud/android/syncadapter/ContactSyncService.java @@ -0,0 +1,26 @@ +package com.owncloud.android.syncadapter; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class ContactSyncService extends Service { + private static final Object syncAdapterLock = new Object(); + private static AbstractOwnCloudSyncAdapter mSyncAdapter = null; + + @Override + public void onCreate() { + synchronized (syncAdapterLock) { + if (mSyncAdapter == null) { + mSyncAdapter = new ContactSyncAdapter(getApplicationContext(), + true); + } + } + } + + @Override + public IBinder onBind(Intent arg0) { + return mSyncAdapter.getSyncAdapterBinder(); + } + +} diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java new file mode 100644 index 00000000..f7bfa432 --- /dev/null +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -0,0 +1,294 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.syncadapter; + +import java.io.IOException; +import java.util.List; +import java.util.Vector; + +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.MultiStatus; +import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; + +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; + +import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.ContentProviderClient; +import android.content.Context; +import android.content.Intent; +import android.content.SyncResult; +import android.os.Bundle; +import android.util.Log; +import eu.alefzero.webdav.WebdavEntry; +import eu.alefzero.webdav.WebdavUtils; + +/** + * 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"; + + /* Commented code for ugly performance tests + private final static int MAX_DELAYS = 100; + private static long[] mResponseDelays = new long[MAX_DELAYS]; + private static long[] mSaveDelays = new long[MAX_DELAYS]; + private int mDelaysIndex = 0; + private int mDelaysCount = 0; + */ + + private long mCurrentSyncTime; + private boolean mCancellation; + private Account mAccount; + + public FileSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + } + + @Override + public synchronized void onPerformSync(Account account, Bundle extras, + String authority, ContentProviderClient provider, + SyncResult syncResult) { + + mCancellation = false; + mAccount = account; + + this.setAccount(mAccount); + this.setContentProvider(provider); + this.setStorageManager(new FileDataStorageManager(mAccount, + getContentProvider())); + + /* Commented code for ugly performance tests + mDelaysIndex = 0; + mDelaysCount = 0; + */ + + + Log.d(TAG, "syncing owncloud account " + mAccount.name); + + sendStickyBroadcast(true, null); // message to signal the start to the UI + + PropFindMethod query; + try { + mCurrentSyncTime = System.currentTimeMillis(); + query = new PropFindMethod(getUri().toString() + "/"); + getClient().executeMethod(query); + MultiStatus resp = null; + resp = query.getResponseBodyAsMultiStatus(); + + if (resp.getResponses().length > 0) { + WebdavEntry we = new WebdavEntry(resp.getResponses()[0], getUri().getPath()); + OCFile file = fillOCFile(we); + file.setParentId(0); + getStorageManager().saveFile(file); + if (!mCancellation) { + fetchData(getUri().toString(), syncResult, file.getFileId()); + } + } + } catch (OperationCanceledException e) { + e.printStackTrace(); + } catch (AuthenticatorException e) { + syncResult.stats.numAuthExceptions++; + e.printStackTrace(); + } catch (IOException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (DavException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (Throwable t) { + // TODO update syncResult + Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t); + t.printStackTrace(); + } + + /* Commented code for ugly performance tests + long sum = 0, mean = 0, max = 0, min = Long.MAX_VALUE; + for (int i=0; i updatedFiles = new Vector(resp.getResponses().length - 1); + for (int i = 1; i < resp.getResponses().length; ++i) { + WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath()); + OCFile file = fillOCFile(we); + file.setParentId(parentId); + if (getStorageManager().getFileByPath(file.getRemotePath()) != null && + getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() && + file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath()) + .getModificationTimestamp()) { + Intent intent = new Intent(this.getContext(), FileDownloader.class); + intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount()); + intent.putExtra(FileDownloader.EXTRA_FILE_PATH, file.getRemotePath()); + intent.putExtra(FileDownloader.EXTRA_REMOTE_PATH, file.getRemotePath()); + intent.putExtra(FileDownloader.EXTRA_FILE_SIZE, file.getFileLength()); + file.setKeepInSync(true); + getContext().startService(intent); + } + if (getStorageManager().getFileByPath(file.getRemotePath()) != null) + file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync()); + + //Log.v(TAG, "adding file: " + file); + updatedFiles.add(file); + if (parentId == 0) + parentId = file.getFileId(); + } + /* Commented code for ugly performance tests + long saveDelay = System.currentTimeMillis(); + */ + getStorageManager().saveFiles(updatedFiles); // all "at once" ; trying to get a best performance in database update + /* Commented code for ugly performance tests + saveDelay = System.currentTimeMillis() - saveDelay; + Log.e(TAG, "syncing: SAVE TIME for " + uri + " contents, " + mSaveDelays[mDelaysIndex] + "ms"); + */ + + // removal of obsolete files + Vector files = getStorageManager().getDirectoryContent( + getStorageManager().getFileById(parentId)); + OCFile file; + for (int i=0; i < files.size(); ) { + file = files.get(i); + if (file.getLastSyncDate() != mCurrentSyncTime) { + Log.v(TAG, "removing file: " + file); + getStorageManager().removeFile(file); + files.remove(i); + } else { + i++; + } + } + + // synchronized folder -> notice to UI + sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath()); + + // recursive fetch + for (int i=0; i < files.size() && !mCancellation; i++) { + OCFile newFile = files.get(i); + if (newFile.getMimetype().equals("DIR")) { + fetchData(getUri().toString() + WebdavUtils.encodePath(newFile.getRemotePath()), syncResult, newFile.getFileId()); + } + } + if (mCancellation) Log.d(TAG, "Leaving " + uri + " because cancelation request"); + + /* Commented code for ugly performance tests + mResponseDelays[mDelaysIndex] = responseDelay; + mSaveDelays[mDelaysIndex] = saveDelay; + mDelaysCount++; + mDelaysIndex++; + if (mDelaysIndex >= MAX_DELAYS) + mDelaysIndex = 0; + */ + + + + } catch (OperationCanceledException e) { + e.printStackTrace(); + } catch (AuthenticatorException e) { + syncResult.stats.numAuthExceptions++; + e.printStackTrace(); + } catch (IOException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (DavException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (Throwable t) { + // TODO update syncResult + Log.e(TAG, "problem while synchronizing owncloud account " + mAccount.name, t); + t.printStackTrace(); + } + } + + private OCFile fillOCFile(WebdavEntry we) { + OCFile file = new OCFile(we.decodedPath()); + file.setCreationTimestamp(we.createTimestamp()); + file.setFileLength(we.contentLength()); + file.setMimetype(we.contentType()); + file.setModificationTimestamp(we.modifiedTimesamp()); + file.setLastSyncDate(mCurrentSyncTime); + return file; + } + + + private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) { + 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); + } + getContext().sendStickyBroadcast(i); + } + + /** + * Called by system SyncManager when a synchronization is required to be cancelled. + * + * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder + * fetched will be still saved in the database. See onPerformSync implementation. + */ + @Override + public void onSyncCanceled() { + Log.d(TAG, "Synchronization of " + mAccount.name + " has been requested to cancell"); + mCancellation = true; + super.onSyncCanceled(); + } + +} diff --git a/src/com/owncloud/android/syncadapter/FileSyncService.java b/src/com/owncloud/android/syncadapter/FileSyncService.java new file mode 100644 index 00000000..74c7fa67 --- /dev/null +++ b/src/com/owncloud/android/syncadapter/FileSyncService.java @@ -0,0 +1,50 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.syncadapter; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * Background service for syncing files to our local Database + * + * @author Bartek Przybylski + * + */ +public class FileSyncService extends Service { + public static final String SYNC_MESSAGE = "ACCOUNT_SYNC"; + public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH"; + public static final String IN_PROGRESS = "SYNC_IN_PROGRESS"; + public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; + + /* + * {@inheritDoc} + */ + @Override + public void onCreate() { + } + + /* + * {@inheritDoc} + */ + @Override + public IBinder onBind(Intent intent) { + return new FileSyncAdapter(getApplicationContext(), true).getSyncAdapterBinder(); + } +} diff --git a/src/com/owncloud/android/ui/ActionItem.java b/src/com/owncloud/android/ui/ActionItem.java new file mode 100644 index 00000000..b2be7029 --- /dev/null +++ b/src/com/owncloud/android/ui/ActionItem.java @@ -0,0 +1,61 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui; + +import android.graphics.drawable.Drawable; +import android.view.View.OnClickListener; + +/** + * Represents an Item on the ActionBar. + * + * @author Bartek Przybylski + * + */ +public class ActionItem { + private Drawable mIcon; + private String mTitle; + private OnClickListener mClickListener; + + public ActionItem() { + } + + public void setTitle(String title) { + mTitle = title; + } + + public String getTitle() { + return mTitle; + } + + public void setIcon(Drawable icon) { + mIcon = icon; + } + + public Drawable getIcon() { + return mIcon; + } + + public void setOnClickListener(OnClickListener listener) { + mClickListener = listener; + } + + public OnClickListener getOnClickListerner() { + return mClickListener; + } + +} diff --git a/src/com/owncloud/android/ui/CustomPopup.java b/src/com/owncloud/android/ui/CustomPopup.java new file mode 100644 index 00000000..b7ce4265 --- /dev/null +++ b/src/com/owncloud/android/ui/CustomPopup.java @@ -0,0 +1,154 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.View.OnTouchListener; +import android.view.ViewGroup.LayoutParams; +import android.widget.PopupWindow; + +/** + * Represents a custom PopupWindows + * + * @author Lorensius. W. T + * + */ +public class CustomPopup { + protected final View mAnchor; + protected final PopupWindow mWindow; + private View root; + private Drawable background = null; + protected final WindowManager mWManager; + + public CustomPopup(View anchor) { + mAnchor = anchor; + mWindow = new PopupWindow(anchor.getContext()); + + mWindow.setTouchInterceptor(new OnTouchListener() { + + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { + CustomPopup.this.dismiss(); + return true; + } + return false; + } + }); + + mWManager = (WindowManager) anchor.getContext().getSystemService( + Context.WINDOW_SERVICE); + onCreate(); + } + + public void onCreate() { + } + + public void onShow() { + } + + public void preShow() { + if (root == null) { + throw new IllegalStateException( + "setContentView called with a view to display"); + } + + onShow(); + + if (background == null) { + mWindow.setBackgroundDrawable(new BitmapDrawable()); + } else { + mWindow.setBackgroundDrawable(background); + } + + mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); + mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); + mWindow.setTouchable(true); + mWindow.setFocusable(true); + mWindow.setOutsideTouchable(true); + + mWindow.setContentView(root); + } + + public void setBackgroundDrawable(Drawable background) { + this.background = background; + } + + public void setContentView(View root) { + this.root = root; + mWindow.setContentView(root); + } + + public void setContentView(int layoutResId) { + LayoutInflater inflater = (LayoutInflater) mAnchor.getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + setContentView(inflater.inflate(layoutResId, null)); + } + + public void showDropDown() { + showDropDown(0, 0); + } + + public void showDropDown(int x, int y) { + preShow(); + mWindow.setAnimationStyle(android.R.style.Animation_Dialog); + mWindow.showAsDropDown(mAnchor, x, y); + } + + public void showLikeQuickAction() { + showLikeQuickAction(0, 0); + } + + public void showLikeQuickAction(int x, int y) { + preShow(); + + mWindow.setAnimationStyle(android.R.style.Animation_Dialog); + int[] location = new int[2]; + mAnchor.getLocationOnScreen(location); + + Rect anchorRect = new Rect(location[0], location[1], location[0] + + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); + + root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT)); + root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + + int rootW = root.getWidth(), rootH = root.getHeight(); + int screenW = mWManager.getDefaultDisplay().getWidth(); + + int xpos = ((screenW - rootW) / 2) + x; + int ypos = anchorRect.top - rootH + y; + + if (rootH > anchorRect.top) { + ypos = anchorRect.bottom + y; + } + mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos); + } + + public void dismiss() { + mWindow.dismiss(); + } + +} diff --git a/src/com/owncloud/android/ui/FragmentListView.java b/src/com/owncloud/android/ui/FragmentListView.java new file mode 100644 index 00000000..98ac0008 --- /dev/null +++ b/src/com/owncloud/android/ui/FragmentListView.java @@ -0,0 +1,52 @@ +package com.owncloud.android.ui; + +import com.actionbarsherlock.app.SherlockFragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.AdapterView.OnItemClickListener; + +public class FragmentListView extends SherlockFragment implements + OnItemClickListener, OnItemLongClickListener { + ListView mList; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + public void setListAdapter(ListAdapter listAdapter) { + mList.setAdapter(listAdapter); + mList.invalidate(); + } + + public ListView getListView() { + return mList; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mList = new ListView(getActivity()); + mList.setOnItemClickListener(this); + mList.setOnItemLongClickListener(this); + return mList; + // return super.onCreateView(inflater, container, savedInstanceState); + } + + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + } + + @Override + public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2, + long arg3) { + return false; + } + +} diff --git a/src/com/owncloud/android/ui/QuickAction.java b/src/com/owncloud/android/ui/QuickAction.java new file mode 100644 index 00000000..122792d5 --- /dev/null +++ b/src/com/owncloud/android/ui/QuickAction.java @@ -0,0 +1,305 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui; + +import android.content.Context; + +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.LinearLayout; +import android.widget.ScrollView; + +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup.LayoutParams; +import android.view.ViewGroup; + +import java.util.ArrayList; + +import com.owncloud.android.R; + +/** + * Popup window, shows action list as icon and text like the one in Gallery3D + * app. + * + * @author Lorensius. W. T + */ +public class QuickAction extends CustomPopup { + private final View root; + private final ImageView mArrowUp; + private final ImageView mArrowDown; + private final LayoutInflater inflater; + private final Context context; + + protected static final int ANIM_GROW_FROM_LEFT = 1; + protected static final int ANIM_GROW_FROM_RIGHT = 2; + protected static final int ANIM_GROW_FROM_CENTER = 3; + protected static final int ANIM_REFLECT = 4; + protected static final int ANIM_AUTO = 5; + + private int animStyle; + private ViewGroup mTrack; + private ScrollView scroller; + private ArrayList actionList; + + /** + * Constructor + * + * @param anchor {@link View} on where the popup window should be displayed + */ + public QuickAction(View anchor) { + super(anchor); + + actionList = new ArrayList(); + context = anchor.getContext(); + inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + root = (ViewGroup) inflater.inflate(R.layout.popup, null); + + mArrowDown = (ImageView) root.findViewById(R.id.arrow_down); + mArrowUp = (ImageView) root.findViewById(R.id.arrow_up); + + setContentView(root); + + mTrack = (ViewGroup) root.findViewById(R.id.tracks); + scroller = (ScrollView) root.findViewById(R.id.scroller); + animStyle = ANIM_AUTO; + } + + /** + * Set animation style + * + * @param animStyle animation style, default is set to ANIM_AUTO + */ + public void setAnimStyle(int animStyle) { + this.animStyle = animStyle; + } + + /** + * Add action item + * + * @param action {@link ActionItem} object + */ + public void addActionItem(ActionItem action) { + actionList.add(action); + } + + /** + * Show popup window. Popup is automatically positioned, on top or bottom of + * anchor view. + * + */ + public void show() { + preShow(); + + int xPos, yPos; + + int[] location = new int[2]; + + mAnchor.getLocationOnScreen(location); + + Rect anchorRect = new Rect(location[0], location[1], location[0] + + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); + + createActionList(); + + root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT)); + root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + + int rootHeight = root.getMeasuredHeight(); + int rootWidth = root.getMeasuredWidth(); + + int screenWidth = mWManager.getDefaultDisplay().getWidth(); + int screenHeight = mWManager.getDefaultDisplay().getHeight(); + + // automatically get X coord of popup (top left) + if ((anchorRect.left + rootWidth) > screenWidth) { + xPos = anchorRect.left - (rootWidth - mAnchor.getWidth()); + } else { + if (mAnchor.getWidth() > rootWidth) { + xPos = anchorRect.centerX() - (rootWidth / 2); + } else { + xPos = anchorRect.left; + } + } + + int dyTop = anchorRect.top; + int dyBottom = screenHeight - anchorRect.bottom; + + boolean onTop = (dyTop > dyBottom) ? true : false; + + if (onTop) { + if (rootHeight > dyTop) { + yPos = 15; + LayoutParams l = scroller.getLayoutParams(); + l.height = dyTop - mAnchor.getHeight(); + } else { + yPos = anchorRect.top - rootHeight; + } + } else { + yPos = anchorRect.bottom; + + if (rootHeight > dyBottom) { + LayoutParams l = scroller.getLayoutParams(); + l.height = dyBottom; + } + } + + showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), + anchorRect.centerX() - xPos); + + setAnimationStyle(screenWidth, anchorRect.centerX(), onTop); + + mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos); + } + + /** + * Set animation style + * + * @param screenWidth screen width + * @param requestedX distance from left edge + * @param onTop flag to indicate where the popup should be displayed. Set + * TRUE if displayed on top of anchor view and vice versa + */ + private void setAnimationStyle(int screenWidth, int requestedX, + boolean onTop) { + int arrowPos = requestedX - mArrowUp.getMeasuredWidth() / 2; + + switch (animStyle) { + case ANIM_GROW_FROM_LEFT: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left + : R.style.Animations_PopDownMenu_Left); + break; + + case ANIM_GROW_FROM_RIGHT: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right + : R.style.Animations_PopDownMenu_Right); + break; + + case ANIM_GROW_FROM_CENTER: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center + : R.style.Animations_PopDownMenu_Center); + break; + + case ANIM_REFLECT: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect + : R.style.Animations_PopDownMenu_Reflect); + break; + + case ANIM_AUTO: + if (arrowPos <= screenWidth / 4) { + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left + : R.style.Animations_PopDownMenu_Left); + } else if (arrowPos > screenWidth / 4 + && arrowPos < 3 * (screenWidth / 4)) { + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center + : R.style.Animations_PopDownMenu_Center); + } else { + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right + : R.style.Animations_PopDownMenu_Right); + } + + break; + } + } + + /** + * Create action list + */ + private void createActionList() { + View view; + String title; + Drawable icon; + OnClickListener listener; + + for (int i = 0; i < actionList.size(); i++) { + title = actionList.get(i).getTitle(); + icon = actionList.get(i).getIcon(); + listener = actionList.get(i).getOnClickListerner(); + + view = getActionItem(title, icon, listener); + + view.setFocusable(true); + view.setClickable(true); + + mTrack.addView(view); + } + } + + /** + * Get action item {@link View} + * + * @param title action item title + * @param icon {@link Drawable} action item icon + * @param listener {@link View.OnClickListener} action item listener + * @return action item {@link View} + */ + private View getActionItem(String title, Drawable icon, + OnClickListener listener) { + LinearLayout container = (LinearLayout) inflater.inflate( + R.layout.action_item, null); + + ImageView img = (ImageView) container.findViewById(R.id.icon); + TextView text = (TextView) container.findViewById(R.id.title); + + if (icon != null) { + img.setImageDrawable(icon); + } + + if (title != null) { + text.setText(title); + } + + if (listener != null) { + container.setOnClickListener(listener); + } + + return container; + } + + /** + * Show arrow + * + * @param whichArrow arrow type resource id + * @param requestedX distance from left screen + */ + private void showArrow(int whichArrow, int requestedX) { + final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp + : mArrowDown; + final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown + : mArrowUp; + + final int arrowWidth = mArrowUp.getMeasuredWidth(); + + showArrow.setVisibility(View.VISIBLE); + + ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow + .getLayoutParams(); + + param.leftMargin = requestedX - arrowWidth / 2; + + hideArrow.setVisibility(View.INVISIBLE); + } +} \ No newline at end of file diff --git a/src/com/owncloud/android/ui/activity/AccountSelectActivity.java b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java new file mode 100644 index 00000000..78ec8c0f --- /dev/null +++ b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java @@ -0,0 +1,189 @@ +package com.owncloud.android.ui.activity; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.ContextMenu; +import android.view.View; +import android.view.ViewGroup; +import android.view.ContextMenu.ContextMenuInfo; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.CheckedTextView; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockListActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; + +import com.owncloud.android.R; + +public class AccountSelectActivity extends SherlockListActivity implements + AccountManagerCallback { + + private final Handler mHandler = new Handler(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActionBar action_bar = getSupportActionBar(); + action_bar.setDisplayShowTitleEnabled(true); + action_bar.setDisplayHomeAsUpEnabled(false); + } + + @Override + protected void onResume() { + super.onResume(); + populateAccountList(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getSherlock().getMenuInflater(); + inflater.inflate(R.menu.account_picker, menu); + return true; + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + getMenuInflater().inflate(R.menu.account_picker_long_click, menu); + super.onCreateContextMenu(menu, v, menuInfo); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + String accountName = ((TextView) v.findViewById(android.R.id.text1)) + .getText().toString(); + AccountUtils.setCurrentOwnCloudAccount(this, accountName); + + // trigger synchronization when current account is changed + ContentResolver.cancelSync(null, "org.owncloud"); + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + ContentResolver.requestSync(AccountUtils.getCurrentOwnCloudAccount(this), "org.owncloud", bundle); + + Intent i = new Intent(this, FileDisplayActivity.class); + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(i); + finish(); + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (item.getItemId() == R.id.createAccount) { + Intent intent = new Intent( + android.provider.Settings.ACTION_ADD_ACCOUNT); + intent.putExtra("authorities", + new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); + return true; + } + return false; + } + + @Override + public boolean onContextItemSelected(android.view.MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + int index = info.position; + HashMap map = (HashMap) getListAdapter() + .getItem(index); + String accountName = map.get("NAME"); + AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); + Account accounts[] = am + .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + for (Account a : accounts) { + if (a.name.equals(accountName)) { + am.removeAccount(a, this, mHandler); + } + } + + return false; + } + + private void populateAccountList() { + AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); + Account accounts[] = am + .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + LinkedList> ll = new LinkedList>(); + for (Account a : accounts) { + HashMap h = new HashMap(); + h.put("NAME", a.name); + h.put("VER", + "ownCloud version: " + + am.getUserData(a, + AccountAuthenticator.KEY_OC_VERSION)); + ll.add(h); + } + + setListAdapter(new AccountCheckedSimpleAdepter(this, ll, + android.R.layout.simple_list_item_single_choice, + new String[] { "NAME" }, new int[] { android.R.id.text1 })); + registerForContextMenu(getListView()); + } + + @Override + public void run(AccountManagerFuture future) { + if (future.isDone()) { + Account a = AccountUtils.getCurrentOwnCloudAccount(this); + String accountName = ""; + if (a == null) { + Account[] accounts = AccountManager.get(this) + .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + if (accounts.length != 0) + accountName = accounts[0].name; + AccountUtils.setCurrentOwnCloudAccount(this, accountName); + } + populateAccountList(); + } + } + + private class AccountCheckedSimpleAdepter extends SimpleAdapter { + private Account mCurrentAccount; + private List> mPrivateData; + + public AccountCheckedSimpleAdepter(Context context, + List> data, int resource, + String[] from, int[] to) { + super(context, data, resource, from, to); + mCurrentAccount = AccountUtils + .getCurrentOwnCloudAccount(AccountSelectActivity.this); + mPrivateData = data; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); + CheckedTextView ctv = (CheckedTextView) v + .findViewById(android.R.id.text1); + if (mPrivateData.get(position).get("NAME") + .equals(mCurrentAccount.name)) { + ctv.setChecked(true); + } + return v; + } + + } + +} diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java new file mode 100644 index 00000000..4aa7cddd --- /dev/null +++ b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java @@ -0,0 +1,399 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.ui.activity; + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.authenticator.AuthenticationRunnable; +import com.owncloud.android.authenticator.ConnectionCheckerRunnable; +import com.owncloud.android.authenticator.OnAuthenticationResultListener; +import com.owncloud.android.authenticator.OnConnectCheckListener; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; +import com.owncloud.android.extensions.ExtensionsAvailableActivity; +import com.owncloud.android.utils.OwnCloudVersion; + +import android.accounts.Account; +import android.accounts.AccountAuthenticatorActivity; +import android.accounts.AccountManager; +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.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.ImageView; +import android.widget.TextView; +import com.owncloud.android.R; + +/** + * This Activity is used to add an ownCloud account to the App + * + * @author Bartek Przybylski + * + */ +public class AuthenticatorActivity extends AccountAuthenticatorActivity + implements OnAuthenticationResultListener, OnConnectCheckListener, + OnFocusChangeListener, OnClickListener { + private static final int DIALOG_LOGIN_PROGRESS = 0; + + private static final String TAG = "AuthActivity"; + + private Thread mAuthThread; + private AuthenticationRunnable mAuthRunnable; + private ConnectionCheckerRunnable 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; + + 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); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putInt(STATUS_ICON, mStatusIcon); + outState.putInt(STATUS_TEXT, mStatusText); + outState.putBoolean(STATUS_CORRECT, mStatusCorrect); + super.onSaveInstanceState(outState); + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog = null; + switch (id) { + case DIALOG_LOGIN_PROGRESS: { + ProgressDialog working_dialog = new ProgressDialog(this); + working_dialog.setMessage(getResources().getString( + R.string.auth_trying_to_login)); + working_dialog.setIndeterminate(true); + working_dialog.setCancelable(true); + working_dialog + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + Log.i(TAG, "Login canceled"); + if (mAuthThread != null) { + mAuthThread.interrupt(); + finish(); + } + } + }); + dialog = working_dialog; + break; + } + default: + Log.e(TAG, "Incorrect dialog called with id = " + id); + } + return dialog; + } + + public void onAuthenticationResult(boolean success, String message) { + if (success) { + TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password); + + URL url; + try { + url = new URL(message); + } catch (MalformedURLException e) { + // should never happen + Log.e(getClass().getName(), "Malformed URL: " + message); + return; + } + + String username = username_text.getText().toString().trim(); + String accountName = username + "@" + url.getHost(); + if (url.getPort() >= 0) { + accountName += ":" + url.getPort(); + } + Account account = new Account(accountName, + AccountAuthenticator.ACCOUNT_TYPE); + AccountManager accManager = AccountManager.get(this); + accManager.addAccountExplicitly(account, password_text.getText() + .toString(), null); + + // Add this account as default in the preferences, if there is none + // already + Account defaultAccount = AccountUtils + .getCurrentOwnCloudAccount(this); + if (defaultAccount == null) { + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(this).edit(); + editor.putString("select_oc_account", accountName); + editor.commit(); + } + + final Intent intent = new Intent(); + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, + AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); + intent.putExtra(AccountManager.KEY_AUTHTOKEN, + AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_USERDATA, username); + + accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, + url.toString()); + 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 { + dismissDialog(DIALOG_LOGIN_PROGRESS); + TextView tv = (TextView) findViewById(R.id.account_username); + tv.setError(message); + } + } + public void onCancelClick(View view) { + finish(); + } + + public void onOkClick(View view) { + String prefix = ""; + String url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString(); + if (mIsSslConn) { + prefix = "https://"; + } else { + prefix = "http://"; + } + if (url.toLowerCase().startsWith("http://") + || url.toLowerCase().startsWith("https://")) { + prefix = ""; + } + continueConnection(prefix); + } + + private void continueConnection(String prefix) { + String url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString(); + 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()); + + try { + mBaseUrl = prefix + url; + String url_str = prefix + url + webdav_path; + uri = new URL(url_str); + } catch (MalformedURLException e) { + // should not happend + e.printStackTrace(); + } + + showDialog(DIALOG_LOGIN_PROGRESS); + mAuthRunnable = new AuthenticationRunnable(uri, username, password); + 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().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 TIMEOUT: + case INORRECT_ADDRESS: + case SSL_INIT_ERROR: + case HOST_NOT_AVAILABLE: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_unknow_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_unknow_error; + break; + case FILE_NOT_FOUND: + mStatusIcon = R.drawable.common_error; + mStatusText = R.string.auth_incorrect_path_title; + break; + default: + Log.e(TAG, "Incorrect connection checker result type: " + type); + } + setResultIconAndText(mStatusIcon, mStatusText); + if (!mStatusCorrect) + findViewById(R.id.refreshButton).setVisibility(View.VISIBLE); + else + findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); + findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); + } + + @Override + public void onFocusChange(View view, boolean hasFocus) { + if (view.getId() == R.id.host_URL) { + if (!hasFocus) { + TextView tv = ((TextView) findViewById(R.id.host_URL)); + String uri = tv.getText().toString(); + if (uri.length() != 0) { + setResultIconAndText(R.drawable.progress_small, + R.string.auth_testing_connection); + findViewById(R.id.buttonOK).setEnabled(false); // avoid connect can be clicked if the test was previously passed + mConnChkRunnable = new ConnectionCheckerRunnable(uri, this); + mConnChkRunnable.setListener(this, mHandler); + mAuthThread = new Thread(mConnChkRunnable); + mAuthThread.start(); + } else { + findViewById(R.id.refreshButton).setVisibility( + View.INVISIBLE); + setResultIconAndText(0, 0); + } + } + } 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) { + TextView view = (TextView) findViewById(R.id.account_password); + int input_type = InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; + view.setInputType(input_type); + } + } +} diff --git a/src/com/owncloud/android/ui/activity/FileDetailActivity.java b/src/com/owncloud/android/ui/activity/FileDetailActivity.java new file mode 100644 index 00000000..3c80a48d --- /dev/null +++ b/src/com/owncloud/android/ui/activity/FileDetailActivity.java @@ -0,0 +1,144 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.activity; + +import android.accounts.Account; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; + +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.ui.fragment.FileDetailFragment; + +import com.owncloud.android.R; + +/** + * This activity displays the details of a file like its name, its size and so + * on. + * + * @author Bartek Przybylski + * + */ +public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity { + + public static final int DIALOG_SHORT_WAIT = 0; + + private boolean mConfigurationChangedToLandscape = false; + + @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) { + setContentView(R.layout.file_activity_details); + + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + + OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); + Account account = getIntent().getParcelableExtra(FileDownloader.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; + } + + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + boolean returnValue = false; + + switch(item.getItemId()){ + case android.R.id.home: + backToDisplayActivity(); + returnValue = true; + } + + return returnValue; + } + + + + @Override + protected void onResume() { + + super.onResume(); + if (!mConfigurationChangedToLandscape) { + FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + fragment.updateFileDetails(); + } + } + + + 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)); + 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! + } + +} diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java new file mode 100644 index 00000000..54c99e6c --- /dev/null +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -0,0 +1,886 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.ui.activity; + +import java.io.File; +import java.util.ArrayList; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.app.AlertDialog.Builder; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources.NotFoundException; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.Window; +import com.owncloud.android.AccountUtils; +import com.owncloud.android.CrashHandler; +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.FileDownloader; +import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.syncadapter.FileSyncService; +import com.owncloud.android.ui.fragment.FileDetailFragment; +import com.owncloud.android.ui.fragment.FileListFragment; + +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +/** + * Displays, what files the user has available in his ownCloud. + * + * @author Bartek Przybylski + * + */ + +public class FileDisplayActivity extends SherlockFragmentActivity implements + FileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnClickListener, android.view.View.OnClickListener { + + private ArrayAdapter mDirectories; + private OCFile mCurrentDir; + private String[] mDirs = null; + + private DataStorageManager mStorageManager; + private SyncBroadcastReceiver mSyncBroadcastReceiver; + private UploadFinishReceiver mUploadFinishReceiver; + private DownloadFinishReceiver mDownloadFinishReceiver; + + private View mLayoutView = null; + private FileListFragment mFileList; + + private boolean mDualPane; + + private boolean mForcedLoginToCreateFirstAccount = false; + + private static final String KEY_DIR_ARRAY = "DIR_ARRAY"; + private static final String KEY_CURRENT_DIR = "DIR"; + + private static final int DIALOG_SETUP_ACCOUNT = 0; + private static final int DIALOG_CREATE_DIR = 1; + private static final int DIALOG_ABOUT_APP = 2; + public static final int DIALOG_SHORT_WAIT = 3; + + private static final int ACTION_SELECT_FILE = 1; + + private static final String TAG = "FileDisplayActivity"; + + + @Override + public void onCreate(Bundle savedInstanceState) { + Log.i(getClass().toString(), "onCreate() start"); + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + + Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(getApplicationContext())); + + if(savedInstanceState != null) { + mDirs = savedInstanceState.getStringArray(KEY_DIR_ARRAY); + mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); + mDirectories.add(OCFile.PATH_SEPARATOR); + if (mDirs != null) + for (String s : mDirs) + mDirectories.insert(s, 0); + mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE); + } + + mLayoutView = getLayoutInflater().inflate(R.layout.files, null); // always inflate this at onCreate() ; just once! + + if (AccountUtils.accountsAreSetup(this)) { + + initDelayedTilAccountAvailabe(); + + // PIN CODE request ; best location is to decide, let's try this first + //if (savedInstanceState == null) { + if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) { + requestPinCode(); + } + + + } else { + + setContentView(R.layout.no_account_available); + getSupportActionBar().setNavigationMode(ActionBar.DISPLAY_SHOW_TITLE); + findViewById(R.id.setup_account).setOnClickListener(this); + + setSupportProgressBarIndeterminateVisibility(false); + + Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); + intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); // although the code is here, the activity won't be created until this.onStart() and this.onResume() are finished; + mForcedLoginToCreateFirstAccount = true; + } + + Log.i(getClass().toString(), "onCreate() end"); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getSherlock().getMenuInflater(); + inflater.inflate(R.menu.menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + boolean retval = true; + switch (item.getItemId()) { + case R.id.createDirectoryItem: { + showDialog(DIALOG_CREATE_DIR); + break; + } + case R.id.startSync: { + ContentResolver.cancelSync(null, "org.owncloud"); // cancel the current synchronizations of any ownCloud account + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + ContentResolver.requestSync( + AccountUtils.getCurrentOwnCloudAccount(this), + "org.owncloud", bundle); + break; + } + case R.id.action_upload: { + Intent action = new Intent(Intent.ACTION_GET_CONTENT); + action = action.setType("*/*") + .addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult( + Intent.createChooser(action, getString(R.string.upload_chooser_title)), + ACTION_SELECT_FILE); + break; + } + case R.id.action_settings: { + Intent settingsIntent = new Intent(this, Preferences.class); + startActivity(settingsIntent); + break; + } + case R.id.about_app : { + showDialog(DIALOG_ABOUT_APP); + break; + } + case android.R.id.home: { + if(mCurrentDir != null && mCurrentDir.getParentId() != 0){ + onBackPressed(); + } + break; + } + default: + retval = false; + } + return retval; + } + + @Override + public boolean onNavigationItemSelected(int itemPosition, long itemId) { + int i = itemPosition; + while (i-- != 0) { + onBackPressed(); + } + return true; + } + + /** + * Called, when the user selected something for uploading + */ + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == ACTION_SELECT_FILE) { + if (resultCode == RESULT_OK) { + String filepath = null; + try { + Uri selectedImageUri = data.getData(); + + String filemanagerstring = selectedImageUri.getPath(); + String selectedImagePath = getPath(selectedImageUri); + + if (selectedImagePath != null) + filepath = selectedImagePath; + else + filepath = filemanagerstring; + + } catch (Exception e) { + Log.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"); + Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG); + t.show(); + return; + } + } + + Intent i = new Intent(this, FileUploader.class); + i.putExtra(FileUploader.KEY_ACCOUNT, + AccountUtils.getCurrentOwnCloudAccount(this)); + String remotepath = new String(); + for (int j = mDirectories.getCount() - 2; j >= 0; --j) { + remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); + } + if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) + remotepath += OCFile.PATH_SEPARATOR; + remotepath += new File(filepath).getName(); + + i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath); + i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath); + i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE); + startService(i); + } + + }/* dvelasco: WIP - not working as expected ... yet :) + else if (requestCode == ACTION_CREATE_FIRST_ACCOUNT) { + if (resultCode != RESULT_OK) { + finish(); // the user cancelled the AuthenticatorActivity + } + }*/ + } + + @Override + public void onBackPressed() { + if (mDirectories == null || mDirectories.getCount() <= 1) { + finish(); + return; + } + popDirname(); + mFileList.onNavigateUp(); + mCurrentDir = mFileList.getCurrentFile(); + + if(mCurrentDir.getParentId() == 0){ + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(false); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + // responsability of restore is prefered in onCreate() before than in onRestoreInstanceState when there are Fragments involved + Log.i(getClass().toString(), "onSaveInstanceState() start"); + super.onSaveInstanceState(outState); + if(mDirectories != null && mDirectories.getCount() != 0){ + mDirs = new String[mDirectories.getCount()-1]; + for (int j = mDirectories.getCount() - 2, i = 0; j >= 0; --j, ++i) { + mDirs[i] = mDirectories.getItem(j); + } + } + outState.putStringArray(KEY_DIR_ARRAY, mDirs); + outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir); + Log.i(getClass().toString(), "onSaveInstanceState() end"); + } + + @Override + protected void onResume() { + Log.i(getClass().toString(), "onResume() start"); + super.onResume(); + + if (AccountUtils.accountsAreSetup(this)) { + // at least an account exist: normal operation + + // set the layout only if it couldn't be set in onCreate + if (mForcedLoginToCreateFirstAccount) { + initDelayedTilAccountAvailabe(); + mForcedLoginToCreateFirstAccount = false; + } + + // Listen for sync messages + IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE); + mSyncBroadcastReceiver = new SyncBroadcastReceiver(); + registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); + + // Listen for upload messages + IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); + mUploadFinishReceiver = new UploadFinishReceiver(); + registerReceiver(mUploadFinishReceiver, uploadIntentFilter); + + // Listen for download messages + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE); + mDownloadFinishReceiver = new DownloadFinishReceiver(); + registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); + + // Storage manager initialization + mStorageManager = new FileDataStorageManager( + AccountUtils.getCurrentOwnCloudAccount(this), + getContentResolver()); + + // File list fragments + mFileList = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + + + // Figure out what directory to list. + // Priority: Intent (here), savedInstanceState (onCreate), root dir (dir is null) + if(getIntent().hasExtra(FileDetailFragment.EXTRA_FILE)){ + mCurrentDir = (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); + if(mCurrentDir != null && !mCurrentDir.isDirectory()){ + mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId()); + } + + // Clear intent extra, so rotating the screen will not return us to this directory + getIntent().removeExtra(FileDetailFragment.EXTRA_FILE); + } + + if (mCurrentDir == null) + mCurrentDir = mStorageManager.getFileByPath("/"); + + // Drop-Down navigation and file list restore + mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); + + + // Given the case we have a file to display: + if(mCurrentDir != null){ + ArrayList files = new ArrayList(); + OCFile currFile = mCurrentDir; + while(currFile != null){ + files.add(currFile); + currFile = mStorageManager.getFileById(currFile.getParentId()); + } + + // Insert in mDirs + mDirs = new String[files.size()]; + for(int i = files.size() - 1; i >= 0; i--){ + mDirs[i] = files.get(i).getFileName(); + } + } + + if (mDirs != null) { + for (String s : mDirs) + mDirectories.add(s); + } else { + mDirectories.add(OCFile.PATH_SEPARATOR); + } + + // Actionbar setup + ActionBar action_bar = getSupportActionBar(); + action_bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + action_bar.setDisplayShowTitleEnabled(false); + action_bar.setListNavigationCallbacks(mDirectories, this); + if(mCurrentDir != null && mCurrentDir.getParentId() != 0){ + action_bar.setDisplayHomeAsUpEnabled(true); + } else { + action_bar.setDisplayHomeAsUpEnabled(false); + } + + // List dir here + mFileList.listDirectory(mCurrentDir); + } + Log.i(getClass().toString(), "onResume() end"); + } + + @Override + protected void onPause() { + Log.i(getClass().toString(), "onPause() start"); + super.onPause(); + if (mSyncBroadcastReceiver != null) { + unregisterReceiver(mSyncBroadcastReceiver); + mSyncBroadcastReceiver = null; + } + if (mUploadFinishReceiver != null) { + unregisterReceiver(mUploadFinishReceiver); + mUploadFinishReceiver = null; + } + if (mDownloadFinishReceiver != null) { + unregisterReceiver(mDownloadFinishReceiver); + mDownloadFinishReceiver = null; + } + + getIntent().putExtra(FileDetailFragment.EXTRA_FILE, mCurrentDir); + Log.i(getClass().toString(), "onPause() end"); + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog = null; + AlertDialog.Builder builder; + switch (id) { + case DIALOG_SETUP_ACCOUNT: + builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.main_tit_accsetup); + builder.setMessage(R.string.main_wrn_accsetup); + builder.setCancelable(false); + builder.setPositiveButton(android.R.string.ok, this); + builder.setNegativeButton(android.R.string.cancel, this); + dialog = builder.create(); + break; + case DIALOG_ABOUT_APP: { + builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.about_title)); + PackageInfo pkg; + try { + pkg = getPackageManager().getPackageInfo(getPackageName(), 0); + builder.setMessage("ownCloud android client\n\nversion: " + pkg.versionName ); + builder.setIcon(android.R.drawable.ic_menu_info_details); + dialog = builder.create(); + } catch (NameNotFoundException e) { + builder = null; + dialog = null; + Log.e(TAG, "Error while showing about dialog", e); + } + break; + } + case DIALOG_CREATE_DIR: { + builder = new Builder(this); + final EditText dirNameInput = new EditText(getBaseContext()); + final Account a = AccountUtils.getCurrentOwnCloudAccount(this); + builder.setView(dirNameInput); + builder.setTitle(R.string.uploader_info_dirname); + int typed_color = getResources().getColor(R.color.setup_text_typed); + dirNameInput.setTextColor(typed_color); + builder.setPositiveButton(android.R.string.ok, + new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String directoryName = dirNameInput.getText().toString(); + if (directoryName.trim().length() == 0) { + dialog.cancel(); + return; + } + + // Figure out the path where the dir needs to be created + String path; + if (mCurrentDir == null) { + // this is just a patch; we should ensure that mCurrentDir never is null + if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) { + OCFile file = new OCFile(OCFile.PATH_SEPARATOR); + mStorageManager.saveFile(file); + } + mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); + } + path = FileDisplayActivity.this.mCurrentDir.getRemotePath(); + + // Create directory + path += directoryName + OCFile.PATH_SEPARATOR; + Thread thread = new Thread(new DirectoryCreator(path, a, new Handler())); + thread.start(); + + dialog.dismiss(); + + showDialog(DIALOG_SHORT_WAIT); + } + }); + builder.setNegativeButton(R.string.common_cancel, + new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + dialog = builder.create(); + break; + } + 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; + } + + + /** + * Responds to the "There are no ownCloud Accounts setup" dialog + * TODO: Dialog is 100% useless -> Remove + */ + @Override + public void onClick(DialogInterface dialog, int which) { + // In any case - we won't need it anymore + dialog.dismiss(); + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", + new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); + break; + case DialogInterface.BUTTON_NEGATIVE: + finish(); + } + + } + + /** + * Translates a content URI of an image to a physical path + * on the disk + * @param uri The URI to resolve + * @return The path to the image or null if it could not be found + */ + public String getPath(Uri uri) { + String[] projection = { MediaStore.Images.Media.DATA }; + Cursor cursor = managedQuery(uri, projection, null, null, null); + if (cursor != null) { + int column_index = cursor + .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(column_index); + } + return null; + } + + /** + * Pushes a directory to the drop down list + * @param directory to push + * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false. + */ + public void pushDirname(OCFile directory) { + if(!directory.isDirectory()){ + throw new IllegalArgumentException("Only directories may be pushed!"); + } + mDirectories.insert(directory.getFileName(), 0); + mCurrentDir = directory; + } + + /** + * Pops a directory name from the drop down list + * @return True, unless the stack is empty + */ + public boolean popDirname() { + mDirectories.remove(mDirectories.getItem(0)); + return !mDirectories.isEmpty(); + } + + private class DirectoryCreator implements Runnable { + private String mTargetPath; + private Account mAccount; + private AccountManager mAm; + private Handler mHandler; + + public DirectoryCreator(String targetPath, Account account, Handler handler) { + mTargetPath = targetPath; + mAccount = account; + mAm = (AccountManager) getSystemService(ACCOUNT_SERVICE); + mHandler = handler; + } + + @Override + public void run() { + WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); + + String username = mAccount.name.substring(0, + mAccount.name.lastIndexOf('@')); + String password = mAm.getPassword(mAccount); + + wdc.setCredentials(username, password); + wdc.allowSelfsignedCertificates(); + boolean created = wdc.createDirectory(mTargetPath); + if (created) { + mHandler.post(new Runnable() { + @Override + public void run() { + dismissDialog(DIALOG_SHORT_WAIT); + + // Save new directory in local database + OCFile newDir = new OCFile(mTargetPath); + newDir.setMimetype("DIR"); + newDir.setParentId(mCurrentDir.getFileId()); + mStorageManager.saveFile(newDir); + + // Display the new folder right away + mFileList.listDirectory(mCurrentDir); + } + }); + + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + dismissDialog(DIALOG_SHORT_WAIT); + try { + Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); + msg.show(); + + } catch (NotFoundException e) { + Log.e(TAG, "Error while trying to show fail message " , e); + } + } + }); + } + } + + } + + // Custom array adapter to override text colors + private class CustomArrayAdapter extends ArrayAdapter { + + public CustomArrayAdapter(FileDisplayActivity ctx, int view) { + super(ctx, view); + } + + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); + + ((TextView) v).setTextColor(getResources().getColorStateList( + android.R.color.white)); + return v; + } + + public View getDropDownView(int position, View convertView, + ViewGroup parent) { + View v = super.getDropDownView(position, convertView, parent); + + ((TextView) v).setTextColor(getResources().getColorStateList( + android.R.color.white)); + + return v; + } + + } + + private class SyncBroadcastReceiver extends BroadcastReceiver { + /** + * {@link BroadcastReceiver} to enable syncing feedback in UI + */ + @Override + public void onReceive(Context context, Intent intent) { + 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); + + if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { + + String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); + + boolean fillBlankRoot = false; + if (mCurrentDir == null) { + mCurrentDir = mStorageManager.getFileByPath("/"); + fillBlankRoot = (mCurrentDir != null); + } + + if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath))) + || fillBlankRoot ) { + if (!fillBlankRoot) + mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath); + FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager() + .findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(mCurrentDir); + } + } + + setSupportProgressBarIndeterminateVisibility(inProgress); + + } + } + } + + + private class UploadFinishReceiver extends BroadcastReceiver { + /** + * Once the file upload has finished -> update view + * @author David A. Velasco + * {@link BroadcastReceiver} to enable upload feedback in UI + */ + @Override + public void onReceive(Context context, Intent intent) { + long parentDirId = intent.getLongExtra(FileUploader.EXTRA_PARENT_DIR_ID, -1); + OCFile parentDir = mStorageManager.getFileById(parentDirId); + String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); + + if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) && + parentDir != null && + ( (mCurrentDir == null && parentDir.getFileName().equals("/")) || + parentDir.equals(mCurrentDir) + ) + ) { + FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + } + } + } + + } + + + /** + * Once the file download has finished -> update view + */ + private class DownloadFinishReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); + + if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) && + mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) { + FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + } + } + } + } + + + @Override + public void onClick(View v) { + if (v.getId() == R.id.setup_account) { + Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); + intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); + mForcedLoginToCreateFirstAccount = true; + } + } + + + + + + /** + * {@inheritDoc} + */ + @Override + public DataStorageManager getStorageManager() { + return mStorageManager; + } + + + /** + * {@inheritDoc} + */ + @Override + public void onDirectoryClick(OCFile directory) { + pushDirname(directory); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + + if (mDualPane) { + // Resets the FileDetailsFragment on Tablets so that it always displays + FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (fileDetails != null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.remove(fileDetails); + transaction.add(R.id.file_details_container, new FileDetailFragment(null, null)); + transaction.commit(); + } + } + } + + + /** + * {@inheritDoc} + */ + @Override + public void onFileClick(OCFile file) { + + // If we are on a large device -> update fragment + if (mDualPane) { + // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous' + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); + transaction.commit(); + + } else { // small or medium screen device -> new Activity + Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); + showDetailsIntent.putExtra(FileDownloader.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + startActivity(showDetailsIntent); + } + } + + + /** + * {@inheritDoc} + */ + @Override + public void onFileStateChanged() { + FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + } + } + + + /** + * Operations in this method should be preferably performed in onCreate to have a lighter onResume method. + * + * But we need to delay them to onResume for the first start of the application, when no account exists and the login activity must be shown; and + * put instead the ugly view that shows the 'Setup' button to restart the login activity. + * + * In other way, if the users cancels or presses BACK in the login page that first time (users can be cruel sometimes) would show a blank view (the + * FragmentList view empty). + * + * This is temporal, until we found out how to get a result in this activity after launching the ADD_ACCOUNT Intent with startActivityForResult (not trivial) + */ + private void initDelayedTilAccountAvailabe() { + setContentView(mLayoutView); + mDualPane = (findViewById(R.id.file_details_container) != null); + if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment + transaction.commit(); + } + setSupportProgressBarIndeterminateVisibility(false); + } + + + /** + * Launch an intent to request the PIN code to the user before letting him use the app + */ + private void requestPinCode() { + boolean pinStart = false; + SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + pinStart = appPrefs.getBoolean("set_pincode", false); + if (pinStart) { + Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); + i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity"); + startActivity(i); + } + } + + +} diff --git a/src/com/owncloud/android/ui/activity/LandingActivity.java b/src/com/owncloud/android/ui/activity/LandingActivity.java new file mode 100644 index 00000000..ce7ff2f6 --- /dev/null +++ b/src/com/owncloud/android/ui/activity/LandingActivity.java @@ -0,0 +1,158 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.activity; + +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.ui.adapter.LandingScreenAdapter; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; +import android.widget.Toast; +import com.owncloud.android.R; + +/** + * This activity is used as a landing page when the user first opens this app. + * + * @author Lennart Rosam + * + */ +public class LandingActivity extends SherlockFragmentActivity implements + OnClickListener, OnItemClickListener { + + public static final int DIALOG_SETUP_ACCOUNT = 1; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // Fill the grid view of the landing screen with icons + GridView landingScreenItems = (GridView) findViewById(R.id.homeScreenGrid); + landingScreenItems.setAdapter(new LandingScreenAdapter(this)); + landingScreenItems.setOnItemClickListener(this); + + // Check, if there are ownCloud accounts + if (!accountsAreSetup()) { + showDialog(DIALOG_SETUP_ACCOUNT); + } else { + // Start device tracking service + Intent locationServiceIntent = new Intent(); + locationServiceIntent + .setAction("eu.alefzero.owncloud.location.LocationLauncher"); + sendBroadcast(locationServiceIntent); + } + + } + + @Override + protected void onRestart() { + super.onRestart(); + // Check, if there are ownCloud accounts + if (!accountsAreSetup()) { + showDialog(DIALOG_SETUP_ACCOUNT); + } + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + // Check, if there are ownCloud accounts + if (!accountsAreSetup()) { + showDialog(DIALOG_SETUP_ACCOUNT); + } + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog; + switch (id) { + case DIALOG_SETUP_ACCOUNT: + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.main_tit_accsetup); + builder.setMessage(R.string.main_wrn_accsetup); + builder.setCancelable(false); + builder.setPositiveButton(R.string.common_ok, this); + builder.setNegativeButton(R.string.common_cancel, this); + dialog = builder.create(); + break; + default: + dialog = null; + } + + return dialog; + } + + public void onClick(DialogInterface dialog, int which) { + // In any case - we won't need it anymore + dialog.dismiss(); + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", + new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); + break; + case DialogInterface.BUTTON_NEGATIVE: + finish(); + } + + } + + @Override + /** + * Start an activity based on the selection + * the user made + */ + public void onItemClick(AdapterView parent, View view, int position, + long id) { + Intent intent; + intent = (Intent) parent.getAdapter().getItem(position); + if (intent != null) { + startActivity(intent); + } else { + // TODO: Implement all of this and make this text go away ;-) + Toast toast = Toast.makeText(this, "Not yet implemented!", + Toast.LENGTH_SHORT); + toast.show(); + } + } + + /** + * Checks, whether or not there are any ownCloud accounts setup. + * + * @return true, if there is at least one account. + */ + private boolean accountsAreSetup() { + AccountManager accMan = AccountManager.get(this); + Account[] accounts = accMan + .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + return accounts.length > 0; + } + +} diff --git a/src/com/owncloud/android/ui/activity/PinCodeActivity.java b/src/com/owncloud/android/ui/activity/PinCodeActivity.java new file mode 100644 index 00000000..fc3926d2 --- /dev/null +++ b/src/com/owncloud/android/ui/activity/PinCodeActivity.java @@ -0,0 +1,652 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.activity; + +import java.util.Arrays; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +import com.owncloud.android.R; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.text.Editable; +import android.text.InputType; +import android.text.TextWatcher; +import android.text.method.PasswordTransformationMethod; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnFocusChangeListener; +import android.view.View.OnKeyListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + + +public class PinCodeActivity extends SherlockFragmentActivity { + + + public final static String EXTRA_ACTIVITY = "eu.alefzero.owncloud.ui.activity.PinCodeActivity.ACTIVITY"; + public final static String EXTRA_NEW_STATE = "eu.alefzero.owncloud.ui.activity.PinCodeActivity.NEW_STATE"; + + Button bCancel; + TextView mPinHdr; + EditText mText1; + EditText mText2; + EditText mText3; + EditText mText4; + + String [] tempText ={"","","",""}; + + String activity; + + boolean confirmingPinCode = false; + boolean pinCodeChecked = false; + boolean newPasswordEntered = false; + boolean bChange = true; // to control that only one blocks jump + int tCounter ; // Count the number of attempts an user could introduce the PIN code + + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.pincodelock); + + Intent intent = getIntent(); + activity = intent.getStringExtra(EXTRA_ACTIVITY); + + bCancel = (Button) findViewById(R.id.cancel); + mPinHdr = (TextView) findViewById(R.id.pinHdr); + mText1 = (EditText) findViewById(R.id.txt1); + mText1.requestFocus(); + getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + mText2 = (EditText) findViewById(R.id.txt2); + mText3 = (EditText) findViewById(R.id.txt3); + mText4 = (EditText) findViewById(R.id.txt4); + + + + SharedPreferences appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + + // Not PIN Code defined yet. + // In a previous version settings is allow from start + if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){ + setChangePincodeView(true); + pinCodeChecked = true; + newPasswordEntered = true; + + }else{ + + if (appPrefs.getBoolean("set_pincode", false)){ + // pincode activated + if (activity.equals("preferences")){ + // PIN has been activated yet + mPinHdr.setText(R.string.pincode_configure_your_pin); + pinCodeChecked = true ; // No need to check it + setChangePincodeView(true); + }else{ + // PIN active + bCancel.setVisibility(View.INVISIBLE); + bCancel.setVisibility(View.GONE); + mPinHdr.setText(R.string.pincode_enter_pin_code); + setChangePincodeView(false); + } + + }else { + // pincode removal + mPinHdr.setText(R.string.pincode_remove_your_pincode); + pinCodeChecked = false; + setChangePincodeView(true); + } + + } + setTextListeners(); + + + } + + + + protected void setInitVars(){ + confirmingPinCode = false; + pinCodeChecked = false; + newPasswordEntered = false; + + } + + protected void setInitView(){ + bCancel.setVisibility(View.INVISIBLE); + bCancel.setVisibility(View.GONE); + mPinHdr.setText(R.string.pincode_enter_pin_code); + } + + + protected void setChangePincodeView(boolean state){ + + if(state){ + bCancel.setVisibility(View.VISIBLE); + bCancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + + SharedPreferences.Editor appPrefsE = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + + SharedPreferences appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + boolean state = appPrefs.getBoolean("set_pincode", false); + appPrefsE.putBoolean("set_pincode",!state); + appPrefsE.commit(); + setInitVars(); + finish(); + } + }); + } + + } + + + + /* + * + */ + protected void setTextListeners(){ + + /*------------------------------------------------ + * FIRST BOX + -------------------------------------------------*/ + + mText1.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + if (!confirmingPinCode){ + tempText[0] = mText1.getText().toString(); + + } + mText2.requestFocus(); + } + } + }); + + + + /*------------------------------------------------ + * SECOND BOX + -------------------------------------------------*/ + mText2.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + if (!confirmingPinCode){ + tempText[1] = mText2.getText().toString(); + } + + mText3.requestFocus(); + } + } + }); + + mText2.setOnKeyListener(new OnKeyListener() { + + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + // TODO Auto-generated method stub + + if (keyCode == KeyEvent.KEYCODE_DEL && bChange) { + + mText1.setText(""); + mText1.requestFocus(); + if (!confirmingPinCode) + tempText[0] = ""; + bChange= false; + + }else if(!bChange){ + bChange=true; + + } + return false; + } + }); + + mText2.setOnFocusChangeListener(new OnFocusChangeListener() { + + @Override + public void onFocusChange(View v, boolean hasFocus) { + // TODO Auto-generated method stub + + mText2.setCursorVisible(true); + if (mText1.getText().toString().equals("")){ + mText2.setSelected(false); + mText2.setCursorVisible(false); + mText1.requestFocus(); + mText1.setSelected(true); + mText1.setSelection(0); + } + + } + }); + + + /*------------------------------------------------ + * THIRD BOX + -------------------------------------------------*/ + mText3.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + if (!confirmingPinCode){ + tempText[2] = mText3.getText().toString(); + } + mText4.requestFocus(); + } + } + }); + + mText3.setOnKeyListener(new OnKeyListener() { + + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + // TODO Auto-generated method stub + + if (keyCode == KeyEvent.KEYCODE_DEL && bChange) { + mText2.requestFocus(); + if (!confirmingPinCode) + tempText[1] = ""; + mText2.setText(""); + bChange= false; + + }else if(!bChange){ + bChange=true; + + } + return false; + } + }); + + mText3.setOnFocusChangeListener(new OnFocusChangeListener() { + + @Override + public void onFocusChange(View v, boolean hasFocus) { + // TODO Auto-generated method stub + mText3.setCursorVisible(true); + if (mText1.getText().toString().equals("")){ + mText3.setSelected(false); + mText3.setCursorVisible(false); + mText1.requestFocus(); + mText1.setSelected(true); + mText1.setSelection(0); + }else if (mText2.getText().toString().equals("")){ + mText3.setSelected(false); + mText3.setCursorVisible(false); + mText2.requestFocus(); + mText2.setSelected(true); + mText2.setSelection(0); + } + + } + }); + + /*------------------------------------------------ + * FOURTH BOX + -------------------------------------------------*/ + mText4.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + + if (!confirmingPinCode){ + tempText[3] = mText4.getText().toString(); + } + mText1.requestFocus(); + + if (!pinCodeChecked){ + pinCodeChecked = checkPincode(); + } + + if (pinCodeChecked && activity.equals("FileDisplayActivity")){ + finish(); + } else if (pinCodeChecked){ + + Intent intent = getIntent(); + String newState = intent.getStringExtra(EXTRA_NEW_STATE); + + if (newState.equals("false")){ + SharedPreferences.Editor appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + appPrefs.putBoolean("set_pincode",false); + appPrefs.commit(); + + setInitVars(); + pinCodeEnd(false); + + }else{ + + if (!confirmingPinCode){ + pinCodeChangeRequest(); + + } else { + confirmPincode(); + } + } + + + } + } + } + }); + + + + mText4.setOnKeyListener(new OnKeyListener() { + + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + // TODO Auto-generated method stub + + if (keyCode == KeyEvent.KEYCODE_DEL && bChange) { + mText3.requestFocus(); + if (!confirmingPinCode) + tempText[2]=""; + mText3.setText(""); + bChange= false; + + }else if(!bChange){ + bChange=true; + } + return false; + } + }); + + mText4.setOnFocusChangeListener(new OnFocusChangeListener() { + + @Override + public void onFocusChange(View v, boolean hasFocus) { + // TODO Auto-generated method stub + + mText4.setCursorVisible(true); + + if (mText1.getText().toString().equals("")){ + mText4.setSelected(false); + mText4.setCursorVisible(false); + mText1.requestFocus(); + mText1.setSelected(true); + mText1.setSelection(0); + }else if (mText2.getText().toString().equals("")){ + mText4.setSelected(false); + mText4.setCursorVisible(false); + mText2.requestFocus(); + mText2.setSelected(true); + mText2.setSelection(0); + }else if (mText3.getText().toString().equals("")){ + mText4.setSelected(false); + mText4.setCursorVisible(false); + mText3.requestFocus(); + mText3.setSelected(true); + mText3.setSelection(0); + } + + } + }); + + + + } // end setTextListener + + + protected void pinCodeChangeRequest(){ + + clearBoxes(); + mPinHdr.setText(R.string.pincode_reenter_your_pincode); + confirmingPinCode =true; + + } + + + protected boolean checkPincode(){ + + + SharedPreferences appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + String pText1 = appPrefs.getString("PrefPinCode1", null); + String pText2 = appPrefs.getString("PrefPinCode2", null); + String pText3 = appPrefs.getString("PrefPinCode3", null); + String pText4 = appPrefs.getString("PrefPinCode4", null); + + if ( tempText[0].equals(pText1) && + tempText[1].equals(pText2) && + tempText[2].equals(pText3) && + tempText[3].equals(pText4) ) { + + return true; + + + }else { + Arrays.fill(tempText, null); + AlertDialog aDialog = new AlertDialog.Builder(this).create(); + CharSequence errorSeq = getString(R.string.common_error); + aDialog.setTitle(errorSeq); + CharSequence cseq = getString(R.string.pincode_wrong); + aDialog.setMessage(cseq); + CharSequence okSeq = getString(R.string.common_ok); + aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){ + + @Override + public void onClick(DialogInterface dialog, int which) { + // TODO Auto-generated method stub(""); + return; + } + + }); + aDialog.show(); + clearBoxes(); + mPinHdr.setText(R.string.pincode_enter_pin_code); + newPasswordEntered = true; + confirmingPinCode = false; + + } + + + return false; + } + + protected void confirmPincode(){ + + confirmingPinCode = false; + + String rText1 = mText1.getText().toString(); + String rText2 = mText2.getText().toString(); + String rText3 = mText3.getText().toString(); + String rText4 = mText4.getText().toString(); + + if ( tempText[0].equals(rText1) && + tempText[1].equals(rText2) && + tempText[2].equals(rText3) && + tempText[3].equals(rText4) ) { + + savePincodeAndExit(); + + } else { + + Arrays.fill(tempText, null); + AlertDialog aDialog = new AlertDialog.Builder(this).create(); + CharSequence errorSeq = getString(R.string.common_error); + aDialog.setTitle(errorSeq); + CharSequence cseq = getString(R.string.pincode_mismatch); + aDialog.setMessage(cseq); + CharSequence okSeq = getString(R.string.common_ok); + aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){ + + @Override + public void onClick(DialogInterface dialog, int which) { + // TODO Auto-generated method stub(""); + return; + } + + }); + aDialog.show(); + mPinHdr.setText(R.string.pincode_configure_your_pin); + clearBoxes(); + } + + } + + + protected void pinCodeEnd(boolean state){ + AlertDialog aDialog = new AlertDialog.Builder(this).create(); + + if (state){ + CharSequence saveSeq = getString(R.string.common_save_exit); + aDialog.setTitle(saveSeq); + CharSequence cseq = getString(R.string.pincode_stored); + aDialog.setMessage(cseq); + + }else{ + CharSequence saveSeq = getString(R.string.common_save_exit); + aDialog.setTitle(saveSeq); + CharSequence cseq = getString(R.string.pincode_removed); + aDialog.setMessage(cseq); + + } + CharSequence okSeq = getString(R.string.common_ok); + aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){ + + @Override + public void onClick(DialogInterface dialog, int which) { + // TODO Auto-generated method stub(""); + finish(); + return; + } + + }); + aDialog.show(); + } + + protected void savePincodeAndExit(){ + SharedPreferences.Editor appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + + appPrefs.putString("PrefPinCode1", tempText[0]); + appPrefs.putString("PrefPinCode2",tempText[1]); + appPrefs.putString("PrefPinCode3", tempText[2]); + appPrefs.putString("PrefPinCode4", tempText[3]); + appPrefs.putBoolean("set_pincode",true); + appPrefs.commit(); + + pinCodeEnd(true); + + + + } + + + protected void clearBoxes(){ + + mText1.setText(""); + mText2.setText(""); + mText3.setText(""); + mText4.setText(""); + mText1.requestFocus(); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event){ + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){ + + if (activity.equals("preferences")){ + SharedPreferences.Editor appPrefsE = PreferenceManager + + .getDefaultSharedPreferences(getApplicationContext()).edit(); + + SharedPreferences appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + boolean state = appPrefs.getBoolean("set_pincode", false); + appPrefsE.putBoolean("set_pincode",!state); + appPrefsE.commit(); + setInitVars(); + finish(); + } + return true; + + } + + return super.onKeyDown(keyCode, event); + } + + + + + +} diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java new file mode 100644 index 00000000..7b23856d --- /dev/null +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -0,0 +1,240 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.activity; + +import java.util.Vector; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceManager; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.Preference.OnPreferenceClickListener; +import android.util.Log; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockPreferenceActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.owncloud.android.AccountUtils; +import com.owncloud.android.OwnCloudSession; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.db.DbHandler; + +import com.owncloud.android.R; + +/** + * An Activity that allows the user to change the application's settings. + * + * @author Bartek Przybylski + * + */ +public class Preferences extends SherlockPreferenceActivity implements + OnPreferenceChangeListener{ + private static final String TAG = "OwnCloudPreferences"; + private final int mNewSession = 47; + private final int mEditSession = 48; + private DbHandler mDbHandler; + private Vector mSessions; + //private Account[] mAccounts; + //private ListPreference mAccountList; + private ListPreference mTrackingUpdateInterval; + private CheckBoxPreference mDeviceTracking; + private CheckBoxPreference pCode; + private int mSelectedMenuItem; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mDbHandler = new DbHandler(getBaseContext()); + mSessions = new Vector(); + addPreferencesFromResource(R.xml.preferences); + //populateAccountList(); + ActionBar actionBar = getSherlock().getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + Preference p = findPreference("manage_account"); + if (p != null) + p.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class); + startActivity(i); + return true; + } + }); + + pCode = (CheckBoxPreference) findPreference("set_pincode"); + + + if (pCode != null){ + + pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + + Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); + i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences"); + i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString()); + + startActivity(i); + + return true; + } + }); + + } + + } + + + @Override + protected void onResume() { + // TODO Auto-generated method stub + SharedPreferences appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + boolean state = appPrefs.getBoolean("set_pincode", false); + pCode.setChecked(state); + + super.onResume(); + } + + + + /** + * Populates the account selector + *-/ + private void populateAccountList() { + AccountManager accMan = AccountManager.get(this); + mAccounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + mAccountList = (ListPreference) findPreference("select_oc_account"); + mAccountList.setOnPreferenceChangeListener(this); + + // Display the name of the current account if there is any + Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this); + if (defaultAccount != null) { + mAccountList.setSummary(defaultAccount.name); + } + + // Transform accounts into array of string for preferences to use + String[] accNames = new String[mAccounts.length]; + for (int i = 0; i < mAccounts.length; i++) { + Account account = mAccounts[i]; + accNames[i] = account.name; + } + + mAccountList.setEntries(accNames); + mAccountList.setEntryValues(accNames); + }*/ + + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + //MenuInflater inflater = getSherlock().getMenuInflater(); + //inflater.inflate(R.menu.prefs_menu, menu); + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + super.onMenuItemSelected(featureId, item); + Intent intent; + + switch (item.getItemId()) { + //case R.id.addSessionItem: + case 1: + intent = new Intent(this, PreferencesNewSession.class); + startActivityForResult(intent, mNewSession); + break; + case R.id.SessionContextEdit: + intent = new Intent(this, PreferencesNewSession.class); + intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem) + .getEntryId()); + intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem) + .getName()); + intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem) + .getUrl()); + startActivityForResult(intent, mEditSession); + break; + case android.R.id.home: + intent = new Intent(getBaseContext(), FileDisplayActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + break; + default: + Log.w(TAG, "Unknown menu item triggered"); + return false; + } + return true; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onDestroy() { + mDbHandler.close(); + super.onDestroy(); + } + + + + @Override + /** + * Updates various summaries after updates. Also starts and stops + * the + */ + public boolean onPreferenceChange(Preference preference, Object newValue) { + // Update current account summary + /*if (preference.equals(mAccountList)) { + mAccountList.setSummary(newValue.toString()); + } + + // Update tracking interval summary + else*/ if (preference.equals(mTrackingUpdateInterval)) { + String trackingSummary = getResources().getString( + R.string.prefs_trackmydevice_interval_summary); + trackingSummary = String.format(trackingSummary, + newValue.toString()); + mTrackingUpdateInterval.setSummary(trackingSummary); + } + + // Start or stop tracking service + else if (preference.equals(mDeviceTracking)) { + Intent locationServiceIntent = new Intent(); + locationServiceIntent + .setAction("eu.alefzero.owncloud.location.LocationLauncher"); + locationServiceIntent.putExtra("TRACKING_SETTING", + (Boolean) newValue); + sendBroadcast(locationServiceIntent); + } + return true; + } + + + +} diff --git a/src/com/owncloud/android/ui/activity/PreferencesNewSession.java b/src/com/owncloud/android/ui/activity/PreferencesNewSession.java new file mode 100644 index 00000000..3e9eb261 --- /dev/null +++ b/src/com/owncloud/android/ui/activity/PreferencesNewSession.java @@ -0,0 +1,98 @@ +package com.owncloud.android.ui.activity; + +import android.accounts.AccountAuthenticatorActivity; +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; + +public class PreferencesNewSession extends AccountAuthenticatorActivity + implements OnClickListener { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // setContentView(R.layout.add_new_session); + /* + * EditText et;// = (EditText) + * findViewById(R.id.newSession_sessionName); + * + * et = (EditText) findViewById(R.id.newSession_URL); if + * (getIntent().hasExtra("sessionURL")) { try { URI uri = new + * URI(getIntent().getStringExtra("sessionURL")); String url = + * uri.getHost(); if (uri.getPort() != -1) { url += ":" + + * String.valueOf(uri.getPort()); } if (uri.getPath() != null) { url += + * uri.getPath(); } else { url += "/"; } et.setText(url); et = + * (EditText) findViewById(R.id.newSession_username); if + * (uri.getAuthority() != null) { if (uri.getUserInfo().indexOf(':') != + * -1) { et.setText(uri.getUserInfo().substring(0, + * uri.getUserInfo().indexOf(':'))); et = (EditText) + * findViewById(R.id.newSession_password); + * et.setText(uri.getUserInfo().substring + * (uri.getUserInfo().indexOf(':')+1)); } else { + * et.setText(uri.getUserInfo()); } } + * + * } catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " + + * e.getLocalizedMessage()); } } + * + * mReturnData = new Intent(); setResult(Activity.RESULT_OK, + * mReturnData); ((Button) + * findViewById(R.id.button1)).setOnClickListener(this); ((Button) + * findViewById(R.id.button2)).setOnClickListener(this); + */ + } + + @Override + protected void onResume() { + super.onResume(); + } + + public void onClick(View v) { + /* + * switch (v.getId()) { case R.id.button1: Intent intent = new Intent(); + * if (getIntent().hasExtra("sessionId")) { intent.putExtra("sessionId", + * getIntent().getIntExtra("sessionId", -1)); } //String sessionName = + * ((EditText) + * findViewById(R.id.newSession_sessionName)).getText().toString(); // + * if (sessionName.trim().equals("") || !isNameValid(sessionName)) { // + * Toast.makeText(this, R.string.new_session_session_name_error, + * Toast.LENGTH_LONG).show(); // break; // } URI uri = prepareURI(); if + * (uri != null) { //intent.putExtra("sessionName", sessionName); + * intent.putExtra("sessionURL", uri.toString()); + * setResult(Activity.RESULT_OK, intent); AccountManager accMgr = + * AccountManager.get(this); Account a = new Account("OwnCloud", + * AccountAuthenticatorService.ACCOUNT_TYPE); + * accMgr.addAccountExplicitly(a, "asd", null); finish(); } break; case + * R.id.button2: setResult(Activity.RESULT_CANCELED); finish(); break; } + */ + } + + /* + * private URI prepareURI() { URI uri = null; String url = ""; try { String + * username = ((EditText) + * findViewById(R.id.newSession_username)).getText().toString().trim(); + * String password = ((EditText) + * findViewById(R.id.newSession_password)).getText().toString().trim(); + * String hostname = ((EditText) + * findViewById(R.id.newSession_URL)).getText().toString().trim(); String + * scheme; if (hostname.matches("[A-Za-z]://")) { scheme = + * hostname.substring(0, hostname.indexOf("://")+3); hostname = + * hostname.substring(hostname.indexOf("://")+3); } else { scheme = + * "http://"; } if (!username.equals("")) { if (!password.equals("")) { + * username += ":" + password + "@"; } else { username += "@"; } } url = + * scheme + username + hostname; Log.i(TAG, url); uri = new URI(url); } + * catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " + + * e.getLocalizedMessage()); Toast.makeText(this, + * R.string.new_session_uri_error, Toast.LENGTH_LONG).show(); } return uri; + * } + * + * private boolean isNameValid(String string) { return + * string.matches("[A-Za-z0-9 _-]*"); } + */ + + @Override + public void onBackPressed() { + setResult(Activity.RESULT_CANCELED); + super.onBackPressed(); + } + +} diff --git a/src/com/owncloud/android/ui/adapter/FileListActionListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListActionListAdapter.java new file mode 100644 index 00000000..872b8132 --- /dev/null +++ b/src/com/owncloud/android/ui/adapter/FileListActionListAdapter.java @@ -0,0 +1,173 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.ui.adapter; + +import java.io.File; + +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; + +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavUtils; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.net.Uri; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.TextView; + +public class FileListActionListAdapter implements ListAdapter { + + private Context mContext; + private Account mAccount; + private String mFilename, mFileType, mFilePath, mFileStoragePath; + + private final int ITEM_DOWNLOAD = 0; + + // private final int ITEM_SHARE = 1; + + public FileListActionListAdapter(Cursor c, Context co, Account account) { + mContext = co; + mFilename = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_NAME)); + mFileType = c.getString(c + .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)); + mFilePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH)); + mFileStoragePath = c.getString(c + .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)); + // mItemId = c.getString(c.getColumnIndex(ProviderTableMeta._ID)); + mAccount = account; + } + + public boolean areAllItemsEnabled() { + // TODO Auto-generated method stub + return true; + } + + public boolean isEnabled(int position) { + // TODO Auto-generated method stub + return true; + } + + public int getCount() { + // TODO Auto-generated method stub + return 1; + } + + public Object getItem(int position) { + if (position == 0) { + Intent intent = new Intent(Intent.ACTION_VIEW); + if (TextUtils.isEmpty(mFileStoragePath)) { + intent.putExtra("toDownload", true); + AccountManager accm = (AccountManager) mContext + .getSystemService(Context.ACCOUNT_SERVICE); + String ocurl = accm.getUserData(mAccount, + AccountAuthenticator.KEY_OC_URL); + ocurl += WebdavUtils.encodePath(mFilePath + mFilename); + intent.setData(Uri.parse(ocurl)); + } else { + intent.putExtra("toDownload", false); + intent.setDataAndType(Uri.fromFile(new File(mFileStoragePath)), + mFileType); + } + return intent; + } + return null; + } + + public long getItemId(int position) { + // TODO Auto-generated method stub + return 0; + } + + public int getItemViewType(int position) { + // TODO Auto-generated method stub + return 0; + } + + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + if (v == null) { + LayoutInflater vi = (LayoutInflater) mContext + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(R.layout.file_display_action_list_element, null); + } + + TextView tv; + ImageView iv; + switch (position) { + case ITEM_DOWNLOAD: + tv = (TextView) v.findViewById(R.id.textView1); + if (mFileStoragePath == null) { + tv.setText("Download"); + } else { + setActionName(tv); + } + iv = (ImageView) v.findViewById(R.id.imageView1); + iv.setImageResource(R.drawable.download); + break; + } + + return v; + } + + public int getViewTypeCount() { + // TODO Auto-generated method stub + return 2; + } + + public boolean hasStableIds() { + // TODO Auto-generated method stub + return false; + } + + public boolean isEmpty() { + // TODO Auto-generated method stub + return false; + } + + public void registerDataSetObserver(DataSetObserver observer) { + // TODO Auto-generated method stub + + } + + public void unregisterDataSetObserver(DataSetObserver observer) { + // TODO Auto-generated method stub + + } + + private void setActionName(TextView tv) { + if (mFileType.matches("image/.*")) { + tv.setText("View"); + } else if (mFileType.matches("audio/.*") + || mFileType.matches("video/.*")) { + tv.setText("Play"); + } else { + tv.setText("Open"); + } + } + +} diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java new file mode 100644 index 00000000..ade2e5e4 --- /dev/null +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -0,0 +1,202 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.adapter; + +import java.util.Vector; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.DisplayUtils; +import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileUploader; + +import com.owncloud.android.R; + +import android.accounts.Account; +import android.content.Context; +import android.database.DataSetObserver; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.TextView; + +/** + * This Adapter populates a ListView with all files and folders in an ownCloud + * instance. + * + * @author Bartek Przybylski + * + */ +public class FileListListAdapter implements ListAdapter { + private Context mContext; + private OCFile mFile; + private Vector mFiles; + private DataStorageManager mStorageManager; + private Account mAccount; + + public FileListListAdapter(OCFile file, DataStorageManager storage_man, + Context context) { + mFile = file; + mStorageManager = storage_man; + mFiles = mStorageManager.getDirectoryContent(mFile); + mContext = context; + mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + } + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public boolean isEnabled(int position) { + // TODO Auto-generated method stub + return true; + } + + @Override + public int getCount() { + return mFiles != null ? mFiles.size() : 0; + } + + @Override + public Object getItem(int position) { + if (mFiles.size() <= position) + return null; + return mFiles.get(position); + } + + @Override + public long getItemId(int position) { + return mFiles != null ? mFiles.get(position).getFileId() : 0; + } + + @Override + public int getItemViewType(int position) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + if (view == null) { + LayoutInflater inflator = (LayoutInflater) mContext + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflator.inflate(R.layout.list_layout, null); + } + if (mFiles.size() > position) { + OCFile file = mFiles.get(position); + TextView fileName = (TextView) view.findViewById(R.id.Filename); + String name = file.getFileName(); + + fileName.setText(name); + ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1); + if (file.getMimetype() == null || !file.getMimetype().equals("DIR")) { + fileIcon.setImageResource(R.drawable.file); + } else { + fileIcon.setImageResource(R.drawable.ic_menu_archive); + } + ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2); + if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) { + localStateView.setImageResource(R.drawable.downloading_file_indicator); + localStateView.setVisibility(View.VISIBLE); + } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) { + localStateView.setImageResource(R.drawable.uploading_file_indicator); + localStateView.setVisibility(View.VISIBLE); + } else if (file.isDown()) { + localStateView.setImageResource(R.drawable.local_file_indicator); + localStateView.setVisibility(View.VISIBLE); + } else { + localStateView.setVisibility(View.INVISIBLE); + } + /* + ImageView down = (ImageView) view.findViewById(R.id.imageView2); + ImageView downloading = (ImageView) view.findViewById(R.id.imageView4); + ImageView uploading = (ImageView) view.findViewById(R.id.imageView5); + if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) { + down.setVisibility(View.INVISIBLE); + downloading.setVisibility(View.VISIBLE); + uploading.setVisibility(View.INVISIBLE); + } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) { + down.setVisibility(View.INVISIBLE); + downloading.setVisibility(View.INVISIBLE); + uploading.setVisibility(View.VISIBLE); + } else if (file.isDown()) { + down.setVisibility(View.VISIBLE); + downloading.setVisibility(View.INVISIBLE); + uploading.setVisibility(View.INVISIBLE); + } else { + down.setVisibility(View.INVISIBLE); + downloading.setVisibility(View.INVISIBLE); + uploading.setVisibility(View.INVISIBLE); + }*/ + + if (!file.isDirectory()) { + view.findViewById(R.id.file_size).setVisibility(View.VISIBLE); + view.findViewById(R.id.last_mod).setVisibility(View.VISIBLE); + ((TextView)view.findViewById(R.id.file_size)).setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); + ((TextView)view.findViewById(R.id.last_mod)).setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); + // this if-else is needed even thoe fav icon is visible by default + // because android reuses views in listview + if (!file.keepInSync()) { + view.findViewById(R.id.imageView3).setVisibility(View.GONE); + } else { + view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE); + } + } else { + view.findViewById(R.id.file_size).setVisibility(View.GONE); + view.findViewById(R.id.last_mod).setVisibility(View.GONE); + view.findViewById(R.id.imageView3).setVisibility(View.GONE); + } + } + + return view; + } + + @Override + public int getViewTypeCount() { + return 4; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public boolean isEmpty() { + return mFiles != null ? mFiles.isEmpty() : false; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + // TODO Auto-generated method stub + + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + // TODO Auto-generated method stub + + } +} diff --git a/src/com/owncloud/android/ui/adapter/LandingScreenAdapter.java b/src/com/owncloud/android/ui/adapter/LandingScreenAdapter.java new file mode 100644 index 00000000..8bc56754 --- /dev/null +++ b/src/com/owncloud/android/ui/adapter/LandingScreenAdapter.java @@ -0,0 +1,112 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.adapter; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.ui.activity.Preferences; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import com.owncloud.android.R; + +/** + * Populates the landing screen icons. + * + * @author Lennart Rosam + * + */ +public class LandingScreenAdapter extends BaseAdapter { + + private Context mContext; + + private final Integer[] mLandingScreenIcons = { R.drawable.home, + R.drawable.music, R.drawable.contacts, R.drawable.calendar, + android.R.drawable.ic_menu_agenda, R.drawable.settings }; + + private final Integer[] mLandingScreenTexts = { R.string.main_files, + R.string.main_music, R.string.main_contacts, + R.string.main_calendar, R.string.main_bookmarks, + R.string.main_settings }; + + public LandingScreenAdapter(Context context) { + mContext = context; + } + + @Override + public int getCount() { + return mLandingScreenIcons.length; + } + + @Override + /** + * Returns the Intent associated with this object + * or null if the functionality is not yet implemented + */ + public Object getItem(int position) { + Intent intent = new Intent(); + + switch (position) { + case 0: + /* + * The FileDisplayActivity requires the ownCloud account as an + * parcableExtra. We will put in the one that is selected in the + * preferences + */ + intent.setClass(mContext, FileDisplayActivity.class); + intent.putExtra("ACCOUNT", + AccountUtils.getCurrentOwnCloudAccount(mContext)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + break; + case 5: + intent.setClass(mContext, Preferences.class); + break; + default: + intent = null; + } + return intent; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + LayoutInflater inflator = LayoutInflater.from(mContext); + convertView = inflator.inflate(R.layout.landing_page_item, null); + + ImageView icon = (ImageView) convertView + .findViewById(R.id.gridImage); + TextView iconText = (TextView) convertView + .findViewById(R.id.gridText); + + icon.setImageResource(mLandingScreenIcons[position]); + iconText.setText(mLandingScreenTexts[position]); + } + return convertView; + } +} diff --git a/src/com/owncloud/android/ui/fragment/AuthenticatorAccountDetailsFragment.java b/src/com/owncloud/android/ui/fragment/AuthenticatorAccountDetailsFragment.java new file mode 100644 index 00000000..9517fcd3 --- /dev/null +++ b/src/com/owncloud/android/ui/fragment/AuthenticatorAccountDetailsFragment.java @@ -0,0 +1,7 @@ +package com.owncloud.android.ui.fragment; + +import com.actionbarsherlock.app.SherlockFragment; + +public class AuthenticatorAccountDetailsFragment extends SherlockFragment { + +} diff --git a/src/com/owncloud/android/ui/fragment/AuthenticatorGetStartedFragment.java b/src/com/owncloud/android/ui/fragment/AuthenticatorGetStartedFragment.java new file mode 100644 index 00000000..f321aa9f --- /dev/null +++ b/src/com/owncloud/android/ui/fragment/AuthenticatorGetStartedFragment.java @@ -0,0 +1,7 @@ +package com.owncloud.android.ui.fragment; + +import com.actionbarsherlock.app.SherlockFragment; + +public class AuthenticatorGetStartedFragment extends SherlockFragment { + +} diff --git a/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java b/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java new file mode 100644 index 00000000..62a68d58 --- /dev/null +++ b/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java @@ -0,0 +1,92 @@ +package com.owncloud.android.ui.fragment; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.Log; + +import com.actionbarsherlock.app.SherlockDialogFragment; + +public class ConfirmationDialogFragment extends SherlockDialogFragment { + + public final static String ARG_CONF_RESOURCE_ID = "resource_id"; + public final static String ARG_CONF_ARGUMENTS = "string_array"; + + public final static String ARG_POSITIVE_BTN_RES = "positive_btn_res"; + public final static String ARG_NEUTRAL_BTN_RES = "neutral_btn_res"; + public final static String ARG_NEGATIVE_BTN_RES = "negative_btn_res"; + + private ConfirmationDialogFragmentListener mListener; + + public static ConfirmationDialogFragment newInstance(int string_id, String[] arguments, int posBtn, int neuBtn, int negBtn) { + ConfirmationDialogFragment frag = new ConfirmationDialogFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_CONF_RESOURCE_ID, string_id); + args.putStringArray(ARG_CONF_ARGUMENTS, arguments); + args.putInt(ARG_POSITIVE_BTN_RES, posBtn); + args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn); + args.putInt(ARG_NEGATIVE_BTN_RES, negBtn); + frag.setArguments(args); + return frag; + } + + public void setOnConfirmationListener(ConfirmationDialogFragmentListener listener) { + mListener = listener; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Object[] confirmationTarget = getArguments().getStringArray(ARG_CONF_ARGUMENTS); + int resourceId = getArguments().getInt(ARG_CONF_RESOURCE_ID, -1); + int posBtn = getArguments().getInt(ARG_POSITIVE_BTN_RES, -1); + int neuBtn = getArguments().getInt(ARG_NEUTRAL_BTN_RES, -1); + int negBtn = getArguments().getInt(ARG_NEGATIVE_BTN_RES, -1); + + if (confirmationTarget == null || resourceId == -1) { + Log.wtf(getTag(), "Calling confirmation dialog without resource or arguments"); + return null; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(String.format(getString(resourceId), confirmationTarget)) + .setTitle(android.R.string.dialog_alert_title); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + builder.setIconAttribute(android.R.attr.alertDialogIcon); + } + + if (posBtn != -1) + builder.setPositiveButton(posBtn, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + mListener.onConfirmation(getTag()); + } + }); + if (neuBtn != -1) + builder.setNeutralButton(neuBtn, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + mListener.onNeutral(getTag()); + } + }); + if (negBtn != -1) + builder.setNegativeButton(negBtn, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mListener.onCancel(getTag()); + } + }); + return builder.create(); + } + + + public interface ConfirmationDialogFragmentListener { + public void onConfirmation(String callerTag); + public void onNeutral(String callerTag); + public void onCancel(String callerTag); + } + +} + diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java new file mode 100644 index 00000000..ae38a0a0 --- /dev/null +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -0,0 +1,1126 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.fragment; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.httpclient.HttpException; +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.DavMethodBase; +import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; +import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; +import org.json.JSONException; +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.content.res.Resources.NotFoundException; +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.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.view.WindowManager.LayoutParams; +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.SherlockDialogFragment; +import com.actionbarsherlock.app.SherlockFragment; +import com.owncloud.android.AccountUtils; +import com.owncloud.android.DisplayUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.ui.activity.FileDetailActivity; +import com.owncloud.android.ui.activity.FileDisplayActivity; +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 { + + 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 ImageView mPreview; + + private DownloadFinishReceiver mDownloadFinishReceiver; + private UploadFinishReceiver mUploadFinishReceiver; + + private static final String TAG = "FileDetailFragment"; + 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; + 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; + mLayout = R.layout.file_details_empty; + + if(fileToDetail != null && ocAccount != null) { + mLayout = R.layout.file_details_fragment; + } + } + + + /** + * {@inheritDoc} + */ + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mContainerActivity = (ContainerActivity) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity"); + } + } + + + @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); + } + + 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(); + return view; + } + + + @Override + public void onSaveInstanceState(Bundle outState) { + Log.i(getClass().toString(), "onSaveInstanceState() start"); + super.onSaveInstanceState(outState); + outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile); + outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount); + Log.i(getClass().toString(), "onSaveInstanceState() end"); + } + + + @Override + public void onResume() { + super.onResume(); + + mDownloadFinishReceiver = new DownloadFinishReceiver(); + IntentFilter filter = new IntentFilter( + FileDownloader.DOWNLOAD_FINISH_MESSAGE); + getActivity().registerReceiver(mDownloadFinishReceiver, filter); + + mUploadFinishReceiver = new UploadFinishReceiver(); + filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); + getActivity().registerReceiver(mUploadFinishReceiver, filter); + + mPreview = (ImageView)mView.findViewById(R.id.fdPreview); + } + + @Override + public void onPause() { + super.onPause(); + + getActivity().unregisterReceiver(mDownloadFinishReceiver); + mDownloadFinishReceiver = null; + + getActivity().unregisterReceiver(mUploadFinishReceiver); + mUploadFinishReceiver = null; + + if (mPreview != null) { + mPreview = null; + } + } + + @Override + public View getView() { + return super.getView() == null ? mView : super.getView(); + } + + + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.fdDownloadBtn: { + Intent i = new Intent(getActivity(), FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); + i.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mFile.getRemotePath()); + i.putExtra(FileDownloader.EXTRA_FILE_PATH, mFile.getRemotePath()); + i.putExtra(FileDownloader.EXTRA_FILE_SIZE, mFile.getFileLength()); + + // update ui + setButtonsForTransferring(); + + getActivity().startService(i); + mContainerActivity.onFileStateChanged(); // this is not working; it is performed before the fileDownloadService registers it as 'in progress' + break; + } + case R.id.fdKeepInSync: { + CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync); + mFile.setKeepInSync(cb.isChecked()); + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver()); + fdsm.saveFile(mFile); + if (mFile.keepInSync()) { + onClick(getView().findViewById(R.id.fdDownloadBtn)); + } else { + mContainerActivity.onFileStateChanged(); // put inside 'else' to not call it twice (here, and in the virtual click on fdDownloadBtn) + } + break; + } + case R.id.fdRenameBtn: { + EditNameFragment dialog = EditNameFragment.newInstance(mFile.getFileName()); + dialog.show(getFragmentManager(), "nameeditdialog"); + dialog.setOnDismissListener(this); + 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); + confDialog.show(getFragmentManager(), FTAG_CONFIRMATION); + break; + } + case R.id.fdOpenBtn: { + String storagePath = mFile.getStoragePath(); + String encodedStoragePath = WebdavUtils.encodePath(storagePath); + try { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype()); + i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + startActivity(i); + + } catch (Throwable t) { + Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype()); + boolean toastIt = true; + String mimeType = ""; + try { + Intent i = new Intent(Intent.ACTION_VIEW); + mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1)); + if (mimeType != null && !mimeType.equals(mFile.getMimetype())) { + i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType); + i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + startActivity(i); + toastIt = false; + } + + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath); + + } catch (ActivityNotFoundException e) { + Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension"); + + } catch (Throwable th) { + Log.e(TAG, "Unexpected problem when opening: " + storagePath, th); + + } finally { + if (toastIt) { + Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show(); + } + } + + } + break; + } + default: + Log.e(TAG, "Incorrect view clicked!"); + } + + /* else if (v.getId() == R.id.fdShareBtn) { + Thread t = new Thread(new ShareRunnable(mFile.getRemotePath())); + t.start(); + }*/ + } + + + @Override + public void onConfirmation(String callerTag) { + if (callerTag.equals(FTAG_CONFIRMATION)) { + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); + if (fdsm.getFileById(mFile.getFileId()) != null) { + new Thread(new RemoveRunnable(mFile, mAccount, new Handler())).start(); + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + } + } + } + + @Override + public void onNeutral(String callerTag) { + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); + File f = null; + if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) { + f.delete(); + mFile.setStoragePath(null); + fdsm.saveFile(mFile); + updateFileDetails(mFile, mAccount); + } + } + + @Override + public void onCancel(String callerTag) { + Log.d(TAG, "REMOVAL CANCELED"); + } + + + /** + * 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; + } + + + /** + * 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; + mAccount = ocAccount; + updateFileDetails(); + } + + + /** + * Updates the view with all relevant details about that file. + */ + public void updateFileDetails() { + + if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) { + + // set file details + setFilename(mFile.getFileName()); + setFiletype(DisplayUtils.convertMIMEtoPrettyPrint(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())) { + setButtonsForTransferring(); + + } else if (mFile.isDown()) { + // Update preview + if (mFile.getMimetype().startsWith("image/")) { + BitmapLoader bl = new BitmapLoader(); + bl.execute(new String[]{mFile.getStoragePath()}); + } + + setButtonsForDown(); + + } else { + setButtonsForRemote(); + } + } + } + + + /** + * 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) + tv.setText(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.filedetails_download_in_progress); // ugly + downloadButton.setEnabled(false); // TODO replace it with a 'cancel download' button + + // 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); + } + } + + /** + * 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_redownload); // ugly + downloadButton.setEnabled(true); + + ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true); + ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); + ((Button) getView().findViewById(R.id.fdRemoveBtn)).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); // unnecessary + downloadButton.setEnabled(true); + + ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false); + ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); + ((Button) getView().findViewById(R.id.fdRemoveBtn)).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 { + + /** + * 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.setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH)); // updates the local object without accessing the database again + } + updateFileDetails(); // 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); + if (mFile.getRemotePath().equals(uploadRemotePath)) { + if (uploadWasFine) { + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver()); + mFile = fdsm.getFileByPath(mFile.getRemotePath()); + } + updateFileDetails(); // 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 + private class ShareRunnable implements Runnable { + private String mPath; + + public ShareRunnable(String path) { + mPath = path; + } + + public void run() { + AccountManager am = AccountManager.get(getActivity()); + Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity()); + OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); + String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv); + + Log.d("share", "sharing for version " + ocv.toString()); + + if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) { + String APPS_PATH = "/apps/files_sharing/"; + String SHARE_PATH = "ajax/share.php"; + + String SHARED_PATH = "/apps/files_sharing/get.php?token="; + + final String WEBDAV_SCRIPT = "webdav.php"; + final String WEBDAV_FILES_LOCATION = "/files/"; + + WebdavClient wc = new WebdavClient(); + HttpConnectionManagerParams params = new HttpConnectionManagerParams(); + params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5); + + //wc.getParams().setParameter("http.protocol.single-cookie-header", true); + //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); + + PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH); + + post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" ); + post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); + List formparams = new ArrayList(); + Log.d("share", mPath+""); + formparams.add(new BasicNameValuePair("sources",mPath)); + formparams.add(new BasicNameValuePair("uid_shared_with", "public")); + formparams.add(new BasicNameValuePair("permissions", "0")); + post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8))); + + int status; + try { + PropFindMethod find = new PropFindMethod(url+"/"); + find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); + Log.d("sharer", ""+ url+"/"); + wc.setCredentials(account.name.substring(0, account.name.lastIndexOf('@')), am.getPassword(account)); + + for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) { + Log.d("sharer-h", a.getName() + ":"+a.getValue()); + } + + int status2 = wc.executeMethod(find); + + Log.d("sharer", "propstatus "+status2); + + GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/"); + get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); + + status2 = wc.executeMethod(get); + + Log.d("sharer", "getstatus "+status2); + Log.d("sharer", "" + get.getResponseBodyAsString()); + + for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) { + Log.d("sharer", a.getName() + ":"+a.getValue()); + } + + status = wc.executeMethod(post); + for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) { + Log.d("sharer-h", a.getName() + ":"+a.getValue()); + } + for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) { + Log.d("sharer", a.getName() + ":"+a.getValue()); + } + String resp = post.getResponseBodyAsString(); + Log.d("share", ""+post.getURI().toString()); + Log.d("share", "returned status " + status); + Log.d("share", " " +resp); + + if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) { + return; + } + + JSONObject jsonObject = new JSONObject (resp); + String jsonStatus = jsonObject.getString("status"); + if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success"); + + String token = jsonObject.getString("data"); + String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; + Log.d("Actions:shareFile ok", "url: " + uri); + + } catch (HttpException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) { + + } + } + } + + public void onDismiss(EditNameFragment dialog) { + if (dialog instanceof EditNameFragment) { + if (((EditNameFragment)dialog).getResult()) { + String newFilename = ((EditNameFragment)dialog).getNewFilename(); + Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); + if (!newFilename.equals(mFile.getFileName())) { + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); + if (fdsm.getFileById(mFile.getFileId()) != null) { + OCFile newFile = new OCFile(fdsm.getFileById(mFile.getParentId()).getRemotePath() + newFilename); + newFile.setCreationTimestamp(mFile.getCreationTimestamp()); + newFile.setFileId(mFile.getFileId()); + newFile.setFileLength(mFile.getFileLength()); + newFile.setKeepInSync(mFile.keepInSync()); + newFile.setLastSyncDate(mFile.getLastSyncDate()); + newFile.setMimetype(mFile.getMimetype()); + newFile.setModificationTimestamp(mFile.getModificationTimestamp()); + newFile.setParentId(mFile.getParentId()); + boolean localRenameFails = false; + if (mFile.isDown()) { + File f = new File(mFile.getStoragePath()); + Log.e(TAG, f.getAbsolutePath()); + localRenameFails = !(f.renameTo(new File(f.getParent() + File.separator + newFilename))); + Log.e(TAG, f.getParent() + File.separator + newFilename); + newFile.setStoragePath(f.getParent() + File.separator + newFilename); + } + + if (localRenameFails) { + Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); + msg.show(); + + } else { + new Thread(new RenameRunnable(mFile, newFile, mAccount, new Handler())).start(); + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + } + + } + } + } + } else { + Log.e(TAG, "Unknown dialog instance passed to onDismissDalog: " + dialog.getClass().getCanonicalName()); + } + + } + + private class RenameRunnable implements Runnable { + + Account mAccount; + OCFile mOld, mNew; + Handler mHandler; + + public RenameRunnable(OCFile oldFile, OCFile newFile, Account account, Handler handler) { + mOld = oldFile; + mNew = newFile; + mAccount = account; + mHandler = handler; + } + + public void run() { + WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext()); + wc.allowSelfsignedCertificates(); + AccountManager am = AccountManager.get(getSherlockActivity()); + String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); + OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); + String webdav_path = AccountUtils.getWebdavPath(ocv); + Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath())); + + Log.e("ASD", Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath())); + LocalMoveMethod move = new LocalMoveMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath()), + Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath())); + + boolean success = false; + try { + int status = wc.executeMethod(move); + success = move.succeeded(); + Log.d(TAG, "Move returned status: " + status); + + } catch (HttpException e) { + Log.e(TAG, "HTTP Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); + + } catch (IOException e) { + Log.e(TAG, "I/O Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); + + } catch (Exception e) { + Log.e(TAG, "Unexpected exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); + } + + if (success) { + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); + fdsm.removeFile(mOld); + fdsm.saveFile(mNew); + mFile = mNew; + mHandler.post(new Runnable() { + @Override + public void run() { + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + updateFileDetails(mFile, mAccount); + mContainerActivity.onFileStateChanged(); + } + }); + + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + // undo the local rename + if (mNew.isDown()) { + File f = new File(mNew.getStoragePath()); + if (!f.renameTo(new File(mOld.getStoragePath()))) { + // the local rename undoing failed; last chance: save the new local storage path in the old file + mFile.setStoragePath(mNew.getStoragePath()); + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); + fdsm.saveFile(mFile); + } + } + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + try { + Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); + msg.show(); + + } catch (NotFoundException e) { + e.printStackTrace(); + } + } + }); + } + } + private class LocalMoveMethod extends DavMethodBase { + + public LocalMoveMethod(String uri, String dest) { + super(uri); + addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest)); + } + + @Override + public String getName() { + return "MOVE"; + } + + @Override + protected boolean isSuccess(int status) { + return status == 201 || status == 204; + } + + } + } + + private static class EditNameFragment extends SherlockDialogFragment implements OnClickListener { + + private String mNewFilename; + private boolean mResult; + private FileDetailFragment mListener; + + static public EditNameFragment newInstance(String filename) { + EditNameFragment f = new EditNameFragment(); + Bundle args = new Bundle(); + args.putString("filename", filename); + f.setArguments(args); + return f; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.edit_box_dialog, container, false); + + String currentName = getArguments().getString("filename"); + if (currentName == null) + currentName = ""; + + ((Button)v.findViewById(R.id.cancel)).setOnClickListener(this); + ((Button)v.findViewById(R.id.ok)).setOnClickListener(this); + ((TextView)v.findViewById(R.id.user_input)).setText(currentName); + ((TextView)v.findViewById(R.id.user_input)).requestFocus(); + getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); + + mResult = false; + return v; + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.ok: { + mNewFilename = ((TextView)getView().findViewById(R.id.user_input)).getText().toString(); + mResult = true; + } + case R.id.cancel: { // fallthought + dismiss(); + mListener.onDismiss(this); + } + } + } + + void setOnDismissListener(FileDetailFragment listener) { + mListener = listener; + } + + public String getNewFilename() { + return mNewFilename; + } + + // true if user click ok + public boolean getResult() { + return mResult; + } + + } + + private class RemoveRunnable implements Runnable { + + Account mAccount; + OCFile mFileToRemove; + Handler mHandler; + + public RemoveRunnable(OCFile fileToRemove, Account account, Handler handler) { + mFileToRemove = fileToRemove; + mAccount = account; + mHandler = handler; + } + + public void run() { + WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext()); + wc.allowSelfsignedCertificates(); + AccountManager am = AccountManager.get(getSherlockActivity()); + String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); + OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); + String webdav_path = AccountUtils.getWebdavPath(ocv); + Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath())); + + DeleteMethod delete = new DeleteMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath())); + + boolean success = false; + int status = -1; + try { + status = wc.executeMethod(delete); + success = (delete.succeeded()); + Log.d(TAG, "Delete: returned status " + status); + + } catch (HttpException e) { + Log.e(TAG, "HTTP Exception removing file " + mFileToRemove.getRemotePath(), e); + + } catch (IOException e) { + Log.e(TAG, "I/O Exception removing file " + mFileToRemove.getRemotePath(), e); + + } catch (Exception e) { + Log.e(TAG, "Unexpected exception removing file " + mFileToRemove.getRemotePath(), e); + } + + if (success) { + FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); + fdsm.removeFile(mFileToRemove); + mHandler.post(new Runnable() { + @Override + public void run() { + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + try { + 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(); + } + + } catch (NotFoundException e) { + e.printStackTrace(); + } + } + }); + + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; + getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); + try { + Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); + msg.show(); + + } catch (NotFoundException e) { + e.printStackTrace(); + } + } + }); + } + } + + } + + class BitmapLoader extends AsyncTask { + @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20 + @Override + protected Bitmap doInBackground(String... params) { + Bitmap result = null; + if (params.length != 1) return result; + String storagePath = params[0]; + try { + + BitmapFactory.Options options = new Options(); + options.inScaled = true; + options.inPurgeable = true; + options.inJustDecodeBounds = true; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { + options.inPreferQualityOverSpeed = false; + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + options.inMutable = false; + } + + result = BitmapFactory.decodeFile(storagePath, options); + options.inJustDecodeBounds = false; + + int width = options.outWidth; + int height = options.outHeight; + int scale = 1; + if (width >= 2048 || height >= 2048) { + scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.))); + options.inSampleSize = scale; + } + Display display = getActivity().getWindowManager().getDefaultDisplay(); + Point size = new Point(); + int screenwidth; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) { + display.getSize(size); + screenwidth = size.x; + } else { + screenwidth = display.getWidth(); + } + + Log.e("ASD", "W " + width + " SW " + screenwidth); + + if (width > screenwidth) { + scale = (int) Math.ceil((float)width / screenwidth); + options.inSampleSize = scale; + } + + result = BitmapFactory.decodeFile(storagePath, options); + + Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight); + + } catch (OutOfMemoryError e) { + result = null; + Log.e(TAG, "Out of memory occured for file with size " + storagePath); + + } catch (NoSuchFieldError e) { + result = null; + Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath); + + } catch (Throwable t) { + result = null; + Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t); + } + return result; + } + @Override + protected void onPostExecute(Bitmap result) { + if (result != null && mPreview != null) { + mPreview.setImageBitmap(result); + } + } + + } + + +} diff --git a/src/com/owncloud/android/ui/fragment/FileListFragment.java b/src/com/owncloud/android/ui/fragment/FileListFragment.java new file mode 100644 index 00000000..5d1a8d1b --- /dev/null +++ b/src/com/owncloud/android/ui/fragment/FileListFragment.java @@ -0,0 +1,205 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.fragment; + +import java.util.Vector; + +import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.ui.FragmentListView; +import com.owncloud.android.ui.adapter.FileListListAdapter; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import com.owncloud.android.R; + +/** + * A Fragment that lists all files and folders in a given path. + * + * @author Bartek Przybylski + * + */ +public class FileListFragment extends FragmentListView { + private static final String TAG = "FileListFragment"; + + private FileListFragment.ContainerActivity mContainerActivity; + + private OCFile mFile = null; + private FileListListAdapter mAdapter; + + + /** + * {@inheritDoc} + */ + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mContainerActivity = (ContainerActivity) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity"); + } + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + Log.i(getClass().toString(), "onCreateView() start"); + super.onCreateView(inflater, container, savedInstanceState); + getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator)); + getListView().setDividerHeight(1); + + Log.i(getClass().toString(), "onCreateView() end"); + return getListView(); + } + + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + Log.i(getClass().toString(), "onActivityCreated() start"); + + super.onCreate(savedInstanceState); + //mAdapter = new FileListListAdapter(); + + Log.i(getClass().toString(), "onActivityCreated() stop"); + } + + + @Override + public void onItemClick(AdapterView l, View v, int position, long id) { + OCFile file = (OCFile) mAdapter.getItem(position); + if (file != null) { + /// Click on a directory + if (file.getMimetype().equals("DIR")) { + // just local updates + mFile = file; + listDirectory(file); + // any other updates are let to the container Activity + mContainerActivity.onDirectoryClick(file); + + } else { /// Click on a file + mContainerActivity.onFileClick(file); + } + + } else { + Log.d(TAG, "Null object in ListAdapter!!"); + } + + } + + /** + * Call this, when the user presses the up button + */ + public void onNavigateUp() { + OCFile parentDir = null; + + if(mFile != null){ + DataStorageManager storageManager = mContainerActivity.getStorageManager(); + parentDir = storageManager.getFileById(mFile.getParentId()); + mFile = parentDir; + } + listDirectory(parentDir); + } + + /** + * Use this to query the {@link OCFile} that is currently + * being displayed by this fragment + * @return The currently viewed OCFile + */ + public OCFile getCurrentFile(){ + return mFile; + } + + /** + * Calls {@link FileListFragment#listDirectory(OCFile)} with a null parameter + */ + public void listDirectory(){ + listDirectory(null); + } + + /** + * Lists the given directory on the view. When the input parameter is null, + * it will either refresh the last known directory, or list the root + * if there never was a directory. + * + * @param directory File to be listed + */ + public void listDirectory(OCFile directory) { + + DataStorageManager storageManager = mContainerActivity.getStorageManager(); + + // Check input parameters for null + if(directory == null){ + if(mFile != null){ + directory = mFile; + } else { + directory = storageManager.getFileByPath("/"); + if (directory == null) return; // no files, wait for sync + } + } + + + // If that's not a directory -> List its parent + if(!directory.isDirectory()){ + Log.w(TAG, "You see, that is not a directory -> " + directory.toString()); + directory = storageManager.getFileById(directory.getParentId()); + } + + mFile = directory; + + mAdapter = new FileListListAdapter(directory, storageManager, getActivity()); + setListAdapter(mAdapter); + } + + + + /** + * Interface to implement by any Activity that includes some instance of FileListFragment + * + * @author David A. Velasco + */ + public interface ContainerActivity { + + /** + * Callback method invoked when a directory is clicked by the user on the files list + * + * @param file + */ + public void onDirectoryClick(OCFile file); + + /** + * Callback method invoked when a file (non directory) is clicked by the user on the files list + * + * @param file + */ + public void onFileClick(OCFile file); + + /** + * Getter for the current DataStorageManager in the container activity + */ + public DataStorageManager getStorageManager(); + + } + +} diff --git a/src/com/owncloud/android/ui/fragment/LandingPageFragment.java b/src/com/owncloud/android/ui/fragment/LandingPageFragment.java new file mode 100644 index 00000000..a021afbf --- /dev/null +++ b/src/com/owncloud/android/ui/fragment/LandingPageFragment.java @@ -0,0 +1,58 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.ui.fragment; + +import com.actionbarsherlock.app.SherlockFragment; +import com.owncloud.android.ui.activity.LandingActivity; +import com.owncloud.android.ui.adapter.LandingScreenAdapter; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; +import com.owncloud.android.R; + +/** + * Used on the Landing page to display what Components of the ownCloud there + * are. Like Files, Music, Contacts, etc. + * + * @author Lennart Rosam + * + */ +public class LandingPageFragment extends SherlockFragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.landing_page_fragment, container); + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + ListView landingScreenItems = (ListView) getView().findViewById( + R.id.homeScreenList); + landingScreenItems.setAdapter(new LandingScreenAdapter(getActivity())); + landingScreenItems + .setOnItemClickListener((LandingActivity) getActivity()); + } + +} diff --git a/src/com/owncloud/android/utils/OwnCloudVersion.java b/src/com/owncloud/android/utils/OwnCloudVersion.java new file mode 100644 index 00000000..b96a9df1 --- /dev/null +++ b/src/com/owncloud/android/utils/OwnCloudVersion.java @@ -0,0 +1,83 @@ +/* ownCloud Android client application + * Copyright (C) 2012 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.utils; + +public class OwnCloudVersion implements Comparable { + public static final OwnCloudVersion owncloud_v1 = new OwnCloudVersion( + 0x010000); + public static final OwnCloudVersion owncloud_v2 = new OwnCloudVersion( + 0x020000); + public static final OwnCloudVersion owncloud_v3 = new OwnCloudVersion( + 0x030000); + public static final OwnCloudVersion owncloud_v4 = new OwnCloudVersion( + 0x040000); + + // format is in version + // 0xAABBCC + // for version AA.BB.CC + // ie version 3.0.3 will be stored as 0x030003 + private int mVersion; + private boolean mIsValid; + + public OwnCloudVersion(int version) { + mVersion = version; + mIsValid = true; + } + + public OwnCloudVersion(String version) { + mVersion = 0; + mIsValid = false; + parseVersionString(version); + } + + public String toString() { + return ((mVersion >> 16) % 256) + "." + ((mVersion >> 8) % 256) + "." + + ((mVersion) % 256); + } + + public boolean isVersionValid() { + return mIsValid; + } + + @Override + public int compareTo(OwnCloudVersion another) { + return another.mVersion == mVersion ? 0 + : another.mVersion < mVersion ? 1 : -1; + } + + private void parseVersionString(String version) { + try { + String[] nums = version.split("\\."); + if (nums.length > 0) { + mVersion += Integer.parseInt(nums[0]); + } + mVersion = mVersion << 8; + if (nums.length > 1) { + mVersion += Integer.parseInt(nums[1]); + } + mVersion = mVersion << 8; + if (nums.length > 2) { + mVersion += Integer.parseInt(nums[2]); + } + mIsValid = true; + } catch (Exception e) { + mIsValid = false; + } + } +} diff --git a/src/com/owncloud/android/widgets/ActionEditText.java b/src/com/owncloud/android/widgets/ActionEditText.java new file mode 100644 index 00000000..be3abfb6 --- /dev/null +++ b/src/com/owncloud/android/widgets/ActionEditText.java @@ -0,0 +1,127 @@ +package com.owncloud.android.widgets; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.owncloud.android.R; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.EditText; + +public class ActionEditText extends EditText { + private String s; + private String optionOneString; + private int optionOneColor; + private String optionTwoString; + private int optionTwoColor; + private Rect mTextBounds, mButtonRect; + + private String badgeClickCallback; + private Rect btn_rect; + + public ActionEditText(Context context, AttributeSet attrs) { + super(context, attrs); + getAttrs(attrs); + s = optionOneString; + mTextBounds = new Rect(); + mButtonRect = new Rect(); + } + + public ActionEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + getAttrs(attrs); + s = optionOneString; + mTextBounds = new Rect(); + mButtonRect = new Rect(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + Paint p = getPaint(); + + p.getTextBounds(s, 0, s.length(), mTextBounds); + + getDrawingRect(mButtonRect); + mButtonRect.top += 10; + mButtonRect.bottom -= 10; + mButtonRect.left = (int) (getWidth() - mTextBounds.width() - 18); + mButtonRect.right = getWidth() - 10; + btn_rect = mButtonRect; + + if (s.equals(optionOneString)) + p.setColor(optionOneColor); + else + p.setColor(optionTwoColor); + canvas.drawRect(mButtonRect, p); + p.setColor(Color.GRAY); + + canvas.drawText(s, mButtonRect.left + 3, mButtonRect.bottom + - (mTextBounds.height() / 2), p); + + invalidate(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int touchX = (int) event.getX(); + int touchY = (int) event.getY(); + boolean r = super.onTouchEvent(event); + if (event.getAction() == MotionEvent.ACTION_UP) { + if (btn_rect.contains(touchX, touchY)) { + if (s.equals(optionTwoString)) + s = optionOneString; + else + s = optionTwoString; + if (badgeClickCallback != null) { + @SuppressWarnings("rawtypes") + Class[] paramtypes = new Class[2]; + paramtypes[0] = android.view.View.class; + paramtypes[1] = String.class; + Method method; + try { + + method = getContext().getClass().getMethod( + badgeClickCallback, paramtypes); + method.invoke(getContext(), this, s); + + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + invalidate(); + } + } + } + return r; + } + + private void getAttrs(AttributeSet attr) { + TypedArray a = getContext().obtainStyledAttributes(attr, + R.styleable.ActionEditText); + optionOneString = a + .getString(R.styleable.ActionEditText_optionOneString); + optionTwoString = a + .getString(R.styleable.ActionEditText_optionTwoString); + optionOneColor = a.getColor(R.styleable.ActionEditText_optionOneColor, + 0x00ff00); + optionTwoColor = a.getColor(R.styleable.ActionEditText_optionTwoColor, + 0xff0000); + badgeClickCallback = a + .getString(R.styleable.ActionEditText_onBadgeClick); + } + +} diff --git a/src/eu/alefzero/owncloud/AccountUtils.java b/src/eu/alefzero/owncloud/AccountUtils.java deleted file mode 100644 index d088d2ce..00000000 --- a/src/eu/alefzero/owncloud/AccountUtils.java +++ /dev/null @@ -1,109 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud; - -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.utils.OwnCloudVersion; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -public class AccountUtils { - public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; - public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; - public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav"; - public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php"; - public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php"; - public static final String STATUS_PATH = "/status.php"; - - /** - * Can be used to get the currently selected ownCloud account in the - * preferences - * - * @param context The current appContext - * @return The current account or first available, if none is available, - * then null. - */ - public static Account getCurrentOwnCloudAccount(Context context) { - Account[] ocAccounts = AccountManager.get(context).getAccountsByType( - AccountAuthenticator.ACCOUNT_TYPE); - Account defaultAccount = null; - - SharedPreferences appPreferences = PreferenceManager - .getDefaultSharedPreferences(context); - String accountName = appPreferences - .getString("select_oc_account", null); - - if (accountName != null) { - for (Account account : ocAccounts) { - if (account.name.equals(accountName)) { - defaultAccount = account; - break; - } - } - } else if (ocAccounts.length != 0) { - // we at least need to take first account as fallback - defaultAccount = ocAccounts[0]; - } - - return defaultAccount; - } - - - - /** - * Checks, whether or not there are any ownCloud accounts setup. - * - * @return true, if there is at least one account. - */ - public static boolean accountsAreSetup(Context context) { - AccountManager accMan = AccountManager.get(context); - Account[] accounts = accMan - .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - return accounts.length > 0; - } - - - public static void setCurrentOwnCloudAccount(Context context, String name) { - SharedPreferences.Editor appPrefs = PreferenceManager - .getDefaultSharedPreferences(context).edit(); - appPrefs.putString("select_oc_account", name); - appPrefs.commit(); - } - - /** - * - * @param version version of owncloud - * @return webdav path for given OC version, null if OC version unknown - */ - public static String getWebdavPath(OwnCloudVersion version) { - if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0) - return WEBDAV_PATH_4_0; - if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0 - || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0) - return WEBDAV_PATH_2_0; - if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0) - return WEBDAV_PATH_1_2; - return null; - } - -} diff --git a/src/eu/alefzero/owncloud/CrashHandler.java b/src/eu/alefzero/owncloud/CrashHandler.java deleted file mode 100644 index 99cd0444..00000000 --- a/src/eu/alefzero/owncloud/CrashHandler.java +++ /dev/null @@ -1,153 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.LinkedList; -import java.util.List; - -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.net.ConnectivityManager; -import android.os.Environment; -import android.util.Log; - -public class CrashHandler implements UncaughtExceptionHandler { - - public static final String KEY_CRASH_FILENAME = "KEY_CRASH_FILENAME"; - - private Context mContext; - private static final String TAG = "CrashHandler"; - private static final String crash_filename_template = "crash"; - private static List TAGS; - private UncaughtExceptionHandler defaultUEH; - - // TODO: create base activity which will register for crashlog tag automaticly - static { - TAGS = new LinkedList(); - TAGS.add("AccountAuthenticator"); - TAGS.add("AccountAuthenticator"); - TAGS.add("ConnectionCheckerRunnable"); - TAGS.add("EasySSLSocketFactory"); - TAGS.add("FileDataStorageManager"); - TAGS.add("PhotoTakenBroadcastReceiver"); - TAGS.add("InstantUploadService"); - TAGS.add("FileDownloader"); - TAGS.add("FileUploader"); - TAGS.add("LocationUpdateService"); - TAGS.add("FileSyncAdapter"); - TAGS.add("AuthActivity"); - TAGS.add("OwnCloudPreferences"); - TAGS.add("FileDetailFragment"); - TAGS.add("FileListFragment"); - TAGS.add("ownCloudUploader"); - TAGS.add("WebdavClient"); - } - - public CrashHandler(Context context) { - mContext = context; - defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); - } - - @Override - public void uncaughtException(Thread thread, Throwable ex) { - final Writer writer = new StringWriter(); - final PrintWriter printwriter = new PrintWriter(writer); - ex.printStackTrace(printwriter); - final String startrace = writer.toString(); - printwriter.close(); - File ocdir = new File(Environment.getExternalStorageDirectory().getAbsoluteFile(), "owncloud"); - ocdir.mkdirs(); - - String crash_filename = crash_filename_template + System.currentTimeMillis() + ".txt"; - File crashfile = new File(ocdir, crash_filename); - try { - PackageInfo pi = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); - ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - String header = String.format("Model: %s, SDK: %d, Current net: %s AppVersion: %s\n\n", - android.os.Build.MODEL, - android.os.Build.VERSION.SDK_INT, - cm.getActiveNetworkInfo() != null ? cm.getActiveNetworkInfo().getTypeName() : "NONE", - pi.versionName); - Account account = AccountUtils.getCurrentOwnCloudAccount(mContext); - AccountManager am = AccountManager.get(mContext); - String header2 = String.format("Account: %s, OCUrl: %s, OCVersion: %s\n\n", - account.name, - am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL), - am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); - - crashfile.createNewFile(); - FileWriter fw = new FileWriter(crashfile); - fw.write(header); - fw.write(header2); - fw.write(startrace); - fw.write("\n\n"); - - String logcat = "logcat -d *:S "; - - for (String s : TAGS) - logcat += s + ":V "; - - Process process = Runtime.getRuntime().exec(logcat); - BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); - String logline; - while ((logline = br.readLine()) != null) - fw.write(logline+"\n"); - - br.close(); - fw.close(); - - Intent dataintent = new Intent(mContext, CrashlogSendActivity.class); - dataintent.putExtra(KEY_CRASH_FILENAME, crashfile.getAbsolutePath()); - PendingIntent intent; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - intent = PendingIntent.getActivity(mContext.getApplicationContext(), 0, dataintent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - } else { - intent = PendingIntent.getActivity(mContext.getApplicationContext(), 0, dataintent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - } - AlarmManager mngr = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - if (mngr == null) { - Log.e(TAG, "Couldn't retrieve alarm manager!"); - defaultUEH.uncaughtException(thread, ex); - return; - } - mngr.set(AlarmManager.RTC, System.currentTimeMillis(), intent); - System.exit(2); - } catch (Exception e1) { - Log.e(TAG, "Crash handler failed!"); - Log.e(TAG, e1.toString()); - defaultUEH.uncaughtException(thread, ex); - return; - } - } -} diff --git a/src/eu/alefzero/owncloud/CrashlogSendActivity.java b/src/eu/alefzero/owncloud/CrashlogSendActivity.java deleted file mode 100644 index 9ff83f67..00000000 --- a/src/eu/alefzero/owncloud/CrashlogSendActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud; - -import java.io.File; -import java.io.IOException; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.multipart.FilePart; -import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; -import org.apache.commons.httpclient.methods.multipart.Part; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.os.Bundle; -import android.util.Log; - -import com.actionbarsherlock.app.SherlockActivity; - -import eu.alefzero.webdav.FileRequestEntity; - -public class CrashlogSendActivity extends SherlockActivity implements OnClickListener, OnCancelListener { - - private static final String TAG = "CrashlogSendActivity"; - private static final String CRASHLOG_SUBMIT_URL = "http://alefzero.eu/a/crashlog/"; - private static final int DIALOG_SUBMIT = 5; - - private String mLogFilename; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mLogFilename = getIntent().getStringExtra(CrashHandler.KEY_CRASH_FILENAME); - if (mLogFilename == null) { - Log.wtf(TAG, "No file crashlog path given!"); - finish(); - return; - } - Log.i(TAG, "crashlog file path " + mLogFilename); - - showDialog(DIALOG_SUBMIT); - } - - - @Override - protected Dialog onCreateDialog(int id) { - if (id == DIALOG_SUBMIT) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(R.string.crashlog_message); - builder.setNegativeButton(R.string.crashlog_dont_send_report, this); - builder.setPositiveButton(R.string.crashlog_send_report, this); - builder.setCancelable(true); - builder.setOnCancelListener(this); - return builder.create(); - } - return super.onCreateDialog(id); - } - - - @Override - public void onClick(DialogInterface dialog, final int which) { - new Thread(new Runnable() { - - @Override - public void run() { - // TODO Auto-generated method stub - File file = new File(mLogFilename); - if (which == Dialog.BUTTON_POSITIVE) { - try { - HttpClient client = new HttpClient(); - PostMethod post = new PostMethod(CRASHLOG_SUBMIT_URL); - Part[] parts = {new FilePart("crashfile", file)}; - post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams())); - client.executeMethod(post); - post.releaseConnection(); - } catch (Exception e) { - e.printStackTrace(); - } - } - file.delete(); - finish(); - } - }).start(); - } - - - @Override - public void onCancel(DialogInterface dialog) { - new File(mLogFilename).delete(); - finish(); - } - -} diff --git a/src/eu/alefzero/owncloud/DisplayUtils.java b/src/eu/alefzero/owncloud/DisplayUtils.java deleted file mode 100644 index 3e9f778e..00000000 --- a/src/eu/alefzero/owncloud/DisplayUtils.java +++ /dev/null @@ -1,117 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud; - -import java.util.Date; -import java.util.HashMap; - -/** - * A helper class for some string operations. - * - * @author Bartek Przybylski - * - */ -public class DisplayUtils { - - private static final String[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; - - private static HashMap mimeType2HUmanReadable; - static { - mimeType2HUmanReadable = new HashMap(); - // images - mimeType2HUmanReadable.put("image/jpeg", "JPEG image"); - mimeType2HUmanReadable.put("image/jpg", "JPEG image"); - mimeType2HUmanReadable.put("image/png", "PNG image"); - mimeType2HUmanReadable.put("image/bmp", "Bitmap image"); - mimeType2HUmanReadable.put("image/gif", "GIF image"); - mimeType2HUmanReadable.put("image/svg+xml", "JPEG image"); - mimeType2HUmanReadable.put("image/tiff", "TIFF image"); - // music - mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file"); - mimeType2HUmanReadable.put("application/ogg", "OGG music file"); - - } - - /** - * Converts the file size in bytes to human readable output. - * - * @param bytes Input file size - * @return Like something readable like "12 MB" - */ - public static String bytesToHumanReadable(long bytes) { - double result = bytes; - int attachedsuff = 0; - while (result > 1024 && attachedsuff < suffixes.length) { - result /= 1024.; - attachedsuff++; - } - result = ((int) (result * 100)) / 100.; - return result + " " + suffixes[attachedsuff]; - } - - /** - * Removes special HTML entities from a string - * - * @param s Input string - * @return A cleaned version of the string - */ - public static String HtmlDecode(String s) { - /* - * TODO: Perhaps we should use something more proven like: - * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29 - */ - - String ret = ""; - for (int i = 0; i < s.length(); ++i) { - if (s.charAt(i) == '%') { - ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16); - i += 2; - } else { - ret += s.charAt(i); - } - } - return ret; - } - - /** - * Converts MIME types like "image/jpg" to more end user friendly output - * like "JPG image". - * - * @param mimetype MIME type to convert - * @return A human friendly version of the MIME type - */ - public static String convertMIMEtoPrettyPrint(String mimetype) { - if (mimeType2HUmanReadable.containsKey(mimetype)) { - return mimeType2HUmanReadable.get(mimetype); - } - if (mimetype.split("/").length >= 2) - return mimetype.split("/")[1].toUpperCase() + " file"; - return "Unknown type"; - } - - /** - * Converts Unix time to human readable format - * @param miliseconds that have passed since 01/01/1970 - * @return The human readable time for the users locale - */ - public static String unixTimeToHumanReadable(long milliseconds) { - Date date = new Date(milliseconds); - return date.toLocaleString(); - } -} diff --git a/src/eu/alefzero/owncloud/OwnCloudSession.java b/src/eu/alefzero/owncloud/OwnCloudSession.java deleted file mode 100644 index 0a090d69..00000000 --- a/src/eu/alefzero/owncloud/OwnCloudSession.java +++ /dev/null @@ -1,56 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud; - -/** - * Represents a session to an ownCloud instance - * - * @author Bartek Przybylski - * - */ -public class OwnCloudSession { - private String mSessionName; - private String mSessionUrl; - private int mEntryId; - - public OwnCloudSession(String name, String url, int entryId) { - mSessionName = name; - mSessionUrl = url; - mEntryId = entryId; - } - - public void setName(String name) { - mSessionName = name; - } - - public String getName() { - return mSessionName; - } - - public void setUrl(String url) { - mSessionUrl = url; - } - - public String getUrl() { - return mSessionUrl; - } - - public int getEntryId() { - return mEntryId; - } -} diff --git a/src/eu/alefzero/owncloud/Uploader.java b/src/eu/alefzero/owncloud/Uploader.java deleted file mode 100644 index 523db940..00000000 --- a/src/eu/alefzero/owncloud/Uploader.java +++ /dev/null @@ -1,413 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud; - -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 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 eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.datamodel.DataStorageManager; -import eu.alefzero.owncloud.datamodel.FileDataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.services.FileUploader; -import eu.alefzero.webdav.WebdavClient; - -/** - * This can be used to upload things to an ownCloud instance. - * - * @author Bartek Przybylski - * - */ -public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { - private static final String TAG = "ownCloudUploader"; - - private Account mAccount; - private AccountManager mAccountManager; - private Stack mParents; - private ArrayList mStreamsToUpload; - private boolean mCreateDir; - private String mUploadPath; - private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE }; - private DataStorageManager mStorageManager; - private OCFile mFile; - - private final static int DIALOG_NO_ACCOUNT = 0; - private final static int DIALOG_WAITING = 1; - private final static int DIALOG_NO_STREAM = 2; - private final static int DIALOG_MULTIPLE_ACCOUNT = 3; - private final static int DIALOG_GET_DIRNAME = 4; - - private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - mParents = new Stack(); - mParents.add(""); - if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { - prepareStreamsToUpload(); - mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - if (accounts.length == 0) { - Log.i(TAG, "No ownCloud account is available"); - showDialog(DIALOG_NO_ACCOUNT); - } else if (accounts.length > 1) { - Log.i(TAG, "More then one ownCloud is available"); - showDialog(DIALOG_MULTIPLE_ACCOUNT); - } else { - mAccount = accounts[0]; - setContentView(R.layout.uploader_layout); - 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(R.string.uploader_wrn_no_account_text); - builder.setCancelable(false); - builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { - 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() { - 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() { - 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() { - public void onCancel(DialogInterface dialog) { - dialog.cancel(); - 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; - } - - 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(); - } - } - - public void onItemClick(AdapterView parent, View view, int position, long id) { - // click on folder in the list - Log.d(TAG, "on item click"); - Vector tmpfiles = mStorageManager.getDirectoryContent(mFile); - if (tmpfiles == null) return; - // filter on dirtype - Vector files = new Vector(); - for (OCFile f : tmpfiles) - if (f.isDirectory()) - files.add(f); - if (files.size() < position) { - throw new IndexOutOfBoundsException("Incorrect item selected"); - } - mParents.push(files.get(position).getFileName()); - populateDirectoryList(); - } - - public void onClick(View v) { - // click on button - switch (v.getId()) { - case R.id.uploader_choose_folder: - mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix - for (String p : mParents) - mUploadPath += p + OCFile.PATH_SEPARATOR; - Log.d(TAG, "Uploading file to dir " + mUploadPath); - - uploadFiles(); - - break; - case android.R.id.button1: // dynamic action for create aditional dir - showDialog(DIALOG_GET_DIRNAME); - break; - default: - throw new IllegalArgumentException("Wrong element clicked"); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); - if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { - dismissDialog(DIALOG_NO_ACCOUNT); - if (resultCode == RESULT_CANCELED) { - finish(); - } - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); - if (accounts.length == 0) { - showDialog(DIALOG_NO_ACCOUNT); - } else { - // there is no need for checking for is there more then one - // account at this point - // since account setup can set only one account at time - mAccount = accounts[0]; - populateDirectoryList(); - } - } - } - - private void populateDirectoryList() { - setContentView(R.layout.uploader_layout); - - String full_path = ""; - for (String a : mParents) - full_path += a + "/"; - - Log.d(TAG, "Populating view with content of : " + full_path); - - mFile = mStorageManager.getFileByPath(full_path); - if (mFile != null) { - Vector files = mStorageManager.getDirectoryContent(mFile); - if (files != null) { - List> data = new LinkedList>(); - for (OCFile f : files) { - HashMap h = new HashMap(); - if (f.isDirectory()) { - h.put("dirname", f.getFileName()); - data.add(h); - } - } - SimpleAdapter sa = new SimpleAdapter(this, - data, - R.layout.uploader_list_item_layout, - new String[] {"dirname"}, - new int[] {R.id.textView1}); - setListAdapter(sa); - Button btn = (Button) findViewById(R.id.uploader_choose_folder); - btn.setOnClickListener(this); - getListView().setOnItemClickListener(this); - } - } - /* - mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, null, ProviderTableMeta.FILE_NAME - + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", new String[] { "/", mAccount.name }, null); - - if (mCursor.moveToFirst()) { - mCursor = managedQuery( - ProviderMeta.ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_CONTENT_TYPE + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " - + ProviderTableMeta.FILE_PARENT + "=?", - new String[] { "DIR", mAccount.name, - mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)) }, null); - - ListView lv = getListView(); - lv.setOnItemClickListener(this); - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, mCursor, - new String[] { ProviderTableMeta.FILE_NAME }, new int[] { R.id.textView1 }); - setListAdapter(sca); - Button btn = (Button) findViewById(R.id.uploader_choose_folder); - btn.setOnClickListener(this); - /* - * disable this until new server interaction service wont be created - * // insert create new directory for multiple items uploading if - * (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - * Button createDirBtn = new Button(this); - * createDirBtn.setId(android.R.id.button1); - * createDirBtn.setText(R.string.uploader_btn_create_dir_text); - * createDirBtn.setOnClickListener(this); ((LinearLayout) - * findViewById(R.id.linearLayout1)).addView( createDirBtn, - * LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); } - * - }*/ - } - - private void prepareStreamsToUpload() { - if (getIntent().getAction().equals(Intent.ACTION_SEND)) { - mStreamsToUpload = new ArrayList(); - mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); - } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); - } else { - // unknow action inserted - throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction()); - } - } - - public void uploadFiles() { - WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); - wdc.allowSelfsignedCertificates(); - - // create last directory in path if nessesary - 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(); - } - -} diff --git a/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java b/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java deleted file mode 100644 index be0b8e00..00000000 --- a/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java +++ /dev/null @@ -1,280 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.authenticator; - -import eu.alefzero.owncloud.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 eu.alefzero.owncloud.authenticator.KEY_OC_BASE_URL} and - * {@link eu.alefzero.owncloud.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 eu.alefzero.owncloud.utils.OwnCloudVersion} - */ - public static final String KEY_OC_VERSION = "oc_version"; - /** - * Base url should point to owncloud installation without trailing / ie: - * http://server/path or https://owncloud.server - */ - public static final String KEY_OC_BASE_URL = "oc_base_url"; - - private static final String TAG = "AccountAuthenticator"; - private Context mContext; - - public AccountAuthenticator(Context context) { - super(context); - mContext = context; - } - - /** - * {@inheritDoc} - */ - @Override - public Bundle addAccount(AccountAuthenticatorResponse response, - String accountType, String authTokenType, - String[] requiredFeatures, Bundle options) - throws NetworkErrorException { - Log.i(TAG, "Adding account with type " + accountType - + " and auth token " + authTokenType); - try { - validateAccountType(accountType); - } catch (AuthenticatorException e) { - Log.e(TAG, "Failed to validate account type " + accountType + ": " - + e.getMessage()); - e.printStackTrace(); - return e.getFailureBundle(); - } - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - - setIntentFlags(intent); - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - /** - * {@inheritDoc} - */ - @Override - public Bundle confirmCredentials(AccountAuthenticatorResponse response, - Account account, Bundle options) throws NetworkErrorException { - try { - validateAccountType(account.type); - } catch (AuthenticatorException e) { - Log.e(TAG, "Failed to validate account type " + account.type + ": " - + e.getMessage()); - e.printStackTrace(); - return e.getFailureBundle(); - } - Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_ACCOUNT, account); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - - setIntentFlags(intent); - - Bundle resultBundle = new Bundle(); - resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); - return resultBundle; - } - - @Override - public Bundle editProperties(AccountAuthenticatorResponse response, - String accountType) { - return null; - } - - @Override - public Bundle getAuthToken(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle options) - throws NetworkErrorException { - try { - validateAccountType(account.type); - validateAuthTokenType(authTokenType); - } catch (AuthenticatorException e) { - Log.e(TAG, "Failed to validate account type " + account.type + ": " - + e.getMessage()); - e.printStackTrace(); - return e.getFailureBundle(); - } - final AccountManager am = AccountManager.get(mContext); - final String password = am.getPassword(account); - if (password != null) { - final Bundle result = new Bundle(); - result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); - result.putString(AccountManager.KEY_AUTHTOKEN, password); - return result; - } - - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); - - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - @Override - public String getAuthTokenLabel(String authTokenType) { - return null; - } - - @Override - public Bundle hasFeatures(AccountAuthenticatorResponse response, - Account account, String[] features) throws NetworkErrorException { - final Bundle result = new Bundle(); - result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); - return result; - } - - @Override - public Bundle updateCredentials(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle options) - throws NetworkErrorException { - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); - intent.putExtra(KEY_ACCOUNT, account); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - setIntentFlags(intent); - - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - @Override - public Bundle getAccountRemovalAllowed( - AccountAuthenticatorResponse response, Account account) - throws NetworkErrorException { - return super.getAccountRemovalAllowed(response, account); - } - - private void setIntentFlags(Intent intent) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.addFlags(Intent.FLAG_FROM_BACKGROUND); - } - - private void validateAccountType(String type) - throws UnsupportedAccountTypeException { - if (!type.equals(ACCOUNT_TYPE)) { - throw new UnsupportedAccountTypeException(); - } - } - - private void validateAuthTokenType(String authTokenType) - throws UnsupportedAuthTokenTypeException { - if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { - throw new UnsupportedAuthTokenTypeException(); - } - } - - public static class AuthenticatorException extends Exception { - private static final long serialVersionUID = 1L; - private Bundle mFailureBundle; - - public AuthenticatorException(int code, String errorMsg) { - mFailureBundle = new Bundle(); - mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code); - mFailureBundle - .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg); - } - - public Bundle getFailureBundle() { - return mFailureBundle; - } - } - - public static class UnsupportedAccountTypeException extends - AuthenticatorException { - private static final long serialVersionUID = 1L; - - public UnsupportedAccountTypeException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, - "Unsupported account type"); - } - } - - public static class UnsupportedAuthTokenTypeException extends - AuthenticatorException { - private static final long serialVersionUID = 1L; - - public UnsupportedAuthTokenTypeException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, - "Unsupported auth token type"); - } - } - - public static class UnsupportedFeaturesException extends - AuthenticatorException { - public static final long serialVersionUID = 1L; - - public UnsupportedFeaturesException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, - "Unsupported features"); - } - } - - public static class AccessDeniedException extends AuthenticatorException { - public AccessDeniedException(int code, String errorMsg) { - super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied"); - } - - private static final long serialVersionUID = 1L; - - } -} diff --git a/src/eu/alefzero/owncloud/authenticator/AccountAuthenticatorService.java b/src/eu/alefzero/owncloud/authenticator/AccountAuthenticatorService.java deleted file mode 100644 index 69e88476..00000000 --- a/src/eu/alefzero/owncloud/authenticator/AccountAuthenticatorService.java +++ /dev/null @@ -1,41 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.authenticator; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class AccountAuthenticatorService extends Service { - - private AccountAuthenticator mAuthenticator; - static final public String ACCOUNT_TYPE = "owncloud"; - - @Override - public void onCreate() { - super.onCreate(); - mAuthenticator = new AccountAuthenticator(this); - } - - @Override - public IBinder onBind(Intent intent) { - return mAuthenticator.getIBinder(); - } - -} diff --git a/src/eu/alefzero/owncloud/authenticator/AuthenticationRunnable.java b/src/eu/alefzero/owncloud/authenticator/AuthenticationRunnable.java deleted file mode 100644 index 691c93e6..00000000 --- a/src/eu/alefzero/owncloud/authenticator/AuthenticationRunnable.java +++ /dev/null @@ -1,81 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.authenticator; - -import java.net.URL; - -import org.apache.commons.httpclient.HttpStatus; - -import eu.alefzero.webdav.WebdavClient; - -import android.net.Uri; -import android.os.Handler; - -public class AuthenticationRunnable implements Runnable { - - private OnAuthenticationResultListener mListener; - private Handler mHandler; - private URL mUrl; - private String mUsername; - private String mPassword; - - public AuthenticationRunnable(URL url, String username, String password) { - mListener = null; - mUrl = url; - mUsername = username; - mPassword = password; - } - - public void setOnAuthenticationResultListener( - OnAuthenticationResultListener listener, Handler handler) { - mListener = listener; - mHandler = handler; - } - - @Override - public void run() { - Uri uri; - uri = Uri.parse(mUrl.toString()); - int login_result = WebdavClient.tryToLogin(uri, mUsername, mPassword); - switch (login_result) { - case HttpStatus.SC_OK: - postResult(true, uri.toString()); - break; - case HttpStatus.SC_UNAUTHORIZED: - postResult(false, "Invalid login or/and password"); - break; - case HttpStatus.SC_NOT_FOUND: - postResult(false, "Wrong path given"); - break; - default: - postResult(false, "Internal server error, code: " + login_result); - } - } - - private void postResult(final boolean success, final String message) { - if (mHandler != null && mListener != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onAuthenticationResult(success, message); - } - }); - } - } -} diff --git a/src/eu/alefzero/owncloud/authenticator/ConnectionCheckerRunnable.java b/src/eu/alefzero/owncloud/authenticator/ConnectionCheckerRunnable.java deleted file mode 100644 index 119b2422..00000000 --- a/src/eu/alefzero/owncloud/authenticator/ConnectionCheckerRunnable.java +++ /dev/null @@ -1,169 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.authenticator; - -import java.net.ConnectException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; - -import javax.net.ssl.SSLHandshakeException; - -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.GetMethod; -import org.json.JSONException; -import org.json.JSONObject; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.authenticator.OnConnectCheckListener.ResultType; -import eu.alefzero.owncloud.utils.OwnCloudVersion; -import eu.alefzero.webdav.WebdavClient; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Uri; -import android.os.Handler; -import android.util.Log; - -public class ConnectionCheckerRunnable implements Runnable { - - /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs. */ - public static final int TRY_CONNECTION_TIMEOUT = 5000; - - private static final String TAG = "ConnectionCheckerRunnable"; - private OnConnectCheckListener mListener; - private String mUrl; - private Handler mHandler; - private ResultType mLatestResult; - private Context mContext; - private OwnCloudVersion mOCVersion; - - public void setListener(OnConnectCheckListener listener, Handler handler) { - mListener = listener; - mHandler = handler; - } - - public ConnectionCheckerRunnable(String url, Context context) { - mListener = null; - mHandler = null; - mUrl = url; - mContext = context; - mOCVersion = null; - } - - @Override - public void run() { - - if (!isOnline()) { - postResult(ResultType.NO_NETWORK_CONNECTION); - return; - } - if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) { - mLatestResult = (mUrl.startsWith("https://"))? ResultType.OK_SSL : ResultType.OK_NO_SSL; - tryConnection(Uri.parse(mUrl + AccountUtils.STATUS_PATH)); - postResult(mLatestResult); - } else { - Uri uri = Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH); - if (tryConnection(uri)) { - postResult(ResultType.OK_SSL); - return; - } - Log.d(TAG, - "establishing secure connection failed, trying non secure connection"); - uri = Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH); - - if (tryConnection(uri)) { - postResult(ResultType.OK_NO_SSL); - return; - } - postResult(mLatestResult); - } - } - - public OwnCloudVersion getDiscoveredVersion() { - return mOCVersion; - } - - private boolean tryConnection(Uri uri) { - WebdavClient wc = new WebdavClient(); - wc.allowSelfsignedCertificates(); - GetMethod get = new GetMethod(uri.toString()); - boolean retval = false; - try { - int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT); - switch (status) { - case HttpStatus.SC_OK: { - String response = get.getResponseBodyAsString(); - JSONObject json = new JSONObject(response); - if (!json.getBoolean("installed")) { - mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; - break; - } - mOCVersion = new OwnCloudVersion(json.getString("version")); - if (!mOCVersion.isVersionValid()) - break; - retval = true; - break; - } - case HttpStatus.SC_NOT_FOUND: - mLatestResult = ResultType.FILE_NOT_FOUND; - break; - case HttpStatus.SC_INTERNAL_SERVER_ERROR: - mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; - break; - default: - mLatestResult = ResultType.UNKNOWN_ERROR; - Log.e(TAG, "Not handled status received from server: " + status); - } - - } catch (Exception e) { - if (e instanceof UnknownHostException - || e instanceof ConnectException - || e instanceof SocketTimeoutException) { - mLatestResult = ResultType.HOST_NOT_AVAILABLE; - } else if (e instanceof JSONException) { - mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; - } else if (e instanceof SSLHandshakeException) { - mLatestResult = ResultType.SSL_INIT_ERROR; - } else { - mLatestResult = ResultType.UNKNOWN_ERROR; - } - e.printStackTrace(); - } - - return retval; - } - - private boolean isOnline() { - ConnectivityManager cm = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); - return cm != null && cm.getActiveNetworkInfo() != null - && cm.getActiveNetworkInfo().isConnectedOrConnecting(); - } - - private void postResult(final ResultType result) { - if (mHandler != null && mListener != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onConnectionCheckResult(result); - } - }); - } - } - -} diff --git a/src/eu/alefzero/owncloud/authenticator/EasySSLSocketFactory.java b/src/eu/alefzero/owncloud/authenticator/EasySSLSocketFactory.java deleted file mode 100644 index f1de8f5f..00000000 --- a/src/eu/alefzero/owncloud/authenticator/EasySSLSocketFactory.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * $HeadURL$ - * $Revision$ - * $Date$ - * - * ==================================================================== - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package eu.alefzero.owncloud.authenticator; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.HttpClientError; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; - -import android.util.Log; - -/** - *

- * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s that - * accept self-signed certificates. - *

- *

- * This socket factory SHOULD NOT be used for productive systems due to security - * reasons, unless it is a concious decision and you are perfectly aware of - * security implications of accepting self-signed certificates - *

- * - *

- * Example of using custom protocol socket factory for a specific host: - * - *

- * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(),
- *         443);
- * 
- * URI uri = new URI("https://localhost/", true);
- * // use relative url only
- * GetMethod httpget = new GetMethod(uri.getPathQuery());
- * HostConfiguration hc = new HostConfiguration();
- * hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
- * HttpClient client = new HttpClient();
- * client.executeMethod(hc, httpget);
- * 
- * - *

- *

- * Example of using custom protocol socket factory per default instead of the - * standard one: - * - *

- * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(),
- *         443);
- * Protocol.registerProtocol("https", easyhttps);
- * 
- * HttpClient client = new HttpClient();
- * GetMethod httpget = new GetMethod("https://localhost/");
- * client.executeMethod(httpget);
- * 
- * - *

- * - * @author Oleg Kalnichevski - * - *

- * DISCLAIMER: HttpClient developers DO NOT actively support this - * component. The component is provided as a reference material, which - * may be inappropriate for use without additional customization. - *

- */ - -public class EasySSLSocketFactory implements ProtocolSocketFactory { - - private static final String TAG = "EasySSLSocketFactory"; - private SSLContext sslcontext = null; - - /** - * Constructor for EasySSLProtocolSocketFactory. - */ - public EasySSLSocketFactory() { - super(); - } - - private static SSLContext createEasySSLContext() { - try { - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, new TrustManager[] { new EasyX509TrustManager( - null) }, null); - return context; - } catch (Exception er) { - Log.e(TAG, er.getMessage() + ""); - throw new HttpClientError(er.toString()); - } - } - - private SSLContext getSSLContext() { - if (this.sslcontext == null) { - this.sslcontext = createEasySSLContext(); - } - return this.sslcontext; - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) - */ - public Socket createSocket(String host, int port, InetAddress clientHost, - int clientPort) throws IOException, UnknownHostException { - - return getSSLContext().getSocketFactory().createSocket(host, port, - clientHost, clientPort); - } - - /** - * Attempts to get a new socket connection to the given host within the - * given time limit. - *

- * To circumvent the limitations of older JREs that do not support connect - * timeout a controller thread is executed. The controller thread attempts - * to create a new socket within the given limit of time. If socket - * constructor does not return until the timeout expires, the controller - * terminates and throws an {@link ConnectTimeoutException} - *

- * - * @param host the host name/IP - * @param port the port on the host - * @param clientHost the local host name/IP to bind the socket to - * @param clientPort the port on the local machine - * @param params {@link HttpConnectionParams Http connection parameters} - * - * @return Socket a new socket - * - * @throws IOException if an I/O error occurs while creating the socket - * @throws UnknownHostException if the IP address of the host cannot be - * determined - */ - public Socket createSocket(final String host, final int port, - final InetAddress localAddress, final int localPort, - final HttpConnectionParams params) throws IOException, - UnknownHostException, ConnectTimeoutException { - if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); - } - int timeout = params.getConnectionTimeout(); - SocketFactory socketfactory = getSSLContext().getSocketFactory(); - if (timeout == 0) { - Socket socket = socketfactory.createSocket(host, port, localAddress, - localPort); - socket.setSoTimeout(params.getSoTimeout()); - return socket; - } else { - Socket socket = socketfactory.createSocket(); - SocketAddress localaddr = new InetSocketAddress(localAddress, - localPort); - SocketAddress remoteaddr = new InetSocketAddress(host, port); - socket.setSoTimeout(params.getSoTimeout()); - socket.bind(localaddr); - socket.connect(remoteaddr, timeout); - return socket; - } - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) - */ - public Socket createSocket(String host, int port) throws IOException, - UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(host, port); - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) - */ - public Socket createSocket(Socket socket, String host, int port, - boolean autoClose) throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(socket, host, - port, autoClose); - } - - public boolean equals(Object obj) { - return ((obj != null) && obj.getClass().equals( - EasySSLSocketFactory.class)); - } - - public int hashCode() { - return EasySSLSocketFactory.class.hashCode(); - } - -} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/authenticator/EasyX509TrustManager.java b/src/eu/alefzero/owncloud/authenticator/EasyX509TrustManager.java deleted file mode 100644 index bdd659d7..00000000 --- a/src/eu/alefzero/owncloud/authenticator/EasyX509TrustManager.java +++ /dev/null @@ -1,88 +0,0 @@ -package eu.alefzero.owncloud.authenticator; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -/** - * @author olamy - * @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse - * $ - * @since 1.2.3 - */ -public class EasyX509TrustManager implements X509TrustManager { - - private X509TrustManager standardTrustManager = null; - - /** - * Constructor for EasyX509TrustManager. - */ - public EasyX509TrustManager(KeyStore keystore) - throws NoSuchAlgorithmException, KeyStoreException { - super(); - TrustManagerFactory factory = TrustManagerFactory - .getInstance(TrustManagerFactory.getDefaultAlgorithm()); - factory.init(keystore); - TrustManager[] trustmanagers = factory.getTrustManagers(); - if (trustmanagers.length == 0) { - throw new NoSuchAlgorithmException("no trust manager found"); - } - this.standardTrustManager = (X509TrustManager) trustmanagers[0]; - } - - /** - * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[], - * String authType) - */ - public void checkClientTrusted(X509Certificate[] certificates, - String authType) throws CertificateException { - standardTrustManager.checkClientTrusted(certificates, authType); - } - - /** - * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], - * String authType) - */ - public void checkServerTrusted(X509Certificate[] certificates, - String authType) throws CertificateException { - if ((certificates != null) && (certificates.length == 1)) { - certificates[0].checkValidity(); - } else { - // standardTrustManager.checkServerTrusted( certificates, authType - // ); - } - } - - /** - * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() - */ - public X509Certificate[] getAcceptedIssuers() { - return this.standardTrustManager.getAcceptedIssuers(); - } - -} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/authenticator/OnAuthenticationResultListener.java b/src/eu/alefzero/owncloud/authenticator/OnAuthenticationResultListener.java deleted file mode 100644 index a8764eef..00000000 --- a/src/eu/alefzero/owncloud/authenticator/OnAuthenticationResultListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package eu.alefzero.owncloud.authenticator; - -public interface OnAuthenticationResultListener { - - public void onAuthenticationResult(boolean success, String message); - -} diff --git a/src/eu/alefzero/owncloud/authenticator/OnConnectCheckListener.java b/src/eu/alefzero/owncloud/authenticator/OnConnectCheckListener.java deleted file mode 100644 index f7da0da0..00000000 --- a/src/eu/alefzero/owncloud/authenticator/OnConnectCheckListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.alefzero.owncloud.authenticator; - -public interface OnConnectCheckListener { - - enum ResultType { - OK_SSL, OK_NO_SSL, SSL_INIT_ERROR, HOST_NOT_AVAILABLE, TIMEOUT, NO_NETWORK_CONNECTION, INORRECT_ADDRESS, INSTANCE_NOT_CONFIGURED, FILE_NOT_FOUND, UNKNOWN_ERROR - } - - public void onConnectionCheckResult(ResultType type); - -} diff --git a/src/eu/alefzero/owncloud/datamodel/DataStorageManager.java b/src/eu/alefzero/owncloud/datamodel/DataStorageManager.java deleted file mode 100644 index 9f1d89bd..00000000 --- a/src/eu/alefzero/owncloud/datamodel/DataStorageManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.datamodel; - -import java.util.List; -import java.util.Vector; - -public interface DataStorageManager { - - public OCFile getFileByPath(String path); - - public OCFile getFileById(long id); - - public boolean fileExists(String path); - - public boolean fileExists(long id); - - public boolean saveFile(OCFile file); - - public void saveFiles(List files); - - public Vector getDirectoryContent(OCFile f); - - public void removeFile(OCFile file); -} diff --git a/src/eu/alefzero/owncloud/datamodel/FileDataStorageManager.java b/src/eu/alefzero/owncloud/datamodel/FileDataStorageManager.java deleted file mode 100644 index f0d0db25..00000000 --- a/src/eu/alefzero/owncloud/datamodel/FileDataStorageManager.java +++ /dev/null @@ -1,421 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.datamodel; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; - -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.owncloud.files.services.FileDownloader; -import android.accounts.Account; -import android.content.ContentProviderClient; -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.OperationApplicationException; -import android.database.Cursor; -import android.net.Uri; -import android.os.Environment; -import android.os.RemoteException; -import android.util.Log; - -public class FileDataStorageManager implements DataStorageManager { - - private ContentResolver mContentResolver; - private ContentProviderClient mContentProvider; - private Account mAccount; - - private static String TAG = "FileDataStorageManager"; - - public FileDataStorageManager(Account account, ContentResolver cr) { - mContentProvider = null; - mContentResolver = cr; - mAccount = account; - } - - public FileDataStorageManager(Account account, ContentProviderClient cp) { - mContentProvider = cp; - mContentResolver = null; - mAccount = account; - } - - @Override - public OCFile getFileByPath(String path) { - Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path); - OCFile file = null; - if (c.moveToFirst()) { - file = createFileInstance(c); - } - c.close(); - return file; - } - - @Override - public OCFile getFileById(long id) { - Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id)); - OCFile file = null; - if (c.moveToFirst()) { - file = createFileInstance(c); - } - c.close(); - return file; - } - - @Override - public boolean fileExists(long id) { - return fileExists(ProviderTableMeta._ID, String.valueOf(id)); - } - - @Override - public boolean fileExists(String path) { - return fileExists(ProviderTableMeta.FILE_PATH, path); - } - - @Override - public boolean saveFile(OCFile file) { - boolean overriden = false; - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp()); - cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp()); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); - cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); - cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); - if (file.getParentId() != 0) - cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); - cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); - if (!file.isDirectory()) - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); - cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); - cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate()); - cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); - - if (fileExists(file.getRemotePath())) { - OCFile oldFile = getFileByPath(file.getRemotePath()); - if (file.getStoragePath() == null && oldFile.getStoragePath() != null) - file.setStoragePath(oldFile.getStoragePath()); - if (!file.isDirectory()); - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); - file.setFileId(oldFile.getFileId()); - - overriden = true; - if (getContentResolver() != null) { - getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, - ProviderTableMeta._ID + "=?", - new String[] { String.valueOf(file.getFileId()) }); - } else { - try { - getContentProvider().update(ProviderTableMeta.CONTENT_URI, - cv, ProviderTableMeta._ID + "=?", - new String[] { String.valueOf(file.getFileId()) }); - } catch (RemoteException e) { - Log.e(TAG, - "Fail to insert insert file to database " - + e.getMessage()); - } - } - } else { - Uri result_uri = null; - if (getContentResolver() != null) { - result_uri = getContentResolver().insert( - ProviderTableMeta.CONTENT_URI_FILE, cv); - } else { - try { - result_uri = getContentProvider().insert( - ProviderTableMeta.CONTENT_URI_FILE, cv); - } catch (RemoteException e) { - Log.e(TAG, - "Fail to insert insert file to database " - + e.getMessage()); - } - } - if (result_uri != null) { - long new_id = Long.parseLong(result_uri.getPathSegments() - .get(1)); - file.setFileId(new_id); - } - } - - if (file.isDirectory() && file.needsUpdatingWhileSaving()) - for (OCFile f : getDirectoryContent(file)) - saveFile(f); - - return overriden; - } - - - @Override - public void saveFiles(List files) { - - Iterator filesIt = files.iterator(); - ArrayList operations = new ArrayList(files.size()); - OCFile file = null; - - // prepare operations to perform - while (filesIt.hasNext()) { - file = filesIt.next(); - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp()); - cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp()); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); - cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); - cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); - if (file.getParentId() != 0) - cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); - cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); - if (!file.isDirectory()) - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); - cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); - cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate()); - cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); - - if (fileExists(file.getRemotePath())) { - OCFile tmpfile = getFileByPath(file.getRemotePath()); - file.setStoragePath(tmpfile.getStoragePath()); - if (!file.isDirectory()); - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); - file.setFileId(tmpfile.getFileId()); - - operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). - withValues(cv). - withSelection( ProviderTableMeta._ID + "=?", - new String[] { String.valueOf(file.getFileId()) }) - .build()); - - } else { - operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build()); - } - } - - // apply operations in batch - ContentProviderResult[] results = null; - try { - if (getContentResolver() != null) { - results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations); - - } else { - results = getContentProvider().applyBatch(operations); - } - - } catch (OperationApplicationException e) { - Log.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()); - } - - // update new id in file objects for insertions - if (results != null) { - long newId; - for (int i=0; i getDirectoryContent(OCFile f) { - if (f != null && f.isDirectory() && f.getFileId() != -1) { - Vector ret = new Vector(); - - Uri req_uri = Uri.withAppendedPath( - ProviderTableMeta.CONTENT_URI_DIR, - String.valueOf(f.getFileId())); - Cursor c = null; - - if (getContentProvider() != null) { - try { - c = getContentProvider().query(req_uri, null, - ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[] { mAccount.name }, null); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); - return ret; - } - } else { - c = getContentResolver().query(req_uri, null, - ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[] { mAccount.name }, null); - } - - if (c.moveToFirst()) { - do { - OCFile child = createFileInstance(c); - ret.add(child); - } while (c.moveToNext()); - } - - c.close(); - - Collections.sort(ret); - - return ret; - } - return null; - } - - private boolean fileExists(String cmp_key, String value) { - Cursor c; - if (getContentResolver() != null) { - c = getContentResolver() - .query(ProviderTableMeta.CONTENT_URI, - null, - cmp_key + "=? AND " - + ProviderTableMeta.FILE_ACCOUNT_OWNER - + "=?", - new String[] { value, mAccount.name }, null); - } else { - try { - c = getContentProvider().query( - ProviderTableMeta.CONTENT_URI, - null, - cmp_key + "=? AND " - + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[] { value, mAccount.name }, null); - } catch (RemoteException e) { - Log.e(TAG, - "Couldn't determine file existance, assuming non existance: " - + e.getMessage()); - return false; - } - } - boolean retval = c.moveToFirst(); - c.close(); - return retval; - } - - private Cursor getCursorForValue(String key, String value) { - Cursor c = null; - if (getContentResolver() != null) { - c = getContentResolver() - .query(ProviderTableMeta.CONTENT_URI, - null, - key + "=? AND " - + ProviderTableMeta.FILE_ACCOUNT_OWNER - + "=?", - new String[] { value, mAccount.name }, null); - } else { - try { - c = getContentProvider().query( - ProviderTableMeta.CONTENT_URI, - null, - key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER - + "=?", new String[] { value, mAccount.name }, - null); - } catch (RemoteException e) { - Log.e(TAG, "Could not get file details: " + e.getMessage()); - c = null; - } - } - return c; - } - - private OCFile createFileInstance(Cursor c) { - OCFile file = null; - if (c != null) { - file = new OCFile(c.getString(c - .getColumnIndex(ProviderTableMeta.FILE_PATH))); - file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID))); - file.setParentId(c.getLong(c - .getColumnIndex(ProviderTableMeta.FILE_PARENT))); - file.setMimetype(c.getString(c - .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE))); - if (!file.isDirectory()) { - file.setStoragePath(c.getString(c - .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))); - if (file.getStoragePath() == null) { - // try to find existing file and bind it with current account - File f = new File(FileDownloader.getSavePath(mAccount.name) + file.getRemotePath()); - if (f.exists()) - file.setStoragePath(f.getAbsolutePath()); - } - } - file.setFileLength(c.getLong(c - .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH))); - file.setCreationTimestamp(c.getLong(c - .getColumnIndex(ProviderTableMeta.FILE_CREATION))); - file.setModificationTimestamp(c.getLong(c - .getColumnIndex(ProviderTableMeta.FILE_MODIFIED))); - file.setLastSyncDate(c.getLong(c - .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE))); - file.setKeepInSync(c.getInt( - c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); - } - return file; - } - - public void removeFile(OCFile file) { - Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId()); - if (getContentProvider() != null) { - try { - getContentProvider().delete(file_uri, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}); - } catch (RemoteException e) { - e.printStackTrace(); - } - } else { - getContentResolver().delete(file_uri, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}); - } - if (file.isDown()) { - new File(file.getStoragePath()).delete(); - } - } - -} diff --git a/src/eu/alefzero/owncloud/datamodel/OCFile.java b/src/eu/alefzero/owncloud/datamodel/OCFile.java deleted file mode 100644 index 01a1f58f..00000000 --- a/src/eu/alefzero/owncloud/datamodel/OCFile.java +++ /dev/null @@ -1,381 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.datamodel; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; - -import eu.alefzero.owncloud.files.services.FileDownloader; - -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; - -public class OCFile implements Parcelable, Comparable { - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public OCFile createFromParcel(Parcel source) { - return new OCFile(source); - } - - @Override - public OCFile[] newArray(int size) { - return new OCFile[size]; - } - }; - - public static final String PATH_SEPARATOR = "/"; - - private long mId; - private long mParentId; - private long mLength; - private long mCreationTimestamp; - private long mModifiedTimestamp; - private String mRemotePath; - private String mLocalPath; - private String mMimeType; - private boolean mNeedsUpdating; - private long mLastSyncDate; - private boolean mKeepInSync; - - /** - * Create new {@link OCFile} with given path. - * - * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'. - * - * @param path The remote path of the file. - */ - public OCFile(String path) { - resetData(); - mNeedsUpdating = false; - if (path == null || path.length() <= 0 || !path.startsWith(PATH_SEPARATOR)) { - throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path); - } - mRemotePath = path; - } - - /** - * Reconstruct from parcel - * - * @param source The source parcel - */ - private OCFile(Parcel source) { - mId = source.readLong(); - mParentId = source.readLong(); - mLength = source.readLong(); - mCreationTimestamp = source.readLong(); - mModifiedTimestamp = source.readLong(); - mRemotePath = source.readString(); - mLocalPath = source.readString(); - mMimeType = source.readString(); - mNeedsUpdating = source.readInt() == 0; - mKeepInSync = source.readInt() == 1; - mLastSyncDate = source.readLong(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mId); - dest.writeLong(mParentId); - dest.writeLong(mLength); - dest.writeLong(mCreationTimestamp); - dest.writeLong(mModifiedTimestamp); - dest.writeString(mRemotePath); - dest.writeString(mLocalPath); - dest.writeString(mMimeType); - dest.writeInt(mNeedsUpdating ? 1 : 0); - dest.writeInt(mKeepInSync ? 1 : 0); - dest.writeLong(mLastSyncDate); - } - - /** - * Gets the ID of the file - * - * @return the file ID - */ - public long getFileId() { - return mId; - } - - /** - * Returns the remote path of the file on ownCloud - * - * @return The remote path to the file - */ - public String getRemotePath() { - return mRemotePath; - } - - /** - * Can be used to check, whether or not this file exists in the database - * already - * - * @return true, if the file exists in the database - */ - public boolean fileExists() { - return mId != -1; - } - - /** - * Use this to find out if this file is a Directory - * - * @return true if it is a directory - */ - public boolean isDirectory() { - return mMimeType != null && mMimeType.equals("DIR"); - } - - /** - * Use this to check if this file is available locally - * - * @return true if it is - */ - public boolean isDown() { - if (mLocalPath != null && mLocalPath.length() > 0) { - File file = new File(mLocalPath); - return (file.exists()); - } - return false; - } - - /** - * The path, where the file is stored locally - * - * @return The local path to the file - */ - public String getStoragePath() { - return mLocalPath; - } - - /** - * Can be used to set the path where the file is stored - * - * @param storage_path to set - */ - public void setStoragePath(String storage_path) { - mLocalPath = storage_path; - } - - /** - * Get a UNIX timestamp of the file creation time - * - * @return A UNIX timestamp of the time that file was created - */ - public long getCreationTimestamp() { - return mCreationTimestamp; - } - - /** - * Set a UNIX timestamp of the time the file was created - * - * @param creation_timestamp to set - */ - public void setCreationTimestamp(long creation_timestamp) { - mCreationTimestamp = creation_timestamp; - } - - /** - * Get a UNIX timestamp of the file modification time - * - * @return A UNIX timestamp of the modification time - */ - public long getModificationTimestamp() { - return mModifiedTimestamp; - } - - /** - * Set a UNIX timestamp of the time the time the file was modified. - * - * @param modification_timestamp to set - */ - public void setModificationTimestamp(long modification_timestamp) { - mModifiedTimestamp = modification_timestamp; - } - - /** - * Returns the filename and "/" for the root directory - * - * @return The name of the file - */ - public String getFileName() { - File f = new File(getRemotePath()); - return f.getName().length() == 0 ? "/" : f.getName(); - } - - /** - * Can be used to get the Mimetype - * - * @return the Mimetype as a String - */ - public String getMimetype() { - return mMimeType; - } - - /** - * Adds a file to this directory. If this file is not a directory, an - * exception gets thrown. - * - * @param file to add - * @throws IllegalStateException if you try to add a something and this is - * not a directory - */ - public void addFile(OCFile file) throws IllegalStateException { - if (isDirectory()) { - file.mParentId = mId; - mNeedsUpdating = true; - return; - } - throw new IllegalStateException( - "This is not a directory where you can add stuff to!"); - } - - /** - * Used internally. Reset all file properties - */ - private void resetData() { - mId = -1; - mRemotePath = null; - mParentId = 0; - mLocalPath = null; - mMimeType = null; - mLength = 0; - mCreationTimestamp = 0; - mModifiedTimestamp = 0; - mLastSyncDate = 0; - mKeepInSync = false; - mNeedsUpdating = false; - } - - /** - * Sets the ID of the file - * - * @param file_id to set - */ - public void setFileId(long file_id) { - mId = file_id; - } - - /** - * Sets the Mime-Type of the - * - * @param mimetype to set - */ - public void setMimetype(String mimetype) { - mMimeType = mimetype; - } - - /** - * Sets the ID of the parent folder - * - * @param parent_id to set - */ - public void setParentId(long parent_id) { - mParentId = parent_id; - } - - /** - * Sets the file size in bytes - * - * @param file_len to set - */ - public void setFileLength(long file_len) { - mLength = file_len; - } - - /** - * Returns the size of the file in bytes - * - * @return The filesize in bytes - */ - public long getFileLength() { - return mLength; - } - - /** - * Returns the ID of the parent Folder - * - * @return The ID - */ - public long getParentId() { - return mParentId; - } - - /** - * Check, if this file needs updating - * - * @return - */ - public boolean needsUpdatingWhileSaving() { - return mNeedsUpdating; - } - - public long getLastSyncDate() { - return mLastSyncDate; - } - - public void setLastSyncDate(long lastSyncDate) { - mLastSyncDate = lastSyncDate; - } - - public void setKeepInSync(boolean keepInSync) { - mKeepInSync = keepInSync; - } - - public boolean keepInSync() { - return mKeepInSync; - } - - @Override - public int describeContents() { - return this.hashCode(); - } - - @Override - public int compareTo(OCFile another) { - if (isDirectory() && another.isDirectory()) { - return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase()); - } else if (isDirectory()) { - return -1; - } else if (another.isDirectory()) { - return 1; - } - return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase()); - } - - public boolean equals(Object o) { - if(o instanceof OCFile){ - OCFile that = (OCFile) o; - if(that != null){ - return this.mId == that.mId; - } - } - - return false; - } - - @Override - public String toString() { - String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s]"; - asString = String.format(asString, new Long(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, new Long(mParentId), new Boolean(mKeepInSync)); - return asString; - } - -} diff --git a/src/eu/alefzero/owncloud/db/DbHandler.java b/src/eu/alefzero/owncloud/db/DbHandler.java deleted file mode 100644 index 23b8bb6e..00000000 --- a/src/eu/alefzero/owncloud/db/DbHandler.java +++ /dev/null @@ -1,86 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.db; - -import java.util.Vector; - -import eu.alefzero.owncloud.OwnCloudSession; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; - -/** - * Custom database helper for ownCloud - * - * @author Bartek Przybylski - * - */ -public class DbHandler { - private SQLiteDatabase mDB; - private OpenerHepler mHelper; - private final String mDatabaseName = "ownCloud"; - private final String TABLE_SESSIONS = "sessions"; - private final int mDatabaseVersion = 1; - - private final String TABLE_INSTANT_UPLOAD = "instant_upload"; - - public DbHandler(Context context) { - mHelper = new OpenerHepler(context); - mDB = mHelper.getWritableDatabase(); - } - - public void close() { - mDB.close(); - } - - public boolean putFileForLater(String filepath, String account) { - ContentValues cv = new ContentValues(); - cv.put("path", filepath); - cv.put("account", account); - return mDB.insert(TABLE_INSTANT_UPLOAD, null, cv) != -1; - } - - public Cursor getAwaitingFiles() { - return mDB.query(TABLE_INSTANT_UPLOAD, null, null, null, null, null, null); - } - - public void clearFiles() { - mDB.delete(TABLE_INSTANT_UPLOAD, null, null); - } - - private class OpenerHepler extends SQLiteOpenHelper { - public OpenerHepler(Context context) { - super(context, mDatabaseName, null, mDatabaseVersion); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " (" - + " _id INTEGET PRIMARY KEY, " - + " path TEXT," - + " account TEXT);"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } - } -} diff --git a/src/eu/alefzero/owncloud/db/ProviderMeta.java b/src/eu/alefzero/owncloud/db/ProviderMeta.java deleted file mode 100644 index 62c0ace5..00000000 --- a/src/eu/alefzero/owncloud/db/ProviderMeta.java +++ /dev/null @@ -1,67 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.db; - -import android.net.Uri; -import android.provider.BaseColumns; - -/** - * Meta-Class that holds various static field information - * - * @author Bartek Przybylski - * - */ -public class ProviderMeta { - - public static final String AUTHORITY_FILES = "org.owncloud"; - public static final String DB_FILE = "owncloud.db"; - public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 2; - - private ProviderMeta() { - } - - static public class ProviderTableMeta implements BaseColumns { - public static final String DB_NAME = "filelist"; - public static final Uri CONTENT_URI = Uri.parse("content://" - + AUTHORITY_FILES + "/"); - public static final Uri CONTENT_URI_FILE = Uri.parse("content://" - + AUTHORITY_FILES + "/file"); - public static final Uri CONTENT_URI_DIR = Uri.parse("content://" - + AUTHORITY_FILES + "/dir"); - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file"; - public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file"; - - public static final String FILE_PARENT = "parent"; - public static final String FILE_NAME = "filename"; - public static final String FILE_CREATION = "created"; - public static final String FILE_MODIFIED = "modified"; - public static final String FILE_CONTENT_LENGTH = "content_length"; - public static final String FILE_CONTENT_TYPE = "content_type"; - public static final String FILE_STORAGE_PATH = "media_path"; - public static final String FILE_PATH = "path"; - public static final String FILE_ACCOUNT_OWNER = "file_owner"; - public static final String FILE_LAST_SYNC_DATE = "last_sync_date"; - public static final String FILE_KEEP_IN_SYNC = "keep_in_sync"; - - public static final String DEFAULT_SORT_ORDER = FILE_NAME - + " collate nocase asc"; - - } -} diff --git a/src/eu/alefzero/owncloud/extensions/ExtensionsAvailableActivity.java b/src/eu/alefzero/owncloud/extensions/ExtensionsAvailableActivity.java deleted file mode 100644 index 3d2554dd..00000000 --- a/src/eu/alefzero/owncloud/extensions/ExtensionsAvailableActivity.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.alefzero.owncloud.extensions; - -import android.os.Bundle; -import android.support.v4.app.FragmentManager; - -import com.actionbarsherlock.app.SherlockFragmentActivity; - -public class ExtensionsAvailableActivity extends SherlockFragmentActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - FragmentManager fm = getSupportFragmentManager(); - ExtensionsAvailableDialog ead = new ExtensionsAvailableDialog(); - ead.show(fm, "extensions_available_dialog"); - } -} diff --git a/src/eu/alefzero/owncloud/extensions/ExtensionsAvailableDialog.java b/src/eu/alefzero/owncloud/extensions/ExtensionsAvailableDialog.java deleted file mode 100644 index 202acf25..00000000 --- a/src/eu/alefzero/owncloud/extensions/ExtensionsAvailableDialog.java +++ /dev/null @@ -1,50 +0,0 @@ -package eu.alefzero.owncloud.extensions; - -import eu.alefzero.owncloud.R; -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.View.OnClickListener; -import android.widget.Button; - -public class ExtensionsAvailableDialog extends DialogFragment implements - OnClickListener { - - public ExtensionsAvailableDialog() { - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.extensions_available_dialog, - container); - Button btnYes = (Button) view.findViewById(R.id.buttonYes); - Button btnNo = (Button) view.findViewById(R.id.buttonNo); - btnYes.setOnClickListener(this); - btnNo.setOnClickListener(this); - getDialog().setTitle(R.string.extensions_avail_title); - return view; - } - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.buttonYes: { - Intent i = new Intent(getActivity(), ExtensionsListActivity.class); - startActivity(i); - getActivity().finish(); - } - break; - case R.id.buttonNo: - getActivity().finish(); - break; - default: - Log.e("EAD", "Button with unknown id clicked " + v.getId()); - } - } - -} diff --git a/src/eu/alefzero/owncloud/extensions/ExtensionsListActivity.java b/src/eu/alefzero/owncloud/extensions/ExtensionsListActivity.java deleted file mode 100644 index ec7d8bb3..00000000 --- a/src/eu/alefzero/owncloud/extensions/ExtensionsListActivity.java +++ /dev/null @@ -1,133 +0,0 @@ -package eu.alefzero.owncloud.extensions; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Vector; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.methods.GetMethod; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import eu.alefzero.owncloud.utils.OwnCloudVersion; - -import android.R; -import android.app.Activity; -import android.app.ListActivity; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.widget.SimpleAdapter; - -public class ExtensionsListActivity extends ListActivity { - - private static final String packages_url = "http://alefzero.eu/a/packages.php"; - - private Thread mGetterThread; - private final Handler mHandler = new Handler(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mGetterThread = new Thread(new JsonGetter()); - mGetterThread.start(); - } - - public void done(JSONArray a) { - LinkedList> ll = new LinkedList>(); - for (int i = 0; i < a.length(); ++i) { - try { - ExtensionApplicationEntry ela = new ExtensionApplicationEntry( - ((JSONObject) a.get(i))); - HashMap ss = new HashMap(); - ss.put("NAME", ela.getName()); - ss.put("DESC", ela.getDescription()); - ll.add(ss); - } catch (JSONException e) { - e.printStackTrace(); - } - } - setListAdapter(new SimpleAdapter(this, ll, R.layout.simple_list_item_2, - new String[] { "NAME", "DESC" }, new int[] { - android.R.id.text1, android.R.id.text2 })); - - } - - private class JsonGetter implements Runnable { - - @Override - public void run() { - HttpClient hc = new HttpClient(); - GetMethod gm = new GetMethod(packages_url); - final JSONArray ar; - try { - hc.executeMethod(gm); - Log.e("ASD", gm.getResponseBodyAsString() + ""); - ar = new JSONObject(gm.getResponseBodyAsString()) - .getJSONArray("apps"); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - mHandler.post(new Runnable() { - @Override - public void run() { - done(ar); - } - }); - - } - - } - - private class ExtensionApplicationEntry { - private static final String APP_NAME = "name"; - private static final String APP_VERSION = "version"; - private static final String APP_DESC = "description"; - private static final String APP_ICON = "icon"; - private static final String APP_URL = "download"; - private static final String APP_PLAYID = "play_id"; - - private String mName, mDescription, mIcon, mDownload, mPlayId; - private OwnCloudVersion mVersion; - - public ExtensionApplicationEntry(JSONObject appentry) { - try { - mName = appentry.getString(APP_NAME); - mDescription = appentry.getString(APP_DESC); - mIcon = appentry.getString(APP_ICON); - mDownload = appentry.getString(APP_URL); - mPlayId = appentry.getString(APP_PLAYID); - mVersion = new OwnCloudVersion(appentry.getString(APP_VERSION)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public String getName() { - return mName; - } - - public String getDescription() { - return mDescription; - } - - public String getIcon() { - return mIcon; - } - - public String getDownload() { - return mDownload; - } - - public String getPlayId() { - return mPlayId; - } - - public OwnCloudVersion getVersion() { - return mVersion; - } - } -} diff --git a/src/eu/alefzero/owncloud/files/PhotoTakenBroadcastReceiver.java b/src/eu/alefzero/owncloud/files/PhotoTakenBroadcastReceiver.java deleted file mode 100644 index c89a825c..00000000 --- a/src/eu/alefzero/owncloud/files/PhotoTakenBroadcastReceiver.java +++ /dev/null @@ -1,150 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.files; - -import java.io.File; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.DbHandler; -import eu.alefzero.owncloud.files.services.InstantUploadService; -import android.accounts.Account; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.ConnectivityManager; -import android.preference.Preference; -import android.preference.PreferenceManager; -import android.provider.MediaStore.Images.Media; -import android.util.Log; -import android.webkit.MimeTypeMap; - -public class PhotoTakenBroadcastReceiver extends BroadcastReceiver { - - private static String TAG = "PhotoTakenBroadcastReceiver"; - private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE }; - - private static String NEW_PHOTO_ACTION = "com.android.camera.NEW_PICTURE"; - - @Override - public void onReceive(Context context, Intent intent) { - if (!PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_uploading", false)) { - Log.d(TAG, "Instant upload disabled, abording uploading"); - return; - } - if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) { - handleConnectivityAction(context, intent); - } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) { - handleNewPhontoAction(context, intent); - } else { - Log.e(TAG, "Incorrect intent sent: " + intent.getAction()); - } - } - - private void handleNewPhontoAction(Context context, Intent intent) { - Account account = AccountUtils.getCurrentOwnCloudAccount(context); - if (account == null) { - Log.w(TAG, "No owncloud account found for instant upload, abording"); - return; - } - - Cursor c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null); - - if (!c.moveToFirst()) { - Log.e(TAG, "Couldn't resolve given uri!"); - return; - } - - String file_path = c.getString(c.getColumnIndex(Media.DATA)); - String file_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)); - String mime_type = c.getString(c.getColumnIndex(Media.MIME_TYPE)); - long file_size = c.getLong(c.getColumnIndex(Media.SIZE)); - - c.close(); - - if (!isOnline(context)) { - DbHandler db = new DbHandler(context); - db.putFileForLater(file_path, account.name); - db.close(); - return; - } - - Intent upload_intent = new Intent(context, InstantUploadService.class); - upload_intent.putExtra(InstantUploadService.KEY_ACCOUNT, account); - upload_intent.putExtra(InstantUploadService.KEY_FILE_PATH, file_path); - upload_intent.putExtra(InstantUploadService.KEY_DISPLAY_NAME, file_name); - upload_intent.putExtra(InstantUploadService.KEY_FILE_SIZE, file_size); - upload_intent.putExtra(InstantUploadService.KEY_MIME_TYPE, mime_type); - - context.startService(upload_intent); - } - - private void handleConnectivityAction(Context context, Intent intent) { - if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY) || - isOnline(context)) { - DbHandler db = new DbHandler(context); - Cursor c = db.getAwaitingFiles(); - if (c.moveToFirst()) { - do { - String account_name = c.getString(c.getColumnIndex("account")); - String file_path = c.getString(c.getColumnIndex("path")); - File f = new File(file_path); - if (f.exists()) { - Intent upload_intent = new Intent(context, InstantUploadService.class); - Account account = new Account(account_name, AccountAuthenticator.ACCOUNT_TYPE); - - String mimeType = null; - try { - mimeType = MimeTypeMap.getSingleton() - .getMimeTypeFromExtension( - f.getName().substring(f.getName().lastIndexOf('.') + 1)); - - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName()); - } - if (mimeType == null) - mimeType = "application/octet-stream"; - - upload_intent.putExtra(InstantUploadService.KEY_ACCOUNT, account); - upload_intent.putExtra(InstantUploadService.KEY_FILE_PATH, file_path); - upload_intent.putExtra(InstantUploadService.KEY_DISPLAY_NAME, f.getName()); - upload_intent.putExtra(InstantUploadService.KEY_FILE_SIZE, f.length()); - upload_intent.putExtra(InstantUploadService.KEY_MIME_TYPE, mimeType); - - context.startService(upload_intent); - } else { - Log.w(TAG, "Instant upload file " + f.getName() + " dont exist anymore"); - } - } while(c.moveToNext()); - c.close(); - } - db.clearFiles(); - db.close(); - } - - } - - private boolean isOnline(Context context) { - ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected(); - } - -} diff --git a/src/eu/alefzero/owncloud/files/interfaces/OnDatatransferProgressListener.java b/src/eu/alefzero/owncloud/files/interfaces/OnDatatransferProgressListener.java deleted file mode 100644 index 4a897dd7..00000000 --- a/src/eu/alefzero/owncloud/files/interfaces/OnDatatransferProgressListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package eu.alefzero.owncloud.files.interfaces; - -public interface OnDatatransferProgressListener { - void transferProgress(long progressRate); - -} diff --git a/src/eu/alefzero/owncloud/files/services/FileDownloader.java b/src/eu/alefzero/owncloud/files/services/FileDownloader.java deleted file mode 100644 index b0dd2b26..00000000 --- a/src/eu/alefzero/owncloud/files/services/FileDownloader.java +++ /dev/null @@ -1,252 +0,0 @@ -package eu.alefzero.owncloud.files.services; - -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.ContentValues; -import android.content.Intent; -import android.net.Uri; -import android.os.Environment; -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 eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.owncloud.files.interfaces.OnDatatransferProgressListener; -import eu.alefzero.webdav.WebdavClient; - -public class FileDownloader extends Service implements OnDatatransferProgressListener { - public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; - public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; - public static final String EXTRA_ACCOUNT = "ACCOUNT"; - public static final String EXTRA_FILE_PATH = "FILE_PATH"; - public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; - public static final String EXTRA_FILE_SIZE = "FILE_SIZE"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - - private static final String TAG = "FileDownloader"; - - private NotificationManager mNotificationMngr; - private Looper mServiceLooper; - private ServiceHandler mServiceHandler; - private Account mAccount; - private String mFilePath; - private String mRemotePath; - private int mLastPercent; - private long mTotalDownloadSize; - private long mCurrentDownloadSize; - private Notification mNotification; - - /** - * Static map with the files being download and the path to the temporal file were are download - */ - private static Map mDownloadsInProgress = Collections.synchronizedMap(new HashMap()); - - /** - * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading - */ - public static boolean isDownloading(Account account, String remotePath) { - return (mDownloadsInProgress.get(buildRemoteName(account.name, remotePath)) != null); - } - - /** - * Builds a key for mDownloadsInProgress from the accountName and remotePath - */ - private static String buildRemoteName(String accountName, String remotePath) { - return accountName + remotePath; - } - - - private final class ServiceHandler extends Handler { - public ServiceHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - downloadFile(); - stopSelf(msg.arg1); - } - } - - public static final String getSavePath(String accountName) { - File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/owncloud/" + Uri.encode(accountName, "@"); - // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B - } - - public static final String getTemporalPath(String accountName) { - File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/owncloud/tmp/" + Uri.encode(accountName, "@"); - // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B - } - - @Override - public void onCreate() { - super.onCreate(); - mNotificationMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - HandlerThread thread = new HandlerThread("FileDownladerThread", - Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - mServiceLooper = thread.getLooper(); - mServiceHandler = new ServiceHandler(mServiceLooper); - } - - @Override - public IBinder onBind(Intent arg0) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if ( !intent.hasExtra(EXTRA_ACCOUNT) || - !intent.hasExtra(EXTRA_FILE_PATH) || - !intent.hasExtra(EXTRA_REMOTE_PATH) - ) { - Log.e(TAG, "Not enough information provided in intent"); - return START_NOT_STICKY; - } - mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT); - mFilePath = intent.getStringExtra(EXTRA_FILE_PATH); - mRemotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); - mTotalDownloadSize = intent.getLongExtra(EXTRA_FILE_SIZE, -1); - mCurrentDownloadSize = mLastPercent = 0; - - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - mServiceHandler.sendMessage(msg); - - return START_NOT_STICKY; - } - - /** - * Core download method: requests the file to download and stores it. - */ - private void downloadFile() { - boolean downloadResult = false; - - /// prepare client object to send the request to the ownCloud server - AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); - WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); - String username = mAccount.name.split("@")[0]; - String password = null; - try { - password = am.blockingGetAuthToken(mAccount, - AccountAuthenticator.AUTH_TOKEN_TYPE, true); - } catch (Exception e) { - Log.e(TAG, "Access to account credentials failed", e); - sendFinalBroadcast(downloadResult, null); - return; - } - wdc.setCredentials(username, password); - wdc.allowSelfsignedCertificates(); - wdc.setDataTransferProgressListener(this); - - - /// download will be in a temporal file - File tmpFile = new File(getTemporalPath(mAccount.name) + mFilePath); - - /// create status notification to show the download progress - 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, mTotalDownloadSize == -1); - mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, tmpFile.getName())); - mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); - // TODO put something smart in the contentIntent below - mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); - mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification); - - - /// perform the download - tmpFile.getParentFile().mkdirs(); - mDownloadsInProgress.put(buildRemoteName(mAccount.name, mRemotePath), tmpFile.getAbsolutePath()); - File newFile = null; - try { - if (wdc.downloadFile(mRemotePath, tmpFile)) { - newFile = new File(getSavePath(mAccount.name) + mFilePath); - newFile.getParentFile().mkdirs(); - boolean moved = tmpFile.renameTo(newFile); - - if (moved) { - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, newFile.getAbsolutePath()); - getContentResolver().update( - ProviderTableMeta.CONTENT_URI, - cv, - ProviderTableMeta.FILE_NAME + "=? AND " - + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[] { - mFilePath.substring(mFilePath.lastIndexOf('/') + 1), - mAccount.name }); - downloadResult = true; - } - } - } finally { - mDownloadsInProgress.remove(buildRemoteName(mAccount.name, mRemotePath)); - } - - - /// notify result - mNotificationMngr.cancel(R.string.downloader_download_in_progress_ticker); - int tickerId = (downloadResult) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; - int contentId = (downloadResult) ? 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(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); - finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), tmpFile.getName()), finalNotification.contentIntent); - mNotificationMngr.notify(tickerId, finalNotification); - - sendFinalBroadcast(downloadResult, (downloadResult)?newFile.getAbsolutePath():null); - } - - /** - * Callback method to update the progress bar in the status notification. - */ - @Override - public void transferProgress(long progressRate) { - mCurrentDownloadSize += progressRate; - int percent = (int)(100.0*((double)mCurrentDownloadSize)/((double)mTotalDownloadSize)); - if (percent != mLastPercent) { - mNotification.contentView.setProgressBar(R.id.status_progress, 100, (int)(100*mCurrentDownloadSize/mTotalDownloadSize), mTotalDownloadSize == -1); - mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), percent, new File(mFilePath).getName())); - mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification); - } - - mLastPercent = percent; - } - - - /** - * Sends a broadcast in order to the interested activities can update their view - * - * @param downloadResult 'True' if the download was successful - * @param newFilePath Absolute path to the download file - */ - private void sendFinalBroadcast(boolean downloadResult, String newFilePath) { - Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE); - end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult); - end.putExtra(ACCOUNT_NAME, mAccount.name); - end.putExtra(EXTRA_REMOTE_PATH, mRemotePath); - if (downloadResult) { - end.putExtra(EXTRA_FILE_PATH, newFilePath); - } - sendBroadcast(end); - } - -} diff --git a/src/eu/alefzero/owncloud/files/services/FileOperation.java b/src/eu/alefzero/owncloud/files/services/FileOperation.java deleted file mode 100644 index b0e9d4a5..00000000 --- a/src/eu/alefzero/owncloud/files/services/FileOperation.java +++ /dev/null @@ -1,53 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.files.services; - -import java.io.File; - -import android.accounts.Account; -import android.content.Context; -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.webdav.WebdavClient; - -public class FileOperation { - - Context mContext; - - public FileOperation(Context contex){ - this.mContext = contex; - } - - /** - * Deletes a file from ownCloud - locally and remote. - * @param file The file to delete - * @return True on success, otherwise false - */ - public boolean delete(OCFile file){ - - Account account = AccountUtils.getCurrentOwnCloudAccount(mContext); - WebdavClient client = new WebdavClient(account, mContext); - if(client.deleteFile(file.getRemotePath())){ - File localFile = new File(file.getStoragePath()); - return localFile.delete(); - } - - return false; - } - -} diff --git a/src/eu/alefzero/owncloud/files/services/FileUploader.java b/src/eu/alefzero/owncloud/files/services/FileUploader.java deleted file mode 100644 index 3f30f1bf..00000000 --- a/src/eu/alefzero/owncloud/files/services/FileUploader.java +++ /dev/null @@ -1,326 +0,0 @@ -package eu.alefzero.owncloud.files.services; - -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -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.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.webkit.MimeTypeMap; -import android.widget.RemoteViews; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.datamodel.FileDataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.interfaces.OnDatatransferProgressListener; -import eu.alefzero.webdav.WebdavClient; - -public class FileUploader extends Service implements OnDatatransferProgressListener { - - public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH"; - public static final String EXTRA_PARENT_DIR_ID = "PARENT_DIR_ID"; - public static final String EXTRA_UPLOAD_RESULT = "RESULT"; - public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; - public static final String EXTRA_FILE_PATH = "FILE_PATH"; - - public static final String KEY_LOCAL_FILE = "LOCAL_FILE"; - public static final String KEY_REMOTE_FILE = "REMOTE_FILE"; - public static final String KEY_ACCOUNT = "ACCOUNT"; - public static final String KEY_UPLOAD_TYPE = "UPLOAD_TYPE"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - - public static final int UPLOAD_SINGLE_FILE = 0; - public static final int UPLOAD_MULTIPLE_FILES = 1; - - private static final String TAG = "FileUploader"; - - private NotificationManager mNotificationManager; - private Looper mServiceLooper; - private ServiceHandler mServiceHandler; - private Account mAccount; - private String[] mLocalPaths, mRemotePaths; - private int mUploadType; - private Notification mNotification; - private long mTotalDataToSend, mSendData; - private int mCurrentIndexUpload, mPreviousPercent; - private int mSuccessCounter; - - /** - * Static map with the files being download and the path to the temporal file were are download - */ - private static Map mUploadsInProgress = Collections.synchronizedMap(new HashMap()); - - /** - * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading - */ - public static boolean isUploading(Account account, String remotePath) { - return (mUploadsInProgress.get(buildRemoteName(account.name, remotePath)) != null); - } - - /** - * Builds a key for mUplaodsInProgress from the accountName and remotePath - */ - private static String buildRemoteName(String accountName, String remotePath) { - return accountName + remotePath; - } - - - - - @Override - public IBinder onBind(Intent arg0) { - return null; - } - - private final class ServiceHandler extends Handler { - public ServiceHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - uploadFile(); - stopSelf(msg.arg1); - } - } - - @Override - public void onCreate() { - super.onCreate(); - mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - HandlerThread thread = new HandlerThread("FileUploaderThread", - Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - mServiceLooper = thread.getLooper(); - mServiceHandler = new ServiceHandler(mServiceLooper); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (!intent.hasExtra(KEY_ACCOUNT) && !intent.hasExtra(KEY_UPLOAD_TYPE)) { - Log.e(TAG, "Not enough information provided in intent"); - return Service.START_NOT_STICKY; - } - mAccount = intent.getParcelableExtra(KEY_ACCOUNT); - mUploadType = intent.getIntExtra(KEY_UPLOAD_TYPE, -1); - if (mUploadType == -1) { - Log.e(TAG, "Incorrect upload type provided"); - return Service.START_NOT_STICKY; - } - if (mUploadType == UPLOAD_SINGLE_FILE) { - mLocalPaths = new String[] { intent.getStringExtra(KEY_LOCAL_FILE) }; - mRemotePaths = new String[] { intent - .getStringExtra(KEY_REMOTE_FILE) }; - } else { // mUploadType == UPLOAD_MULTIPLE_FILES - mLocalPaths = intent.getStringArrayExtra(KEY_LOCAL_FILE); - mRemotePaths = intent.getStringArrayExtra(KEY_REMOTE_FILE); - } - - if (mLocalPaths.length != mRemotePaths.length) { - Log.e(TAG, "Different number of remote paths and local paths!"); - return Service.START_NOT_STICKY; - } - - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - mServiceHandler.sendMessage(msg); - - return Service.START_NOT_STICKY; - } - - - /** - * Core upload method: sends the file(s) to upload - */ - public void uploadFile() { - FileDataStorageManager storageManager = new FileDataStorageManager(mAccount, getContentResolver()); - - mTotalDataToSend = mSendData = mPreviousPercent = 0; - - /// prepare client object to send the request to the ownCloud server - WebdavClient wc = new WebdavClient(mAccount, getApplicationContext()); - wc.allowSelfsignedCertificates(); - wc.setDataTransferProgressListener(this); - - /// create status notification to show the upload progress - mNotification = new Notification(eu.alefzero.owncloud.R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker), System.currentTimeMillis()); - mNotification.flags |= Notification.FLAG_ONGOING_EVENT; - RemoteViews oldContentView = mNotification.contentView; - mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout); - mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false); - mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); - // dvelasco ; contentIntent MUST be assigned to avoid app crashes in versions previous to Android 4.x ; - // BUT an empty Intent is not a very elegant solution; something smart should happen when a user 'clicks' on an upload in the notification bar - mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); - mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); - - - /// perform the upload - File [] localFiles = new File[mLocalPaths.length]; - for (int i = 0; i < mLocalPaths.length; ++i) { - localFiles[i] = new File(mLocalPaths[i]); - mTotalDataToSend += localFiles[i].length(); - } - Log.d(TAG, "Will upload " + mTotalDataToSend + " bytes, with " + mLocalPaths.length + " files"); - mSuccessCounter = 0; - for (int i = 0; i < mLocalPaths.length; ++i) { - String mimeType = null; - try { - mimeType = MimeTypeMap.getSingleton() - .getMimeTypeFromExtension( - mLocalPaths[i].substring(mLocalPaths[i] - .lastIndexOf('.') + 1)); - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Trying to find out MIME type of a file without extension: " + mLocalPaths[i]); - } - if (mimeType == null) - mimeType = "application/octet-stream"; - mCurrentIndexUpload = i; - long parentDirId = -1; - boolean uploadResult = false; - String availablePath = getAvailableRemotePath(wc, mRemotePaths[i]); - try { - File f = new File(mRemotePaths[i]); - parentDirId = storageManager.getFileByPath(f.getParent().endsWith("/")?f.getParent():f.getParent()+"/").getFileId(); - if(availablePath != null) { - mRemotePaths[i] = availablePath; - mUploadsInProgress.put(buildRemoteName(mAccount.name, mRemotePaths[i]), mLocalPaths[i]); - if (wc.putFile(mLocalPaths[i], mRemotePaths[i], mimeType)) { - OCFile new_file = new OCFile(mRemotePaths[i]); - new_file.setMimetype(mimeType); - new_file.setFileLength(localFiles[i].length()); - new_file.setModificationTimestamp(System.currentTimeMillis()); - new_file.setLastSyncDate(0); - new_file.setStoragePath(mLocalPaths[i]); - new_file.setParentId(parentDirId); - storageManager.saveFile(new_file); - mSuccessCounter++; - uploadResult = true; - } - } - } finally { - mUploadsInProgress.remove(buildRemoteName(mAccount.name, mRemotePaths[i])); - - /// notify upload (or fail) of EACH file to activities interested - Intent end = new Intent(UPLOAD_FINISH_MESSAGE); - end.putExtra(EXTRA_PARENT_DIR_ID, parentDirId); - end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult); - end.putExtra(EXTRA_REMOTE_PATH, mRemotePaths[i]); - end.putExtra(EXTRA_FILE_PATH, mLocalPaths[i]); - end.putExtra(ACCOUNT_NAME, mAccount.name); - sendBroadcast(end); - } - - } - - /// notify final result - if (mSuccessCounter == mLocalPaths.length) { // success - //Notification finalNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_succeeded_ticker), System.currentTimeMillis()); - mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove the ongoing flag - mNotification.flags |= Notification.FLAG_AUTO_CANCEL; - mNotification.contentView = oldContentView; - // TODO put something smart in the contentIntent below - mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); - if (mLocalPaths.length == 1) { - mNotification.setLatestEventInfo( getApplicationContext(), - getString(R.string.uploader_upload_succeeded_ticker), - String.format(getString(R.string.uploader_upload_succeeded_content_single), localFiles[0].getName()), - mNotification.contentIntent); - } else { - mNotification.setLatestEventInfo( getApplicationContext(), - getString(R.string.uploader_upload_succeeded_ticker), - String.format(getString(R.string.uploader_upload_succeeded_content_multiple), mSuccessCounter), - mNotification.contentIntent); - } - mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); // NOT AN ERROR; uploader_upload_in_progress_ticker is the target, not a new notification - - } else { - mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); - Notification finalNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis()); - finalNotification.flags |= Notification.FLAG_AUTO_CANCEL; - // TODO put something smart in the contentIntent below - finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); - if (mLocalPaths.length == 1) { - finalNotification.setLatestEventInfo( getApplicationContext(), - getString(R.string.uploader_upload_failed_ticker), - String.format(getString(R.string.uploader_upload_failed_content_single), localFiles[0].getName()), - finalNotification.contentIntent); - } else { - finalNotification.setLatestEventInfo( getApplicationContext(), - getString(R.string.uploader_upload_failed_ticker), - String.format(getString(R.string.uploader_upload_failed_content_multiple), mSuccessCounter, mLocalPaths.length), - finalNotification.contentIntent); - } - mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification); - } - - } - - /** - * Checks if remotePath does not exist in the server and returns it, or adds a suffix to it in order to avoid the server - * file is overwritten. - * - * @param string - * @return - */ - private String getAvailableRemotePath(WebdavClient wc, String remotePath) { - Boolean check = wc.existsFile(remotePath); - if (check == null) { // null means fail - return null; - } else if (!check) { - return remotePath; - } - - int pos = remotePath.lastIndexOf("."); - String suffix = ""; - String extension = ""; - if (pos >= 0) { - extension = remotePath.substring(pos+1); - remotePath = remotePath.substring(0, pos); - } - int count = 2; - while (check != null && check) { - suffix = " (" + count + ")"; - if (pos >= 0) - check = wc.existsFile(remotePath + suffix + "." + extension); - else - check = wc.existsFile(remotePath + suffix); - count++; - } - if (check == null) { - return null; - } else if (pos >=0) { - return remotePath + suffix + "." + extension; - } else { - return remotePath + suffix; - } - } - - - /** - * Callback method to update the progress bar in the status notification. - */ - @Override - public void transferProgress(long progressRate) { - mSendData += progressRate; - int percent = (int)(100*((double)mSendData)/((double)mTotalDataToSend)); - if (percent != mPreviousPercent) { - String text = String.format(getString(R.string.uploader_upload_in_progress_content), percent, new File(mLocalPaths[mCurrentIndexUpload]).getName()); - mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, false); - mNotification.contentView.setTextViewText(R.id.status_text, text); - mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); - } - mPreviousPercent = percent; - } -} diff --git a/src/eu/alefzero/owncloud/files/services/InstantUploadService.java b/src/eu/alefzero/owncloud/files/services/InstantUploadService.java deleted file mode 100644 index b666e593..00000000 --- a/src/eu/alefzero/owncloud/files/services/InstantUploadService.java +++ /dev/null @@ -1,161 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.files.services; - -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; - -import org.apache.commons.httpclient.HttpException; -import org.apache.jackrabbit.webdav.client.methods.MkColMethod; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.utils.OwnCloudVersion; -import eu.alefzero.webdav.WebdavClient; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.Service; -import android.content.Intent; -import android.net.Uri; -import android.os.IBinder; -import android.util.Log; - -public class InstantUploadService extends Service { - - public static String KEY_FILE_PATH = "KEY_FILEPATH"; - public static String KEY_FILE_SIZE = "KEY_FILESIZE"; - public static String KEY_MIME_TYPE = "KEY_MIMETYPE"; - public static String KEY_DISPLAY_NAME = "KEY_FILENAME"; - public static String KEY_ACCOUNT = "KEY_ACCOUNT"; - - private static String TAG = "InstantUploadService"; - private static String INSTANT_UPLOAD_DIR = "/InstantUpload"; - private UploaderRunnable mUploaderRunnable; - - @Override - public IBinder onBind(Intent arg0) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - 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"); - return Service.START_NOT_STICKY; - } - - if (mUploaderRunnable == null) { - mUploaderRunnable = new UploaderRunnable(); - } - - String filename = intent.getStringExtra(KEY_DISPLAY_NAME); - String filepath = intent.getStringExtra(KEY_FILE_PATH); - String mimetype = intent.getStringExtra(KEY_MIME_TYPE); - Account account = intent.getParcelableExtra(KEY_ACCOUNT); - long filesize = intent.getLongExtra(KEY_FILE_SIZE, -1); - - mUploaderRunnable.addElementToQueue(filename, filepath, mimetype, filesize, account); - - // 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"); - new Thread(mUploaderRunnable).start(); - - return Service.START_STICKY; - } - - private class UploaderRunnable implements Runnable { - - Object mLock; - List> mHashMapList; - - public UploaderRunnable() { - mHashMapList = new LinkedList>(); - mLock = new Object(); - } - - public void addElementToQueue(String filename, - String filepath, - String mimetype, - long length, - Account account) { - HashMap new_map = new HashMap(); - new_map.put(KEY_ACCOUNT, account); - new_map.put(KEY_DISPLAY_NAME, filename); - new_map.put(KEY_FILE_PATH, filepath); - new_map.put(KEY_MIME_TYPE, mimetype); - new_map.put(KEY_FILE_SIZE, length); - - synchronized (mLock) { - mHashMapList.add(new_map); - } - } - - private HashMap getFirstObject() { - synchronized (mLock) { - if (mHashMapList.size() == 0) - return null; - HashMap ret = mHashMapList.get(0); - mHashMapList.remove(0); - return ret; - } - } - - public void run() { - HashMap working_map; - AccountManager am = AccountManager.get(getApplicationContext()); - - while ((working_map = getFirstObject()) != null) { - Account account = (Account) working_map.get(KEY_ACCOUNT); - String username = account.name.substring(0, account.name.lastIndexOf('@')); - String password = am.getPassword(account); - String filename = (String) working_map.get(KEY_DISPLAY_NAME); - String filepath = (String) working_map.get(KEY_FILE_PATH); - String mimetype = (String) working_map.get(KEY_MIME_TYPE); - - String oc_base_url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); - String oc_version = am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION); - OwnCloudVersion ocv = new OwnCloudVersion(oc_version); - String webdav_path = AccountUtils.getWebdavPath(ocv); - WebdavClient wdc = new WebdavClient(account, getApplicationContext()); - wdc.allowSelfsignedCertificates(); - wdc.setCredentials(username, password); - - MkColMethod mkcol = new MkColMethod(oc_base_url+webdav_path+INSTANT_UPLOAD_DIR); - int status = 0; - try { - status = wdc.executeMethod(mkcol); - Log.e(TAG, "mkcol returned " + status); - wdc.putFile(filepath, INSTANT_UPLOAD_DIR + "/" + filename, mimetype); - } catch (HttpException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - -} diff --git a/src/eu/alefzero/owncloud/files/services/OnUploadCompletedListener.java b/src/eu/alefzero/owncloud/files/services/OnUploadCompletedListener.java deleted file mode 100644 index 99d0bfa3..00000000 --- a/src/eu/alefzero/owncloud/files/services/OnUploadCompletedListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package eu.alefzero.owncloud.files.services; - -public interface OnUploadCompletedListener extends Runnable { - - public boolean getUploadResult(); - - public void setUploadResult(boolean result); -} diff --git a/src/eu/alefzero/owncloud/location/LocationServiceLauncherReciever.java b/src/eu/alefzero/owncloud/location/LocationServiceLauncherReciever.java deleted file mode 100644 index a435414b..00000000 --- a/src/eu/alefzero/owncloud/location/LocationServiceLauncherReciever.java +++ /dev/null @@ -1,87 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.location; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningServiceInfo; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.util.Log; - -public class LocationServiceLauncherReciever extends BroadcastReceiver { - - private final String TAG = getClass().getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - Intent deviceTrackingIntent = new Intent(); - deviceTrackingIntent - .setAction("eu.alefzero.owncloud.location.LocationUpdateService"); - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(context); - boolean trackDevice = preferences.getBoolean("enable_devicetracking", - true); - - // Used in Preferences activity so that tracking is disabled or - // reenabled - if (intent.hasExtra("TRACKING_SETTING")) { - trackDevice = intent.getBooleanExtra("TRACKING_SETTING", true); - } - - startOrStopDeviceTracking(context, trackDevice); - } - - /** - * Used internally. Starts or stops the device tracking service - * - * @param trackDevice true to start the service, false to stop it - */ - private void startOrStopDeviceTracking(Context context, boolean trackDevice) { - Intent deviceTrackingIntent = new Intent(); - deviceTrackingIntent - .setAction("eu.alefzero.owncloud.location.LocationUpdateService"); - if (!isDeviceTrackingServiceRunning(context) && trackDevice) { - Log.d(TAG, "Starting device tracker service"); - context.startService(deviceTrackingIntent); - } else if (isDeviceTrackingServiceRunning(context) && !trackDevice) { - Log.d(TAG, "Stopping device tracker service"); - context.stopService(deviceTrackingIntent); - } - } - - /** - * Checks to see whether or not the LocationUpdateService is running - * - * @return true, if it is. Otherwise false - */ - private boolean isDeviceTrackingServiceRunning(Context context) { - ActivityManager manager = (ActivityManager) context - .getSystemService(Context.ACTIVITY_SERVICE); - for (RunningServiceInfo service : manager - .getRunningServices(Integer.MAX_VALUE)) { - if (getClass().getName().equals(service.service.getClassName())) { - return true; - } - } - return false; - } - -} diff --git a/src/eu/alefzero/owncloud/location/LocationUpdateService.java b/src/eu/alefzero/owncloud/location/LocationUpdateService.java deleted file mode 100644 index 96ae329f..00000000 --- a/src/eu/alefzero/owncloud/location/LocationUpdateService.java +++ /dev/null @@ -1,108 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.location; - -import android.app.IntentService; -import android.content.Intent; -import android.content.SharedPreferences; -import android.location.Criteria; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.location.LocationProvider; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.util.Log; -import android.widget.Toast; - -public class LocationUpdateService extends IntentService implements - LocationListener { - - public static final String TAG = "LocationUpdateService"; - - private LocationManager mLocationManager; - private LocationProvider mLocationProvider; - private SharedPreferences mPreferences; - - public LocationUpdateService() { - super(TAG); - } - - @Override - protected void onHandleIntent(Intent intent) { - mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); - // Determine, how we can track the device - Criteria criteria = new Criteria(); - criteria.setAccuracy(Criteria.ACCURACY_FINE); - criteria.setPowerRequirement(Criteria.POWER_LOW); - mLocationProvider = mLocationManager.getProvider(mLocationManager - .getBestProvider(criteria, true)); - - // Notify user if there is no way to track the device - if (mLocationProvider == null) { - Toast.makeText(this, - eu.alefzero.owncloud.R.string.location_no_provider, - Toast.LENGTH_LONG); - stopSelf(); - return; - } - - // Get preferences for device tracking - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); - boolean trackDevice = mPreferences.getBoolean("enable_devicetracking", - true); - int updateIntervall = Integer.parseInt(mPreferences.getString( - "devicetracking_update_intervall", "30")) * 60 * 1000; - int distanceBetweenLocationChecks = 50; - - // If we do shall track the device -> Stop - if (!trackDevice) { - Log.d(TAG, "Devicetracking is disabled"); - stopSelf(); - return; - } - - mLocationManager.requestLocationUpdates(mLocationProvider.getName(), - updateIntervall, distanceBetweenLocationChecks, this); - } - - @Override - public void onLocationChanged(Location location) { - Log.d(TAG, "Location changed: " + location); - - } - - @Override - public void onProviderDisabled(String arg0) { - // TODO Auto-generated method stub - - } - - @Override - public void onProviderEnabled(String arg0) { - // TODO Auto-generated method stub - - } - - @Override - public void onStatusChanged(String arg0, int arg1, Bundle arg2) { - // TODO Auto-generated method stub - - } - -} diff --git a/src/eu/alefzero/owncloud/providers/FileContentProvider.java b/src/eu/alefzero/owncloud/providers/FileContentProvider.java deleted file mode 100644 index 7ed73a9f..00000000 --- a/src/eu/alefzero/owncloud/providers/FileContentProvider.java +++ /dev/null @@ -1,237 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.providers; - -import java.util.HashMap; - -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; - -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; - -/** - * The ContentProvider for the ownCloud App. - * - * @author Bartek Przybylski - * - */ -public class FileContentProvider extends ContentProvider { - - private DataBaseHelper mDbHelper; - - private static HashMap mProjectionMap; - static { - mProjectionMap = new HashMap(); - mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); - mProjectionMap.put(ProviderTableMeta.FILE_PARENT, - ProviderTableMeta.FILE_PARENT); - mProjectionMap.put(ProviderTableMeta.FILE_PATH, - ProviderTableMeta.FILE_PATH); - mProjectionMap.put(ProviderTableMeta.FILE_NAME, - ProviderTableMeta.FILE_NAME); - mProjectionMap.put(ProviderTableMeta.FILE_CREATION, - ProviderTableMeta.FILE_CREATION); - mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, - ProviderTableMeta.FILE_MODIFIED); - mProjectionMap.put(ProviderTableMeta.FILE_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_KEEP_IN_SYNC, - ProviderTableMeta.FILE_KEEP_IN_SYNC); - } - - private static final int SINGLE_FILE = 1; - private static final int DIRECTORY = 2; - private static final int ROOT_DIRECTORY = 3; - private static final UriMatcher mUriMatcher; - static { - mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); - } - - @Override - public int delete(Uri uri, String where, String[] whereArgs) { - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - int count = 0; - switch (mUriMatcher.match(uri)) { - case SINGLE_FILE: - count = db.delete(ProviderTableMeta.DB_NAME, - ProviderTableMeta._ID - + "=" - + uri.getPathSegments().get(1) - + (!TextUtils.isEmpty(where) ? " AND (" + where - + ")" : ""), whereArgs); - break; - case ROOT_DIRECTORY: - count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); - break; - default: - throw new IllegalArgumentException("Unknown uri: " + uri.toString()); - } - getContext().getContentResolver().notifyChange(uri, null); - return count; - } - - @Override - public String getType(Uri uri) { - switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - return ProviderTableMeta.CONTENT_TYPE; - case SINGLE_FILE: - return ProviderTableMeta.CONTENT_TYPE_ITEM; - default: - throw new IllegalArgumentException("Unknown Uri id." - + uri.toString()); - } - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - if (mUriMatcher.match(uri) != SINGLE_FILE && - mUriMatcher.match(uri) != ROOT_DIRECTORY) { - - throw new IllegalArgumentException("Unknown uri id: " + uri); - } - - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values); - if (rowId > 0) { - Uri insertedFileUri = ContentUris.withAppendedId( - ProviderTableMeta.CONTENT_URI_FILE, rowId); - getContext().getContentResolver().notifyChange(insertedFileUri, - null); - return insertedFileUri; - } - throw new SQLException("ERROR " + uri); - } - - @Override - public boolean onCreate() { - mDbHelper = new DataBaseHelper(getContext()); - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); - - sqlQuery.setTables(ProviderTableMeta.DB_NAME); - sqlQuery.setProjectionMap(mProjectionMap); - - switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - break; - case DIRECTORY: - sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" - + uri.getPathSegments().get(1)); - break; - case SINGLE_FILE: - if (uri.getPathSegments().size() > 1) { - sqlQuery.appendWhere(ProviderTableMeta._ID + "=" - + uri.getPathSegments().get(1)); - } - break; - default: - throw new IllegalArgumentException("Unknown uri id: " + uri); - } - - String order; - if (TextUtils.isEmpty(sortOrder)) { - order = ProviderTableMeta.DEFAULT_SORT_ORDER; - } else { - order = sortOrder; - } - - SQLiteDatabase db = mDbHelper.getReadableDatabase(); - Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, - null, null, order); - - c.setNotificationUri(getContext().getContentResolver(), uri); - - return c; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - return mDbHelper.getWritableDatabase().update( - ProviderTableMeta.DB_NAME, values, selection, selectionArgs); - } - - class DataBaseHelper extends SQLiteOpenHelper { - - public DataBaseHelper(Context context) { - super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION); - - } - - @Override - public void onCreate(SQLiteDatabase db) { - // files table - Log.i("SQL", "Entering in onCreate"); - db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" - + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " - + ProviderTableMeta.FILE_NAME + " TEXT, " - + ProviderTableMeta.FILE_PATH + " TEXT, " - + ProviderTableMeta.FILE_PARENT + " INTEGER, " - + ProviderTableMeta.FILE_CREATION + " INTEGER, " - + ProviderTableMeta.FILE_MODIFIED + " INTEGER, " - + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " - + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " - + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " - + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, " - + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, " - + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER );"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.i("SQL", "Entering in onUpgrade"); - if (oldVersion == 1 && newVersion >= 2) { - Log.i("SQL", "Entering in the ADD in onUpgrade"); - db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + - " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + - " DEFAULT 0"); - } else Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); - } - - } - -} diff --git a/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java deleted file mode 100644 index fa982e7e..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java +++ /dev/null @@ -1,163 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.syncadapter; - -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.Date; - -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.protocol.HttpContext; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.AbstractThreadedSyncAdapter; -import android.content.ContentProviderClient; -import android.content.Context; -import android.net.Uri; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.datamodel.DataStorageManager; -import eu.alefzero.webdav.WebdavClient; - -/** - * Base SyncAdapter for OwnCloud Designed to be subclassed for the concrete - * SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc.. - * - * @author sassman - * - */ -public abstract class AbstractOwnCloudSyncAdapter extends - AbstractThreadedSyncAdapter { - - private AccountManager accountManager; - private Account account; - private ContentProviderClient contentProvider; - private Date lastUpdated; - private DataStorageManager mStoreManager; - - private WebdavClient mClient = null; - - public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - this.setAccountManager(AccountManager.get(context)); - } - - public AccountManager getAccountManager() { - return accountManager; - } - - public void setAccountManager(AccountManager accountManager) { - this.accountManager = accountManager; - } - - public Account getAccount() { - return account; - } - - public void setAccount(Account account) { - this.account = account; - } - - public ContentProviderClient getContentProvider() { - return contentProvider; - } - - public void setContentProvider(ContentProviderClient contentProvider) { - this.contentProvider = contentProvider; - } - - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - - public void setStorageManager(DataStorageManager storage_manager) { - mStoreManager = storage_manager; - } - - public DataStorageManager getStorageManager() { - return mStoreManager; - } - - protected ConnectionKeepAliveStrategy getKeepAliveStrategy() { - return new ConnectionKeepAliveStrategy() { - public long getKeepAliveDuration(HttpResponse response, - HttpContext context) { - // Change keep alive straategy basing on response: ie - // forbidden/not found/etc - // should have keep alive 0 - // default return: 5s - int statusCode = response.getStatusLine().getStatusCode(); - - // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed - // out - if ((statusCode >= 400 && statusCode <= 418) - || (statusCode >= 421 && statusCode <= 426) - || (statusCode >= 500 && statusCode <= 510) - || statusCode == 118) { - return 0; - } - - return 5 * 1000; - } - }; - } - - protected HttpResponse fireRawRequest(HttpRequest query) - throws ClientProtocolException, OperationCanceledException, - AuthenticatorException, IOException { - /* - * BasicHttpContext httpContext = new BasicHttpContext(); BasicScheme - * basicAuth = new BasicScheme(); - * httpContext.setAttribute("preemptive-auth", basicAuth); - * - * HttpResponse response = getClient().execute(mHost, query, - * httpContext); - */ - return null; - } - - protected Uri getUri() { - return Uri.parse(this.getAccountManager().getUserData(getAccount(), - AccountAuthenticator.KEY_OC_URL)); - } - - protected WebdavClient getClient() throws OperationCanceledException, - AuthenticatorException, IOException { - if (mClient == null) { - if (this.getAccountManager().getUserData(getAccount(), - AccountAuthenticator.KEY_OC_URL) == null) { - throw new UnknownHostException(); - } - mClient = new WebdavClient(account, getContext()); - mClient.allowSelfsignedCertificates(); - // mHost = mClient.getTargetHost(); - } - - return mClient; - } -} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/syncadapter/ContactSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/ContactSyncAdapter.java deleted file mode 100644 index b0ab9569..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/ContactSyncAdapter.java +++ /dev/null @@ -1,106 +0,0 @@ -package eu.alefzero.owncloud.syncadapter; - -import java.io.FileInputStream; -import java.io.IOException; - -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.ByteArrayEntity; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.ContentProviderClient; -import android.content.Context; -import android.content.SyncResult; -import android.content.res.AssetFileDescriptor; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.provider.ContactsContract; -import android.util.Log; - -public class ContactSyncAdapter extends AbstractOwnCloudSyncAdapter { - private String mAddrBookUri; - - public ContactSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - mAddrBookUri = null; - } - - @Override - public void onPerformSync(Account account, Bundle extras, String authority, - ContentProviderClient provider, SyncResult syncResult) { - setAccount(account); - setContentProvider(provider); - Cursor c = getLocalContacts(false); - if (c.moveToFirst()) { - do { - String lookup = c.getString(c - .getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); - String a = getAddressBookUri(); - String uri = a + lookup + ".vcf"; - FileInputStream f; - try { - f = getContactVcard(lookup); - HttpPut query = new HttpPut(uri); - byte[] b = new byte[f.available()]; - f.read(b); - query.setEntity(new ByteArrayEntity(b)); - HttpResponse response = fireRawRequest(query); - } catch (IOException e) { - e.printStackTrace(); - return; - } catch (OperationCanceledException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (AuthenticatorException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } while (c.moveToNext()); - // } while (c.moveToNext()); - } - - } - - private String getAddressBookUri() { - if (mAddrBookUri != null) - return mAddrBookUri; - - AccountManager am = getAccountManager(); - String uri = am.getUserData(getAccount(), - AccountAuthenticator.KEY_OC_URL).replace( - AccountUtils.WEBDAV_PATH_2_0, AccountUtils.CARDDAV_PATH_2_0); - uri += "/addressbooks/" - + getAccount().name.substring(0, - getAccount().name.lastIndexOf('@')) + "/default/"; - mAddrBookUri = uri; - return uri; - } - - private FileInputStream getContactVcard(String lookupKey) - throws IOException { - Uri uri = Uri.withAppendedPath( - ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey); - AssetFileDescriptor fd = getContext().getContentResolver() - .openAssetFileDescriptor(uri, "r"); - return fd.createInputStream(); - } - - private Cursor getLocalContacts(boolean include_hidden_contacts) { - return getContext().getContentResolver().query( - ContactsContract.Contacts.CONTENT_URI, - new String[] { ContactsContract.Contacts._ID, - ContactsContract.Contacts.LOOKUP_KEY }, - ContactsContract.Contacts.IN_VISIBLE_GROUP + " = ?", - new String[] { (include_hidden_contacts ? "0" : "1") }, - ContactsContract.Contacts._ID + " DESC"); - } - -} diff --git a/src/eu/alefzero/owncloud/syncadapter/ContactSyncService.java b/src/eu/alefzero/owncloud/syncadapter/ContactSyncService.java deleted file mode 100644 index 465a9406..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/ContactSyncService.java +++ /dev/null @@ -1,26 +0,0 @@ -package eu.alefzero.owncloud.syncadapter; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class ContactSyncService extends Service { - private static final Object syncAdapterLock = new Object(); - private static AbstractOwnCloudSyncAdapter mSyncAdapter = null; - - @Override - public void onCreate() { - synchronized (syncAdapterLock) { - if (mSyncAdapter == null) { - mSyncAdapter = new ContactSyncAdapter(getApplicationContext(), - true); - } - } - } - - @Override - public IBinder onBind(Intent arg0) { - return mSyncAdapter.getSyncAdapterBinder(); - } - -} diff --git a/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java deleted file mode 100644 index 8be8dff9..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java +++ /dev/null @@ -1,293 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.syncadapter; - -import java.io.IOException; -import java.util.List; -import java.util.Vector; - -import org.apache.jackrabbit.webdav.DavException; -import org.apache.jackrabbit.webdav.MultiStatus; -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; - -import android.accounts.Account; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.ContentProviderClient; -import android.content.Context; -import android.content.Intent; -import android.content.SyncResult; -import android.os.Bundle; -import android.util.Log; -import eu.alefzero.owncloud.datamodel.FileDataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.services.FileDownloader; -import eu.alefzero.webdav.WebdavEntry; -import eu.alefzero.webdav.WebdavUtils; - -/** - * 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"; - - /* Commented code for ugly performance tests - private final static int MAX_DELAYS = 100; - private static long[] mResponseDelays = new long[MAX_DELAYS]; - private static long[] mSaveDelays = new long[MAX_DELAYS]; - private int mDelaysIndex = 0; - private int mDelaysCount = 0; - */ - - private long mCurrentSyncTime; - private boolean mCancellation; - private Account mAccount; - - public FileSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - - @Override - public synchronized void onPerformSync(Account account, Bundle extras, - String authority, ContentProviderClient provider, - SyncResult syncResult) { - - mCancellation = false; - mAccount = account; - - this.setAccount(mAccount); - this.setContentProvider(provider); - this.setStorageManager(new FileDataStorageManager(mAccount, - getContentProvider())); - - /* Commented code for ugly performance tests - mDelaysIndex = 0; - mDelaysCount = 0; - */ - - - Log.d(TAG, "syncing owncloud account " + mAccount.name); - - sendStickyBroadcast(true, null); // message to signal the start to the UI - - PropFindMethod query; - try { - mCurrentSyncTime = System.currentTimeMillis(); - query = new PropFindMethod(getUri().toString() + "/"); - getClient().executeMethod(query); - MultiStatus resp = null; - resp = query.getResponseBodyAsMultiStatus(); - - if (resp.getResponses().length > 0) { - WebdavEntry we = new WebdavEntry(resp.getResponses()[0], getUri().getPath()); - OCFile file = fillOCFile(we); - file.setParentId(0); - getStorageManager().saveFile(file); - if (!mCancellation) { - fetchData(getUri().toString(), syncResult, file.getFileId()); - } - } - } catch (OperationCanceledException e) { - e.printStackTrace(); - } catch (AuthenticatorException e) { - syncResult.stats.numAuthExceptions++; - e.printStackTrace(); - } catch (IOException e) { - syncResult.stats.numIoExceptions++; - e.printStackTrace(); - } catch (DavException e) { - syncResult.stats.numIoExceptions++; - e.printStackTrace(); - } catch (Throwable t) { - // TODO update syncResult - Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t); - t.printStackTrace(); - } - - /* Commented code for ugly performance tests - long sum = 0, mean = 0, max = 0, min = Long.MAX_VALUE; - for (int i=0; i updatedFiles = new Vector(resp.getResponses().length - 1); - for (int i = 1; i < resp.getResponses().length; ++i) { - WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath()); - OCFile file = fillOCFile(we); - file.setParentId(parentId); - if (getStorageManager().getFileByPath(file.getRemotePath()) != null && - getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() && - file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath()) - .getModificationTimestamp()) { - Intent intent = new Intent(this.getContext(), FileDownloader.class); - intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount()); - intent.putExtra(FileDownloader.EXTRA_FILE_PATH, file.getRemotePath()); - intent.putExtra(FileDownloader.EXTRA_REMOTE_PATH, file.getRemotePath()); - intent.putExtra(FileDownloader.EXTRA_FILE_SIZE, file.getFileLength()); - file.setKeepInSync(true); - getContext().startService(intent); - } - if (getStorageManager().getFileByPath(file.getRemotePath()) != null) - file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync()); - - //Log.v(TAG, "adding file: " + file); - updatedFiles.add(file); - if (parentId == 0) - parentId = file.getFileId(); - } - /* Commented code for ugly performance tests - long saveDelay = System.currentTimeMillis(); - */ - getStorageManager().saveFiles(updatedFiles); // all "at once" ; trying to get a best performance in database update - /* Commented code for ugly performance tests - saveDelay = System.currentTimeMillis() - saveDelay; - Log.e(TAG, "syncing: SAVE TIME for " + uri + " contents, " + mSaveDelays[mDelaysIndex] + "ms"); - */ - - // removal of obsolete files - Vector files = getStorageManager().getDirectoryContent( - getStorageManager().getFileById(parentId)); - OCFile file; - for (int i=0; i < files.size(); ) { - file = files.get(i); - if (file.getLastSyncDate() != mCurrentSyncTime) { - Log.v(TAG, "removing file: " + file); - getStorageManager().removeFile(file); - files.remove(i); - } else { - i++; - } - } - - // synchronized folder -> notice to UI - sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath()); - - // recursive fetch - for (int i=0; i < files.size() && !mCancellation; i++) { - OCFile newFile = files.get(i); - if (newFile.getMimetype().equals("DIR")) { - fetchData(getUri().toString() + WebdavUtils.encodePath(newFile.getRemotePath()), syncResult, newFile.getFileId()); - } - } - if (mCancellation) Log.d(TAG, "Leaving " + uri + " because cancelation request"); - - /* Commented code for ugly performance tests - mResponseDelays[mDelaysIndex] = responseDelay; - mSaveDelays[mDelaysIndex] = saveDelay; - mDelaysCount++; - mDelaysIndex++; - if (mDelaysIndex >= MAX_DELAYS) - mDelaysIndex = 0; - */ - - - - } catch (OperationCanceledException e) { - e.printStackTrace(); - } catch (AuthenticatorException e) { - syncResult.stats.numAuthExceptions++; - e.printStackTrace(); - } catch (IOException e) { - syncResult.stats.numIoExceptions++; - e.printStackTrace(); - } catch (DavException e) { - syncResult.stats.numIoExceptions++; - e.printStackTrace(); - } catch (Throwable t) { - // TODO update syncResult - Log.e(TAG, "problem while synchronizing owncloud account " + mAccount.name, t); - t.printStackTrace(); - } - } - - private OCFile fillOCFile(WebdavEntry we) { - OCFile file = new OCFile(we.decodedPath()); - file.setCreationTimestamp(we.createTimestamp()); - file.setFileLength(we.contentLength()); - file.setMimetype(we.contentType()); - file.setModificationTimestamp(we.modifiedTimesamp()); - file.setLastSyncDate(mCurrentSyncTime); - return file; - } - - - private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) { - 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); - } - getContext().sendStickyBroadcast(i); - } - - /** - * Called by system SyncManager when a synchronization is required to be cancelled. - * - * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder - * fetched will be still saved in the database. See onPerformSync implementation. - */ - @Override - public void onSyncCanceled() { - Log.d(TAG, "Synchronization of " + mAccount.name + " has been requested to cancell"); - mCancellation = true; - super.onSyncCanceled(); - } - -} diff --git a/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java b/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java deleted file mode 100644 index 5396f582..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java +++ /dev/null @@ -1,50 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.syncadapter; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Background service for syncing files to our local Database - * - * @author Bartek Przybylski - * - */ -public class FileSyncService extends Service { - public static final String SYNC_MESSAGE = "ACCOUNT_SYNC"; - public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH"; - public static final String IN_PROGRESS = "SYNC_IN_PROGRESS"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - - /* - * {@inheritDoc} - */ - @Override - public void onCreate() { - } - - /* - * {@inheritDoc} - */ - @Override - public IBinder onBind(Intent intent) { - return new FileSyncAdapter(getApplicationContext(), true).getSyncAdapterBinder(); - } -} diff --git a/src/eu/alefzero/owncloud/ui/ActionItem.java b/src/eu/alefzero/owncloud/ui/ActionItem.java deleted file mode 100644 index 6f96f194..00000000 --- a/src/eu/alefzero/owncloud/ui/ActionItem.java +++ /dev/null @@ -1,61 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui; - -import android.graphics.drawable.Drawable; -import android.view.View.OnClickListener; - -/** - * Represents an Item on the ActionBar. - * - * @author Bartek Przybylski - * - */ -public class ActionItem { - private Drawable mIcon; - private String mTitle; - private OnClickListener mClickListener; - - public ActionItem() { - } - - public void setTitle(String title) { - mTitle = title; - } - - public String getTitle() { - return mTitle; - } - - public void setIcon(Drawable icon) { - mIcon = icon; - } - - public Drawable getIcon() { - return mIcon; - } - - public void setOnClickListener(OnClickListener listener) { - mClickListener = listener; - } - - public OnClickListener getOnClickListerner() { - return mClickListener; - } - -} diff --git a/src/eu/alefzero/owncloud/ui/CustomPopup.java b/src/eu/alefzero/owncloud/ui/CustomPopup.java deleted file mode 100644 index cd8d8459..00000000 --- a/src/eu/alefzero/owncloud/ui/CustomPopup.java +++ /dev/null @@ -1,154 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui; - -import android.content.Context; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.view.View.OnTouchListener; -import android.view.ViewGroup.LayoutParams; -import android.widget.PopupWindow; - -/** - * Represents a custom PopupWindows - * - * @author Lorensius. W. T - * - */ -public class CustomPopup { - protected final View mAnchor; - protected final PopupWindow mWindow; - private View root; - private Drawable background = null; - protected final WindowManager mWManager; - - public CustomPopup(View anchor) { - mAnchor = anchor; - mWindow = new PopupWindow(anchor.getContext()); - - mWindow.setTouchInterceptor(new OnTouchListener() { - - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { - CustomPopup.this.dismiss(); - return true; - } - return false; - } - }); - - mWManager = (WindowManager) anchor.getContext().getSystemService( - Context.WINDOW_SERVICE); - onCreate(); - } - - public void onCreate() { - } - - public void onShow() { - } - - public void preShow() { - if (root == null) { - throw new IllegalStateException( - "setContentView called with a view to display"); - } - - onShow(); - - if (background == null) { - mWindow.setBackgroundDrawable(new BitmapDrawable()); - } else { - mWindow.setBackgroundDrawable(background); - } - - mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); - mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); - mWindow.setTouchable(true); - mWindow.setFocusable(true); - mWindow.setOutsideTouchable(true); - - mWindow.setContentView(root); - } - - public void setBackgroundDrawable(Drawable background) { - this.background = background; - } - - public void setContentView(View root) { - this.root = root; - mWindow.setContentView(root); - } - - public void setContentView(int layoutResId) { - LayoutInflater inflater = (LayoutInflater) mAnchor.getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - setContentView(inflater.inflate(layoutResId, null)); - } - - public void showDropDown() { - showDropDown(0, 0); - } - - public void showDropDown(int x, int y) { - preShow(); - mWindow.setAnimationStyle(android.R.style.Animation_Dialog); - mWindow.showAsDropDown(mAnchor, x, y); - } - - public void showLikeQuickAction() { - showLikeQuickAction(0, 0); - } - - public void showLikeQuickAction(int x, int y) { - preShow(); - - mWindow.setAnimationStyle(android.R.style.Animation_Dialog); - int[] location = new int[2]; - mAnchor.getLocationOnScreen(location); - - Rect anchorRect = new Rect(location[0], location[1], location[0] - + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); - - root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT)); - root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - int rootW = root.getWidth(), rootH = root.getHeight(); - int screenW = mWManager.getDefaultDisplay().getWidth(); - - int xpos = ((screenW - rootW) / 2) + x; - int ypos = anchorRect.top - rootH + y; - - if (rootH > anchorRect.top) { - ypos = anchorRect.bottom + y; - } - mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos); - } - - public void dismiss() { - mWindow.dismiss(); - } - -} diff --git a/src/eu/alefzero/owncloud/ui/FragmentListView.java b/src/eu/alefzero/owncloud/ui/FragmentListView.java deleted file mode 100644 index 17e64835..00000000 --- a/src/eu/alefzero/owncloud/ui/FragmentListView.java +++ /dev/null @@ -1,52 +0,0 @@ -package eu.alefzero.owncloud.ui; - -import com.actionbarsherlock.app.SherlockFragment; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.AdapterView.OnItemClickListener; - -public class FragmentListView extends SherlockFragment implements - OnItemClickListener, OnItemLongClickListener { - ListView mList; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - public void setListAdapter(ListAdapter listAdapter) { - mList.setAdapter(listAdapter); - mList.invalidate(); - } - - public ListView getListView() { - return mList; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mList = new ListView(getActivity()); - mList.setOnItemClickListener(this); - mList.setOnItemLongClickListener(this); - return mList; - // return super.onCreateView(inflater, container, savedInstanceState); - } - - public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { - } - - @Override - public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2, - long arg3) { - return false; - } - -} diff --git a/src/eu/alefzero/owncloud/ui/QuickAction.java b/src/eu/alefzero/owncloud/ui/QuickAction.java deleted file mode 100644 index e1d97d22..00000000 --- a/src/eu/alefzero/owncloud/ui/QuickAction.java +++ /dev/null @@ -1,305 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui; - -import android.content.Context; - -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.LinearLayout; -import android.widget.ScrollView; - -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup; - -import java.util.ArrayList; - -import eu.alefzero.owncloud.R; - -/** - * Popup window, shows action list as icon and text like the one in Gallery3D - * app. - * - * @author Lorensius. W. T - */ -public class QuickAction extends CustomPopup { - private final View root; - private final ImageView mArrowUp; - private final ImageView mArrowDown; - private final LayoutInflater inflater; - private final Context context; - - protected static final int ANIM_GROW_FROM_LEFT = 1; - protected static final int ANIM_GROW_FROM_RIGHT = 2; - protected static final int ANIM_GROW_FROM_CENTER = 3; - protected static final int ANIM_REFLECT = 4; - protected static final int ANIM_AUTO = 5; - - private int animStyle; - private ViewGroup mTrack; - private ScrollView scroller; - private ArrayList actionList; - - /** - * Constructor - * - * @param anchor {@link View} on where the popup window should be displayed - */ - public QuickAction(View anchor) { - super(anchor); - - actionList = new ArrayList(); - context = anchor.getContext(); - inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - root = (ViewGroup) inflater.inflate(R.layout.popup, null); - - mArrowDown = (ImageView) root.findViewById(R.id.arrow_down); - mArrowUp = (ImageView) root.findViewById(R.id.arrow_up); - - setContentView(root); - - mTrack = (ViewGroup) root.findViewById(R.id.tracks); - scroller = (ScrollView) root.findViewById(R.id.scroller); - animStyle = ANIM_AUTO; - } - - /** - * Set animation style - * - * @param animStyle animation style, default is set to ANIM_AUTO - */ - public void setAnimStyle(int animStyle) { - this.animStyle = animStyle; - } - - /** - * Add action item - * - * @param action {@link ActionItem} object - */ - public void addActionItem(ActionItem action) { - actionList.add(action); - } - - /** - * Show popup window. Popup is automatically positioned, on top or bottom of - * anchor view. - * - */ - public void show() { - preShow(); - - int xPos, yPos; - - int[] location = new int[2]; - - mAnchor.getLocationOnScreen(location); - - Rect anchorRect = new Rect(location[0], location[1], location[0] - + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); - - createActionList(); - - root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT)); - root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - int rootHeight = root.getMeasuredHeight(); - int rootWidth = root.getMeasuredWidth(); - - int screenWidth = mWManager.getDefaultDisplay().getWidth(); - int screenHeight = mWManager.getDefaultDisplay().getHeight(); - - // automatically get X coord of popup (top left) - if ((anchorRect.left + rootWidth) > screenWidth) { - xPos = anchorRect.left - (rootWidth - mAnchor.getWidth()); - } else { - if (mAnchor.getWidth() > rootWidth) { - xPos = anchorRect.centerX() - (rootWidth / 2); - } else { - xPos = anchorRect.left; - } - } - - int dyTop = anchorRect.top; - int dyBottom = screenHeight - anchorRect.bottom; - - boolean onTop = (dyTop > dyBottom) ? true : false; - - if (onTop) { - if (rootHeight > dyTop) { - yPos = 15; - LayoutParams l = scroller.getLayoutParams(); - l.height = dyTop - mAnchor.getHeight(); - } else { - yPos = anchorRect.top - rootHeight; - } - } else { - yPos = anchorRect.bottom; - - if (rootHeight > dyBottom) { - LayoutParams l = scroller.getLayoutParams(); - l.height = dyBottom; - } - } - - showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), - anchorRect.centerX() - xPos); - - setAnimationStyle(screenWidth, anchorRect.centerX(), onTop); - - mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos); - } - - /** - * Set animation style - * - * @param screenWidth screen width - * @param requestedX distance from left edge - * @param onTop flag to indicate where the popup should be displayed. Set - * TRUE if displayed on top of anchor view and vice versa - */ - private void setAnimationStyle(int screenWidth, int requestedX, - boolean onTop) { - int arrowPos = requestedX - mArrowUp.getMeasuredWidth() / 2; - - switch (animStyle) { - case ANIM_GROW_FROM_LEFT: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left - : R.style.Animations_PopDownMenu_Left); - break; - - case ANIM_GROW_FROM_RIGHT: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right - : R.style.Animations_PopDownMenu_Right); - break; - - case ANIM_GROW_FROM_CENTER: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center - : R.style.Animations_PopDownMenu_Center); - break; - - case ANIM_REFLECT: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect - : R.style.Animations_PopDownMenu_Reflect); - break; - - case ANIM_AUTO: - if (arrowPos <= screenWidth / 4) { - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left - : R.style.Animations_PopDownMenu_Left); - } else if (arrowPos > screenWidth / 4 - && arrowPos < 3 * (screenWidth / 4)) { - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center - : R.style.Animations_PopDownMenu_Center); - } else { - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right - : R.style.Animations_PopDownMenu_Right); - } - - break; - } - } - - /** - * Create action list - */ - private void createActionList() { - View view; - String title; - Drawable icon; - OnClickListener listener; - - for (int i = 0; i < actionList.size(); i++) { - title = actionList.get(i).getTitle(); - icon = actionList.get(i).getIcon(); - listener = actionList.get(i).getOnClickListerner(); - - view = getActionItem(title, icon, listener); - - view.setFocusable(true); - view.setClickable(true); - - mTrack.addView(view); - } - } - - /** - * Get action item {@link View} - * - * @param title action item title - * @param icon {@link Drawable} action item icon - * @param listener {@link View.OnClickListener} action item listener - * @return action item {@link View} - */ - private View getActionItem(String title, Drawable icon, - OnClickListener listener) { - LinearLayout container = (LinearLayout) inflater.inflate( - R.layout.action_item, null); - - ImageView img = (ImageView) container.findViewById(R.id.icon); - TextView text = (TextView) container.findViewById(R.id.title); - - if (icon != null) { - img.setImageDrawable(icon); - } - - if (title != null) { - text.setText(title); - } - - if (listener != null) { - container.setOnClickListener(listener); - } - - return container; - } - - /** - * Show arrow - * - * @param whichArrow arrow type resource id - * @param requestedX distance from left screen - */ - private void showArrow(int whichArrow, int requestedX) { - final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp - : mArrowDown; - final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown - : mArrowUp; - - final int arrowWidth = mArrowUp.getMeasuredWidth(); - - showArrow.setVisibility(View.VISIBLE); - - ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow - .getLayoutParams(); - - param.leftMargin = requestedX - arrowWidth / 2; - - hideArrow.setVisibility(View.INVISIBLE); - } -} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/ui/activity/AccountSelectActivity.java b/src/eu/alefzero/owncloud/ui/activity/AccountSelectActivity.java deleted file mode 100644 index 8600a473..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/AccountSelectActivity.java +++ /dev/null @@ -1,189 +0,0 @@ -package eu.alefzero.owncloud.ui.activity; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.ContextMenu; -import android.view.View; -import android.view.ViewGroup; -import android.view.ContextMenu.ContextMenuInfo; -import android.widget.AdapterView; -import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.CheckedTextView; -import android.widget.ListView; -import android.widget.SimpleAdapter; -import android.widget.TextView; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockListActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuInflater; -import com.actionbarsherlock.view.MenuItem; - -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.R; - -public class AccountSelectActivity extends SherlockListActivity implements - AccountManagerCallback { - - private final Handler mHandler = new Handler(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ActionBar action_bar = getSupportActionBar(); - action_bar.setDisplayShowTitleEnabled(true); - action_bar.setDisplayHomeAsUpEnabled(false); - } - - @Override - protected void onResume() { - super.onResume(); - populateAccountList(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getSherlock().getMenuInflater(); - inflater.inflate(eu.alefzero.owncloud.R.menu.account_picker, menu); - return true; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - getMenuInflater().inflate(R.menu.account_picker_long_click, menu); - super.onCreateContextMenu(menu, v, menuInfo); - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - String accountName = ((TextView) v.findViewById(android.R.id.text1)) - .getText().toString(); - AccountUtils.setCurrentOwnCloudAccount(this, accountName); - - // trigger synchronization when current account is changed - ContentResolver.cancelSync(null, "org.owncloud"); - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - ContentResolver.requestSync(AccountUtils.getCurrentOwnCloudAccount(this), "org.owncloud", bundle); - - Intent i = new Intent(this, FileDisplayActivity.class); - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); - finish(); - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - if (item.getItemId() == R.id.createAccount) { - Intent intent = new Intent( - android.provider.Settings.ACTION_ADD_ACCOUNT); - intent.putExtra("authorities", - new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); - return true; - } - return false; - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem item) { - AdapterContextMenuInfo info = (AdapterContextMenuInfo) item - .getMenuInfo(); - int index = info.position; - HashMap map = (HashMap) getListAdapter() - .getItem(index); - String accountName = map.get("NAME"); - AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); - Account accounts[] = am - .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - for (Account a : accounts) { - if (a.name.equals(accountName)) { - am.removeAccount(a, this, mHandler); - } - } - - return false; - } - - private void populateAccountList() { - AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); - Account accounts[] = am - .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - LinkedList> ll = new LinkedList>(); - for (Account a : accounts) { - HashMap h = new HashMap(); - h.put("NAME", a.name); - h.put("VER", - "ownCloud version: " - + am.getUserData(a, - AccountAuthenticator.KEY_OC_VERSION)); - ll.add(h); - } - - setListAdapter(new AccountCheckedSimpleAdepter(this, ll, - android.R.layout.simple_list_item_single_choice, - new String[] { "NAME" }, new int[] { android.R.id.text1 })); - registerForContextMenu(getListView()); - } - - @Override - public void run(AccountManagerFuture future) { - if (future.isDone()) { - Account a = AccountUtils.getCurrentOwnCloudAccount(this); - String accountName = ""; - if (a == null) { - Account[] accounts = AccountManager.get(this) - .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - if (accounts.length != 0) - accountName = accounts[0].name; - AccountUtils.setCurrentOwnCloudAccount(this, accountName); - } - populateAccountList(); - } - } - - private class AccountCheckedSimpleAdepter extends SimpleAdapter { - private Account mCurrentAccount; - private List> mPrivateData; - - public AccountCheckedSimpleAdepter(Context context, - List> data, int resource, - String[] from, int[] to) { - super(context, data, resource, from, to); - mCurrentAccount = AccountUtils - .getCurrentOwnCloudAccount(AccountSelectActivity.this); - mPrivateData = data; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - CheckedTextView ctv = (CheckedTextView) v - .findViewById(android.R.id.text1); - if (mPrivateData.get(position).get("NAME") - .equals(mCurrentAccount.name)) { - ctv.setChecked(true); - } - return v; - } - - } - -} diff --git a/src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java b/src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java deleted file mode 100644 index caa9820a..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java +++ /dev/null @@ -1,398 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.ui.activity; - -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; - -import android.accounts.Account; -import android.accounts.AccountAuthenticatorActivity; -import android.accounts.AccountManager; -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.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.ImageView; -import android.widget.TextView; -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.authenticator.AuthenticationRunnable; -import eu.alefzero.owncloud.authenticator.ConnectionCheckerRunnable; -import eu.alefzero.owncloud.authenticator.OnAuthenticationResultListener; -import eu.alefzero.owncloud.authenticator.OnConnectCheckListener; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.owncloud.extensions.ExtensionsAvailableActivity; -import eu.alefzero.owncloud.utils.OwnCloudVersion; - -/** - * This Activity is used to add an ownCloud account to the App - * - * @author Bartek Przybylski - * - */ -public class AuthenticatorActivity extends AccountAuthenticatorActivity - implements OnAuthenticationResultListener, OnConnectCheckListener, - OnFocusChangeListener, OnClickListener { - private static final int DIALOG_LOGIN_PROGRESS = 0; - - private static final String TAG = "AuthActivity"; - - private Thread mAuthThread; - private AuthenticationRunnable mAuthRunnable; - private ConnectionCheckerRunnable 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; - - 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); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putInt(STATUS_ICON, mStatusIcon); - outState.putInt(STATUS_TEXT, mStatusText); - outState.putBoolean(STATUS_CORRECT, mStatusCorrect); - super.onSaveInstanceState(outState); - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog = null; - switch (id) { - case DIALOG_LOGIN_PROGRESS: { - ProgressDialog working_dialog = new ProgressDialog(this); - working_dialog.setMessage(getResources().getString( - R.string.auth_trying_to_login)); - working_dialog.setIndeterminate(true); - working_dialog.setCancelable(true); - working_dialog - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - Log.i(TAG, "Login canceled"); - if (mAuthThread != null) { - mAuthThread.interrupt(); - finish(); - } - } - }); - dialog = working_dialog; - break; - } - default: - Log.e(TAG, "Incorrect dialog called with id = " + id); - } - return dialog; - } - - public void onAuthenticationResult(boolean success, String message) { - if (success) { - TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password); - - URL url; - try { - url = new URL(message); - } catch (MalformedURLException e) { - // should never happen - Log.e(getClass().getName(), "Malformed URL: " + message); - return; - } - - String username = username_text.getText().toString().trim(); - String accountName = username + "@" + url.getHost(); - if (url.getPort() >= 0) { - accountName += ":" + url.getPort(); - } - Account account = new Account(accountName, - AccountAuthenticator.ACCOUNT_TYPE); - AccountManager accManager = AccountManager.get(this); - accManager.addAccountExplicitly(account, password_text.getText() - .toString(), null); - - // Add this account as default in the preferences, if there is none - // already - Account defaultAccount = AccountUtils - .getCurrentOwnCloudAccount(this); - if (defaultAccount == null) { - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(this).edit(); - editor.putString("select_oc_account", accountName); - editor.commit(); - } - - final Intent intent = new Intent(); - intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, - AccountAuthenticator.ACCOUNT_TYPE); - intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); - intent.putExtra(AccountManager.KEY_AUTHTOKEN, - AccountAuthenticator.ACCOUNT_TYPE); - intent.putExtra(AccountManager.KEY_USERDATA, username); - - accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, - url.toString()); - 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 { - dismissDialog(DIALOG_LOGIN_PROGRESS); - TextView tv = (TextView) findViewById(R.id.account_username); - tv.setError(message); - } - } - public void onCancelClick(View view) { - finish(); - } - - public void onOkClick(View view) { - String prefix = ""; - String url = ((TextView) findViewById(R.id.host_URL)).getText() - .toString(); - if (mIsSslConn) { - prefix = "https://"; - } else { - prefix = "http://"; - } - if (url.toLowerCase().startsWith("http://") - || url.toLowerCase().startsWith("https://")) { - prefix = ""; - } - continueConnection(prefix); - } - - private void continueConnection(String prefix) { - String url = ((TextView) findViewById(R.id.host_URL)).getText() - .toString(); - 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()); - - try { - mBaseUrl = prefix + url; - String url_str = prefix + url + webdav_path; - uri = new URL(url_str); - } catch (MalformedURLException e) { - // should not happend - e.printStackTrace(); - } - - showDialog(DIALOG_LOGIN_PROGRESS); - mAuthRunnable = new AuthenticationRunnable(uri, username, password); - 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().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 TIMEOUT: - case INORRECT_ADDRESS: - case SSL_INIT_ERROR: - case HOST_NOT_AVAILABLE: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_unknow_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_unknow_error; - break; - case FILE_NOT_FOUND: - mStatusIcon = R.drawable.common_error; - mStatusText = R.string.auth_incorrect_path_title; - break; - default: - Log.e(TAG, "Incorrect connection checker result type: " + type); - } - setResultIconAndText(mStatusIcon, mStatusText); - if (!mStatusCorrect) - findViewById(R.id.refreshButton).setVisibility(View.VISIBLE); - else - findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); - findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); - } - - @Override - public void onFocusChange(View view, boolean hasFocus) { - if (view.getId() == R.id.host_URL) { - if (!hasFocus) { - TextView tv = ((TextView) findViewById(R.id.host_URL)); - String uri = tv.getText().toString(); - if (uri.length() != 0) { - setResultIconAndText(R.drawable.progress_small, - R.string.auth_testing_connection); - findViewById(R.id.buttonOK).setEnabled(false); // avoid connect can be clicked if the test was previously passed - mConnChkRunnable = new ConnectionCheckerRunnable(uri, this); - mConnChkRunnable.setListener(this, mHandler); - mAuthThread = new Thread(mConnChkRunnable); - mAuthThread.start(); - } else { - findViewById(R.id.refreshButton).setVisibility( - View.INVISIBLE); - setResultIconAndText(0, 0); - } - } - } 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) { - TextView view = (TextView) findViewById(R.id.account_password); - int input_type = InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; - view.setInputType(input_type); - } - } -} diff --git a/src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java b/src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java deleted file mode 100644 index 461485c5..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java +++ /dev/null @@ -1,144 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.activity; - -import android.accounts.Account; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Bundle; -import android.support.v4.app.FragmentTransaction; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.MenuItem; - -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.services.FileDownloader; -import eu.alefzero.owncloud.ui.fragment.FileDetailFragment; - -/** - * 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; - - private boolean mConfigurationChangedToLandscape = false; - - @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) { - setContentView(R.layout.file_activity_details); - - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - - OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); - Account account = getIntent().getParcelableExtra(FileDownloader.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; - } - - - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - boolean returnValue = false; - - switch(item.getItemId()){ - case android.R.id.home: - backToDisplayActivity(); - returnValue = true; - } - - return returnValue; - } - - - - @Override - protected void onResume() { - - super.onResume(); - if (!mConfigurationChangedToLandscape) { - FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); - fragment.updateFileDetails(); - } - } - - - 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)); - 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! - } - -} diff --git a/src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java b/src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java deleted file mode 100644 index c440847c..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java +++ /dev/null @@ -1,886 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.ui.activity; - -import java.io.File; -import java.util.ArrayList; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources.NotFoundException; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.provider.MediaStore; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.Toast; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.ActionBar.OnNavigationListener; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuInflater; -import com.actionbarsherlock.view.MenuItem; -import com.actionbarsherlock.view.Window; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.CrashHandler; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.datamodel.DataStorageManager; -import eu.alefzero.owncloud.datamodel.FileDataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.services.FileDownloader; -import eu.alefzero.owncloud.files.services.FileUploader; -import eu.alefzero.owncloud.syncadapter.FileSyncService; -import eu.alefzero.owncloud.ui.fragment.FileDetailFragment; -import eu.alefzero.owncloud.ui.fragment.FileListFragment; -import eu.alefzero.webdav.WebdavClient; - -/** - * Displays, what files the user has available in his ownCloud. - * - * @author Bartek Przybylski - * - */ - -public class FileDisplayActivity extends SherlockFragmentActivity implements - FileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnClickListener, android.view.View.OnClickListener { - - private ArrayAdapter mDirectories; - private OCFile mCurrentDir; - private String[] mDirs = null; - - private DataStorageManager mStorageManager; - private SyncBroadcastReceiver mSyncBroadcastReceiver; - private UploadFinishReceiver mUploadFinishReceiver; - private DownloadFinishReceiver mDownloadFinishReceiver; - - private View mLayoutView = null; - private FileListFragment mFileList; - - private boolean mDualPane; - - private boolean mForcedLoginToCreateFirstAccount = false; - - private static final String KEY_DIR_ARRAY = "DIR_ARRAY"; - private static final String KEY_CURRENT_DIR = "DIR"; - - private static final int DIALOG_SETUP_ACCOUNT = 0; - private static final int DIALOG_CREATE_DIR = 1; - private static final int DIALOG_ABOUT_APP = 2; - public static final int DIALOG_SHORT_WAIT = 3; - - private static final int ACTION_SELECT_FILE = 1; - - private static final String TAG = "FileDisplayActivity"; - - - @Override - public void onCreate(Bundle savedInstanceState) { - Log.i(getClass().toString(), "onCreate() start"); - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(getApplicationContext())); - - if(savedInstanceState != null) { - mDirs = savedInstanceState.getStringArray(KEY_DIR_ARRAY); - mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); - mDirectories.add(OCFile.PATH_SEPARATOR); - if (mDirs != null) - for (String s : mDirs) - mDirectories.insert(s, 0); - mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE); - } - - mLayoutView = getLayoutInflater().inflate(R.layout.files, null); // always inflate this at onCreate() ; just once! - - if (AccountUtils.accountsAreSetup(this)) { - - initDelayedTilAccountAvailabe(); - - // PIN CODE request ; best location is to decide, let's try this first - //if (savedInstanceState == null) { - if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) { - requestPinCode(); - } - - - } else { - - setContentView(R.layout.no_account_available); - getSupportActionBar().setNavigationMode(ActionBar.DISPLAY_SHOW_TITLE); - findViewById(R.id.setup_account).setOnClickListener(this); - - setSupportProgressBarIndeterminateVisibility(false); - - Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); - intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); // although the code is here, the activity won't be created until this.onStart() and this.onResume() are finished; - mForcedLoginToCreateFirstAccount = true; - } - - Log.i(getClass().toString(), "onCreate() end"); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getSherlock().getMenuInflater(); - inflater.inflate(R.menu.menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - boolean retval = true; - switch (item.getItemId()) { - case R.id.createDirectoryItem: { - showDialog(DIALOG_CREATE_DIR); - break; - } - case R.id.startSync: { - ContentResolver.cancelSync(null, "org.owncloud"); // cancel the current synchronizations of any ownCloud account - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - ContentResolver.requestSync( - AccountUtils.getCurrentOwnCloudAccount(this), - "org.owncloud", bundle); - break; - } - case R.id.action_upload: { - Intent action = new Intent(Intent.ACTION_GET_CONTENT); - action = action.setType("*/*") - .addCategory(Intent.CATEGORY_OPENABLE); - startActivityForResult( - Intent.createChooser(action, getString(R.string.upload_chooser_title)), - ACTION_SELECT_FILE); - break; - } - case R.id.action_settings: { - Intent settingsIntent = new Intent(this, Preferences.class); - startActivity(settingsIntent); - break; - } - case R.id.about_app : { - showDialog(DIALOG_ABOUT_APP); - break; - } - case android.R.id.home: { - if(mCurrentDir != null && mCurrentDir.getParentId() != 0){ - onBackPressed(); - } - break; - } - default: - retval = false; - } - return retval; - } - - @Override - public boolean onNavigationItemSelected(int itemPosition, long itemId) { - int i = itemPosition; - while (i-- != 0) { - onBackPressed(); - } - return true; - } - - /** - * Called, when the user selected something for uploading - */ - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == ACTION_SELECT_FILE) { - if (resultCode == RESULT_OK) { - String filepath = null; - try { - Uri selectedImageUri = data.getData(); - - String filemanagerstring = selectedImageUri.getPath(); - String selectedImagePath = getPath(selectedImageUri); - - if (selectedImagePath != null) - filepath = selectedImagePath; - else - filepath = filemanagerstring; - - } catch (Exception e) { - Log.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"); - Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG); - t.show(); - return; - } - } - - Intent i = new Intent(this, FileUploader.class); - i.putExtra(FileUploader.KEY_ACCOUNT, - AccountUtils.getCurrentOwnCloudAccount(this)); - String remotepath = new String(); - for (int j = mDirectories.getCount() - 2; j >= 0; --j) { - remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); - } - if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) - remotepath += OCFile.PATH_SEPARATOR; - remotepath += new File(filepath).getName(); - - i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath); - i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath); - i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE); - startService(i); - } - - }/* dvelasco: WIP - not working as expected ... yet :) - else if (requestCode == ACTION_CREATE_FIRST_ACCOUNT) { - if (resultCode != RESULT_OK) { - finish(); // the user cancelled the AuthenticatorActivity - } - }*/ - } - - @Override - public void onBackPressed() { - if (mDirectories == null || mDirectories.getCount() <= 1) { - finish(); - return; - } - popDirname(); - mFileList.onNavigateUp(); - mCurrentDir = mFileList.getCurrentFile(); - - if(mCurrentDir.getParentId() == 0){ - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(false); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - // responsability of restore is prefered in onCreate() before than in onRestoreInstanceState when there are Fragments involved - Log.i(getClass().toString(), "onSaveInstanceState() start"); - super.onSaveInstanceState(outState); - if(mDirectories != null && mDirectories.getCount() != 0){ - mDirs = new String[mDirectories.getCount()-1]; - for (int j = mDirectories.getCount() - 2, i = 0; j >= 0; --j, ++i) { - mDirs[i] = mDirectories.getItem(j); - } - } - outState.putStringArray(KEY_DIR_ARRAY, mDirs); - outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir); - Log.i(getClass().toString(), "onSaveInstanceState() end"); - } - - @Override - protected void onResume() { - Log.i(getClass().toString(), "onResume() start"); - super.onResume(); - - if (AccountUtils.accountsAreSetup(this)) { - // at least an account exist: normal operation - - // set the layout only if it couldn't be set in onCreate - if (mForcedLoginToCreateFirstAccount) { - initDelayedTilAccountAvailabe(); - mForcedLoginToCreateFirstAccount = false; - } - - // Listen for sync messages - IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE); - mSyncBroadcastReceiver = new SyncBroadcastReceiver(); - registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); - - // Listen for upload messages - IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); - mUploadFinishReceiver = new UploadFinishReceiver(); - registerReceiver(mUploadFinishReceiver, uploadIntentFilter); - - // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE); - mDownloadFinishReceiver = new DownloadFinishReceiver(); - registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); - - // Storage manager initialization - mStorageManager = new FileDataStorageManager( - AccountUtils.getCurrentOwnCloudAccount(this), - getContentResolver()); - - // File list fragments - mFileList = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); - - - // Figure out what directory to list. - // Priority: Intent (here), savedInstanceState (onCreate), root dir (dir is null) - if(getIntent().hasExtra(FileDetailFragment.EXTRA_FILE)){ - mCurrentDir = (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); - if(mCurrentDir != null && !mCurrentDir.isDirectory()){ - mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId()); - } - - // Clear intent extra, so rotating the screen will not return us to this directory - getIntent().removeExtra(FileDetailFragment.EXTRA_FILE); - } - - if (mCurrentDir == null) - mCurrentDir = mStorageManager.getFileByPath("/"); - - // Drop-Down navigation and file list restore - mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); - - - // Given the case we have a file to display: - if(mCurrentDir != null){ - ArrayList files = new ArrayList(); - OCFile currFile = mCurrentDir; - while(currFile != null){ - files.add(currFile); - currFile = mStorageManager.getFileById(currFile.getParentId()); - } - - // Insert in mDirs - mDirs = new String[files.size()]; - for(int i = files.size() - 1; i >= 0; i--){ - mDirs[i] = files.get(i).getFileName(); - } - } - - if (mDirs != null) { - for (String s : mDirs) - mDirectories.add(s); - } else { - mDirectories.add(OCFile.PATH_SEPARATOR); - } - - // Actionbar setup - ActionBar action_bar = getSupportActionBar(); - action_bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - action_bar.setDisplayShowTitleEnabled(false); - action_bar.setListNavigationCallbacks(mDirectories, this); - if(mCurrentDir != null && mCurrentDir.getParentId() != 0){ - action_bar.setDisplayHomeAsUpEnabled(true); - } else { - action_bar.setDisplayHomeAsUpEnabled(false); - } - - // List dir here - mFileList.listDirectory(mCurrentDir); - } - Log.i(getClass().toString(), "onResume() end"); - } - - @Override - protected void onPause() { - Log.i(getClass().toString(), "onPause() start"); - super.onPause(); - if (mSyncBroadcastReceiver != null) { - unregisterReceiver(mSyncBroadcastReceiver); - mSyncBroadcastReceiver = null; - } - if (mUploadFinishReceiver != null) { - unregisterReceiver(mUploadFinishReceiver); - mUploadFinishReceiver = null; - } - if (mDownloadFinishReceiver != null) { - unregisterReceiver(mDownloadFinishReceiver); - mDownloadFinishReceiver = null; - } - - getIntent().putExtra(FileDetailFragment.EXTRA_FILE, mCurrentDir); - Log.i(getClass().toString(), "onPause() end"); - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog = null; - AlertDialog.Builder builder; - switch (id) { - case DIALOG_SETUP_ACCOUNT: - builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.main_tit_accsetup); - builder.setMessage(R.string.main_wrn_accsetup); - builder.setCancelable(false); - builder.setPositiveButton(android.R.string.ok, this); - builder.setNegativeButton(android.R.string.cancel, this); - dialog = builder.create(); - break; - case DIALOG_ABOUT_APP: { - builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.about_title)); - PackageInfo pkg; - try { - pkg = getPackageManager().getPackageInfo(getPackageName(), 0); - builder.setMessage("ownCloud android client\n\nversion: " + pkg.versionName ); - builder.setIcon(android.R.drawable.ic_menu_info_details); - dialog = builder.create(); - } catch (NameNotFoundException e) { - builder = null; - dialog = null; - Log.e(TAG, "Error while showing about dialog", e); - } - break; - } - case DIALOG_CREATE_DIR: { - builder = new Builder(this); - final EditText dirNameInput = new EditText(getBaseContext()); - final Account a = AccountUtils.getCurrentOwnCloudAccount(this); - builder.setView(dirNameInput); - builder.setTitle(R.string.uploader_info_dirname); - int typed_color = getResources().getColor(R.color.setup_text_typed); - dirNameInput.setTextColor(typed_color); - builder.setPositiveButton(android.R.string.ok, - new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - String directoryName = dirNameInput.getText().toString(); - if (directoryName.trim().length() == 0) { - dialog.cancel(); - return; - } - - // Figure out the path where the dir needs to be created - String path; - if (mCurrentDir == null) { - // this is just a patch; we should ensure that mCurrentDir never is null - if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) { - OCFile file = new OCFile(OCFile.PATH_SEPARATOR); - mStorageManager.saveFile(file); - } - mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); - } - path = FileDisplayActivity.this.mCurrentDir.getRemotePath(); - - // Create directory - path += directoryName + OCFile.PATH_SEPARATOR; - Thread thread = new Thread(new DirectoryCreator(path, a, new Handler())); - thread.start(); - - dialog.dismiss(); - - showDialog(DIALOG_SHORT_WAIT); - } - }); - builder.setNegativeButton(R.string.common_cancel, - new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - dialog = builder.create(); - break; - } - 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; - } - - - /** - * Responds to the "There are no ownCloud Accounts setup" dialog - * TODO: Dialog is 100% useless -> Remove - */ - @Override - public void onClick(DialogInterface dialog, int which) { - // In any case - we won't need it anymore - dialog.dismiss(); - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", - new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); - break; - case DialogInterface.BUTTON_NEGATIVE: - finish(); - } - - } - - /** - * Translates a content URI of an image to a physical path - * on the disk - * @param uri The URI to resolve - * @return The path to the image or null if it could not be found - */ - public String getPath(Uri uri) { - String[] projection = { MediaStore.Images.Media.DATA }; - Cursor cursor = managedQuery(uri, projection, null, null, null); - if (cursor != null) { - int column_index = cursor - .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - cursor.moveToFirst(); - return cursor.getString(column_index); - } - return null; - } - - /** - * Pushes a directory to the drop down list - * @param directory to push - * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false. - */ - public void pushDirname(OCFile directory) { - if(!directory.isDirectory()){ - throw new IllegalArgumentException("Only directories may be pushed!"); - } - mDirectories.insert(directory.getFileName(), 0); - mCurrentDir = directory; - } - - /** - * Pops a directory name from the drop down list - * @return True, unless the stack is empty - */ - public boolean popDirname() { - mDirectories.remove(mDirectories.getItem(0)); - return !mDirectories.isEmpty(); - } - - private class DirectoryCreator implements Runnable { - private String mTargetPath; - private Account mAccount; - private AccountManager mAm; - private Handler mHandler; - - public DirectoryCreator(String targetPath, Account account, Handler handler) { - mTargetPath = targetPath; - mAccount = account; - mAm = (AccountManager) getSystemService(ACCOUNT_SERVICE); - mHandler = handler; - } - - @Override - public void run() { - WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); - - String username = mAccount.name.substring(0, - mAccount.name.lastIndexOf('@')); - String password = mAm.getPassword(mAccount); - - wdc.setCredentials(username, password); - wdc.allowSelfsignedCertificates(); - boolean created = wdc.createDirectory(mTargetPath); - if (created) { - mHandler.post(new Runnable() { - @Override - public void run() { - dismissDialog(DIALOG_SHORT_WAIT); - - // Save new directory in local database - OCFile newDir = new OCFile(mTargetPath); - newDir.setMimetype("DIR"); - newDir.setParentId(mCurrentDir.getFileId()); - mStorageManager.saveFile(newDir); - - // Display the new folder right away - mFileList.listDirectory(mCurrentDir); - } - }); - - } else { - mHandler.post(new Runnable() { - @Override - public void run() { - dismissDialog(DIALOG_SHORT_WAIT); - try { - Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); - msg.show(); - - } catch (NotFoundException e) { - Log.e(TAG, "Error while trying to show fail message " , e); - } - } - }); - } - } - - } - - // Custom array adapter to override text colors - private class CustomArrayAdapter extends ArrayAdapter { - - public CustomArrayAdapter(FileDisplayActivity ctx, int view) { - super(ctx, view); - } - - public View getView(int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - - ((TextView) v).setTextColor(getResources().getColorStateList( - android.R.color.white)); - return v; - } - - public View getDropDownView(int position, View convertView, - ViewGroup parent) { - View v = super.getDropDownView(position, convertView, parent); - - ((TextView) v).setTextColor(getResources().getColorStateList( - android.R.color.white)); - - return v; - } - - } - - private class SyncBroadcastReceiver extends BroadcastReceiver { - /** - * {@link BroadcastReceiver} to enable syncing feedback in UI - */ - @Override - public void onReceive(Context context, Intent intent) { - 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); - - if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { - - String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); - - boolean fillBlankRoot = false; - if (mCurrentDir == null) { - mCurrentDir = mStorageManager.getFileByPath("/"); - fillBlankRoot = (mCurrentDir != null); - } - - if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath))) - || fillBlankRoot ) { - if (!fillBlankRoot) - mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath); - FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager() - .findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(mCurrentDir); - } - } - - setSupportProgressBarIndeterminateVisibility(inProgress); - - } - } - } - - - private class UploadFinishReceiver extends BroadcastReceiver { - /** - * Once the file upload has finished -> update view - * @author David A. Velasco - * {@link BroadcastReceiver} to enable upload feedback in UI - */ - @Override - public void onReceive(Context context, Intent intent) { - long parentDirId = intent.getLongExtra(FileUploader.EXTRA_PARENT_DIR_ID, -1); - OCFile parentDir = mStorageManager.getFileById(parentDirId); - String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); - - if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) && - parentDir != null && - ( (mCurrentDir == null && parentDir.getFileName().equals("/")) || - parentDir.equals(mCurrentDir) - ) - ) { - FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - } - } - } - - } - - - /** - * Once the file download has finished -> update view - */ - private class DownloadFinishReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); - String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); - - if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) && - mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) { - FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - } - } - } - } - - - @Override - public void onClick(View v) { - if (v.getId() == R.id.setup_account) { - Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); - intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); - mForcedLoginToCreateFirstAccount = true; - } - } - - - - - - /** - * {@inheritDoc} - */ - @Override - public DataStorageManager getStorageManager() { - return mStorageManager; - } - - - /** - * {@inheritDoc} - */ - @Override - public void onDirectoryClick(OCFile directory) { - pushDirname(directory); - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - - if (mDualPane) { - // Resets the FileDetailsFragment on Tablets so that it always displays - FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); - if (fileDetails != null) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.remove(fileDetails); - transaction.add(R.id.file_details_container, new FileDetailFragment(null, null)); - transaction.commit(); - } - } - } - - - /** - * {@inheritDoc} - */ - @Override - public void onFileClick(OCFile file) { - - // If we are on a large device -> update fragment - if (mDualPane) { - // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous' - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); - transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - transaction.commit(); - - } else { // small or medium screen device -> new Activity - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); - showDetailsIntent.putExtra(FileDownloader.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); - startActivity(showDetailsIntent); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public void onFileStateChanged() { - FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - } - } - - - /** - * Operations in this method should be preferably performed in onCreate to have a lighter onResume method. - * - * But we need to delay them to onResume for the first start of the application, when no account exists and the login activity must be shown; and - * put instead the ugly view that shows the 'Setup' button to restart the login activity. - * - * In other way, if the users cancels or presses BACK in the login page that first time (users can be cruel sometimes) would show a blank view (the - * FragmentList view empty). - * - * This is temporal, until we found out how to get a result in this activity after launching the ADD_ACCOUNT Intent with startActivityForResult (not trivial) - */ - private void initDelayedTilAccountAvailabe() { - setContentView(mLayoutView); - mDualPane = (findViewById(R.id.file_details_container) != null); - if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment - transaction.commit(); - } - setSupportProgressBarIndeterminateVisibility(false); - } - - - /** - * Launch an intent to request the PIN code to the user before letting him use the app - */ - private void requestPinCode() { - boolean pinStart = false; - SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - pinStart = appPrefs.getBoolean("set_pincode", false); - if (pinStart) { - Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); - i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity"); - startActivity(i); - } - } - - -} diff --git a/src/eu/alefzero/owncloud/ui/activity/LandingActivity.java b/src/eu/alefzero/owncloud/ui/activity/LandingActivity.java deleted file mode 100644 index d40d8d75..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/LandingActivity.java +++ /dev/null @@ -1,158 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.activity; - -import com.actionbarsherlock.app.SherlockFragmentActivity; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.GridView; -import android.widget.Toast; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.ui.adapter.LandingScreenAdapter; - -/** - * This activity is used as a landing page when the user first opens this app. - * - * @author Lennart Rosam - * - */ -public class LandingActivity extends SherlockFragmentActivity implements - OnClickListener, OnItemClickListener { - - public static final int DIALOG_SETUP_ACCOUNT = 1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - // Fill the grid view of the landing screen with icons - GridView landingScreenItems = (GridView) findViewById(R.id.homeScreenGrid); - landingScreenItems.setAdapter(new LandingScreenAdapter(this)); - landingScreenItems.setOnItemClickListener(this); - - // Check, if there are ownCloud accounts - if (!accountsAreSetup()) { - showDialog(DIALOG_SETUP_ACCOUNT); - } else { - // Start device tracking service - Intent locationServiceIntent = new Intent(); - locationServiceIntent - .setAction("eu.alefzero.owncloud.location.LocationLauncher"); - sendBroadcast(locationServiceIntent); - } - - } - - @Override - protected void onRestart() { - super.onRestart(); - // Check, if there are ownCloud accounts - if (!accountsAreSetup()) { - showDialog(DIALOG_SETUP_ACCOUNT); - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - // Check, if there are ownCloud accounts - if (!accountsAreSetup()) { - showDialog(DIALOG_SETUP_ACCOUNT); - } - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog; - switch (id) { - case DIALOG_SETUP_ACCOUNT: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.main_tit_accsetup); - builder.setMessage(R.string.main_wrn_accsetup); - builder.setCancelable(false); - builder.setPositiveButton(R.string.common_ok, this); - builder.setNegativeButton(R.string.common_cancel, this); - dialog = builder.create(); - break; - default: - dialog = null; - } - - return dialog; - } - - public void onClick(DialogInterface dialog, int which) { - // In any case - we won't need it anymore - dialog.dismiss(); - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", - new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); - break; - case DialogInterface.BUTTON_NEGATIVE: - finish(); - } - - } - - @Override - /** - * Start an activity based on the selection - * the user made - */ - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Intent intent; - intent = (Intent) parent.getAdapter().getItem(position); - if (intent != null) { - startActivity(intent); - } else { - // TODO: Implement all of this and make this text go away ;-) - Toast toast = Toast.makeText(this, "Not yet implemented!", - Toast.LENGTH_SHORT); - toast.show(); - } - } - - /** - * Checks, whether or not there are any ownCloud accounts setup. - * - * @return true, if there is at least one account. - */ - private boolean accountsAreSetup() { - AccountManager accMan = AccountManager.get(this); - Account[] accounts = accMan - .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - return accounts.length > 0; - } - -} diff --git a/src/eu/alefzero/owncloud/ui/activity/PinCodeActivity.java b/src/eu/alefzero/owncloud/ui/activity/PinCodeActivity.java deleted file mode 100644 index 5fd7213a..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/PinCodeActivity.java +++ /dev/null @@ -1,653 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.activity; - -import java.util.Arrays; - -import com.actionbarsherlock.app.SherlockFragmentActivity; - -import eu.alefzero.owncloud.R; - - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Typeface; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.text.method.PasswordTransformationMethod; -import android.view.KeyEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; -import android.view.View.OnKeyListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.EditText; -import android.widget.TextView; - - -public class PinCodeActivity extends SherlockFragmentActivity { - - - public final static String EXTRA_ACTIVITY = "eu.alefzero.owncloud.ui.activity.PinCodeActivity.ACTIVITY"; - public final static String EXTRA_NEW_STATE = "eu.alefzero.owncloud.ui.activity.PinCodeActivity.NEW_STATE"; - - Button bCancel; - TextView mPinHdr; - EditText mText1; - EditText mText2; - EditText mText3; - EditText mText4; - - String [] tempText ={"","","",""}; - - String activity; - - boolean confirmingPinCode = false; - boolean pinCodeChecked = false; - boolean newPasswordEntered = false; - boolean bChange = true; // to control that only one blocks jump - int tCounter ; // Count the number of attempts an user could introduce the PIN code - - - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.pincodelock); - - Intent intent = getIntent(); - activity = intent.getStringExtra(EXTRA_ACTIVITY); - - bCancel = (Button) findViewById(R.id.cancel); - mPinHdr = (TextView) findViewById(R.id.pinHdr); - mText1 = (EditText) findViewById(R.id.txt1); - mText1.requestFocus(); - getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - mText2 = (EditText) findViewById(R.id.txt2); - mText3 = (EditText) findViewById(R.id.txt3); - mText4 = (EditText) findViewById(R.id.txt4); - - - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - - // Not PIN Code defined yet. - // In a previous version settings is allow from start - if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){ - setChangePincodeView(true); - pinCodeChecked = true; - newPasswordEntered = true; - - }else{ - - if (appPrefs.getBoolean("set_pincode", false)){ - // pincode activated - if (activity.equals("preferences")){ - // PIN has been activated yet - mPinHdr.setText(R.string.pincode_configure_your_pin); - pinCodeChecked = true ; // No need to check it - setChangePincodeView(true); - }else{ - // PIN active - bCancel.setVisibility(View.INVISIBLE); - bCancel.setVisibility(View.GONE); - mPinHdr.setText(R.string.pincode_enter_pin_code); - setChangePincodeView(false); - } - - }else { - // pincode removal - mPinHdr.setText(R.string.pincode_remove_your_pincode); - pinCodeChecked = false; - setChangePincodeView(true); - } - - } - setTextListeners(); - - - } - - - - protected void setInitVars(){ - confirmingPinCode = false; - pinCodeChecked = false; - newPasswordEntered = false; - - } - - protected void setInitView(){ - bCancel.setVisibility(View.INVISIBLE); - bCancel.setVisibility(View.GONE); - mPinHdr.setText(R.string.pincode_enter_pin_code); - } - - - protected void setChangePincodeView(boolean state){ - - if(state){ - bCancel.setVisibility(View.VISIBLE); - bCancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - - SharedPreferences.Editor appPrefsE = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - boolean state = appPrefs.getBoolean("set_pincode", false); - appPrefsE.putBoolean("set_pincode",!state); - appPrefsE.commit(); - setInitVars(); - finish(); - } - }); - } - - } - - - - /* - * - */ - protected void setTextListeners(){ - - /*------------------------------------------------ - * FIRST BOX - -------------------------------------------------*/ - - mText1.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - if (!confirmingPinCode){ - tempText[0] = mText1.getText().toString(); - - } - mText2.requestFocus(); - } - } - }); - - - - /*------------------------------------------------ - * SECOND BOX - -------------------------------------------------*/ - mText2.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - if (!confirmingPinCode){ - tempText[1] = mText2.getText().toString(); - } - - mText3.requestFocus(); - } - } - }); - - mText2.setOnKeyListener(new OnKeyListener() { - - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - // TODO Auto-generated method stub - - if (keyCode == KeyEvent.KEYCODE_DEL && bChange) { - - mText1.setText(""); - mText1.requestFocus(); - if (!confirmingPinCode) - tempText[0] = ""; - bChange= false; - - }else if(!bChange){ - bChange=true; - - } - return false; - } - }); - - mText2.setOnFocusChangeListener(new OnFocusChangeListener() { - - @Override - public void onFocusChange(View v, boolean hasFocus) { - // TODO Auto-generated method stub - - mText2.setCursorVisible(true); - if (mText1.getText().toString().equals("")){ - mText2.setSelected(false); - mText2.setCursorVisible(false); - mText1.requestFocus(); - mText1.setSelected(true); - mText1.setSelection(0); - } - - } - }); - - - /*------------------------------------------------ - * THIRD BOX - -------------------------------------------------*/ - mText3.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - if (!confirmingPinCode){ - tempText[2] = mText3.getText().toString(); - } - mText4.requestFocus(); - } - } - }); - - mText3.setOnKeyListener(new OnKeyListener() { - - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - // TODO Auto-generated method stub - - if (keyCode == KeyEvent.KEYCODE_DEL && bChange) { - mText2.requestFocus(); - if (!confirmingPinCode) - tempText[1] = ""; - mText2.setText(""); - bChange= false; - - }else if(!bChange){ - bChange=true; - - } - return false; - } - }); - - mText3.setOnFocusChangeListener(new OnFocusChangeListener() { - - @Override - public void onFocusChange(View v, boolean hasFocus) { - // TODO Auto-generated method stub - mText3.setCursorVisible(true); - if (mText1.getText().toString().equals("")){ - mText3.setSelected(false); - mText3.setCursorVisible(false); - mText1.requestFocus(); - mText1.setSelected(true); - mText1.setSelection(0); - }else if (mText2.getText().toString().equals("")){ - mText3.setSelected(false); - mText3.setCursorVisible(false); - mText2.requestFocus(); - mText2.setSelected(true); - mText2.setSelection(0); - } - - } - }); - - /*------------------------------------------------ - * FOURTH BOX - -------------------------------------------------*/ - mText4.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - - if (!confirmingPinCode){ - tempText[3] = mText4.getText().toString(); - } - mText1.requestFocus(); - - if (!pinCodeChecked){ - pinCodeChecked = checkPincode(); - } - - if (pinCodeChecked && activity.equals("FileDisplayActivity")){ - finish(); - } else if (pinCodeChecked){ - - Intent intent = getIntent(); - String newState = intent.getStringExtra(EXTRA_NEW_STATE); - - if (newState.equals("false")){ - SharedPreferences.Editor appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - appPrefs.putBoolean("set_pincode",false); - appPrefs.commit(); - - setInitVars(); - pinCodeEnd(false); - - }else{ - - if (!confirmingPinCode){ - pinCodeChangeRequest(); - - } else { - confirmPincode(); - } - } - - - } - } - } - }); - - - - mText4.setOnKeyListener(new OnKeyListener() { - - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - // TODO Auto-generated method stub - - if (keyCode == KeyEvent.KEYCODE_DEL && bChange) { - mText3.requestFocus(); - if (!confirmingPinCode) - tempText[2]=""; - mText3.setText(""); - bChange= false; - - }else if(!bChange){ - bChange=true; - } - return false; - } - }); - - mText4.setOnFocusChangeListener(new OnFocusChangeListener() { - - @Override - public void onFocusChange(View v, boolean hasFocus) { - // TODO Auto-generated method stub - - mText4.setCursorVisible(true); - - if (mText1.getText().toString().equals("")){ - mText4.setSelected(false); - mText4.setCursorVisible(false); - mText1.requestFocus(); - mText1.setSelected(true); - mText1.setSelection(0); - }else if (mText2.getText().toString().equals("")){ - mText4.setSelected(false); - mText4.setCursorVisible(false); - mText2.requestFocus(); - mText2.setSelected(true); - mText2.setSelection(0); - }else if (mText3.getText().toString().equals("")){ - mText4.setSelected(false); - mText4.setCursorVisible(false); - mText3.requestFocus(); - mText3.setSelected(true); - mText3.setSelection(0); - } - - } - }); - - - - } // end setTextListener - - - protected void pinCodeChangeRequest(){ - - clearBoxes(); - mPinHdr.setText(R.string.pincode_reenter_your_pincode); - confirmingPinCode =true; - - } - - - protected boolean checkPincode(){ - - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - String pText1 = appPrefs.getString("PrefPinCode1", null); - String pText2 = appPrefs.getString("PrefPinCode2", null); - String pText3 = appPrefs.getString("PrefPinCode3", null); - String pText4 = appPrefs.getString("PrefPinCode4", null); - - if ( tempText[0].equals(pText1) && - tempText[1].equals(pText2) && - tempText[2].equals(pText3) && - tempText[3].equals(pText4) ) { - - return true; - - - }else { - Arrays.fill(tempText, null); - AlertDialog aDialog = new AlertDialog.Builder(this).create(); - CharSequence errorSeq = getString(R.string.common_error); - aDialog.setTitle(errorSeq); - CharSequence cseq = getString(R.string.pincode_wrong); - aDialog.setMessage(cseq); - CharSequence okSeq = getString(R.string.common_ok); - aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface dialog, int which) { - // TODO Auto-generated method stub(""); - return; - } - - }); - aDialog.show(); - clearBoxes(); - mPinHdr.setText(R.string.pincode_enter_pin_code); - newPasswordEntered = true; - confirmingPinCode = false; - - } - - - return false; - } - - protected void confirmPincode(){ - - confirmingPinCode = false; - - String rText1 = mText1.getText().toString(); - String rText2 = mText2.getText().toString(); - String rText3 = mText3.getText().toString(); - String rText4 = mText4.getText().toString(); - - if ( tempText[0].equals(rText1) && - tempText[1].equals(rText2) && - tempText[2].equals(rText3) && - tempText[3].equals(rText4) ) { - - savePincodeAndExit(); - - } else { - - Arrays.fill(tempText, null); - AlertDialog aDialog = new AlertDialog.Builder(this).create(); - CharSequence errorSeq = getString(R.string.common_error); - aDialog.setTitle(errorSeq); - CharSequence cseq = getString(R.string.pincode_mismatch); - aDialog.setMessage(cseq); - CharSequence okSeq = getString(R.string.common_ok); - aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface dialog, int which) { - // TODO Auto-generated method stub(""); - return; - } - - }); - aDialog.show(); - mPinHdr.setText(R.string.pincode_configure_your_pin); - clearBoxes(); - } - - } - - - protected void pinCodeEnd(boolean state){ - AlertDialog aDialog = new AlertDialog.Builder(this).create(); - - if (state){ - CharSequence saveSeq = getString(R.string.common_save_exit); - aDialog.setTitle(saveSeq); - CharSequence cseq = getString(R.string.pincode_stored); - aDialog.setMessage(cseq); - - }else{ - CharSequence saveSeq = getString(R.string.common_save_exit); - aDialog.setTitle(saveSeq); - CharSequence cseq = getString(R.string.pincode_removed); - aDialog.setMessage(cseq); - - } - CharSequence okSeq = getString(R.string.common_ok); - aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){ - - @Override - public void onClick(DialogInterface dialog, int which) { - // TODO Auto-generated method stub(""); - finish(); - return; - } - - }); - aDialog.show(); - } - - protected void savePincodeAndExit(){ - SharedPreferences.Editor appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - - appPrefs.putString("PrefPinCode1", tempText[0]); - appPrefs.putString("PrefPinCode2",tempText[1]); - appPrefs.putString("PrefPinCode3", tempText[2]); - appPrefs.putString("PrefPinCode4", tempText[3]); - appPrefs.putBoolean("set_pincode",true); - appPrefs.commit(); - - pinCodeEnd(true); - - - - } - - - protected void clearBoxes(){ - - mText1.setText(""); - mText2.setText(""); - mText3.setText(""); - mText4.setText(""); - mText1.requestFocus(); - } - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event){ - if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){ - - if (activity.equals("preferences")){ - SharedPreferences.Editor appPrefsE = PreferenceManager - - .getDefaultSharedPreferences(getApplicationContext()).edit(); - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - boolean state = appPrefs.getBoolean("set_pincode", false); - appPrefsE.putBoolean("set_pincode",!state); - appPrefsE.commit(); - setInitVars(); - finish(); - } - return true; - - } - - return super.onKeyDown(keyCode, event); - } - - - - - -} diff --git a/src/eu/alefzero/owncloud/ui/activity/Preferences.java b/src/eu/alefzero/owncloud/ui/activity/Preferences.java deleted file mode 100644 index c2173956..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/Preferences.java +++ /dev/null @@ -1,240 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.activity; - -import java.util.Vector; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceManager; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.Preference.OnPreferenceClickListener; -import android.util.Log; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockPreferenceActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuItem; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.OwnCloudSession; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.DbHandler; - -/** - * An Activity that allows the user to change the application's settings. - * - * @author Bartek Przybylski - * - */ -public class Preferences extends SherlockPreferenceActivity implements - OnPreferenceChangeListener{ - private static final String TAG = "OwnCloudPreferences"; - private final int mNewSession = 47; - private final int mEditSession = 48; - private DbHandler mDbHandler; - private Vector mSessions; - //private Account[] mAccounts; - //private ListPreference mAccountList; - private ListPreference mTrackingUpdateInterval; - private CheckBoxPreference mDeviceTracking; - private CheckBoxPreference pCode; - private int mSelectedMenuItem; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mDbHandler = new DbHandler(getBaseContext()); - mSessions = new Vector(); - addPreferencesFromResource(R.xml.preferences); - //populateAccountList(); - ActionBar actionBar = getSherlock().getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - Preference p = findPreference("manage_account"); - if (p != null) - p.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class); - startActivity(i); - return true; - } - }); - - pCode = (CheckBoxPreference) findPreference("set_pincode"); - - - if (pCode != null){ - - pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - - Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); - i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences"); - i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString()); - - startActivity(i); - - return true; - } - }); - - } - - } - - - @Override - protected void onResume() { - // TODO Auto-generated method stub - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - boolean state = appPrefs.getBoolean("set_pincode", false); - pCode.setChecked(state); - - super.onResume(); - } - - - - /** - * Populates the account selector - *-/ - private void populateAccountList() { - AccountManager accMan = AccountManager.get(this); - mAccounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - mAccountList = (ListPreference) findPreference("select_oc_account"); - mAccountList.setOnPreferenceChangeListener(this); - - // Display the name of the current account if there is any - Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this); - if (defaultAccount != null) { - mAccountList.setSummary(defaultAccount.name); - } - - // Transform accounts into array of string for preferences to use - String[] accNames = new String[mAccounts.length]; - for (int i = 0; i < mAccounts.length; i++) { - Account account = mAccounts[i]; - accNames[i] = account.name; - } - - mAccountList.setEntries(accNames); - mAccountList.setEntryValues(accNames); - }*/ - - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - //MenuInflater inflater = getSherlock().getMenuInflater(); - //inflater.inflate(R.menu.prefs_menu, menu); - return true; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - super.onMenuItemSelected(featureId, item); - Intent intent; - - switch (item.getItemId()) { - //case R.id.addSessionItem: - case 1: - intent = new Intent(this, PreferencesNewSession.class); - startActivityForResult(intent, mNewSession); - break; - case R.id.SessionContextEdit: - intent = new Intent(this, PreferencesNewSession.class); - intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem) - .getEntryId()); - intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem) - .getName()); - intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem) - .getUrl()); - startActivityForResult(intent, mEditSession); - break; - case android.R.id.home: - intent = new Intent(getBaseContext(), FileDisplayActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - break; - default: - Log.w(TAG, "Unknown menu item triggered"); - return false; - } - return true; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onDestroy() { - mDbHandler.close(); - super.onDestroy(); - } - - - - @Override - /** - * Updates various summaries after updates. Also starts and stops - * the - */ - public boolean onPreferenceChange(Preference preference, Object newValue) { - // Update current account summary - /*if (preference.equals(mAccountList)) { - mAccountList.setSummary(newValue.toString()); - } - - // Update tracking interval summary - else*/ if (preference.equals(mTrackingUpdateInterval)) { - String trackingSummary = getResources().getString( - R.string.prefs_trackmydevice_interval_summary); - trackingSummary = String.format(trackingSummary, - newValue.toString()); - mTrackingUpdateInterval.setSummary(trackingSummary); - } - - // Start or stop tracking service - else if (preference.equals(mDeviceTracking)) { - Intent locationServiceIntent = new Intent(); - locationServiceIntent - .setAction("eu.alefzero.owncloud.location.LocationLauncher"); - locationServiceIntent.putExtra("TRACKING_SETTING", - (Boolean) newValue); - sendBroadcast(locationServiceIntent); - } - return true; - } - - - -} diff --git a/src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java b/src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java deleted file mode 100644 index 35d65dae..00000000 --- a/src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java +++ /dev/null @@ -1,98 +0,0 @@ -package eu.alefzero.owncloud.ui.activity; - -import android.accounts.AccountAuthenticatorActivity; -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; - -public class PreferencesNewSession extends AccountAuthenticatorActivity - implements OnClickListener { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // setContentView(R.layout.add_new_session); - /* - * EditText et;// = (EditText) - * findViewById(R.id.newSession_sessionName); - * - * et = (EditText) findViewById(R.id.newSession_URL); if - * (getIntent().hasExtra("sessionURL")) { try { URI uri = new - * URI(getIntent().getStringExtra("sessionURL")); String url = - * uri.getHost(); if (uri.getPort() != -1) { url += ":" + - * String.valueOf(uri.getPort()); } if (uri.getPath() != null) { url += - * uri.getPath(); } else { url += "/"; } et.setText(url); et = - * (EditText) findViewById(R.id.newSession_username); if - * (uri.getAuthority() != null) { if (uri.getUserInfo().indexOf(':') != - * -1) { et.setText(uri.getUserInfo().substring(0, - * uri.getUserInfo().indexOf(':'))); et = (EditText) - * findViewById(R.id.newSession_password); - * et.setText(uri.getUserInfo().substring - * (uri.getUserInfo().indexOf(':')+1)); } else { - * et.setText(uri.getUserInfo()); } } - * - * } catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " + - * e.getLocalizedMessage()); } } - * - * mReturnData = new Intent(); setResult(Activity.RESULT_OK, - * mReturnData); ((Button) - * findViewById(R.id.button1)).setOnClickListener(this); ((Button) - * findViewById(R.id.button2)).setOnClickListener(this); - */ - } - - @Override - protected void onResume() { - super.onResume(); - } - - public void onClick(View v) { - /* - * switch (v.getId()) { case R.id.button1: Intent intent = new Intent(); - * if (getIntent().hasExtra("sessionId")) { intent.putExtra("sessionId", - * getIntent().getIntExtra("sessionId", -1)); } //String sessionName = - * ((EditText) - * findViewById(R.id.newSession_sessionName)).getText().toString(); // - * if (sessionName.trim().equals("") || !isNameValid(sessionName)) { // - * Toast.makeText(this, R.string.new_session_session_name_error, - * Toast.LENGTH_LONG).show(); // break; // } URI uri = prepareURI(); if - * (uri != null) { //intent.putExtra("sessionName", sessionName); - * intent.putExtra("sessionURL", uri.toString()); - * setResult(Activity.RESULT_OK, intent); AccountManager accMgr = - * AccountManager.get(this); Account a = new Account("OwnCloud", - * AccountAuthenticatorService.ACCOUNT_TYPE); - * accMgr.addAccountExplicitly(a, "asd", null); finish(); } break; case - * R.id.button2: setResult(Activity.RESULT_CANCELED); finish(); break; } - */ - } - - /* - * private URI prepareURI() { URI uri = null; String url = ""; try { String - * username = ((EditText) - * findViewById(R.id.newSession_username)).getText().toString().trim(); - * String password = ((EditText) - * findViewById(R.id.newSession_password)).getText().toString().trim(); - * String hostname = ((EditText) - * findViewById(R.id.newSession_URL)).getText().toString().trim(); String - * scheme; if (hostname.matches("[A-Za-z]://")) { scheme = - * hostname.substring(0, hostname.indexOf("://")+3); hostname = - * hostname.substring(hostname.indexOf("://")+3); } else { scheme = - * "http://"; } if (!username.equals("")) { if (!password.equals("")) { - * username += ":" + password + "@"; } else { username += "@"; } } url = - * scheme + username + hostname; Log.i(TAG, url); uri = new URI(url); } - * catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " + - * e.getLocalizedMessage()); Toast.makeText(this, - * R.string.new_session_uri_error, Toast.LENGTH_LONG).show(); } return uri; - * } - * - * private boolean isNameValid(String string) { return - * string.matches("[A-Za-z0-9 _-]*"); } - */ - - @Override - public void onBackPressed() { - setResult(Activity.RESULT_CANCELED); - super.onBackPressed(); - } - -} diff --git a/src/eu/alefzero/owncloud/ui/adapter/FileListActionListAdapter.java b/src/eu/alefzero/owncloud/ui/adapter/FileListActionListAdapter.java deleted file mode 100644 index 1556e0d8..00000000 --- a/src/eu/alefzero/owncloud/ui/adapter/FileListActionListAdapter.java +++ /dev/null @@ -1,172 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.ui.adapter; - -import java.io.File; - -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.webdav.WebdavUtils; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.net.Uri; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.TextView; - -public class FileListActionListAdapter implements ListAdapter { - - private Context mContext; - private Account mAccount; - private String mFilename, mFileType, mFilePath, mFileStoragePath; - - private final int ITEM_DOWNLOAD = 0; - - // private final int ITEM_SHARE = 1; - - public FileListActionListAdapter(Cursor c, Context co, Account account) { - mContext = co; - mFilename = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_NAME)); - mFileType = c.getString(c - .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)); - mFilePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH)); - mFileStoragePath = c.getString(c - .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)); - // mItemId = c.getString(c.getColumnIndex(ProviderTableMeta._ID)); - mAccount = account; - } - - public boolean areAllItemsEnabled() { - // TODO Auto-generated method stub - return true; - } - - public boolean isEnabled(int position) { - // TODO Auto-generated method stub - return true; - } - - public int getCount() { - // TODO Auto-generated method stub - return 1; - } - - public Object getItem(int position) { - if (position == 0) { - Intent intent = new Intent(Intent.ACTION_VIEW); - if (TextUtils.isEmpty(mFileStoragePath)) { - intent.putExtra("toDownload", true); - AccountManager accm = (AccountManager) mContext - .getSystemService(Context.ACCOUNT_SERVICE); - String ocurl = accm.getUserData(mAccount, - AccountAuthenticator.KEY_OC_URL); - ocurl += WebdavUtils.encodePath(mFilePath + mFilename); - intent.setData(Uri.parse(ocurl)); - } else { - intent.putExtra("toDownload", false); - intent.setDataAndType(Uri.fromFile(new File(mFileStoragePath)), - mFileType); - } - return intent; - } - return null; - } - - public long getItemId(int position) { - // TODO Auto-generated method stub - return 0; - } - - public int getItemViewType(int position) { - // TODO Auto-generated method stub - return 0; - } - - public View getView(int position, View convertView, ViewGroup parent) { - View v = convertView; - if (v == null) { - LayoutInflater vi = (LayoutInflater) mContext - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - v = vi.inflate(R.layout.file_display_action_list_element, null); - } - - TextView tv; - ImageView iv; - switch (position) { - case ITEM_DOWNLOAD: - tv = (TextView) v.findViewById(R.id.textView1); - if (mFileStoragePath == null) { - tv.setText("Download"); - } else { - setActionName(tv); - } - iv = (ImageView) v.findViewById(R.id.imageView1); - iv.setImageResource(R.drawable.download); - break; - } - - return v; - } - - public int getViewTypeCount() { - // TODO Auto-generated method stub - return 2; - } - - public boolean hasStableIds() { - // TODO Auto-generated method stub - return false; - } - - public boolean isEmpty() { - // TODO Auto-generated method stub - return false; - } - - public void registerDataSetObserver(DataSetObserver observer) { - // TODO Auto-generated method stub - - } - - public void unregisterDataSetObserver(DataSetObserver observer) { - // TODO Auto-generated method stub - - } - - private void setActionName(TextView tv) { - if (mFileType.matches("image/.*")) { - tv.setText("View"); - } else if (mFileType.matches("audio/.*") - || mFileType.matches("video/.*")) { - tv.setText("Play"); - } else { - tv.setText("Open"); - } - } - -} diff --git a/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java b/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java deleted file mode 100644 index 9ab68db4..00000000 --- a/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java +++ /dev/null @@ -1,201 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.adapter; - -import java.util.Vector; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.DisplayUtils; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.datamodel.DataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.services.FileDownloader; -import eu.alefzero.owncloud.files.services.FileUploader; - -import android.accounts.Account; -import android.content.Context; -import android.database.DataSetObserver; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.TextView; - -/** - * This Adapter populates a ListView with all files and folders in an ownCloud - * instance. - * - * @author Bartek Przybylski - * - */ -public class FileListListAdapter implements ListAdapter { - private Context mContext; - private OCFile mFile; - private Vector mFiles; - private DataStorageManager mStorageManager; - private Account mAccount; - - public FileListListAdapter(OCFile file, DataStorageManager storage_man, - Context context) { - mFile = file; - mStorageManager = storage_man; - mFiles = mStorageManager.getDirectoryContent(mFile); - mContext = context; - mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); - } - - @Override - public boolean areAllItemsEnabled() { - return true; - } - - @Override - public boolean isEnabled(int position) { - // TODO Auto-generated method stub - return true; - } - - @Override - public int getCount() { - return mFiles != null ? mFiles.size() : 0; - } - - @Override - public Object getItem(int position) { - if (mFiles.size() <= position) - return null; - return mFiles.get(position); - } - - @Override - public long getItemId(int position) { - return mFiles != null ? mFiles.get(position).getFileId() : 0; - } - - @Override - public int getItemViewType(int position) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View view = convertView; - if (view == null) { - LayoutInflater inflator = (LayoutInflater) mContext - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflator.inflate(R.layout.list_layout, null); - } - if (mFiles.size() > position) { - OCFile file = mFiles.get(position); - TextView fileName = (TextView) view.findViewById(R.id.Filename); - String name = file.getFileName(); - - fileName.setText(name); - ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1); - if (file.getMimetype() == null || !file.getMimetype().equals("DIR")) { - fileIcon.setImageResource(R.drawable.file); - } else { - fileIcon.setImageResource(R.drawable.ic_menu_archive); - } - ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2); - if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) { - localStateView.setImageResource(R.drawable.downloading_file_indicator); - localStateView.setVisibility(View.VISIBLE); - } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) { - localStateView.setImageResource(R.drawable.uploading_file_indicator); - localStateView.setVisibility(View.VISIBLE); - } else if (file.isDown()) { - localStateView.setImageResource(R.drawable.local_file_indicator); - localStateView.setVisibility(View.VISIBLE); - } else { - localStateView.setVisibility(View.INVISIBLE); - } - /* - ImageView down = (ImageView) view.findViewById(R.id.imageView2); - ImageView downloading = (ImageView) view.findViewById(R.id.imageView4); - ImageView uploading = (ImageView) view.findViewById(R.id.imageView5); - if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) { - down.setVisibility(View.INVISIBLE); - downloading.setVisibility(View.VISIBLE); - uploading.setVisibility(View.INVISIBLE); - } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) { - down.setVisibility(View.INVISIBLE); - downloading.setVisibility(View.INVISIBLE); - uploading.setVisibility(View.VISIBLE); - } else if (file.isDown()) { - down.setVisibility(View.VISIBLE); - downloading.setVisibility(View.INVISIBLE); - uploading.setVisibility(View.INVISIBLE); - } else { - down.setVisibility(View.INVISIBLE); - downloading.setVisibility(View.INVISIBLE); - uploading.setVisibility(View.INVISIBLE); - }*/ - - if (!file.isDirectory()) { - view.findViewById(R.id.file_size).setVisibility(View.VISIBLE); - view.findViewById(R.id.last_mod).setVisibility(View.VISIBLE); - ((TextView)view.findViewById(R.id.file_size)).setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); - ((TextView)view.findViewById(R.id.last_mod)).setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); - // this if-else is needed even thoe fav icon is visible by default - // because android reuses views in listview - if (!file.keepInSync()) { - view.findViewById(R.id.imageView3).setVisibility(View.GONE); - } else { - view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE); - } - } else { - view.findViewById(R.id.file_size).setVisibility(View.GONE); - view.findViewById(R.id.last_mod).setVisibility(View.GONE); - view.findViewById(R.id.imageView3).setVisibility(View.GONE); - } - } - - return view; - } - - @Override - public int getViewTypeCount() { - return 4; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public boolean isEmpty() { - return mFiles != null ? mFiles.isEmpty() : false; - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - // TODO Auto-generated method stub - - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - // TODO Auto-generated method stub - - } -} diff --git a/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java b/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java deleted file mode 100644 index 7128886c..00000000 --- a/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.adapter; - -import android.content.Context; -import android.content.Intent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.TextView; -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.ui.activity.FileDisplayActivity; -import eu.alefzero.owncloud.ui.activity.Preferences; - -/** - * Populates the landing screen icons. - * - * @author Lennart Rosam - * - */ -public class LandingScreenAdapter extends BaseAdapter { - - private Context mContext; - - private final Integer[] mLandingScreenIcons = { R.drawable.home, - R.drawable.music, R.drawable.contacts, R.drawable.calendar, - android.R.drawable.ic_menu_agenda, R.drawable.settings }; - - private final Integer[] mLandingScreenTexts = { R.string.main_files, - R.string.main_music, R.string.main_contacts, - R.string.main_calendar, R.string.main_bookmarks, - R.string.main_settings }; - - public LandingScreenAdapter(Context context) { - mContext = context; - } - - @Override - public int getCount() { - return mLandingScreenIcons.length; - } - - @Override - /** - * Returns the Intent associated with this object - * or null if the functionality is not yet implemented - */ - public Object getItem(int position) { - Intent intent = new Intent(); - - switch (position) { - case 0: - /* - * The FileDisplayActivity requires the ownCloud account as an - * parcableExtra. We will put in the one that is selected in the - * preferences - */ - intent.setClass(mContext, FileDisplayActivity.class); - intent.putExtra("ACCOUNT", - AccountUtils.getCurrentOwnCloudAccount(mContext)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - break; - case 5: - intent.setClass(mContext, Preferences.class); - break; - default: - intent = null; - } - return intent; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - LayoutInflater inflator = LayoutInflater.from(mContext); - convertView = inflator.inflate(R.layout.landing_page_item, null); - - ImageView icon = (ImageView) convertView - .findViewById(R.id.gridImage); - TextView iconText = (TextView) convertView - .findViewById(R.id.gridText); - - icon.setImageResource(mLandingScreenIcons[position]); - iconText.setText(mLandingScreenTexts[position]); - } - return convertView; - } -} diff --git a/src/eu/alefzero/owncloud/ui/fragment/AuthenticatorAccountDetailsFragment.java b/src/eu/alefzero/owncloud/ui/fragment/AuthenticatorAccountDetailsFragment.java deleted file mode 100644 index e17cf795..00000000 --- a/src/eu/alefzero/owncloud/ui/fragment/AuthenticatorAccountDetailsFragment.java +++ /dev/null @@ -1,7 +0,0 @@ -package eu.alefzero.owncloud.ui.fragment; - -import com.actionbarsherlock.app.SherlockFragment; - -public class AuthenticatorAccountDetailsFragment extends SherlockFragment { - -} diff --git a/src/eu/alefzero/owncloud/ui/fragment/AuthenticatorGetStartedFragment.java b/src/eu/alefzero/owncloud/ui/fragment/AuthenticatorGetStartedFragment.java deleted file mode 100644 index 84ef8875..00000000 --- a/src/eu/alefzero/owncloud/ui/fragment/AuthenticatorGetStartedFragment.java +++ /dev/null @@ -1,7 +0,0 @@ -package eu.alefzero.owncloud.ui.fragment; - -import com.actionbarsherlock.app.SherlockFragment; - -public class AuthenticatorGetStartedFragment extends SherlockFragment { - -} diff --git a/src/eu/alefzero/owncloud/ui/fragment/ConfirmationDialogFragment.java b/src/eu/alefzero/owncloud/ui/fragment/ConfirmationDialogFragment.java deleted file mode 100644 index cc6a0f7f..00000000 --- a/src/eu/alefzero/owncloud/ui/fragment/ConfirmationDialogFragment.java +++ /dev/null @@ -1,94 +0,0 @@ -package eu.alefzero.owncloud.ui.fragment; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.util.Log; - -import com.actionbarsherlock.app.SherlockDialogFragment; - -import eu.alefzero.owncloud.R; - -public class ConfirmationDialogFragment extends SherlockDialogFragment { - - public final static String ARG_CONF_RESOURCE_ID = "resource_id"; - public final static String ARG_CONF_ARGUMENTS = "string_array"; - - public final static String ARG_POSITIVE_BTN_RES = "positive_btn_res"; - public final static String ARG_NEUTRAL_BTN_RES = "neutral_btn_res"; - public final static String ARG_NEGATIVE_BTN_RES = "negative_btn_res"; - - private ConfirmationDialogFragmentListener mListener; - - public static ConfirmationDialogFragment newInstance(int string_id, String[] arguments, int posBtn, int neuBtn, int negBtn) { - ConfirmationDialogFragment frag = new ConfirmationDialogFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_CONF_RESOURCE_ID, string_id); - args.putStringArray(ARG_CONF_ARGUMENTS, arguments); - args.putInt(ARG_POSITIVE_BTN_RES, posBtn); - args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn); - args.putInt(ARG_NEGATIVE_BTN_RES, negBtn); - frag.setArguments(args); - return frag; - } - - public void setOnConfirmationListener(ConfirmationDialogFragmentListener listener) { - mListener = listener; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Object[] confirmationTarget = getArguments().getStringArray(ARG_CONF_ARGUMENTS); - int resourceId = getArguments().getInt(ARG_CONF_RESOURCE_ID, -1); - int posBtn = getArguments().getInt(ARG_POSITIVE_BTN_RES, -1); - int neuBtn = getArguments().getInt(ARG_NEUTRAL_BTN_RES, -1); - int negBtn = getArguments().getInt(ARG_NEGATIVE_BTN_RES, -1); - - if (confirmationTarget == null || resourceId == -1) { - Log.wtf(getTag(), "Calling confirmation dialog without resource or arguments"); - return null; - } - - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(String.format(getString(resourceId), confirmationTarget)) - .setTitle(android.R.string.dialog_alert_title); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - builder.setIconAttribute(android.R.attr.alertDialogIcon); - } - - if (posBtn != -1) - builder.setPositiveButton(posBtn, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mListener.onConfirmation(getTag()); - } - }); - if (neuBtn != -1) - builder.setNeutralButton(neuBtn, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mListener.onNeutral(getTag()); - } - }); - if (negBtn != -1) - builder.setNegativeButton(negBtn, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mListener.onCancel(getTag()); - } - }); - return builder.create(); - } - - - public interface ConfirmationDialogFragmentListener { - public void onConfirmation(String callerTag); - public void onNeutral(String callerTag); - public void onCancel(String callerTag); - } - -} - diff --git a/src/eu/alefzero/owncloud/ui/fragment/FileDetailFragment.java b/src/eu/alefzero/owncloud/ui/fragment/FileDetailFragment.java deleted file mode 100644 index f8f42061..00000000 --- a/src/eu/alefzero/owncloud/ui/fragment/FileDetailFragment.java +++ /dev/null @@ -1,1126 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.fragment; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.httpclient.HttpException; -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.DavMethodBase; -import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import org.json.JSONException; -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.content.res.Resources.NotFoundException; -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.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.view.WindowManager.LayoutParams; -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.SherlockDialogFragment; -import com.actionbarsherlock.app.SherlockFragment; - -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.DisplayUtils; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.datamodel.FileDataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.files.services.FileDownloader; -import eu.alefzero.owncloud.files.services.FileUploader; -import eu.alefzero.owncloud.ui.activity.FileDetailActivity; -import eu.alefzero.owncloud.ui.activity.FileDisplayActivity; -import eu.alefzero.owncloud.utils.OwnCloudVersion; -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 { - - 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 ImageView mPreview; - - private DownloadFinishReceiver mDownloadFinishReceiver; - private UploadFinishReceiver mUploadFinishReceiver; - - private static final String TAG = "FileDetailFragment"; - 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; - 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; - mLayout = R.layout.file_details_empty; - - if(fileToDetail != null && ocAccount != null) { - mLayout = R.layout.file_details_fragment; - } - } - - - /** - * {@inheritDoc} - */ - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mContainerActivity = (ContainerActivity) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity"); - } - } - - - @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); - } - - 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(); - return view; - } - - - @Override - public void onSaveInstanceState(Bundle outState) { - Log.i(getClass().toString(), "onSaveInstanceState() start"); - super.onSaveInstanceState(outState); - outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile); - outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount); - Log.i(getClass().toString(), "onSaveInstanceState() end"); - } - - - @Override - public void onResume() { - super.onResume(); - - mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter filter = new IntentFilter( - FileDownloader.DOWNLOAD_FINISH_MESSAGE); - getActivity().registerReceiver(mDownloadFinishReceiver, filter); - - mUploadFinishReceiver = new UploadFinishReceiver(); - filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); - getActivity().registerReceiver(mUploadFinishReceiver, filter); - - mPreview = (ImageView)mView.findViewById(R.id.fdPreview); - } - - @Override - public void onPause() { - super.onPause(); - - getActivity().unregisterReceiver(mDownloadFinishReceiver); - mDownloadFinishReceiver = null; - - getActivity().unregisterReceiver(mUploadFinishReceiver); - mUploadFinishReceiver = null; - - if (mPreview != null) { - mPreview = null; - } - } - - @Override - public View getView() { - return super.getView() == null ? mView : super.getView(); - } - - - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.fdDownloadBtn: { - Intent i = new Intent(getActivity(), FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); - i.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mFile.getRemotePath()); - i.putExtra(FileDownloader.EXTRA_FILE_PATH, mFile.getRemotePath()); - i.putExtra(FileDownloader.EXTRA_FILE_SIZE, mFile.getFileLength()); - - // update ui - setButtonsForTransferring(); - - getActivity().startService(i); - mContainerActivity.onFileStateChanged(); // this is not working; it is performed before the fileDownloadService registers it as 'in progress' - break; - } - case R.id.fdKeepInSync: { - CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync); - mFile.setKeepInSync(cb.isChecked()); - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver()); - fdsm.saveFile(mFile); - if (mFile.keepInSync()) { - onClick(getView().findViewById(R.id.fdDownloadBtn)); - } else { - mContainerActivity.onFileStateChanged(); // put inside 'else' to not call it twice (here, and in the virtual click on fdDownloadBtn) - } - break; - } - case R.id.fdRenameBtn: { - EditNameFragment dialog = EditNameFragment.newInstance(mFile.getFileName()); - dialog.show(getFragmentManager(), "nameeditdialog"); - dialog.setOnDismissListener(this); - 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); - confDialog.show(getFragmentManager(), FTAG_CONFIRMATION); - break; - } - case R.id.fdOpenBtn: { - String storagePath = mFile.getStoragePath(); - String encodedStoragePath = WebdavUtils.encodePath(storagePath); - try { - Intent i = new Intent(Intent.ACTION_VIEW); - i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype()); - i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - startActivity(i); - - } catch (Throwable t) { - Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype()); - boolean toastIt = true; - String mimeType = ""; - try { - Intent i = new Intent(Intent.ACTION_VIEW); - mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1)); - if (mimeType != null && !mimeType.equals(mFile.getMimetype())) { - i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType); - i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - startActivity(i); - toastIt = false; - } - - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath); - - } catch (ActivityNotFoundException e) { - Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension"); - - } catch (Throwable th) { - Log.e(TAG, "Unexpected problem when opening: " + storagePath, th); - - } finally { - if (toastIt) { - Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show(); - } - } - - } - break; - } - default: - Log.e(TAG, "Incorrect view clicked!"); - } - - /* else if (v.getId() == R.id.fdShareBtn) { - Thread t = new Thread(new ShareRunnable(mFile.getRemotePath())); - t.start(); - }*/ - } - - - @Override - public void onConfirmation(String callerTag) { - if (callerTag.equals(FTAG_CONFIRMATION)) { - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); - if (fdsm.getFileById(mFile.getFileId()) != null) { - new Thread(new RemoveRunnable(mFile, mAccount, new Handler())).start(); - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - } - } - } - - @Override - public void onNeutral(String callerTag) { - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); - File f = null; - if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) { - f.delete(); - mFile.setStoragePath(null); - fdsm.saveFile(mFile); - updateFileDetails(mFile, mAccount); - } - } - - @Override - public void onCancel(String callerTag) { - Log.d(TAG, "REMOVAL CANCELED"); - } - - - /** - * 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; - } - - - /** - * 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; - mAccount = ocAccount; - updateFileDetails(); - } - - - /** - * Updates the view with all relevant details about that file. - */ - public void updateFileDetails() { - - if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) { - - // set file details - setFilename(mFile.getFileName()); - setFiletype(DisplayUtils.convertMIMEtoPrettyPrint(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())) { - setButtonsForTransferring(); - - } else if (mFile.isDown()) { - // Update preview - if (mFile.getMimetype().startsWith("image/")) { - BitmapLoader bl = new BitmapLoader(); - bl.execute(new String[]{mFile.getStoragePath()}); - } - - setButtonsForDown(); - - } else { - setButtonsForRemote(); - } - } - } - - - /** - * 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) - tv.setText(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.filedetails_download_in_progress); // ugly - downloadButton.setEnabled(false); // TODO replace it with a 'cancel download' button - - // 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); - } - } - - /** - * 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_redownload); // ugly - downloadButton.setEnabled(true); - - ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true); - ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); - ((Button) getView().findViewById(R.id.fdRemoveBtn)).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); // unnecessary - downloadButton.setEnabled(true); - - ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false); - ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true); - ((Button) getView().findViewById(R.id.fdRemoveBtn)).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 { - - /** - * 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.setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH)); // updates the local object without accessing the database again - } - updateFileDetails(); // 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); - if (mFile.getRemotePath().equals(uploadRemotePath)) { - if (uploadWasFine) { - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver()); - mFile = fdsm.getFileByPath(mFile.getRemotePath()); - } - updateFileDetails(); // 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 - private class ShareRunnable implements Runnable { - private String mPath; - - public ShareRunnable(String path) { - mPath = path; - } - - public void run() { - AccountManager am = AccountManager.get(getActivity()); - Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity()); - OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); - String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv); - - Log.d("share", "sharing for version " + ocv.toString()); - - if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) { - String APPS_PATH = "/apps/files_sharing/"; - String SHARE_PATH = "ajax/share.php"; - - String SHARED_PATH = "/apps/files_sharing/get.php?token="; - - final String WEBDAV_SCRIPT = "webdav.php"; - final String WEBDAV_FILES_LOCATION = "/files/"; - - WebdavClient wc = new WebdavClient(); - HttpConnectionManagerParams params = new HttpConnectionManagerParams(); - params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5); - - //wc.getParams().setParameter("http.protocol.single-cookie-header", true); - //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); - - PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH); - - post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" ); - post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); - List formparams = new ArrayList(); - Log.d("share", mPath+""); - formparams.add(new BasicNameValuePair("sources",mPath)); - formparams.add(new BasicNameValuePair("uid_shared_with", "public")); - formparams.add(new BasicNameValuePair("permissions", "0")); - post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8))); - - int status; - try { - PropFindMethod find = new PropFindMethod(url+"/"); - find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); - Log.d("sharer", ""+ url+"/"); - wc.setCredentials(account.name.substring(0, account.name.lastIndexOf('@')), am.getPassword(account)); - - for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) { - Log.d("sharer-h", a.getName() + ":"+a.getValue()); - } - - int status2 = wc.executeMethod(find); - - Log.d("sharer", "propstatus "+status2); - - GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/"); - get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); - - status2 = wc.executeMethod(get); - - Log.d("sharer", "getstatus "+status2); - Log.d("sharer", "" + get.getResponseBodyAsString()); - - for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) { - Log.d("sharer", a.getName() + ":"+a.getValue()); - } - - status = wc.executeMethod(post); - for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) { - Log.d("sharer-h", a.getName() + ":"+a.getValue()); - } - for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) { - Log.d("sharer", a.getName() + ":"+a.getValue()); - } - String resp = post.getResponseBodyAsString(); - Log.d("share", ""+post.getURI().toString()); - Log.d("share", "returned status " + status); - Log.d("share", " " +resp); - - if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) { - return; - } - - JSONObject jsonObject = new JSONObject (resp); - String jsonStatus = jsonObject.getString("status"); - if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success"); - - String token = jsonObject.getString("data"); - String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; - Log.d("Actions:shareFile ok", "url: " + uri); - - } catch (HttpException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) { - - } - } - } - - public void onDismiss(EditNameFragment dialog) { - if (dialog instanceof EditNameFragment) { - if (((EditNameFragment)dialog).getResult()) { - String newFilename = ((EditNameFragment)dialog).getNewFilename(); - Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); - if (!newFilename.equals(mFile.getFileName())) { - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); - if (fdsm.getFileById(mFile.getFileId()) != null) { - OCFile newFile = new OCFile(fdsm.getFileById(mFile.getParentId()).getRemotePath() + newFilename); - newFile.setCreationTimestamp(mFile.getCreationTimestamp()); - newFile.setFileId(mFile.getFileId()); - newFile.setFileLength(mFile.getFileLength()); - newFile.setKeepInSync(mFile.keepInSync()); - newFile.setLastSyncDate(mFile.getLastSyncDate()); - newFile.setMimetype(mFile.getMimetype()); - newFile.setModificationTimestamp(mFile.getModificationTimestamp()); - newFile.setParentId(mFile.getParentId()); - boolean localRenameFails = false; - if (mFile.isDown()) { - File f = new File(mFile.getStoragePath()); - Log.e(TAG, f.getAbsolutePath()); - localRenameFails = !(f.renameTo(new File(f.getParent() + File.separator + newFilename))); - Log.e(TAG, f.getParent() + File.separator + newFilename); - newFile.setStoragePath(f.getParent() + File.separator + newFilename); - } - - if (localRenameFails) { - Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); - msg.show(); - - } else { - new Thread(new RenameRunnable(mFile, newFile, mAccount, new Handler())).start(); - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - } - - } - } - } - } else { - Log.e(TAG, "Unknown dialog instance passed to onDismissDalog: " + dialog.getClass().getCanonicalName()); - } - - } - - private class RenameRunnable implements Runnable { - - Account mAccount; - OCFile mOld, mNew; - Handler mHandler; - - public RenameRunnable(OCFile oldFile, OCFile newFile, Account account, Handler handler) { - mOld = oldFile; - mNew = newFile; - mAccount = account; - mHandler = handler; - } - - public void run() { - WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext()); - wc.allowSelfsignedCertificates(); - AccountManager am = AccountManager.get(getSherlockActivity()); - String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); - OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); - String webdav_path = AccountUtils.getWebdavPath(ocv); - Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath())); - - Log.e("ASD", Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath())); - LocalMoveMethod move = new LocalMoveMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath()), - Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath())); - - boolean success = false; - try { - int status = wc.executeMethod(move); - success = move.succeeded(); - Log.d(TAG, "Move returned status: " + status); - - } catch (HttpException e) { - Log.e(TAG, "HTTP Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); - - } catch (IOException e) { - Log.e(TAG, "I/O Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); - - } catch (Exception e) { - Log.e(TAG, "Unexpected exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); - } - - if (success) { - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); - fdsm.removeFile(mOld); - fdsm.saveFile(mNew); - mFile = mNew; - mHandler.post(new Runnable() { - @Override - public void run() { - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - updateFileDetails(mFile, mAccount); - mContainerActivity.onFileStateChanged(); - } - }); - - } else { - mHandler.post(new Runnable() { - @Override - public void run() { - // undo the local rename - if (mNew.isDown()) { - File f = new File(mNew.getStoragePath()); - if (!f.renameTo(new File(mOld.getStoragePath()))) { - // the local rename undoing failed; last chance: save the new local storage path in the old file - mFile.setStoragePath(mNew.getStoragePath()); - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); - fdsm.saveFile(mFile); - } - } - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - try { - Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); - msg.show(); - - } catch (NotFoundException e) { - e.printStackTrace(); - } - } - }); - } - } - private class LocalMoveMethod extends DavMethodBase { - - public LocalMoveMethod(String uri, String dest) { - super(uri); - addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest)); - } - - @Override - public String getName() { - return "MOVE"; - } - - @Override - protected boolean isSuccess(int status) { - return status == 201 || status == 204; - } - - } - } - - private static class EditNameFragment extends SherlockDialogFragment implements OnClickListener { - - private String mNewFilename; - private boolean mResult; - private FileDetailFragment mListener; - - static public EditNameFragment newInstance(String filename) { - EditNameFragment f = new EditNameFragment(); - Bundle args = new Bundle(); - args.putString("filename", filename); - f.setArguments(args); - return f; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.edit_box_dialog, container, false); - - String currentName = getArguments().getString("filename"); - if (currentName == null) - currentName = ""; - - ((Button)v.findViewById(R.id.cancel)).setOnClickListener(this); - ((Button)v.findViewById(R.id.ok)).setOnClickListener(this); - ((TextView)v.findViewById(R.id.user_input)).setText(currentName); - ((TextView)v.findViewById(R.id.user_input)).requestFocus(); - getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); - - mResult = false; - return v; - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.ok: { - mNewFilename = ((TextView)getView().findViewById(R.id.user_input)).getText().toString(); - mResult = true; - } - case R.id.cancel: { // fallthought - dismiss(); - mListener.onDismiss(this); - } - } - } - - void setOnDismissListener(FileDetailFragment listener) { - mListener = listener; - } - - public String getNewFilename() { - return mNewFilename; - } - - // true if user click ok - public boolean getResult() { - return mResult; - } - - } - - private class RemoveRunnable implements Runnable { - - Account mAccount; - OCFile mFileToRemove; - Handler mHandler; - - public RemoveRunnable(OCFile fileToRemove, Account account, Handler handler) { - mFileToRemove = fileToRemove; - mAccount = account; - mHandler = handler; - } - - public void run() { - WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext()); - wc.allowSelfsignedCertificates(); - AccountManager am = AccountManager.get(getSherlockActivity()); - String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); - OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); - String webdav_path = AccountUtils.getWebdavPath(ocv); - Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath())); - - DeleteMethod delete = new DeleteMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath())); - - boolean success = false; - int status = -1; - try { - status = wc.executeMethod(delete); - success = (delete.succeeded()); - Log.d(TAG, "Delete: returned status " + status); - - } catch (HttpException e) { - Log.e(TAG, "HTTP Exception removing file " + mFileToRemove.getRemotePath(), e); - - } catch (IOException e) { - Log.e(TAG, "I/O Exception removing file " + mFileToRemove.getRemotePath(), e); - - } catch (Exception e) { - Log.e(TAG, "Unexpected exception removing file " + mFileToRemove.getRemotePath(), e); - } - - if (success) { - FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); - fdsm.removeFile(mFileToRemove); - mHandler.post(new Runnable() { - @Override - public void run() { - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - try { - 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(); - } - - } catch (NotFoundException e) { - e.printStackTrace(); - } - } - }); - - } else { - mHandler.post(new Runnable() { - @Override - public void run() { - boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; - getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); - try { - Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); - msg.show(); - - } catch (NotFoundException e) { - e.printStackTrace(); - } - } - }); - } - } - - } - - class BitmapLoader extends AsyncTask { - @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20 - @Override - protected Bitmap doInBackground(String... params) { - Bitmap result = null; - if (params.length != 1) return result; - String storagePath = params[0]; - try { - - BitmapFactory.Options options = new Options(); - options.inScaled = true; - options.inPurgeable = true; - options.inJustDecodeBounds = true; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - options.inPreferQualityOverSpeed = false; - } - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - options.inMutable = false; - } - - result = BitmapFactory.decodeFile(storagePath, options); - options.inJustDecodeBounds = false; - - int width = options.outWidth; - int height = options.outHeight; - int scale = 1; - if (width >= 2048 || height >= 2048) { - scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.))); - options.inSampleSize = scale; - } - Display display = getActivity().getWindowManager().getDefaultDisplay(); - Point size = new Point(); - int screenwidth; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) { - display.getSize(size); - screenwidth = size.x; - } else { - screenwidth = display.getWidth(); - } - - Log.e("ASD", "W " + width + " SW " + screenwidth); - - if (width > screenwidth) { - scale = (int) Math.ceil((float)width / screenwidth); - options.inSampleSize = scale; - } - - result = BitmapFactory.decodeFile(storagePath, options); - - Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight); - - } catch (OutOfMemoryError e) { - result = null; - Log.e(TAG, "Out of memory occured for file with size " + storagePath); - - } catch (NoSuchFieldError e) { - result = null; - Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath); - - } catch (Throwable t) { - result = null; - Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t); - } - return result; - } - @Override - protected void onPostExecute(Bitmap result) { - if (result != null && mPreview != null) { - mPreview.setImageBitmap(result); - } - } - - } - - -} diff --git a/src/eu/alefzero/owncloud/ui/fragment/FileListFragment.java b/src/eu/alefzero/owncloud/ui/fragment/FileListFragment.java deleted file mode 100644 index 66d0af84..00000000 --- a/src/eu/alefzero/owncloud/ui/fragment/FileListFragment.java +++ /dev/null @@ -1,204 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.fragment; - -import java.util.Vector; - -import android.app.Activity; -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.datamodel.DataStorageManager; -import eu.alefzero.owncloud.datamodel.OCFile; -import eu.alefzero.owncloud.ui.FragmentListView; -import eu.alefzero.owncloud.ui.adapter.FileListListAdapter; - -/** - * A Fragment that lists all files and folders in a given path. - * - * @author Bartek Przybylski - * - */ -public class FileListFragment extends FragmentListView { - private static final String TAG = "FileListFragment"; - - private FileListFragment.ContainerActivity mContainerActivity; - - private OCFile mFile = null; - private FileListListAdapter mAdapter; - - - /** - * {@inheritDoc} - */ - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mContainerActivity = (ContainerActivity) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity"); - } - } - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - Log.i(getClass().toString(), "onCreateView() start"); - super.onCreateView(inflater, container, savedInstanceState); - getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator)); - getListView().setDividerHeight(1); - - Log.i(getClass().toString(), "onCreateView() end"); - return getListView(); - } - - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - Log.i(getClass().toString(), "onActivityCreated() start"); - - super.onCreate(savedInstanceState); - //mAdapter = new FileListListAdapter(); - - Log.i(getClass().toString(), "onActivityCreated() stop"); - } - - - @Override - public void onItemClick(AdapterView l, View v, int position, long id) { - OCFile file = (OCFile) mAdapter.getItem(position); - if (file != null) { - /// Click on a directory - if (file.getMimetype().equals("DIR")) { - // just local updates - mFile = file; - listDirectory(file); - // any other updates are let to the container Activity - mContainerActivity.onDirectoryClick(file); - - } else { /// Click on a file - mContainerActivity.onFileClick(file); - } - - } else { - Log.d(TAG, "Null object in ListAdapter!!"); - } - - } - - /** - * Call this, when the user presses the up button - */ - public void onNavigateUp() { - OCFile parentDir = null; - - if(mFile != null){ - DataStorageManager storageManager = mContainerActivity.getStorageManager(); - parentDir = storageManager.getFileById(mFile.getParentId()); - mFile = parentDir; - } - listDirectory(parentDir); - } - - /** - * Use this to query the {@link OCFile} that is currently - * being displayed by this fragment - * @return The currently viewed OCFile - */ - public OCFile getCurrentFile(){ - return mFile; - } - - /** - * Calls {@link FileListFragment#listDirectory(OCFile)} with a null parameter - */ - public void listDirectory(){ - listDirectory(null); - } - - /** - * Lists the given directory on the view. When the input parameter is null, - * it will either refresh the last known directory, or list the root - * if there never was a directory. - * - * @param directory File to be listed - */ - public void listDirectory(OCFile directory) { - - DataStorageManager storageManager = mContainerActivity.getStorageManager(); - - // Check input parameters for null - if(directory == null){ - if(mFile != null){ - directory = mFile; - } else { - directory = storageManager.getFileByPath("/"); - if (directory == null) return; // no files, wait for sync - } - } - - - // If that's not a directory -> List its parent - if(!directory.isDirectory()){ - Log.w(TAG, "You see, that is not a directory -> " + directory.toString()); - directory = storageManager.getFileById(directory.getParentId()); - } - - mFile = directory; - - mAdapter = new FileListListAdapter(directory, storageManager, getActivity()); - setListAdapter(mAdapter); - } - - - - /** - * Interface to implement by any Activity that includes some instance of FileListFragment - * - * @author David A. Velasco - */ - public interface ContainerActivity { - - /** - * Callback method invoked when a directory is clicked by the user on the files list - * - * @param file - */ - public void onDirectoryClick(OCFile file); - - /** - * Callback method invoked when a file (non directory) is clicked by the user on the files list - * - * @param file - */ - public void onFileClick(OCFile file); - - /** - * Getter for the current DataStorageManager in the container activity - */ - public DataStorageManager getStorageManager(); - - } - -} diff --git a/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java b/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java deleted file mode 100644 index f5649a08..00000000 --- a/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java +++ /dev/null @@ -1,58 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui.fragment; - -import com.actionbarsherlock.app.SherlockFragment; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.ui.activity.LandingActivity; -import eu.alefzero.owncloud.ui.adapter.LandingScreenAdapter; - -/** - * Used on the Landing page to display what Components of the ownCloud there - * are. Like Files, Music, Contacts, etc. - * - * @author Lennart Rosam - * - */ -public class LandingPageFragment extends SherlockFragment { - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.landing_page_fragment, container); - return root; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - ListView landingScreenItems = (ListView) getView().findViewById( - R.id.homeScreenList); - landingScreenItems.setAdapter(new LandingScreenAdapter(getActivity())); - landingScreenItems - .setOnItemClickListener((LandingActivity) getActivity()); - } - -} diff --git a/src/eu/alefzero/owncloud/utils/OwnCloudVersion.java b/src/eu/alefzero/owncloud/utils/OwnCloudVersion.java deleted file mode 100644 index a7726672..00000000 --- a/src/eu/alefzero/owncloud/utils/OwnCloudVersion.java +++ /dev/null @@ -1,83 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.utils; - -public class OwnCloudVersion implements Comparable { - public static final OwnCloudVersion owncloud_v1 = new OwnCloudVersion( - 0x010000); - public static final OwnCloudVersion owncloud_v2 = new OwnCloudVersion( - 0x020000); - public static final OwnCloudVersion owncloud_v3 = new OwnCloudVersion( - 0x030000); - public static final OwnCloudVersion owncloud_v4 = new OwnCloudVersion( - 0x040000); - - // format is in version - // 0xAABBCC - // for version AA.BB.CC - // ie version 3.0.3 will be stored as 0x030003 - private int mVersion; - private boolean mIsValid; - - public OwnCloudVersion(int version) { - mVersion = version; - mIsValid = true; - } - - public OwnCloudVersion(String version) { - mVersion = 0; - mIsValid = false; - parseVersionString(version); - } - - public String toString() { - return ((mVersion >> 16) % 256) + "." + ((mVersion >> 8) % 256) + "." - + ((mVersion) % 256); - } - - public boolean isVersionValid() { - return mIsValid; - } - - @Override - public int compareTo(OwnCloudVersion another) { - return another.mVersion == mVersion ? 0 - : another.mVersion < mVersion ? 1 : -1; - } - - private void parseVersionString(String version) { - try { - String[] nums = version.split("\\."); - if (nums.length > 0) { - mVersion += Integer.parseInt(nums[0]); - } - mVersion = mVersion << 8; - if (nums.length > 1) { - mVersion += Integer.parseInt(nums[1]); - } - mVersion = mVersion << 8; - if (nums.length > 2) { - mVersion += Integer.parseInt(nums[2]); - } - mIsValid = true; - } catch (Exception e) { - mIsValid = false; - } - } -} diff --git a/src/eu/alefzero/owncloud/widgets/ActionEditText.java b/src/eu/alefzero/owncloud/widgets/ActionEditText.java deleted file mode 100644 index 4b11b6c4..00000000 --- a/src/eu/alefzero/owncloud/widgets/ActionEditText.java +++ /dev/null @@ -1,127 +0,0 @@ -package eu.alefzero.owncloud.widgets; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import eu.alefzero.owncloud.R; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.widget.EditText; - -public class ActionEditText extends EditText { - private String s; - private String optionOneString; - private int optionOneColor; - private String optionTwoString; - private int optionTwoColor; - private Rect mTextBounds, mButtonRect; - - private String badgeClickCallback; - private Rect btn_rect; - - public ActionEditText(Context context, AttributeSet attrs) { - super(context, attrs); - getAttrs(attrs); - s = optionOneString; - mTextBounds = new Rect(); - mButtonRect = new Rect(); - } - - public ActionEditText(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - getAttrs(attrs); - s = optionOneString; - mTextBounds = new Rect(); - mButtonRect = new Rect(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - Paint p = getPaint(); - - p.getTextBounds(s, 0, s.length(), mTextBounds); - - getDrawingRect(mButtonRect); - mButtonRect.top += 10; - mButtonRect.bottom -= 10; - mButtonRect.left = (int) (getWidth() - mTextBounds.width() - 18); - mButtonRect.right = getWidth() - 10; - btn_rect = mButtonRect; - - if (s.equals(optionOneString)) - p.setColor(optionOneColor); - else - p.setColor(optionTwoColor); - canvas.drawRect(mButtonRect, p); - p.setColor(Color.GRAY); - - canvas.drawText(s, mButtonRect.left + 3, mButtonRect.bottom - - (mTextBounds.height() / 2), p); - - invalidate(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - int touchX = (int) event.getX(); - int touchY = (int) event.getY(); - boolean r = super.onTouchEvent(event); - if (event.getAction() == MotionEvent.ACTION_UP) { - if (btn_rect.contains(touchX, touchY)) { - if (s.equals(optionTwoString)) - s = optionOneString; - else - s = optionTwoString; - if (badgeClickCallback != null) { - @SuppressWarnings("rawtypes") - Class[] paramtypes = new Class[2]; - paramtypes[0] = android.view.View.class; - paramtypes[1] = String.class; - Method method; - try { - - method = getContext().getClass().getMethod( - badgeClickCallback, paramtypes); - method.invoke(getContext(), this, s); - - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - - invalidate(); - } - } - } - return r; - } - - private void getAttrs(AttributeSet attr) { - TypedArray a = getContext().obtainStyledAttributes(attr, - R.styleable.ActionEditText); - optionOneString = a - .getString(R.styleable.ActionEditText_optionOneString); - optionTwoString = a - .getString(R.styleable.ActionEditText_optionTwoString); - optionOneColor = a.getColor(R.styleable.ActionEditText_optionOneColor, - 0x00ff00); - optionTwoColor = a.getColor(R.styleable.ActionEditText_optionTwoColor, - 0xff0000); - badgeClickCallback = a - .getString(R.styleable.ActionEditText_onBadgeClick); - } - -} diff --git a/src/eu/alefzero/webdav/FileRequestEntity.java b/src/eu/alefzero/webdav/FileRequestEntity.java index 3e7977c4..61ba4565 100644 --- a/src/eu/alefzero/webdav/FileRequestEntity.java +++ b/src/eu/alefzero/webdav/FileRequestEntity.java @@ -8,9 +8,10 @@ import java.io.OutputStream; import org.apache.commons.httpclient.methods.RequestEntity; +import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; + import android.util.Log; -import eu.alefzero.owncloud.files.interfaces.OnDatatransferProgressListener; /** * A RequestEntity that represents a File. diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java index 1135dafa..1e64bdfe 100644 --- a/src/eu/alefzero/webdav/WebdavClient.java +++ b/src/eu/alefzero/webdav/WebdavClient.java @@ -41,16 +41,17 @@ 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.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.authenticator.EasySSLSocketFactory; +import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; +import com.owncloud.android.utils.OwnCloudVersion; + import android.accounts.Account; import android.accounts.AccountManager; import android.content.Context; import android.net.Uri; import android.util.Log; -import eu.alefzero.owncloud.AccountUtils; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory; -import eu.alefzero.owncloud.files.interfaces.OnDatatransferProgressListener; -import eu.alefzero.owncloud.utils.OwnCloudVersion; public class WebdavClient extends HttpClient { private Uri mUri;