You should have received a copy of the GNU General Public License\r
along with this program. If not, see <http://www.gnu.org/licenses/>.\r
-->\r
-<manifest package="eu.alefzero.owncloud"\r
+<manifest package="com.owncloud.android"\r
android:versionCode="103000"\r
android:versionName="1.3.0" xmlns:android="http://schemas.android.com/apk/res/android">\r
\r
\r
<service android:name=".files.services.FileDownloader" >\r
</service>\r
- <service android:name=".location.LocationUpdateService" >\r
- <intent-filter>\r
- <action android:name="eu.alefzero.owncloud.location.LocationUpdateService" />\r
- </intent-filter>\r
- </service>\r
\r
<activity android:name=".ui.activity.FileDetailActivity" />
<activity android:name=".ui.activity.PinCodeActivity" />\r
along with this program. If not, see <http://www.gnu.org/licenses/>.\r
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:oc="http://schemas.android.com/apk/res/eu.alefzero.owncloud"
+ xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"
</LinearLayout>
</RelativeLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
android:id="@+id/fileList"\r
android:layout_width="fill_parent"\r
android:layout_height="fill_parent"\r
- class="eu.alefzero.owncloud.ui.fragment.FileListFragment" >\r
+ class="com.owncloud.android.ui.fragment.FileListFragment" >\r
\r
<!-- Preview: layout=@layout/list_layout -->\r
</fragment>\r
<!-- Preview: layout=@layout/file_details_empty -->\r
</LinearLayout>\r
\r
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>\r
along with this program. If not, see <http://www.gnu.org/licenses/>.\r
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:oc="http://schemas.android.com/apk/res/eu.alefzero.owncloud"
+ xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"
</LinearLayout>
</RelativeLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
android:id="@+id/fileList"\r
android:layout_width="fill_parent"\r
android:layout_height="fill_parent"\r
- class="eu.alefzero.owncloud.ui.fragment.FileListFragment" >\r
+ class="com.owncloud.android.ui.fragment.FileListFragment" >\r
\r
<!-- Preview: layout=@layout/list_layout -->\r
</fragment>\r
\r
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>\r
along with this program. If not, see <http://www.gnu.org/licenses/>.\r
-->\r
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
- xmlns:oc="http://schemas.android.com/apk/res/eu.alefzero.owncloud"\r
+ xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"\r
android:layout_width="fill_parent"\r
android:layout_height="fill_parent"\r
android:gravity="center_horizontal"\r
android:text="@android:string/cancel"\r
android:textColor="@android:color/black"\r
android:id="@+id/cancel"/>\r
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2012 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android;\r
+\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.utils.OwnCloudVersion;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.content.Context;\r
+import android.content.SharedPreferences;\r
+import android.preference.PreferenceManager;\r
+\r
+public class AccountUtils {\r
+ public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";\r
+ public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";\r
+ public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";\r
+ public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";\r
+ public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";\r
+ public static final String STATUS_PATH = "/status.php";\r
+\r
+ /**\r
+ * Can be used to get the currently selected ownCloud account in the\r
+ * preferences\r
+ * \r
+ * @param context The current appContext\r
+ * @return The current account or first available, if none is available,\r
+ * then null.\r
+ */\r
+ public static Account getCurrentOwnCloudAccount(Context context) {\r
+ Account[] ocAccounts = AccountManager.get(context).getAccountsByType(\r
+ AccountAuthenticator.ACCOUNT_TYPE);\r
+ Account defaultAccount = null;\r
+\r
+ SharedPreferences appPreferences = PreferenceManager\r
+ .getDefaultSharedPreferences(context);\r
+ String accountName = appPreferences\r
+ .getString("select_oc_account", null);\r
+\r
+ if (accountName != null) {\r
+ for (Account account : ocAccounts) {\r
+ if (account.name.equals(accountName)) {\r
+ defaultAccount = account;\r
+ break;\r
+ }\r
+ }\r
+ } else if (ocAccounts.length != 0) {\r
+ // we at least need to take first account as fallback\r
+ defaultAccount = ocAccounts[0];\r
+ }\r
+\r
+ return defaultAccount;\r
+ }\r
+\r
+ \r
+\r
+ /**\r
+ * Checks, whether or not there are any ownCloud accounts setup.\r
+ * \r
+ * @return true, if there is at least one account.\r
+ */\r
+ public static boolean accountsAreSetup(Context context) {\r
+ AccountManager accMan = AccountManager.get(context);\r
+ Account[] accounts = accMan\r
+ .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
+ return accounts.length > 0;\r
+ }\r
+ \r
+ \r
+ public static void setCurrentOwnCloudAccount(Context context, String name) {\r
+ SharedPreferences.Editor appPrefs = PreferenceManager\r
+ .getDefaultSharedPreferences(context).edit();\r
+ appPrefs.putString("select_oc_account", name);\r
+ appPrefs.commit();\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param version version of owncloud\r
+ * @return webdav path for given OC version, null if OC version unknown\r
+ */\r
+ public static String getWebdavPath(OwnCloudVersion version) {\r
+ if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
+ return WEBDAV_PATH_4_0;\r
+ if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0\r
+ || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0)\r
+ return WEBDAV_PATH_2_0;\r
+ if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0)\r
+ return WEBDAV_PATH_1_2;\r
+ return null;\r
+ }\r
+\r
+}\r
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<String> TAGS;
+ private UncaughtExceptionHandler defaultUEH;
+
+ // TODO: create base activity which will register for crashlog tag automaticly
+ static {
+ TAGS = new LinkedList<String>();
+ 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;
+ }
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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();
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android;\r
+\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+\r
+/**\r
+ * A helper class for some string operations.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class DisplayUtils {\r
+\r
+ private static final String[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };\r
+\r
+ private static HashMap<String, String> mimeType2HUmanReadable;\r
+ static {\r
+ mimeType2HUmanReadable = new HashMap<String, String>();\r
+ // images\r
+ mimeType2HUmanReadable.put("image/jpeg", "JPEG image");\r
+ mimeType2HUmanReadable.put("image/jpg", "JPEG image");\r
+ mimeType2HUmanReadable.put("image/png", "PNG image");\r
+ mimeType2HUmanReadable.put("image/bmp", "Bitmap image");\r
+ mimeType2HUmanReadable.put("image/gif", "GIF image");\r
+ mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");\r
+ mimeType2HUmanReadable.put("image/tiff", "TIFF image");\r
+ // music\r
+ mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");\r
+ mimeType2HUmanReadable.put("application/ogg", "OGG music file");\r
+\r
+ }\r
+\r
+ /**\r
+ * Converts the file size in bytes to human readable output.\r
+ * \r
+ * @param bytes Input file size\r
+ * @return Like something readable like "12 MB"\r
+ */\r
+ public static String bytesToHumanReadable(long bytes) {\r
+ double result = bytes;\r
+ int attachedsuff = 0;\r
+ while (result > 1024 && attachedsuff < suffixes.length) {\r
+ result /= 1024.;\r
+ attachedsuff++;\r
+ }\r
+ result = ((int) (result * 100)) / 100.;\r
+ return result + " " + suffixes[attachedsuff];\r
+ }\r
+\r
+ /**\r
+ * Removes special HTML entities from a string\r
+ * \r
+ * @param s Input string\r
+ * @return A cleaned version of the string\r
+ */\r
+ public static String HtmlDecode(String s) {\r
+ /*\r
+ * TODO: Perhaps we should use something more proven like:\r
+ * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29\r
+ */\r
+\r
+ String ret = "";\r
+ for (int i = 0; i < s.length(); ++i) {\r
+ if (s.charAt(i) == '%') {\r
+ ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16);\r
+ i += 2;\r
+ } else {\r
+ ret += s.charAt(i);\r
+ }\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * Converts MIME types like "image/jpg" to more end user friendly output\r
+ * like "JPG image".\r
+ * \r
+ * @param mimetype MIME type to convert\r
+ * @return A human friendly version of the MIME type\r
+ */\r
+ public static String convertMIMEtoPrettyPrint(String mimetype) {\r
+ if (mimeType2HUmanReadable.containsKey(mimetype)) {\r
+ return mimeType2HUmanReadable.get(mimetype);\r
+ }\r
+ if (mimetype.split("/").length >= 2)\r
+ return mimetype.split("/")[1].toUpperCase() + " file";\r
+ return "Unknown type";\r
+ }\r
+\r
+ /**\r
+ * Converts Unix time to human readable format\r
+ * @param miliseconds that have passed since 01/01/1970\r
+ * @return The human readable time for the users locale\r
+ */\r
+ public static String unixTimeToHumanReadable(long milliseconds) {\r
+ Date date = new Date(milliseconds);\r
+ return date.toLocaleString();\r
+ }\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android;\r
+\r
+/**\r
+ * Represents a session to an ownCloud instance\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class OwnCloudSession {\r
+ private String mSessionName;\r
+ private String mSessionUrl;\r
+ private int mEntryId;\r
+\r
+ public OwnCloudSession(String name, String url, int entryId) {\r
+ mSessionName = name;\r
+ mSessionUrl = url;\r
+ mEntryId = entryId;\r
+ }\r
+\r
+ public void setName(String name) {\r
+ mSessionName = name;\r
+ }\r
+\r
+ public String getName() {\r
+ return mSessionName;\r
+ }\r
+\r
+ public void setUrl(String url) {\r
+ mSessionUrl = url;\r
+ }\r
+\r
+ public String getUrl() {\r
+ return mSessionUrl;\r
+ }\r
+\r
+ public int getEntryId() {\r
+ return mEntryId;\r
+ }\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2012 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android;\r
+\r
+import java.io.File;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Stack;\r
+import java.util.Vector;\r
+\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.datamodel.DataStorageManager;\r
+import com.owncloud.android.datamodel.FileDataStorageManager;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.files.services.FileUploader;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.app.AlertDialog;\r
+import android.app.AlertDialog.Builder;\r
+import android.app.Dialog;\r
+import android.app.ListActivity;\r
+import android.app.ProgressDialog;\r
+import android.content.Context;\r
+import android.content.DialogInterface;\r
+import android.content.DialogInterface.OnCancelListener;\r
+import android.content.DialogInterface.OnClickListener;\r
+import android.content.Intent;\r
+import android.database.Cursor;\r
+import android.net.Uri;\r
+import android.os.Bundle;\r
+import android.os.Parcelable;\r
+import android.provider.MediaStore.Images.Media;\r
+import android.util.Log;\r
+import android.view.View;\r
+import android.view.Window;\r
+import android.widget.AdapterView;\r
+import android.widget.AdapterView.OnItemClickListener;\r
+import android.widget.Button;\r
+import android.widget.EditText;\r
+import android.widget.SimpleAdapter;\r
+import com.owncloud.android.R;\r
+import eu.alefzero.webdav.WebdavClient;\r
+\r
+/**\r
+ * This can be used to upload things to an ownCloud instance.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
+ private static final String TAG = "ownCloudUploader";\r
+\r
+ private Account mAccount;\r
+ private AccountManager mAccountManager;\r
+ private Stack<String> mParents;\r
+ private ArrayList<Parcelable> mStreamsToUpload;\r
+ private boolean mCreateDir;\r
+ private String mUploadPath;\r
+ private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };\r
+ private DataStorageManager mStorageManager;\r
+ private OCFile mFile;\r
+\r
+ private final static int DIALOG_NO_ACCOUNT = 0;\r
+ private final static int DIALOG_WAITING = 1;\r
+ private final static int DIALOG_NO_STREAM = 2;\r
+ private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
+ private final static int DIALOG_GET_DIRNAME = 4;\r
+\r
+ private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
+ mParents = new Stack<String>();\r
+ mParents.add("");\r
+ if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
+ prepareStreamsToUpload();\r
+ mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);\r
+ Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
+ if (accounts.length == 0) {\r
+ Log.i(TAG, "No ownCloud account is available");\r
+ showDialog(DIALOG_NO_ACCOUNT);\r
+ } else if (accounts.length > 1) {\r
+ Log.i(TAG, "More then one ownCloud is available");\r
+ showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
+ } else {\r
+ mAccount = accounts[0];\r
+ setContentView(R.layout.uploader_layout);\r
+ mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
+ populateDirectoryList();\r
+ }\r
+ } else {\r
+ showDialog(DIALOG_NO_STREAM);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ protected Dialog onCreateDialog(final int id) {\r
+ final AlertDialog.Builder builder = new Builder(this);\r
+ switch (id) {\r
+ case DIALOG_WAITING:\r
+ ProgressDialog pDialog = new ProgressDialog(this);\r
+ pDialog.setIndeterminate(false);\r
+ pDialog.setCancelable(false);\r
+ pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
+ return pDialog;\r
+ case DIALOG_NO_ACCOUNT:\r
+ builder.setIcon(android.R.drawable.ic_dialog_alert);\r
+ builder.setTitle(R.string.uploader_wrn_no_account_title);\r
+ builder.setMessage(R.string.uploader_wrn_no_account_text);\r
+ builder.setCancelable(false);\r
+ builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
+ // using string value since in API7 this\r
+ // constatn is not defined\r
+ // in API7 < this constatant is defined in\r
+ // Settings.ADD_ACCOUNT_SETTINGS\r
+ // and Settings.EXTRA_AUTHORITIES\r
+ Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
+ intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
+ startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
+ } else {\r
+ // since in API7 there is no direct call for\r
+ // account setup, so we need to\r
+ // show our own AccountSetupAcricity, get\r
+ // desired results and setup\r
+ // everything for ourself\r
+ Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
+ startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
+ }\r
+ }\r
+ });\r
+ builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ finish();\r
+ }\r
+ });\r
+ return builder.create();\r
+ /*case DIALOG_GET_DIRNAME:\r
+ final EditText dirName = new EditText(getBaseContext());\r
+ builder.setView(dirName);\r
+ builder.setTitle(R.string.uploader_info_dirname);\r
+ String pathToUpload;\r
+ if (mParents.empty()) {\r
+ pathToUpload = "/";\r
+ } else {\r
+ mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,\r
+ null, null, null);\r
+ mCursor.moveToFirst();\r
+ pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))\r
+ + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); // TODO don't make this ; use WebdavUtils.encode in the right moment\r
+ }\r
+ a a = new a(pathToUpload, dirName);\r
+ builder.setPositiveButton(R.string.common_ok, a);\r
+ builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ dialog.cancel();\r
+ }\r
+ });\r
+ return builder.create();*/\r
+ case DIALOG_MULTIPLE_ACCOUNT:\r
+ CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
+ for (int i = 0; i < ac.length; ++i) {\r
+ ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
+ }\r
+ builder.setTitle(R.string.common_choose_account);\r
+ builder.setItems(ac, new OnClickListener() {\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
+ mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
+ populateDirectoryList();\r
+ }\r
+ });\r
+ builder.setCancelable(true);\r
+ builder.setOnCancelListener(new OnCancelListener() {\r
+ public void onCancel(DialogInterface dialog) {\r
+ dialog.cancel();\r
+ finish();\r
+ }\r
+ });\r
+ return builder.create();\r
+ default:\r
+ throw new IllegalArgumentException("Unknown dialog id: " + id);\r
+ }\r
+ }\r
+\r
+ class a implements OnClickListener {\r
+ String mPath;\r
+ EditText mDirname;\r
+\r
+ public a(String path, EditText dirname) {\r
+ mPath = path; \r
+ mDirname = dirname;\r
+ }\r
+\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ Uploader.this.mUploadPath = mPath + mDirname.getText().toString();\r
+ Uploader.this.mCreateDir = true;\r
+ uploadFiles();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void onBackPressed() {\r
+\r
+ if (mParents.size() <= 1) {\r
+ super.onBackPressed();\r
+ return;\r
+ } else {\r
+ mParents.pop();\r
+ populateDirectoryList();\r
+ }\r
+ }\r
+\r
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
+ // click on folder in the list\r
+ Log.d(TAG, "on item click");\r
+ Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);\r
+ if (tmpfiles == null) return;\r
+ // filter on dirtype\r
+ Vector<OCFile> files = new Vector<OCFile>();\r
+ for (OCFile f : tmpfiles)\r
+ if (f.isDirectory())\r
+ files.add(f);\r
+ if (files.size() < position) {\r
+ throw new IndexOutOfBoundsException("Incorrect item selected");\r
+ }\r
+ mParents.push(files.get(position).getFileName());\r
+ populateDirectoryList();\r
+ }\r
+\r
+ public void onClick(View v) {\r
+ // click on button\r
+ switch (v.getId()) {\r
+ case R.id.uploader_choose_folder:\r
+ mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix\r
+ for (String p : mParents)\r
+ mUploadPath += p + OCFile.PATH_SEPARATOR;\r
+ Log.d(TAG, "Uploading file to dir " + mUploadPath);\r
+\r
+ uploadFiles();\r
+\r
+ break;\r
+ case android.R.id.button1: // dynamic action for create aditional dir\r
+ showDialog(DIALOG_GET_DIRNAME);\r
+ break;\r
+ default:\r
+ throw new IllegalArgumentException("Wrong element clicked");\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
+ super.onActivityResult(requestCode, resultCode, data);\r
+ Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
+ if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
+ dismissDialog(DIALOG_NO_ACCOUNT);\r
+ if (resultCode == RESULT_CANCELED) {\r
+ finish();\r
+ }\r
+ Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
+ if (accounts.length == 0) {\r
+ showDialog(DIALOG_NO_ACCOUNT);\r
+ } else {\r
+ // there is no need for checking for is there more then one\r
+ // account at this point\r
+ // since account setup can set only one account at time\r
+ mAccount = accounts[0];\r
+ populateDirectoryList();\r
+ }\r
+ }\r
+ }\r
+\r
+ private void populateDirectoryList() {\r
+ setContentView(R.layout.uploader_layout);\r
+\r
+ String full_path = "";\r
+ for (String a : mParents)\r
+ full_path += a + "/";\r
+ \r
+ Log.d(TAG, "Populating view with content of : " + full_path);\r
+ \r
+ mFile = mStorageManager.getFileByPath(full_path);\r
+ if (mFile != null) {\r
+ Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);\r
+ if (files != null) {\r
+ List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();\r
+ for (OCFile f : files) {\r
+ HashMap<String, Object> h = new HashMap<String, Object>();\r
+ if (f.isDirectory()) {\r
+ h.put("dirname", f.getFileName());\r
+ data.add(h);\r
+ }\r
+ }\r
+ SimpleAdapter sa = new SimpleAdapter(this,\r
+ data,\r
+ R.layout.uploader_list_item_layout,\r
+ new String[] {"dirname"},\r
+ new int[] {R.id.textView1});\r
+ setListAdapter(sa);\r
+ Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
+ btn.setOnClickListener(this);\r
+ getListView().setOnItemClickListener(this);\r
+ }\r
+ }\r
+ /*\r
+ mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, null, ProviderTableMeta.FILE_NAME\r
+ + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", new String[] { "/", mAccount.name }, null);\r
+\r
+ if (mCursor.moveToFirst()) {\r
+ mCursor = managedQuery(\r
+ ProviderMeta.ProviderTableMeta.CONTENT_URI,\r
+ null,\r
+ ProviderTableMeta.FILE_CONTENT_TYPE + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND "\r
+ + ProviderTableMeta.FILE_PARENT + "=?",\r
+ new String[] { "DIR", mAccount.name,\r
+ mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)) }, null);\r
+\r
+ ListView lv = getListView();\r
+ lv.setOnItemClickListener(this);\r
+ SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, mCursor,\r
+ new String[] { ProviderTableMeta.FILE_NAME }, new int[] { R.id.textView1 });\r
+ setListAdapter(sca);\r
+ Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
+ btn.setOnClickListener(this);\r
+ /*\r
+ * disable this until new server interaction service wont be created\r
+ * // insert create new directory for multiple items uploading if\r
+ * (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
+ * Button createDirBtn = new Button(this);\r
+ * createDirBtn.setId(android.R.id.button1);\r
+ * createDirBtn.setText(R.string.uploader_btn_create_dir_text);\r
+ * createDirBtn.setOnClickListener(this); ((LinearLayout)\r
+ * findViewById(R.id.linearLayout1)).addView( createDirBtn,\r
+ * LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); }\r
+ *\r
+ }*/\r
+ }\r
+\r
+ private void prepareStreamsToUpload() {\r
+ if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
+ mStreamsToUpload = new ArrayList<Parcelable>();\r
+ mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
+ } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
+ mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
+ } else {\r
+ // unknow action inserted\r
+ throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());\r
+ }\r
+ }\r
+\r
+ public void uploadFiles() {\r
+ WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext());\r
+ wdc.allowSelfsignedCertificates();\r
+\r
+ // create last directory in path if nessesary\r
+ if (mCreateDir) {\r
+ wdc.createDirectory(mUploadPath);\r
+ }\r
+\r
+ String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
+\r
+ for (int i = 0; i < mStreamsToUpload.size(); ++i) {\r
+ Uri uri = (Uri) mStreamsToUpload.get(i);\r
+ if (uri.getScheme().equals("content")) {\r
+ Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),\r
+ CONTENT_PROJECTION,\r
+ null,\r
+ null,\r
+ null);\r
+\r
+ if (!c.moveToFirst())\r
+ continue;\r
+\r
+ final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
+ data = c.getString(c.getColumnIndex(Media.DATA));\r
+ local[i] = data;\r
+ remote[i] = mUploadPath + display_name;\r
+ } else if (uri.getScheme().equals("file")) {\r
+ final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));\r
+ local[i] = file.getAbsolutePath();\r
+ remote[i] = mUploadPath + file.getName();\r
+ }\r
+\r
+ }\r
+ Intent intent = new Intent(getApplicationContext(), FileUploader.class);\r
+ intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
+ intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);\r
+ intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);\r
+ intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);\r
+ startService(intent);\r
+ finish();\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2012 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.authenticator;\r
+\r
+import com.owncloud.android.ui.activity.AuthenticatorActivity;\r
+\r
+import android.accounts.*;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.os.Bundle;\r
+import android.util.Log;\r
+\r
+public class AccountAuthenticator extends AbstractAccountAuthenticator {\r
+ /**\r
+ * Is used by android system to assign accounts to authenticators. Should be\r
+ * used by application and all extensions.\r
+ */\r
+ public static final String ACCOUNT_TYPE = "owncloud";\r
+ public static final String AUTH_TOKEN_TYPE = "org.owncloud";\r
+\r
+ public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";\r
+ public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";\r
+ public static final String KEY_LOGIN_OPTIONS = "loginOptions";\r
+ public static final String KEY_ACCOUNT = "account";\r
+ /**\r
+ * Value under this key should handle path to webdav php script. Will be\r
+ * removed and usage should be replaced by combining\r
+ * {@link eu.alefzero.owncloud.authenticator.KEY_OC_BASE_URL} and\r
+ * {@link com.owncloud.android.utils.OwnCloudVersion}\r
+ * \r
+ * @deprecated\r
+ */\r
+ public static final String KEY_OC_URL = "oc_url";\r
+ /**\r
+ * Version should be 3 numbers separated by dot so it can be parsed by\r
+ * {@link com.owncloud.android.utils.OwnCloudVersion}\r
+ */\r
+ public static final String KEY_OC_VERSION = "oc_version";\r
+ /**\r
+ * Base url should point to owncloud installation without trailing / ie:\r
+ * http://server/path or https://owncloud.server\r
+ */\r
+ public static final String KEY_OC_BASE_URL = "oc_base_url";\r
+\r
+ private static final String TAG = "AccountAuthenticator";\r
+ private Context mContext;\r
+\r
+ public AccountAuthenticator(Context context) {\r
+ super(context);\r
+ mContext = context;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public Bundle addAccount(AccountAuthenticatorResponse response,\r
+ String accountType, String authTokenType,\r
+ String[] requiredFeatures, Bundle options)\r
+ throws NetworkErrorException {\r
+ Log.i(TAG, "Adding account with type " + accountType\r
+ + " and auth token " + authTokenType);\r
+ try {\r
+ validateAccountType(accountType);\r
+ } catch (AuthenticatorException e) {\r
+ Log.e(TAG, "Failed to validate account type " + accountType + ": "\r
+ + e.getMessage());\r
+ e.printStackTrace();\r
+ return e.getFailureBundle();\r
+ }\r
+ final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
+ response);\r
+ intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
+ intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);\r
+ intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
+\r
+ setIntentFlags(intent);\r
+ final Bundle bundle = new Bundle();\r
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
+ return bundle;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
+ Account account, Bundle options) throws NetworkErrorException {\r
+ try {\r
+ validateAccountType(account.type);\r
+ } catch (AuthenticatorException e) {\r
+ Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
+ + e.getMessage());\r
+ e.printStackTrace();\r
+ return e.getFailureBundle();\r
+ }\r
+ Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
+ response);\r
+ intent.putExtra(KEY_ACCOUNT, account);\r
+ intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
+\r
+ setIntentFlags(intent);\r
+\r
+ Bundle resultBundle = new Bundle();\r
+ resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
+ return resultBundle;\r
+ }\r
+\r
+ @Override\r
+ public Bundle editProperties(AccountAuthenticatorResponse response,\r
+ String accountType) {\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public Bundle getAuthToken(AccountAuthenticatorResponse response,\r
+ Account account, String authTokenType, Bundle options)\r
+ throws NetworkErrorException {\r
+ try {\r
+ validateAccountType(account.type);\r
+ validateAuthTokenType(authTokenType);\r
+ } catch (AuthenticatorException e) {\r
+ Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
+ + e.getMessage());\r
+ e.printStackTrace();\r
+ return e.getFailureBundle();\r
+ }\r
+ final AccountManager am = AccountManager.get(mContext);\r
+ final String password = am.getPassword(account);\r
+ if (password != null) {\r
+ final Bundle result = new Bundle();\r
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);\r
+ result.putString(AccountManager.KEY_AUTHTOKEN, password);\r
+ return result;\r
+ }\r
+\r
+ final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
+ response);\r
+ intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
+ intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
+ intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);\r
+\r
+ final Bundle bundle = new Bundle();\r
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
+ return bundle;\r
+ }\r
+\r
+ @Override\r
+ public String getAuthTokenLabel(String authTokenType) {\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public Bundle hasFeatures(AccountAuthenticatorResponse response,\r
+ Account account, String[] features) throws NetworkErrorException {\r
+ final Bundle result = new Bundle();\r
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public Bundle updateCredentials(AccountAuthenticatorResponse response,\r
+ Account account, String authTokenType, Bundle options)\r
+ throws NetworkErrorException {\r
+ final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
+ response);\r
+ intent.putExtra(KEY_ACCOUNT, account);\r
+ intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
+ intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
+ setIntentFlags(intent);\r
+\r
+ final Bundle bundle = new Bundle();\r
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
+ return bundle;\r
+ }\r
+\r
+ @Override\r
+ public Bundle getAccountRemovalAllowed(\r
+ AccountAuthenticatorResponse response, Account account)\r
+ throws NetworkErrorException {\r
+ return super.getAccountRemovalAllowed(response, account);\r
+ }\r
+\r
+ private void setIntentFlags(Intent intent) {\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
+ intent.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
+ }\r
+\r
+ private void validateAccountType(String type)\r
+ throws UnsupportedAccountTypeException {\r
+ if (!type.equals(ACCOUNT_TYPE)) {\r
+ throw new UnsupportedAccountTypeException();\r
+ }\r
+ }\r
+\r
+ private void validateAuthTokenType(String authTokenType)\r
+ throws UnsupportedAuthTokenTypeException {\r
+ if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {\r
+ throw new UnsupportedAuthTokenTypeException();\r
+ }\r
+ }\r
+\r
+ public static class AuthenticatorException extends Exception {\r
+ private static final long serialVersionUID = 1L;\r
+ private Bundle mFailureBundle;\r
+\r
+ public AuthenticatorException(int code, String errorMsg) {\r
+ mFailureBundle = new Bundle();\r
+ mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
+ mFailureBundle\r
+ .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
+ }\r
+\r
+ public Bundle getFailureBundle() {\r
+ return mFailureBundle;\r
+ }\r
+ }\r
+\r
+ public static class UnsupportedAccountTypeException extends\r
+ AuthenticatorException {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ public UnsupportedAccountTypeException() {\r
+ super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
+ "Unsupported account type");\r
+ }\r
+ }\r
+\r
+ public static class UnsupportedAuthTokenTypeException extends\r
+ AuthenticatorException {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ public UnsupportedAuthTokenTypeException() {\r
+ super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
+ "Unsupported auth token type");\r
+ }\r
+ }\r
+\r
+ public static class UnsupportedFeaturesException extends\r
+ AuthenticatorException {\r
+ public static final long serialVersionUID = 1L;\r
+\r
+ public UnsupportedFeaturesException() {\r
+ super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
+ "Unsupported features");\r
+ }\r
+ }\r
+\r
+ public static class AccessDeniedException extends AuthenticatorException {\r
+ public AccessDeniedException(int code, String errorMsg) {\r
+ super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
+ }\r
+\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ }\r
+}\r
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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();
+ }
+
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+ });
+ }
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+ });
+ }
+ }
+
+}
--- /dev/null
+/*
+ * $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
+ * <http://www.apache.org/>.
+ *
+ */
+
+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;
+
+/**
+ * <p>
+ * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s that
+ * accept self-signed certificates.
+ * </p>
+ * <p>
+ * 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
+ * </p>
+ *
+ * <p>
+ * Example of using custom protocol socket factory for a specific host:
+ *
+ * <pre>
+ * 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);
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * Example of using custom protocol socket factory per default instead of the
+ * standard one:
+ *
+ * <pre>
+ * 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);
+ * </pre>
+ *
+ * </p>
+ *
+ * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
+ *
+ * <p>
+ * 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.
+ * </p>
+ */
+
+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.
+ * <p>
+ * 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}
+ * </p>
+ *
+ * @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
--- /dev/null
+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
--- /dev/null
+package com.owncloud.android.authenticator;
+
+public interface OnAuthenticationResultListener {
+
+ public void onAuthenticationResult(boolean success, String message);
+
+}
--- /dev/null
+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);
+
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<OCFile> files);
+
+ public Vector<OCFile> getDirectoryContent(OCFile f);
+
+ public void removeFile(OCFile file);
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<OCFile> files) {
+
+ Iterator<OCFile> filesIt = files.iterator();
+ ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(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<results.length; i++) {
+ if (results[i].uri != null) {
+ newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
+ files.get(i).setFileId(newId);
+ //Log.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
+ }
+ }
+ }
+
+ for (OCFile aFile : files) {
+ if (aFile.isDirectory() && aFile.needsUpdatingWhileSaving())
+ saveFiles(getDirectoryContent(aFile));
+ }
+
+ }
+
+ public void setAccount(Account account) {
+ mAccount = account;
+ }
+
+ public Account getAccount() {
+ return mAccount;
+ }
+
+ public void setContentResolver(ContentResolver cr) {
+ mContentResolver = cr;
+ }
+
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
+
+ public void setContentProvider(ContentProviderClient cp) {
+ mContentProvider = cp;
+ }
+
+ public ContentProviderClient getContentProvider() {
+ return mContentProvider;
+ }
+
+ public Vector<OCFile> getDirectoryContent(OCFile f) {
+ if (f != null && f.isDirectory() && f.getFileId() != -1) {
+ Vector<OCFile> ret = new Vector<OCFile>();
+
+ 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();
+ }
+ }
+
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<OCFile> {
+
+ public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
+ @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;
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.db;\r
+\r
+import java.util.Vector;\r
+\r
+import com.owncloud.android.OwnCloudSession;\r
+\r
+\r
+import android.content.ContentValues;\r
+import android.content.Context;\r
+import android.database.Cursor;\r
+import android.database.sqlite.SQLiteDatabase;\r
+import android.database.sqlite.SQLiteOpenHelper;\r
+\r
+/**\r
+ * Custom database helper for ownCloud\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class DbHandler {\r
+ private SQLiteDatabase mDB;\r
+ private OpenerHepler mHelper;\r
+ private final String mDatabaseName = "ownCloud";\r
+ private final String TABLE_SESSIONS = "sessions";\r
+ private final int mDatabaseVersion = 1;\r
+ \r
+ private final String TABLE_INSTANT_UPLOAD = "instant_upload";\r
+\r
+ public DbHandler(Context context) {\r
+ mHelper = new OpenerHepler(context);\r
+ mDB = mHelper.getWritableDatabase();\r
+ }\r
+\r
+ public void close() {\r
+ mDB.close();\r
+ }\r
+\r
+ public boolean putFileForLater(String filepath, String account) {\r
+ ContentValues cv = new ContentValues();\r
+ cv.put("path", filepath);\r
+ cv.put("account", account);\r
+ return mDB.insert(TABLE_INSTANT_UPLOAD, null, cv) != -1;\r
+ }\r
+ \r
+ public Cursor getAwaitingFiles() {\r
+ return mDB.query(TABLE_INSTANT_UPLOAD, null, null, null, null, null, null);\r
+ }\r
+ \r
+ public void clearFiles() {\r
+ mDB.delete(TABLE_INSTANT_UPLOAD, null, null);\r
+ }\r
+ \r
+ private class OpenerHepler extends SQLiteOpenHelper {\r
+ public OpenerHepler(Context context) {\r
+ super(context, mDatabaseName, null, mDatabaseVersion);\r
+ }\r
+\r
+ @Override\r
+ public void onCreate(SQLiteDatabase db) {\r
+ db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " ("\r
+ + " _id INTEGET PRIMARY KEY, "\r
+ + " path TEXT,"\r
+ + " account TEXT);");\r
+ }\r
+\r
+ @Override\r
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.db;\r
+\r
+import android.net.Uri;\r
+import android.provider.BaseColumns;\r
+\r
+/**\r
+ * Meta-Class that holds various static field information\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class ProviderMeta {\r
+\r
+ public static final String AUTHORITY_FILES = "org.owncloud";\r
+ public static final String DB_FILE = "owncloud.db";\r
+ public static final String DB_NAME = "filelist";\r
+ public static final int DB_VERSION = 2;\r
+\r
+ private ProviderMeta() {\r
+ }\r
+\r
+ static public class ProviderTableMeta implements BaseColumns {\r
+ public static final String DB_NAME = "filelist";\r
+ public static final Uri CONTENT_URI = Uri.parse("content://"\r
+ + AUTHORITY_FILES + "/");\r
+ public static final Uri CONTENT_URI_FILE = Uri.parse("content://"\r
+ + AUTHORITY_FILES + "/file");\r
+ public static final Uri CONTENT_URI_DIR = Uri.parse("content://"\r
+ + AUTHORITY_FILES + "/dir");\r
+\r
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";\r
+ public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";\r
+\r
+ public static final String FILE_PARENT = "parent";\r
+ public static final String FILE_NAME = "filename";\r
+ public static final String FILE_CREATION = "created";\r
+ public static final String FILE_MODIFIED = "modified";\r
+ public static final String FILE_CONTENT_LENGTH = "content_length";\r
+ public static final String FILE_CONTENT_TYPE = "content_type";\r
+ public static final String FILE_STORAGE_PATH = "media_path";\r
+ public static final String FILE_PATH = "path";\r
+ public static final String FILE_ACCOUNT_OWNER = "file_owner";\r
+ public static final String FILE_LAST_SYNC_DATE = "last_sync_date";\r
+ public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";\r
+\r
+ public static final String DEFAULT_SORT_ORDER = FILE_NAME\r
+ + " collate nocase asc";\r
+\r
+ }\r
+}\r
--- /dev/null
+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");
+ }
+}
--- /dev/null
+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());
+ }
+ }
+
+}
--- /dev/null
+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<HashMap<String, String>> ll = new LinkedList<HashMap<String, String>>();
+ for (int i = 0; i < a.length(); ++i) {
+ try {
+ ExtensionApplicationEntry ela = new ExtensionApplicationEntry(
+ ((JSONObject) a.get(i)));
+ HashMap<String, String> ss = new HashMap<String, String>();
+ 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;
+ }
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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();
+ }
+
+}
--- /dev/null
+package com.owncloud.android.files.interfaces;
+
+public interface OnDatatransferProgressListener {
+ void transferProgress(long progressRate);
+
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<Integer, NotificationTypePair> 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<Integer, NotificationTypePair>();
+ 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);
+ }
+}
--- /dev/null
+package com.owncloud.android.files.services;\r
+\r
+import java.io.File;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
+import com.owncloud.android.files.interfaces.OnDatatransferProgressListener;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.app.Notification;\r
+import android.app.NotificationManager;\r
+import android.app.PendingIntent;\r
+import android.app.Service;\r
+import android.content.ContentValues;\r
+import android.content.Intent;\r
+import android.net.Uri;\r
+import android.os.Environment;\r
+import android.os.Handler;\r
+import android.os.HandlerThread;\r
+import android.os.IBinder;\r
+import android.os.Looper;\r
+import android.os.Message;\r
+import android.os.Process;\r
+import android.util.Log;\r
+import android.widget.RemoteViews;\r
+import com.owncloud.android.R;\r
+import eu.alefzero.webdav.WebdavClient;\r
+\r
+public class FileDownloader extends Service implements OnDatatransferProgressListener {\r
+ public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";\r
+ public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; \r
+ public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
+ public static final String EXTRA_FILE_PATH = "FILE_PATH";\r
+ public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";\r
+ public static final String EXTRA_FILE_SIZE = "FILE_SIZE";\r
+ public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
+ \r
+ private static final String TAG = "FileDownloader";\r
+\r
+ private NotificationManager mNotificationMngr;\r
+ private Looper mServiceLooper;\r
+ private ServiceHandler mServiceHandler;\r
+ private Account mAccount;\r
+ private String mFilePath;\r
+ private String mRemotePath;\r
+ private int mLastPercent;\r
+ private long mTotalDownloadSize;\r
+ private long mCurrentDownloadSize;\r
+ private Notification mNotification;\r
+ \r
+ /**\r
+ * Static map with the files being download and the path to the temporal file were are download\r
+ */\r
+ private static Map<String, String> mDownloadsInProgress = Collections.synchronizedMap(new HashMap<String, String>());\r
+ \r
+ /**\r
+ * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading\r
+ */\r
+ public static boolean isDownloading(Account account, String remotePath) {\r
+ return (mDownloadsInProgress.get(buildRemoteName(account.name, remotePath)) != null);\r
+ }\r
+ \r
+ /**\r
+ * Builds a key for mDownloadsInProgress from the accountName and remotePath\r
+ */\r
+ private static String buildRemoteName(String accountName, String remotePath) {\r
+ return accountName + remotePath;\r
+ }\r
+\r
+ \r
+ private final class ServiceHandler extends Handler {\r
+ public ServiceHandler(Looper looper) {\r
+ super(looper);\r
+ }\r
+\r
+ @Override\r
+ public void handleMessage(Message msg) {\r
+ downloadFile();\r
+ stopSelf(msg.arg1);\r
+ }\r
+ }\r
+ \r
+ public static final String getSavePath(String accountName) {\r
+ File sdCard = Environment.getExternalStorageDirectory();\r
+ return sdCard.getAbsolutePath() + "/owncloud/" + Uri.encode(accountName, "@"); \r
+ // 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\r
+ }\r
+ \r
+ public static final String getTemporalPath(String accountName) {\r
+ File sdCard = Environment.getExternalStorageDirectory();\r
+ return sdCard.getAbsolutePath() + "/owncloud/tmp/" + Uri.encode(accountName, "@");\r
+ // 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\r
+ }\r
+\r
+ @Override\r
+ public void onCreate() {\r
+ super.onCreate();\r
+ mNotificationMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);\r
+ HandlerThread thread = new HandlerThread("FileDownladerThread",\r
+ Process.THREAD_PRIORITY_BACKGROUND);\r
+ thread.start();\r
+ mServiceLooper = thread.getLooper();\r
+ mServiceHandler = new ServiceHandler(mServiceLooper);\r
+ }\r
+\r
+ @Override\r
+ public IBinder onBind(Intent arg0) {\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public int onStartCommand(Intent intent, int flags, int startId) {\r
+ if ( !intent.hasExtra(EXTRA_ACCOUNT) ||\r
+ !intent.hasExtra(EXTRA_FILE_PATH) ||\r
+ !intent.hasExtra(EXTRA_REMOTE_PATH)\r
+ ) {\r
+ Log.e(TAG, "Not enough information provided in intent");\r
+ return START_NOT_STICKY;\r
+ }\r
+ mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT);\r
+ mFilePath = intent.getStringExtra(EXTRA_FILE_PATH);\r
+ mRemotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);\r
+ mTotalDownloadSize = intent.getLongExtra(EXTRA_FILE_SIZE, -1);\r
+ mCurrentDownloadSize = mLastPercent = 0;\r
+\r
+ Message msg = mServiceHandler.obtainMessage();\r
+ msg.arg1 = startId;\r
+ mServiceHandler.sendMessage(msg);\r
+\r
+ return START_NOT_STICKY;\r
+ }\r
+\r
+ /**\r
+ * Core download method: requests the file to download and stores it.\r
+ */\r
+ private void downloadFile() {\r
+ boolean downloadResult = false;\r
+\r
+ /// prepare client object to send the request to the ownCloud server\r
+ AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);\r
+ WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext());\r
+ String username = mAccount.name.split("@")[0];\r
+ String password = null;\r
+ try {\r
+ password = am.blockingGetAuthToken(mAccount,\r
+ AccountAuthenticator.AUTH_TOKEN_TYPE, true);\r
+ } catch (Exception e) {\r
+ Log.e(TAG, "Access to account credentials failed", e);\r
+ sendFinalBroadcast(downloadResult, null);\r
+ return;\r
+ }\r
+ wdc.setCredentials(username, password);\r
+ wdc.allowSelfsignedCertificates();\r
+ wdc.setDataTransferProgressListener(this);\r
+\r
+ \r
+ /// download will be in a temporal file\r
+ File tmpFile = new File(getTemporalPath(mAccount.name) + mFilePath);\r
+ \r
+ /// create status notification to show the download progress\r
+ mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());\r
+ mNotification.flags |= Notification.FLAG_ONGOING_EVENT;\r
+ mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);\r
+ mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, mTotalDownloadSize == -1);\r
+ mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, tmpFile.getName()));\r
+ mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);\r
+ // TODO put something smart in the contentIntent below\r
+ mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);\r
+ mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
+ \r
+\r
+ /// perform the download\r
+ tmpFile.getParentFile().mkdirs();\r
+ mDownloadsInProgress.put(buildRemoteName(mAccount.name, mRemotePath), tmpFile.getAbsolutePath());\r
+ File newFile = null;\r
+ try {\r
+ if (wdc.downloadFile(mRemotePath, tmpFile)) {\r
+ newFile = new File(getSavePath(mAccount.name) + mFilePath);\r
+ newFile.getParentFile().mkdirs();\r
+ boolean moved = tmpFile.renameTo(newFile);\r
+ \r
+ if (moved) {\r
+ ContentValues cv = new ContentValues();\r
+ cv.put(ProviderTableMeta.FILE_STORAGE_PATH, newFile.getAbsolutePath());\r
+ getContentResolver().update(\r
+ ProviderTableMeta.CONTENT_URI,\r
+ cv,\r
+ ProviderTableMeta.FILE_NAME + "=? AND "\r
+ + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",\r
+ new String[] {\r
+ mFilePath.substring(mFilePath.lastIndexOf('/') + 1),\r
+ mAccount.name });\r
+ downloadResult = true;\r
+ }\r
+ }\r
+ } finally {\r
+ mDownloadsInProgress.remove(buildRemoteName(mAccount.name, mRemotePath));\r
+ }\r
+\r
+ \r
+ /// notify result\r
+ mNotificationMngr.cancel(R.string.downloader_download_in_progress_ticker);\r
+ int tickerId = (downloadResult) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;\r
+ int contentId = (downloadResult) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;\r
+ Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());\r
+ finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;\r
+ // TODO put something smart in the contentIntent below\r
+ finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);\r
+ finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), tmpFile.getName()), finalNotification.contentIntent);\r
+ mNotificationMngr.notify(tickerId, finalNotification);\r
+ \r
+ sendFinalBroadcast(downloadResult, (downloadResult)?newFile.getAbsolutePath():null);\r
+ }\r
+\r
+ /**\r
+ * Callback method to update the progress bar in the status notification.\r
+ */\r
+ @Override\r
+ public void transferProgress(long progressRate) {\r
+ mCurrentDownloadSize += progressRate;\r
+ int percent = (int)(100.0*((double)mCurrentDownloadSize)/((double)mTotalDownloadSize));\r
+ if (percent != mLastPercent) {\r
+ mNotification.contentView.setProgressBar(R.id.status_progress, 100, (int)(100*mCurrentDownloadSize/mTotalDownloadSize), mTotalDownloadSize == -1);\r
+ mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), percent, new File(mFilePath).getName()));\r
+ mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
+ }\r
+ \r
+ mLastPercent = percent;\r
+ }\r
+ \r
+\r
+ /**\r
+ * Sends a broadcast in order to the interested activities can update their view\r
+ * \r
+ * @param downloadResult 'True' if the download was successful\r
+ * @param newFilePath Absolute path to the download file\r
+ */\r
+ private void sendFinalBroadcast(boolean downloadResult, String newFilePath) {\r
+ Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);\r
+ end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult);\r
+ end.putExtra(ACCOUNT_NAME, mAccount.name);\r
+ end.putExtra(EXTRA_REMOTE_PATH, mRemotePath);\r
+ if (downloadResult) {\r
+ end.putExtra(EXTRA_FILE_PATH, newFilePath);\r
+ }\r
+ sendBroadcast(end);\r
+ }\r
+\r
+}\r
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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;
+ }
+
+}
--- /dev/null
+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<String, String> mUploadsInProgress = Collections.synchronizedMap(new HashMap<String, String>());
+
+ /**
+ * 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;
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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<HashMap<String, Object>> mHashMapList;
+
+ public UploaderRunnable() {
+ mHashMapList = new LinkedList<HashMap<String, Object>>();
+ mLock = new Object();
+ }
+
+ public void addElementToQueue(String filename,
+ String filepath,
+ String mimetype,
+ long length,
+ Account account) {
+ HashMap<String, Object> new_map = new HashMap<String, Object>();
+ 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<String, Object> getFirstObject() {
+ synchronized (mLock) {
+ if (mHashMapList.size() == 0)
+ return null;
+ HashMap<String, Object> ret = mHashMapList.get(0);
+ mHashMapList.remove(0);
+ return ret;
+ }
+ }
+
+ public void run() {
+ HashMap<String, Object> 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();
+ }
+ }
+ }
+ }
+
+}
--- /dev/null
+package com.owncloud.android.files.services;
+
+public interface OnUploadCompletedListener extends Runnable {
+
+ public boolean getUploadResult();
+
+ public void setUploadResult(boolean result);
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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;
+ }
+
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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
+
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.providers;\r
+\r
+import java.util.HashMap;\r
+\r
+import com.owncloud.android.db.ProviderMeta;\r
+import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
+\r
+\r
+import android.content.ContentProvider;\r
+import android.content.ContentUris;\r
+import android.content.ContentValues;\r
+import android.content.Context;\r
+import android.content.UriMatcher;\r
+import android.database.Cursor;\r
+import android.database.SQLException;\r
+import android.database.sqlite.SQLiteDatabase;\r
+import android.database.sqlite.SQLiteOpenHelper;\r
+import android.database.sqlite.SQLiteQueryBuilder;\r
+import android.net.Uri;\r
+import android.text.TextUtils;\r
+import android.util.Log;\r
+\r
+/**\r
+ * The ContentProvider for the ownCloud App.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class FileContentProvider extends ContentProvider {\r
+\r
+ private DataBaseHelper mDbHelper;\r
+\r
+ private static HashMap<String, String> mProjectionMap;\r
+ static {\r
+ mProjectionMap = new HashMap<String, String>();\r
+ mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_PARENT,\r
+ ProviderTableMeta.FILE_PARENT);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_PATH,\r
+ ProviderTableMeta.FILE_PATH);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_NAME,\r
+ ProviderTableMeta.FILE_NAME);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_CREATION,\r
+ ProviderTableMeta.FILE_CREATION);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,\r
+ ProviderTableMeta.FILE_MODIFIED);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,\r
+ ProviderTableMeta.FILE_CONTENT_LENGTH);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,\r
+ ProviderTableMeta.FILE_CONTENT_TYPE);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,\r
+ ProviderTableMeta.FILE_STORAGE_PATH);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,\r
+ ProviderTableMeta.FILE_LAST_SYNC_DATE);\r
+ mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,\r
+ ProviderTableMeta.FILE_KEEP_IN_SYNC);\r
+ }\r
+\r
+ private static final int SINGLE_FILE = 1;\r
+ private static final int DIRECTORY = 2;\r
+ private static final int ROOT_DIRECTORY = 3;\r
+ private static final UriMatcher mUriMatcher;\r
+ static {\r
+ mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\r
+ mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);\r
+ mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);\r
+ mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);\r
+ mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);\r
+ }\r
+\r
+ @Override\r
+ public int delete(Uri uri, String where, String[] whereArgs) {\r
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
+ int count = 0;\r
+ switch (mUriMatcher.match(uri)) {\r
+ case SINGLE_FILE:\r
+ count = db.delete(ProviderTableMeta.DB_NAME,\r
+ ProviderTableMeta._ID\r
+ + "="\r
+ + uri.getPathSegments().get(1)\r
+ + (!TextUtils.isEmpty(where) ? " AND (" + where\r
+ + ")" : ""), whereArgs);\r
+ break;\r
+ case ROOT_DIRECTORY:\r
+ count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);\r
+ break;\r
+ default:\r
+ throw new IllegalArgumentException("Unknown uri: " + uri.toString());\r
+ }\r
+ getContext().getContentResolver().notifyChange(uri, null);\r
+ return count;\r
+ }\r
+\r
+ @Override\r
+ public String getType(Uri uri) {\r
+ switch (mUriMatcher.match(uri)) {\r
+ case ROOT_DIRECTORY:\r
+ return ProviderTableMeta.CONTENT_TYPE;\r
+ case SINGLE_FILE:\r
+ return ProviderTableMeta.CONTENT_TYPE_ITEM;\r
+ default:\r
+ throw new IllegalArgumentException("Unknown Uri id."\r
+ + uri.toString());\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Uri insert(Uri uri, ContentValues values) {\r
+ if (mUriMatcher.match(uri) != SINGLE_FILE &&\r
+ mUriMatcher.match(uri) != ROOT_DIRECTORY) {\r
+ \r
+ throw new IllegalArgumentException("Unknown uri id: " + uri);\r
+ }\r
+\r
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
+ long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);\r
+ if (rowId > 0) {\r
+ Uri insertedFileUri = ContentUris.withAppendedId(\r
+ ProviderTableMeta.CONTENT_URI_FILE, rowId);\r
+ getContext().getContentResolver().notifyChange(insertedFileUri,\r
+ null);\r
+ return insertedFileUri;\r
+ }\r
+ throw new SQLException("ERROR " + uri);\r
+ }\r
+\r
+ @Override\r
+ public boolean onCreate() {\r
+ mDbHelper = new DataBaseHelper(getContext());\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public Cursor query(Uri uri, String[] projection, String selection,\r
+ String[] selectionArgs, String sortOrder) {\r
+ SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();\r
+\r
+ sqlQuery.setTables(ProviderTableMeta.DB_NAME);\r
+ sqlQuery.setProjectionMap(mProjectionMap);\r
+\r
+ switch (mUriMatcher.match(uri)) {\r
+ case ROOT_DIRECTORY:\r
+ break;\r
+ case DIRECTORY:\r
+ sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="\r
+ + uri.getPathSegments().get(1));\r
+ break;\r
+ case SINGLE_FILE:\r
+ if (uri.getPathSegments().size() > 1) {\r
+ sqlQuery.appendWhere(ProviderTableMeta._ID + "="\r
+ + uri.getPathSegments().get(1));\r
+ }\r
+ break;\r
+ default:\r
+ throw new IllegalArgumentException("Unknown uri id: " + uri);\r
+ }\r
+\r
+ String order;\r
+ if (TextUtils.isEmpty(sortOrder)) {\r
+ order = ProviderTableMeta.DEFAULT_SORT_ORDER;\r
+ } else {\r
+ order = sortOrder;\r
+ }\r
+\r
+ SQLiteDatabase db = mDbHelper.getReadableDatabase();\r
+ Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,\r
+ null, null, order);\r
+\r
+ c.setNotificationUri(getContext().getContentResolver(), uri);\r
+\r
+ return c;\r
+ }\r
+\r
+ @Override\r
+ public int update(Uri uri, ContentValues values, String selection,\r
+ String[] selectionArgs) {\r
+ return mDbHelper.getWritableDatabase().update(\r
+ ProviderTableMeta.DB_NAME, values, selection, selectionArgs);\r
+ }\r
+\r
+ class DataBaseHelper extends SQLiteOpenHelper {\r
+\r
+ public DataBaseHelper(Context context) {\r
+ super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);\r
+\r
+ }\r
+\r
+ @Override\r
+ public void onCreate(SQLiteDatabase db) {\r
+ // files table\r
+ Log.i("SQL", "Entering in onCreate");\r
+ db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("\r
+ + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "\r
+ + ProviderTableMeta.FILE_NAME + " TEXT, "\r
+ + ProviderTableMeta.FILE_PATH + " TEXT, "\r
+ + ProviderTableMeta.FILE_PARENT + " INTEGER, "\r
+ + ProviderTableMeta.FILE_CREATION + " INTEGER, "\r
+ + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "\r
+ + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "\r
+ + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "\r
+ + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "\r
+ + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "\r
+ + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "\r
+ + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER );");\r
+ }\r
+\r
+ @Override\r
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
+ Log.i("SQL", "Entering in onUpgrade");\r
+ if (oldVersion == 1 && newVersion >= 2) {\r
+ Log.i("SQL", "Entering in the ADD in onUpgrade");\r
+ db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
+ " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +\r
+ " DEFAULT 0");\r
+ } else Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);\r
+ }\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.syncadapter;\r
+\r
+import java.io.IOException;\r
+import java.net.UnknownHostException;\r
+import java.util.Date;\r
+\r
+import org.apache.http.HttpRequest;\r
+import org.apache.http.HttpResponse;\r
+import org.apache.http.client.ClientProtocolException;\r
+import org.apache.http.conn.ConnectionKeepAliveStrategy;\r
+import org.apache.http.protocol.HttpContext;\r
+\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.datamodel.DataStorageManager;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.accounts.AuthenticatorException;\r
+import android.accounts.OperationCanceledException;\r
+import android.content.AbstractThreadedSyncAdapter;\r
+import android.content.ContentProviderClient;\r
+import android.content.Context;\r
+import android.net.Uri;\r
+import eu.alefzero.webdav.WebdavClient;\r
+\r
+/**\r
+ * Base SyncAdapter for OwnCloud Designed to be subclassed for the concrete\r
+ * SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc..\r
+ * \r
+ * @author sassman\r
+ * \r
+ */\r
+public abstract class AbstractOwnCloudSyncAdapter extends\r
+ AbstractThreadedSyncAdapter {\r
+\r
+ private AccountManager accountManager;\r
+ private Account account;\r
+ private ContentProviderClient contentProvider;\r
+ private Date lastUpdated;\r
+ private DataStorageManager mStoreManager;\r
+\r
+ private WebdavClient mClient = null;\r
+\r
+ public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) {\r
+ super(context, autoInitialize);\r
+ this.setAccountManager(AccountManager.get(context));\r
+ }\r
+\r
+ public AccountManager getAccountManager() {\r
+ return accountManager;\r
+ }\r
+\r
+ public void setAccountManager(AccountManager accountManager) {\r
+ this.accountManager = accountManager;\r
+ }\r
+\r
+ public Account getAccount() {\r
+ return account;\r
+ }\r
+\r
+ public void setAccount(Account account) {\r
+ this.account = account;\r
+ }\r
+\r
+ public ContentProviderClient getContentProvider() {\r
+ return contentProvider;\r
+ }\r
+\r
+ public void setContentProvider(ContentProviderClient contentProvider) {\r
+ this.contentProvider = contentProvider;\r
+ }\r
+\r
+ public Date getLastUpdated() {\r
+ return lastUpdated;\r
+ }\r
+\r
+ public void setLastUpdated(Date lastUpdated) {\r
+ this.lastUpdated = lastUpdated;\r
+ }\r
+\r
+ public void setStorageManager(DataStorageManager storage_manager) {\r
+ mStoreManager = storage_manager;\r
+ }\r
+\r
+ public DataStorageManager getStorageManager() {\r
+ return mStoreManager;\r
+ }\r
+\r
+ protected ConnectionKeepAliveStrategy getKeepAliveStrategy() {\r
+ return new ConnectionKeepAliveStrategy() {\r
+ public long getKeepAliveDuration(HttpResponse response,\r
+ HttpContext context) {\r
+ // Change keep alive straategy basing on response: ie\r
+ // forbidden/not found/etc\r
+ // should have keep alive 0\r
+ // default return: 5s\r
+ int statusCode = response.getStatusLine().getStatusCode();\r
+\r
+ // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed\r
+ // out\r
+ if ((statusCode >= 400 && statusCode <= 418)\r
+ || (statusCode >= 421 && statusCode <= 426)\r
+ || (statusCode >= 500 && statusCode <= 510)\r
+ || statusCode == 118) {\r
+ return 0;\r
+ }\r
+\r
+ return 5 * 1000;\r
+ }\r
+ };\r
+ }\r
+\r
+ protected HttpResponse fireRawRequest(HttpRequest query)\r
+ throws ClientProtocolException, OperationCanceledException,\r
+ AuthenticatorException, IOException {\r
+ /*\r
+ * BasicHttpContext httpContext = new BasicHttpContext(); BasicScheme\r
+ * basicAuth = new BasicScheme();\r
+ * httpContext.setAttribute("preemptive-auth", basicAuth);\r
+ * \r
+ * HttpResponse response = getClient().execute(mHost, query,\r
+ * httpContext);\r
+ */\r
+ return null;\r
+ }\r
+\r
+ protected Uri getUri() {\r
+ return Uri.parse(this.getAccountManager().getUserData(getAccount(),\r
+ AccountAuthenticator.KEY_OC_URL));\r
+ }\r
+\r
+ protected WebdavClient getClient() throws OperationCanceledException,\r
+ AuthenticatorException, IOException {\r
+ if (mClient == null) {\r
+ if (this.getAccountManager().getUserData(getAccount(),\r
+ AccountAuthenticator.KEY_OC_URL) == null) {\r
+ throw new UnknownHostException();\r
+ }\r
+ mClient = new WebdavClient(account, getContext());\r
+ mClient.allowSelfsignedCertificates();\r
+ // mHost = mClient.getTargetHost();\r
+ }\r
+\r
+ return mClient;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+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");
+ }
+
+}
--- /dev/null
+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();
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.syncadapter;\r
+\r
+import java.io.IOException;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+import org.apache.jackrabbit.webdav.DavException;\r
+import org.apache.jackrabbit.webdav.MultiStatus;\r
+import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
+\r
+import com.owncloud.android.datamodel.FileDataStorageManager;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.files.services.FileDownloader;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AuthenticatorException;\r
+import android.accounts.OperationCanceledException;\r
+import android.content.ContentProviderClient;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.content.SyncResult;\r
+import android.os.Bundle;\r
+import android.util.Log;\r
+import eu.alefzero.webdav.WebdavEntry;\r
+import eu.alefzero.webdav.WebdavUtils;\r
+\r
+/**\r
+ * SyncAdapter implementation for syncing sample SyncAdapter contacts to the\r
+ * platform ContactOperations provider.\r
+ * \r
+ * @author Bartek Przybylski\r
+ */\r
+public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {\r
+\r
+ private final static String TAG = "FileSyncAdapter"; \r
+ \r
+ /* Commented code for ugly performance tests\r
+ private final static int MAX_DELAYS = 100;\r
+ private static long[] mResponseDelays = new long[MAX_DELAYS]; \r
+ private static long[] mSaveDelays = new long[MAX_DELAYS];\r
+ private int mDelaysIndex = 0;\r
+ private int mDelaysCount = 0;\r
+ */\r
+ \r
+ private long mCurrentSyncTime;\r
+ private boolean mCancellation;\r
+ private Account mAccount;\r
+ \r
+ public FileSyncAdapter(Context context, boolean autoInitialize) {\r
+ super(context, autoInitialize);\r
+ }\r
+\r
+ @Override\r
+ public synchronized void onPerformSync(Account account, Bundle extras,\r
+ String authority, ContentProviderClient provider,\r
+ SyncResult syncResult) {\r
+\r
+ mCancellation = false;\r
+ mAccount = account;\r
+ \r
+ this.setAccount(mAccount);\r
+ this.setContentProvider(provider);\r
+ this.setStorageManager(new FileDataStorageManager(mAccount,\r
+ getContentProvider()));\r
+ \r
+ /* Commented code for ugly performance tests\r
+ mDelaysIndex = 0;\r
+ mDelaysCount = 0;\r
+ */\r
+ \r
+ \r
+ Log.d(TAG, "syncing owncloud account " + mAccount.name);\r
+\r
+ sendStickyBroadcast(true, null); // message to signal the start to the UI\r
+\r
+ PropFindMethod query;\r
+ try {\r
+ mCurrentSyncTime = System.currentTimeMillis();\r
+ query = new PropFindMethod(getUri().toString() + "/");\r
+ getClient().executeMethod(query);\r
+ MultiStatus resp = null;\r
+ resp = query.getResponseBodyAsMultiStatus();\r
+\r
+ if (resp.getResponses().length > 0) {\r
+ WebdavEntry we = new WebdavEntry(resp.getResponses()[0], getUri().getPath());\r
+ OCFile file = fillOCFile(we);\r
+ file.setParentId(0);\r
+ getStorageManager().saveFile(file);\r
+ if (!mCancellation) {\r
+ fetchData(getUri().toString(), syncResult, file.getFileId());\r
+ }\r
+ }\r
+ } catch (OperationCanceledException e) {\r
+ e.printStackTrace();\r
+ } catch (AuthenticatorException e) {\r
+ syncResult.stats.numAuthExceptions++;\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ syncResult.stats.numIoExceptions++;\r
+ e.printStackTrace();\r
+ } catch (DavException e) {\r
+ syncResult.stats.numIoExceptions++;\r
+ e.printStackTrace();\r
+ } catch (Throwable t) {\r
+ // TODO update syncResult\r
+ Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t);\r
+ t.printStackTrace();\r
+ }\r
+ \r
+ /* Commented code for ugly performance tests\r
+ long sum = 0, mean = 0, max = 0, min = Long.MAX_VALUE;\r
+ for (int i=0; i<MAX_DELAYS && i<mDelaysCount; i++) {\r
+ sum += mResponseDelays[i];\r
+ max = Math.max(max, mResponseDelays[i]);\r
+ min = Math.min(min, mResponseDelays[i]);\r
+ }\r
+ mean = sum / mDelaysCount;\r
+ Log.e(TAG, "SYNC STATS - response: mean time = " + mean + " ; max time = " + max + " ; min time = " + min);\r
+ \r
+ sum = 0; max = 0; min = Long.MAX_VALUE;\r
+ for (int i=0; i<MAX_DELAYS && i<mDelaysCount; i++) {\r
+ sum += mSaveDelays[i];\r
+ max = Math.max(max, mSaveDelays[i]);\r
+ min = Math.min(min, mSaveDelays[i]);\r
+ }\r
+ mean = sum / mDelaysCount;\r
+ Log.e(TAG, "SYNC STATS - save: mean time = " + mean + " ; max time = " + max + " ; min time = " + min);\r
+ Log.e(TAG, "SYNC STATS - folders measured: " + mDelaysCount);\r
+ */\r
+ \r
+ sendStickyBroadcast(false, null); \r
+ }\r
+\r
+ private void fetchData(String uri, SyncResult syncResult, long parentId) {\r
+ try {\r
+ Log.d(TAG, "fetching " + uri);\r
+ \r
+ // remote request \r
+ PropFindMethod query = new PropFindMethod(uri);\r
+ /* Commented code for ugly performance tests\r
+ long responseDelay = System.currentTimeMillis();\r
+ */\r
+ getClient().executeMethod(query);\r
+ /* Commented code for ugly performance tests\r
+ responseDelay = System.currentTimeMillis() - responseDelay;\r
+ Log.e(TAG, "syncing: RESPONSE TIME for " + uri + " contents, " + responseDelay + "ms");\r
+ */\r
+ MultiStatus resp = null;\r
+ resp = query.getResponseBodyAsMultiStatus();\r
+ \r
+ // insertion or update of files\r
+ List<OCFile> updatedFiles = new Vector<OCFile>(resp.getResponses().length - 1);\r
+ for (int i = 1; i < resp.getResponses().length; ++i) {\r
+ WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath());\r
+ OCFile file = fillOCFile(we);\r
+ file.setParentId(parentId);\r
+ if (getStorageManager().getFileByPath(file.getRemotePath()) != null &&\r
+ getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() &&\r
+ file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath())\r
+ .getModificationTimestamp()) {\r
+ Intent intent = new Intent(this.getContext(), FileDownloader.class);\r
+ intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());\r
+ intent.putExtra(FileDownloader.EXTRA_FILE_PATH, file.getRemotePath());\r
+ intent.putExtra(FileDownloader.EXTRA_REMOTE_PATH, file.getRemotePath());\r
+ intent.putExtra(FileDownloader.EXTRA_FILE_SIZE, file.getFileLength());\r
+ file.setKeepInSync(true);\r
+ getContext().startService(intent);\r
+ }\r
+ if (getStorageManager().getFileByPath(file.getRemotePath()) != null)\r
+ file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync());\r
+ \r
+ //Log.v(TAG, "adding file: " + file);\r
+ updatedFiles.add(file);\r
+ if (parentId == 0)\r
+ parentId = file.getFileId();\r
+ }\r
+ /* Commented code for ugly performance tests\r
+ long saveDelay = System.currentTimeMillis();\r
+ */ \r
+ getStorageManager().saveFiles(updatedFiles); // all "at once" ; trying to get a best performance in database update\r
+ /* Commented code for ugly performance tests\r
+ saveDelay = System.currentTimeMillis() - saveDelay;\r
+ Log.e(TAG, "syncing: SAVE TIME for " + uri + " contents, " + mSaveDelays[mDelaysIndex] + "ms");\r
+ */\r
+ \r
+ // removal of obsolete files\r
+ Vector<OCFile> files = getStorageManager().getDirectoryContent(\r
+ getStorageManager().getFileById(parentId));\r
+ OCFile file;\r
+ for (int i=0; i < files.size(); ) {\r
+ file = files.get(i);\r
+ if (file.getLastSyncDate() != mCurrentSyncTime) {\r
+ Log.v(TAG, "removing file: " + file);\r
+ getStorageManager().removeFile(file);\r
+ files.remove(i);\r
+ } else {\r
+ i++;\r
+ }\r
+ }\r
+ \r
+ // synchronized folder -> notice to UI\r
+ sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath());\r
+\r
+ // recursive fetch\r
+ for (int i=0; i < files.size() && !mCancellation; i++) {\r
+ OCFile newFile = files.get(i);\r
+ if (newFile.getMimetype().equals("DIR")) {\r
+ fetchData(getUri().toString() + WebdavUtils.encodePath(newFile.getRemotePath()), syncResult, newFile.getFileId());\r
+ }\r
+ }\r
+ if (mCancellation) Log.d(TAG, "Leaving " + uri + " because cancelation request");\r
+ \r
+ /* Commented code for ugly performance tests\r
+ mResponseDelays[mDelaysIndex] = responseDelay;\r
+ mSaveDelays[mDelaysIndex] = saveDelay;\r
+ mDelaysCount++;\r
+ mDelaysIndex++;\r
+ if (mDelaysIndex >= MAX_DELAYS)\r
+ mDelaysIndex = 0;\r
+ */\r
+ \r
+\r
+\r
+ } catch (OperationCanceledException e) {\r
+ e.printStackTrace();\r
+ } catch (AuthenticatorException e) {\r
+ syncResult.stats.numAuthExceptions++;\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ syncResult.stats.numIoExceptions++;\r
+ e.printStackTrace();\r
+ } catch (DavException e) {\r
+ syncResult.stats.numIoExceptions++;\r
+ e.printStackTrace();\r
+ } catch (Throwable t) {\r
+ // TODO update syncResult\r
+ Log.e(TAG, "problem while synchronizing owncloud account " + mAccount.name, t);\r
+ t.printStackTrace();\r
+ }\r
+ }\r
+\r
+ private OCFile fillOCFile(WebdavEntry we) {\r
+ OCFile file = new OCFile(we.decodedPath());\r
+ file.setCreationTimestamp(we.createTimestamp());\r
+ file.setFileLength(we.contentLength());\r
+ file.setMimetype(we.contentType());\r
+ file.setModificationTimestamp(we.modifiedTimesamp());\r
+ file.setLastSyncDate(mCurrentSyncTime);\r
+ return file;\r
+ }\r
+ \r
+ \r
+ private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) {\r
+ Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
+ i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
+ i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
+ if (dirRemotePath != null) {\r
+ i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
+ }\r
+ getContext().sendStickyBroadcast(i);\r
+ }\r
+ \r
+ /**\r
+ * Called by system SyncManager when a synchronization is required to be cancelled.\r
+ * \r
+ * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder\r
+ * fetched will be still saved in the database. See onPerformSync implementation.\r
+ */\r
+ @Override\r
+ public void onSyncCanceled() {\r
+ Log.d(TAG, "Synchronization of " + mAccount.name + " has been requested to cancell");\r
+ mCancellation = true;\r
+ super.onSyncCanceled();\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.syncadapter;\r
+\r
+import android.app.Service;\r
+import android.content.Intent;\r
+import android.os.IBinder;\r
+\r
+/**\r
+ * Background service for syncing files to our local Database\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class FileSyncService extends Service {\r
+ public static final String SYNC_MESSAGE = "ACCOUNT_SYNC";\r
+ public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH";\r
+ public static final String IN_PROGRESS = "SYNC_IN_PROGRESS";\r
+ public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
+\r
+ /*\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onCreate() {\r
+ }\r
+\r
+ /*\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public IBinder onBind(Intent intent) {\r
+ return new FileSyncAdapter(getApplicationContext(), true).getSyncAdapterBinder();\r
+ }\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui;\r
+\r
+import android.graphics.drawable.Drawable;\r
+import android.view.View.OnClickListener;\r
+\r
+/**\r
+ * Represents an Item on the ActionBar.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class ActionItem {\r
+ private Drawable mIcon;\r
+ private String mTitle;\r
+ private OnClickListener mClickListener;\r
+\r
+ public ActionItem() {\r
+ }\r
+\r
+ public void setTitle(String title) {\r
+ mTitle = title;\r
+ }\r
+\r
+ public String getTitle() {\r
+ return mTitle;\r
+ }\r
+\r
+ public void setIcon(Drawable icon) {\r
+ mIcon = icon;\r
+ }\r
+\r
+ public Drawable getIcon() {\r
+ return mIcon;\r
+ }\r
+\r
+ public void setOnClickListener(OnClickListener listener) {\r
+ mClickListener = listener;\r
+ }\r
+\r
+ public OnClickListener getOnClickListerner() {\r
+ return mClickListener;\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui;\r
+\r
+import android.content.Context;\r
+import android.graphics.Rect;\r
+import android.graphics.drawable.BitmapDrawable;\r
+import android.graphics.drawable.Drawable;\r
+import android.view.Gravity;\r
+import android.view.LayoutInflater;\r
+import android.view.MotionEvent;\r
+import android.view.View;\r
+import android.view.WindowManager;\r
+import android.view.View.OnTouchListener;\r
+import android.view.ViewGroup.LayoutParams;\r
+import android.widget.PopupWindow;\r
+\r
+/**\r
+ * Represents a custom PopupWindows\r
+ * \r
+ * @author Lorensius. W. T\r
+ * \r
+ */\r
+public class CustomPopup {\r
+ protected final View mAnchor;\r
+ protected final PopupWindow mWindow;\r
+ private View root;\r
+ private Drawable background = null;\r
+ protected final WindowManager mWManager;\r
+\r
+ public CustomPopup(View anchor) {\r
+ mAnchor = anchor;\r
+ mWindow = new PopupWindow(anchor.getContext());\r
+\r
+ mWindow.setTouchInterceptor(new OnTouchListener() {\r
+\r
+ public boolean onTouch(View v, MotionEvent event) {\r
+ if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {\r
+ CustomPopup.this.dismiss();\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+ });\r
+\r
+ mWManager = (WindowManager) anchor.getContext().getSystemService(\r
+ Context.WINDOW_SERVICE);\r
+ onCreate();\r
+ }\r
+\r
+ public void onCreate() {\r
+ }\r
+\r
+ public void onShow() {\r
+ }\r
+\r
+ public void preShow() {\r
+ if (root == null) {\r
+ throw new IllegalStateException(\r
+ "setContentView called with a view to display");\r
+ }\r
+\r
+ onShow();\r
+\r
+ if (background == null) {\r
+ mWindow.setBackgroundDrawable(new BitmapDrawable());\r
+ } else {\r
+ mWindow.setBackgroundDrawable(background);\r
+ }\r
+\r
+ mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);\r
+ mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);\r
+ mWindow.setTouchable(true);\r
+ mWindow.setFocusable(true);\r
+ mWindow.setOutsideTouchable(true);\r
+\r
+ mWindow.setContentView(root);\r
+ }\r
+\r
+ public void setBackgroundDrawable(Drawable background) {\r
+ this.background = background;\r
+ }\r
+\r
+ public void setContentView(View root) {\r
+ this.root = root;\r
+ mWindow.setContentView(root);\r
+ }\r
+\r
+ public void setContentView(int layoutResId) {\r
+ LayoutInflater inflater = (LayoutInflater) mAnchor.getContext()\r
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
+ setContentView(inflater.inflate(layoutResId, null));\r
+ }\r
+\r
+ public void showDropDown() {\r
+ showDropDown(0, 0);\r
+ }\r
+\r
+ public void showDropDown(int x, int y) {\r
+ preShow();\r
+ mWindow.setAnimationStyle(android.R.style.Animation_Dialog);\r
+ mWindow.showAsDropDown(mAnchor, x, y);\r
+ }\r
+\r
+ public void showLikeQuickAction() {\r
+ showLikeQuickAction(0, 0);\r
+ }\r
+\r
+ public void showLikeQuickAction(int x, int y) {\r
+ preShow();\r
+\r
+ mWindow.setAnimationStyle(android.R.style.Animation_Dialog);\r
+ int[] location = new int[2];\r
+ mAnchor.getLocationOnScreen(location);\r
+\r
+ Rect anchorRect = new Rect(location[0], location[1], location[0]\r
+ + mAnchor.getWidth(), location[1] + mAnchor.getHeight());\r
+\r
+ root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,\r
+ LayoutParams.WRAP_CONTENT));\r
+ root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\r
+\r
+ int rootW = root.getWidth(), rootH = root.getHeight();\r
+ int screenW = mWManager.getDefaultDisplay().getWidth();\r
+\r
+ int xpos = ((screenW - rootW) / 2) + x;\r
+ int ypos = anchorRect.top - rootH + y;\r
+\r
+ if (rootH > anchorRect.top) {\r
+ ypos = anchorRect.bottom + y;\r
+ }\r
+ mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos);\r
+ }\r
+\r
+ public void dismiss() {\r
+ mWindow.dismiss();\r
+ }\r
+\r
+}\r
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui;\r
+\r
+import android.content.Context;\r
+\r
+import android.graphics.Rect;\r
+import android.graphics.drawable.Drawable;\r
+\r
+import android.widget.ImageView;\r
+import android.widget.TextView;\r
+import android.widget.LinearLayout;\r
+import android.widget.ScrollView;\r
+\r
+import android.view.Gravity;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.View.OnClickListener;\r
+import android.view.ViewGroup.LayoutParams;\r
+import android.view.ViewGroup;\r
+\r
+import java.util.ArrayList;\r
+\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * Popup window, shows action list as icon and text like the one in Gallery3D\r
+ * app.\r
+ * \r
+ * @author Lorensius. W. T\r
+ */\r
+public class QuickAction extends CustomPopup {\r
+ private final View root;\r
+ private final ImageView mArrowUp;\r
+ private final ImageView mArrowDown;\r
+ private final LayoutInflater inflater;\r
+ private final Context context;\r
+\r
+ protected static final int ANIM_GROW_FROM_LEFT = 1;\r
+ protected static final int ANIM_GROW_FROM_RIGHT = 2;\r
+ protected static final int ANIM_GROW_FROM_CENTER = 3;\r
+ protected static final int ANIM_REFLECT = 4;\r
+ protected static final int ANIM_AUTO = 5;\r
+\r
+ private int animStyle;\r
+ private ViewGroup mTrack;\r
+ private ScrollView scroller;\r
+ private ArrayList<ActionItem> actionList;\r
+\r
+ /**\r
+ * Constructor\r
+ * \r
+ * @param anchor {@link View} on where the popup window should be displayed\r
+ */\r
+ public QuickAction(View anchor) {\r
+ super(anchor);\r
+\r
+ actionList = new ArrayList<ActionItem>();\r
+ context = anchor.getContext();\r
+ inflater = (LayoutInflater) context\r
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
+\r
+ root = (ViewGroup) inflater.inflate(R.layout.popup, null);\r
+\r
+ mArrowDown = (ImageView) root.findViewById(R.id.arrow_down);\r
+ mArrowUp = (ImageView) root.findViewById(R.id.arrow_up);\r
+\r
+ setContentView(root);\r
+\r
+ mTrack = (ViewGroup) root.findViewById(R.id.tracks);\r
+ scroller = (ScrollView) root.findViewById(R.id.scroller);\r
+ animStyle = ANIM_AUTO;\r
+ }\r
+\r
+ /**\r
+ * Set animation style\r
+ * \r
+ * @param animStyle animation style, default is set to ANIM_AUTO\r
+ */\r
+ public void setAnimStyle(int animStyle) {\r
+ this.animStyle = animStyle;\r
+ }\r
+\r
+ /**\r
+ * Add action item\r
+ * \r
+ * @param action {@link ActionItem} object\r
+ */\r
+ public void addActionItem(ActionItem action) {\r
+ actionList.add(action);\r
+ }\r
+\r
+ /**\r
+ * Show popup window. Popup is automatically positioned, on top or bottom of\r
+ * anchor view.\r
+ * \r
+ */\r
+ public void show() {\r
+ preShow();\r
+\r
+ int xPos, yPos;\r
+\r
+ int[] location = new int[2];\r
+\r
+ mAnchor.getLocationOnScreen(location);\r
+\r
+ Rect anchorRect = new Rect(location[0], location[1], location[0]\r
+ + mAnchor.getWidth(), location[1] + mAnchor.getHeight());\r
+\r
+ createActionList();\r
+\r
+ root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,\r
+ LayoutParams.WRAP_CONTENT));\r
+ root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\r
+\r
+ int rootHeight = root.getMeasuredHeight();\r
+ int rootWidth = root.getMeasuredWidth();\r
+\r
+ int screenWidth = mWManager.getDefaultDisplay().getWidth();\r
+ int screenHeight = mWManager.getDefaultDisplay().getHeight();\r
+\r
+ // automatically get X coord of popup (top left)\r
+ if ((anchorRect.left + rootWidth) > screenWidth) {\r
+ xPos = anchorRect.left - (rootWidth - mAnchor.getWidth());\r
+ } else {\r
+ if (mAnchor.getWidth() > rootWidth) {\r
+ xPos = anchorRect.centerX() - (rootWidth / 2);\r
+ } else {\r
+ xPos = anchorRect.left;\r
+ }\r
+ }\r
+\r
+ int dyTop = anchorRect.top;\r
+ int dyBottom = screenHeight - anchorRect.bottom;\r
+\r
+ boolean onTop = (dyTop > dyBottom) ? true : false;\r
+\r
+ if (onTop) {\r
+ if (rootHeight > dyTop) {\r
+ yPos = 15;\r
+ LayoutParams l = scroller.getLayoutParams();\r
+ l.height = dyTop - mAnchor.getHeight();\r
+ } else {\r
+ yPos = anchorRect.top - rootHeight;\r
+ }\r
+ } else {\r
+ yPos = anchorRect.bottom;\r
+\r
+ if (rootHeight > dyBottom) {\r
+ LayoutParams l = scroller.getLayoutParams();\r
+ l.height = dyBottom;\r
+ }\r
+ }\r
+\r
+ showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up),\r
+ anchorRect.centerX() - xPos);\r
+\r
+ setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);\r
+\r
+ mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos);\r
+ }\r
+\r
+ /**\r
+ * Set animation style\r
+ * \r
+ * @param screenWidth screen width\r
+ * @param requestedX distance from left edge\r
+ * @param onTop flag to indicate where the popup should be displayed. Set\r
+ * TRUE if displayed on top of anchor view and vice versa\r
+ */\r
+ private void setAnimationStyle(int screenWidth, int requestedX,\r
+ boolean onTop) {\r
+ int arrowPos = requestedX - mArrowUp.getMeasuredWidth() / 2;\r
+\r
+ switch (animStyle) {\r
+ case ANIM_GROW_FROM_LEFT:\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left\r
+ : R.style.Animations_PopDownMenu_Left);\r
+ break;\r
+\r
+ case ANIM_GROW_FROM_RIGHT:\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right\r
+ : R.style.Animations_PopDownMenu_Right);\r
+ break;\r
+\r
+ case ANIM_GROW_FROM_CENTER:\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center\r
+ : R.style.Animations_PopDownMenu_Center);\r
+ break;\r
+\r
+ case ANIM_REFLECT:\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect\r
+ : R.style.Animations_PopDownMenu_Reflect);\r
+ break;\r
+\r
+ case ANIM_AUTO:\r
+ if (arrowPos <= screenWidth / 4) {\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left\r
+ : R.style.Animations_PopDownMenu_Left);\r
+ } else if (arrowPos > screenWidth / 4\r
+ && arrowPos < 3 * (screenWidth / 4)) {\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center\r
+ : R.style.Animations_PopDownMenu_Center);\r
+ } else {\r
+ mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right\r
+ : R.style.Animations_PopDownMenu_Right);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Create action list\r
+ */\r
+ private void createActionList() {\r
+ View view;\r
+ String title;\r
+ Drawable icon;\r
+ OnClickListener listener;\r
+\r
+ for (int i = 0; i < actionList.size(); i++) {\r
+ title = actionList.get(i).getTitle();\r
+ icon = actionList.get(i).getIcon();\r
+ listener = actionList.get(i).getOnClickListerner();\r
+\r
+ view = getActionItem(title, icon, listener);\r
+\r
+ view.setFocusable(true);\r
+ view.setClickable(true);\r
+\r
+ mTrack.addView(view);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get action item {@link View}\r
+ * \r
+ * @param title action item title\r
+ * @param icon {@link Drawable} action item icon\r
+ * @param listener {@link View.OnClickListener} action item listener\r
+ * @return action item {@link View}\r
+ */\r
+ private View getActionItem(String title, Drawable icon,\r
+ OnClickListener listener) {\r
+ LinearLayout container = (LinearLayout) inflater.inflate(\r
+ R.layout.action_item, null);\r
+\r
+ ImageView img = (ImageView) container.findViewById(R.id.icon);\r
+ TextView text = (TextView) container.findViewById(R.id.title);\r
+\r
+ if (icon != null) {\r
+ img.setImageDrawable(icon);\r
+ }\r
+\r
+ if (title != null) {\r
+ text.setText(title);\r
+ }\r
+\r
+ if (listener != null) {\r
+ container.setOnClickListener(listener);\r
+ }\r
+\r
+ return container;\r
+ }\r
+\r
+ /**\r
+ * Show arrow\r
+ * \r
+ * @param whichArrow arrow type resource id\r
+ * @param requestedX distance from left screen\r
+ */\r
+ private void showArrow(int whichArrow, int requestedX) {\r
+ final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp\r
+ : mArrowDown;\r
+ final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown\r
+ : mArrowUp;\r
+\r
+ final int arrowWidth = mArrowUp.getMeasuredWidth();\r
+\r
+ showArrow.setVisibility(View.VISIBLE);\r
+\r
+ ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow\r
+ .getLayoutParams();\r
+\r
+ param.leftMargin = requestedX - arrowWidth / 2;\r
+\r
+ hideArrow.setVisibility(View.INVISIBLE);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+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<Boolean> {
+
+ 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<String, String> map = (HashMap<String, String>) 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<HashMap<String, String>> ll = new LinkedList<HashMap<String, String>>();
+ for (Account a : accounts) {
+ HashMap<String, String> h = new HashMap<String, String>();
+ 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<Boolean> 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<? extends Map<String, ?>> mPrivateData;
+
+ public AccountCheckedSimpleAdepter(Context context,
+ List<? extends Map<String, ?>> 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;
+ }
+
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2012 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.ui.activity;\r
+\r
+import java.net.MalformedURLException;\r
+import java.net.URL;\r
+import java.net.URLEncoder;\r
+\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.authenticator.AuthenticationRunnable;\r
+import com.owncloud.android.authenticator.ConnectionCheckerRunnable;\r
+import com.owncloud.android.authenticator.OnAuthenticationResultListener;\r
+import com.owncloud.android.authenticator.OnConnectCheckListener;\r
+import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
+import com.owncloud.android.extensions.ExtensionsAvailableActivity;\r
+import com.owncloud.android.utils.OwnCloudVersion;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountAuthenticatorActivity;\r
+import android.accounts.AccountManager;\r
+import android.app.Dialog;\r
+import android.app.ProgressDialog;\r
+import android.content.ContentResolver;\r
+import android.content.DialogInterface;\r
+import android.content.Intent;\r
+import android.content.SharedPreferences;\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.preference.PreferenceManager;\r
+import android.text.InputType;\r
+import android.util.Log;\r
+import android.view.View;\r
+import android.view.View.OnClickListener;\r
+import android.view.View.OnFocusChangeListener;\r
+import android.view.Window;\r
+import android.widget.ImageView;\r
+import android.widget.TextView;\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * This Activity is used to add an ownCloud account to the App\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
+ implements OnAuthenticationResultListener, OnConnectCheckListener,\r
+ OnFocusChangeListener, OnClickListener {\r
+ private static final int DIALOG_LOGIN_PROGRESS = 0;\r
+\r
+ private static final String TAG = "AuthActivity";\r
+\r
+ private Thread mAuthThread;\r
+ private AuthenticationRunnable mAuthRunnable;\r
+ private ConnectionCheckerRunnable mConnChkRunnable;\r
+ private final Handler mHandler = new Handler();\r
+ private String mBaseUrl;\r
+\r
+ private static final String STATUS_TEXT = "STATUS_TEXT";\r
+ private static final String STATUS_ICON = "STATUS_ICON";\r
+ private static final String STATUS_CORRECT = "STATUS_CORRECT";\r
+ private static final String IS_SSL_CONN = "IS_SSL_CONN";\r
+ private int mStatusText, mStatusIcon;\r
+ private boolean mStatusCorrect, mIsSslConn;\r
+\r
+ public static final String PARAM_USERNAME = "param_Username";\r
+ public static final String PARAM_HOSTNAME = "param_Hostname";\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
+ setContentView(R.layout.account_setup);\r
+ ImageView iv = (ImageView) findViewById(R.id.refreshButton);\r
+ ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);\r
+ TextView tv = (TextView) findViewById(R.id.host_URL);\r
+ TextView tv2 = (TextView) findViewById(R.id.account_password);\r
+\r
+ if (savedInstanceState != null) {\r
+ mStatusIcon = savedInstanceState.getInt(STATUS_ICON);\r
+ mStatusText = savedInstanceState.getInt(STATUS_TEXT);\r
+ mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);\r
+ mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);\r
+ setResultIconAndText(mStatusIcon, mStatusText);\r
+ findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
+ if (!mStatusCorrect)\r
+ iv.setVisibility(View.VISIBLE);\r
+ else\r
+ iv.setVisibility(View.INVISIBLE);\r
+\r
+ } else {\r
+ mStatusText = mStatusIcon = 0;\r
+ mStatusCorrect = false;\r
+ mIsSslConn = false;\r
+ }\r
+ iv.setOnClickListener(this);\r
+ iv2.setOnClickListener(this);\r
+ tv.setOnFocusChangeListener(this);\r
+ tv2.setOnFocusChangeListener(this);\r
+ }\r
+\r
+ @Override\r
+ protected void onSaveInstanceState(Bundle outState) {\r
+ outState.putInt(STATUS_ICON, mStatusIcon);\r
+ outState.putInt(STATUS_TEXT, mStatusText);\r
+ outState.putBoolean(STATUS_CORRECT, mStatusCorrect);\r
+ super.onSaveInstanceState(outState);\r
+ }\r
+\r
+ @Override\r
+ protected Dialog onCreateDialog(int id) {\r
+ Dialog dialog = null;\r
+ switch (id) {\r
+ case DIALOG_LOGIN_PROGRESS: {\r
+ ProgressDialog working_dialog = new ProgressDialog(this);\r
+ working_dialog.setMessage(getResources().getString(\r
+ R.string.auth_trying_to_login));\r
+ working_dialog.setIndeterminate(true);\r
+ working_dialog.setCancelable(true);\r
+ working_dialog\r
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
+ @Override\r
+ public void onCancel(DialogInterface dialog) {\r
+ Log.i(TAG, "Login canceled");\r
+ if (mAuthThread != null) {\r
+ mAuthThread.interrupt();\r
+ finish();\r
+ }\r
+ }\r
+ });\r
+ dialog = working_dialog;\r
+ break;\r
+ }\r
+ default:\r
+ Log.e(TAG, "Incorrect dialog called with id = " + id);\r
+ }\r
+ return dialog;\r
+ }\r
+\r
+ public void onAuthenticationResult(boolean success, String message) {\r
+ if (success) {\r
+ TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);\r
+\r
+ URL url;\r
+ try {\r
+ url = new URL(message);\r
+ } catch (MalformedURLException e) {\r
+ // should never happen\r
+ Log.e(getClass().getName(), "Malformed URL: " + message);\r
+ return;\r
+ }\r
+\r
+ String username = username_text.getText().toString().trim();\r
+ String accountName = username + "@" + url.getHost();\r
+ if (url.getPort() >= 0) {\r
+ accountName += ":" + url.getPort();\r
+ }\r
+ Account account = new Account(accountName,\r
+ AccountAuthenticator.ACCOUNT_TYPE);\r
+ AccountManager accManager = AccountManager.get(this);\r
+ accManager.addAccountExplicitly(account, password_text.getText()\r
+ .toString(), null);\r
+\r
+ // Add this account as default in the preferences, if there is none\r
+ // already\r
+ Account defaultAccount = AccountUtils\r
+ .getCurrentOwnCloudAccount(this);\r
+ if (defaultAccount == null) {\r
+ SharedPreferences.Editor editor = PreferenceManager\r
+ .getDefaultSharedPreferences(this).edit();\r
+ editor.putString("select_oc_account", accountName);\r
+ editor.commit();\r
+ }\r
+\r
+ final Intent intent = new Intent();\r
+ intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,\r
+ AccountAuthenticator.ACCOUNT_TYPE);\r
+ intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
+ intent.putExtra(AccountManager.KEY_AUTHTOKEN,\r
+ AccountAuthenticator.ACCOUNT_TYPE);\r
+ intent.putExtra(AccountManager.KEY_USERDATA, username);\r
+\r
+ accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL,\r
+ url.toString());\r
+ accManager.setUserData(account,\r
+ AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable\r
+ .getDiscoveredVersion().toString());\r
+ accManager.setUserData(account,\r
+ AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);\r
+\r
+ setAccountAuthenticatorResult(intent.getExtras());\r
+ setResult(RESULT_OK, intent);\r
+ Bundle bundle = new Bundle();\r
+ bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
+ //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,\r
+ // bundle);\r
+ ContentResolver.requestSync(account, "org.owncloud", bundle);\r
+\r
+ /*\r
+ * if\r
+ * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion\r
+ * .owncloud_v2) >= 0) { Intent i = new Intent(this,\r
+ * ExtensionsAvailableActivity.class); startActivity(i); }\r
+ */\r
+\r
+ finish();\r
+ } else {\r
+ dismissDialog(DIALOG_LOGIN_PROGRESS);\r
+ TextView tv = (TextView) findViewById(R.id.account_username);\r
+ tv.setError(message);\r
+ }\r
+ }\r
+ public void onCancelClick(View view) {\r
+ finish();\r
+ }\r
+ \r
+ public void onOkClick(View view) {\r
+ String prefix = "";\r
+ String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
+ .toString();\r
+ if (mIsSslConn) {\r
+ prefix = "https://";\r
+ } else {\r
+ prefix = "http://";\r
+ }\r
+ if (url.toLowerCase().startsWith("http://")\r
+ || url.toLowerCase().startsWith("https://")) {\r
+ prefix = "";\r
+ }\r
+ continueConnection(prefix);\r
+ }\r
+\r
+ private void continueConnection(String prefix) {\r
+ String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
+ .toString();\r
+ String username = ((TextView) findViewById(R.id.account_username))\r
+ .getText().toString();\r
+ String password = ((TextView) findViewById(R.id.account_password))\r
+ .getText().toString();\r
+ if (url.endsWith("/"))\r
+ url = url.substring(0, url.length() - 1);\r
+\r
+ URL uri = null;\r
+ String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable\r
+ .getDiscoveredVersion());\r
+\r
+ try {\r
+ mBaseUrl = prefix + url;\r
+ String url_str = prefix + url + webdav_path;\r
+ uri = new URL(url_str);\r
+ } catch (MalformedURLException e) {\r
+ // should not happend\r
+ e.printStackTrace();\r
+ }\r
+\r
+ showDialog(DIALOG_LOGIN_PROGRESS);\r
+ mAuthRunnable = new AuthenticationRunnable(uri, username, password);\r
+ mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);\r
+ mAuthThread = new Thread(mAuthRunnable);\r
+ mAuthThread.start();\r
+ }\r
+\r
+ @Override\r
+ public void onConnectionCheckResult(ResultType type) {\r
+ mStatusText = mStatusIcon = 0;\r
+ mStatusCorrect = false;\r
+ String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
+ .toString().toLowerCase();\r
+\r
+ switch (type) {\r
+ case OK_SSL:\r
+ mIsSslConn = true;\r
+ mStatusIcon = android.R.drawable.ic_secure;\r
+ mStatusText = R.string.auth_secure_connection;\r
+ mStatusCorrect = true;\r
+ break;\r
+ case OK_NO_SSL:\r
+ mIsSslConn = false;\r
+ mStatusCorrect = true;\r
+ if (t_url.startsWith("http://") ) {\r
+ mStatusText = R.string.auth_connection_established;\r
+ mStatusIcon = R.drawable.ic_ok;\r
+ } else {\r
+ mStatusText = R.string.auth_nossl_plain_ok_title;\r
+ mStatusIcon = android.R.drawable.ic_partial_secure;\r
+ }\r
+ break;\r
+ case TIMEOUT:\r
+ case INORRECT_ADDRESS:\r
+ case SSL_INIT_ERROR:\r
+ case HOST_NOT_AVAILABLE:\r
+ mStatusIcon = R.drawable.common_error;\r
+ mStatusText = R.string.auth_unknow_host_title;\r
+ break;\r
+ case NO_NETWORK_CONNECTION:\r
+ mStatusIcon = R.drawable.no_network;\r
+ mStatusText = R.string.auth_no_net_conn_title;\r
+ break;\r
+ case INSTANCE_NOT_CONFIGURED:\r
+ mStatusIcon = R.drawable.common_error;\r
+ mStatusText = R.string.auth_not_configured_title;\r
+ break;\r
+ case UNKNOWN_ERROR:\r
+ mStatusIcon = R.drawable.common_error;\r
+ mStatusText = R.string.auth_unknow_error;\r
+ break;\r
+ case FILE_NOT_FOUND:\r
+ mStatusIcon = R.drawable.common_error;\r
+ mStatusText = R.string.auth_incorrect_path_title;\r
+ break;\r
+ default:\r
+ Log.e(TAG, "Incorrect connection checker result type: " + type);\r
+ }\r
+ setResultIconAndText(mStatusIcon, mStatusText);\r
+ if (!mStatusCorrect)\r
+ findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
+ else\r
+ findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
+ findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
+ }\r
+\r
+ @Override\r
+ public void onFocusChange(View view, boolean hasFocus) {\r
+ if (view.getId() == R.id.host_URL) {\r
+ if (!hasFocus) {\r
+ TextView tv = ((TextView) findViewById(R.id.host_URL));\r
+ String uri = tv.getText().toString();\r
+ if (uri.length() != 0) {\r
+ setResultIconAndText(R.drawable.progress_small,\r
+ R.string.auth_testing_connection);\r
+ findViewById(R.id.buttonOK).setEnabled(false); // avoid connect can be clicked if the test was previously passed\r
+ mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);\r
+ mConnChkRunnable.setListener(this, mHandler);\r
+ mAuthThread = new Thread(mConnChkRunnable);\r
+ mAuthThread.start();\r
+ } else {\r
+ findViewById(R.id.refreshButton).setVisibility(\r
+ View.INVISIBLE);\r
+ setResultIconAndText(0, 0);\r
+ }\r
+ }\r
+ } else if (view.getId() == R.id.account_password) {\r
+ ImageView iv = (ImageView) findViewById(R.id.viewPassword);\r
+ if (hasFocus) {\r
+ iv.setVisibility(View.VISIBLE);\r
+ } else {\r
+ TextView v = (TextView) findViewById(R.id.account_password);\r
+ int input_type = InputType.TYPE_CLASS_TEXT\r
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
+ v.setInputType(input_type);\r
+ iv.setVisibility(View.INVISIBLE);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void setResultIconAndText(int drawable_id, int text_id) {\r
+ ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
+ TextView tv = (TextView) findViewById(R.id.status_text);\r
+\r
+ if (drawable_id == 0 && text_id == 0) {\r
+ iv.setVisibility(View.INVISIBLE);\r
+ tv.setVisibility(View.INVISIBLE);\r
+ } else {\r
+ iv.setImageResource(drawable_id);\r
+ tv.setText(text_id);\r
+ iv.setVisibility(View.VISIBLE);\r
+ tv.setVisibility(View.VISIBLE);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void onClick(View v) {\r
+ if (v.getId() == R.id.refreshButton) {\r
+ onFocusChange(findViewById(R.id.host_URL), false);\r
+ } else if (v.getId() == R.id.viewPassword) {\r
+ TextView view = (TextView) findViewById(R.id.account_password);\r
+ int input_type = InputType.TYPE_CLASS_TEXT\r
+ | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
+ view.setInputType(input_type);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.activity;\r
+\r
+import android.accounts.Account;\r
+import android.app.Dialog;\r
+import android.app.ProgressDialog;\r
+import android.content.Intent;\r
+import android.content.res.Configuration;\r
+import android.os.Bundle;\r
+import android.support.v4.app.FragmentTransaction;\r
+\r
+import com.actionbarsherlock.app.ActionBar;\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+import com.actionbarsherlock.view.MenuItem;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.files.services.FileDownloader;\r
+import com.owncloud.android.ui.fragment.FileDetailFragment;\r
+\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * This activity displays the details of a file like its name, its size and so\r
+ * on.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity {\r
+ \r
+ public static final int DIALOG_SHORT_WAIT = 0;\r
+ \r
+ private boolean mConfigurationChangedToLandscape = false;\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+\r
+ // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity \r
+ Configuration conf = getResources().getConfiguration();\r
+ mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && \r
+ (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE\r
+ );\r
+\r
+ if (!mConfigurationChangedToLandscape) {\r
+ setContentView(R.layout.file_activity_details);\r
+ \r
+ ActionBar actionBar = getSupportActionBar();\r
+ actionBar.setDisplayHomeAsUpEnabled(true);\r
+ \r
+ OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
+ Account account = getIntent().getParcelableExtra(FileDownloader.EXTRA_ACCOUNT);\r
+ FileDetailFragment mFileDetail = new FileDetailFragment(file, account);\r
+ \r
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
+ ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG);\r
+ ft.commit();\r
+ \r
+ } else {\r
+ backToDisplayActivity(); // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
+ }\r
+ \r
+ \r
+ }\r
+\r
+ @Override\r
+ public boolean onOptionsItemSelected(MenuItem item) {\r
+ boolean returnValue = false;\r
+ \r
+ switch(item.getItemId()){\r
+ case android.R.id.home:\r
+ backToDisplayActivity();\r
+ returnValue = true;\r
+ }\r
+ \r
+ return returnValue;\r
+ }\r
+\r
+\r
+\r
+ @Override\r
+ protected void onResume() {\r
+ \r
+ super.onResume();\r
+ if (!mConfigurationChangedToLandscape) { \r
+ FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+ fragment.updateFileDetails();\r
+ }\r
+ }\r
+ \r
+\r
+ private void backToDisplayActivity() {\r
+ Intent intent = new Intent(this, FileDisplayActivity.class);\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
+ intent.putExtra(FileDetailFragment.EXTRA_FILE, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE));\r
+ startActivity(intent);\r
+ finish();\r
+ }\r
+ \r
+ \r
+ @Override\r
+ protected Dialog onCreateDialog(int id) {\r
+ Dialog dialog = null;\r
+ switch (id) {\r
+ case DIALOG_SHORT_WAIT: {\r
+ ProgressDialog working_dialog = new ProgressDialog(this);\r
+ working_dialog.setMessage(getResources().getString(\r
+ R.string.wait_a_moment));\r
+ working_dialog.setIndeterminate(true);\r
+ working_dialog.setCancelable(false);\r
+ dialog = working_dialog;\r
+ break;\r
+ }\r
+ default:\r
+ dialog = null;\r
+ }\r
+ return dialog;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onFileStateChanged() {\r
+ // nothing to do here!\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.ui.activity;\r
+\r
+import java.io.File;\r
+import java.util.ArrayList;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.app.AlertDialog;\r
+import android.app.ProgressDialog;\r
+import android.app.AlertDialog.Builder;\r
+import android.app.Dialog;\r
+import android.content.BroadcastReceiver;\r
+import android.content.ContentResolver;\r
+import android.content.Context;\r
+import android.content.DialogInterface;\r
+import android.content.DialogInterface.OnClickListener;\r
+import android.content.Intent;\r
+import android.content.IntentFilter;\r
+import android.content.SharedPreferences;\r
+import android.content.pm.PackageInfo;\r
+import android.content.pm.PackageManager.NameNotFoundException;\r
+import android.content.res.Resources.NotFoundException;\r
+import android.database.Cursor;\r
+import android.net.Uri;\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.preference.PreferenceManager;\r
+import android.provider.MediaStore;\r
+import android.support.v4.app.FragmentTransaction;\r
+import android.util.Log;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.EditText;\r
+import android.widget.TextView;\r
+import android.widget.Toast;\r
+\r
+import com.actionbarsherlock.app.ActionBar;\r
+import com.actionbarsherlock.app.ActionBar.OnNavigationListener;\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+import com.actionbarsherlock.view.Window;\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.CrashHandler;\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.datamodel.DataStorageManager;\r
+import com.owncloud.android.datamodel.FileDataStorageManager;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.files.services.FileDownloader;\r
+import com.owncloud.android.files.services.FileUploader;\r
+import com.owncloud.android.syncadapter.FileSyncService;\r
+import com.owncloud.android.ui.fragment.FileDetailFragment;\r
+import com.owncloud.android.ui.fragment.FileListFragment;\r
+\r
+import com.owncloud.android.R;\r
+import eu.alefzero.webdav.WebdavClient;\r
+\r
+/**\r
+ * Displays, what files the user has available in his ownCloud.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+\r
+public class FileDisplayActivity extends SherlockFragmentActivity implements\r
+ FileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnClickListener, android.view.View.OnClickListener {\r
+ \r
+ private ArrayAdapter<String> mDirectories;\r
+ private OCFile mCurrentDir;\r
+ private String[] mDirs = null;\r
+\r
+ private DataStorageManager mStorageManager;\r
+ private SyncBroadcastReceiver mSyncBroadcastReceiver;\r
+ private UploadFinishReceiver mUploadFinishReceiver;\r
+ private DownloadFinishReceiver mDownloadFinishReceiver;\r
+ \r
+ private View mLayoutView = null;\r
+ private FileListFragment mFileList;\r
+ \r
+ private boolean mDualPane;\r
+ \r
+ private boolean mForcedLoginToCreateFirstAccount = false;\r
+ \r
+ private static final String KEY_DIR_ARRAY = "DIR_ARRAY";\r
+ private static final String KEY_CURRENT_DIR = "DIR";\r
+ \r
+ private static final int DIALOG_SETUP_ACCOUNT = 0;\r
+ private static final int DIALOG_CREATE_DIR = 1;\r
+ private static final int DIALOG_ABOUT_APP = 2;\r
+ public static final int DIALOG_SHORT_WAIT = 3;\r
+ \r
+ private static final int ACTION_SELECT_FILE = 1;\r
+ \r
+ private static final String TAG = "FileDisplayActivity";\r
+ \r
+ \r
+ @Override\r
+ public void onCreate(Bundle savedInstanceState) {\r
+ Log.i(getClass().toString(), "onCreate() start");\r
+ super.onCreate(savedInstanceState);\r
+\r
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);\r
+\r
+ Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(getApplicationContext()));\r
+\r
+ if(savedInstanceState != null) {\r
+ mDirs = savedInstanceState.getStringArray(KEY_DIR_ARRAY);\r
+ mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);\r
+ mDirectories.add(OCFile.PATH_SEPARATOR);\r
+ if (mDirs != null)\r
+ for (String s : mDirs)\r
+ mDirectories.insert(s, 0);\r
+ mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
+ }\r
+ \r
+ mLayoutView = getLayoutInflater().inflate(R.layout.files, null); // always inflate this at onCreate() ; just once!\r
+ \r
+ if (AccountUtils.accountsAreSetup(this)) {\r
+ \r
+ initDelayedTilAccountAvailabe();\r
+ \r
+ // PIN CODE request ; best location is to decide, let's try this first\r
+ //if (savedInstanceState == null) {\r
+ if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {\r
+ requestPinCode();\r
+ }\r
+ \r
+ \r
+ } else {\r
+ \r
+ setContentView(R.layout.no_account_available);\r
+ getSupportActionBar().setNavigationMode(ActionBar.DISPLAY_SHOW_TITLE);\r
+ findViewById(R.id.setup_account).setOnClickListener(this);\r
+\r
+ setSupportProgressBarIndeterminateVisibility(false);\r
+\r
+ Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
+ intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
+ startActivity(intent); // although the code is here, the activity won't be created until this.onStart() and this.onResume() are finished;\r
+ mForcedLoginToCreateFirstAccount = true;\r
+ }\r
+ \r
+ Log.i(getClass().toString(), "onCreate() end");\r
+ }\r
+\r
+ @Override\r
+ public boolean onCreateOptionsMenu(Menu menu) {\r
+ MenuInflater inflater = getSherlock().getMenuInflater();\r
+ inflater.inflate(R.menu.menu, menu);\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public boolean onOptionsItemSelected(MenuItem item) {\r
+ boolean retval = true;\r
+ switch (item.getItemId()) {\r
+ case R.id.createDirectoryItem: {\r
+ showDialog(DIALOG_CREATE_DIR);\r
+ break;\r
+ }\r
+ case R.id.startSync: {\r
+ ContentResolver.cancelSync(null, "org.owncloud"); // cancel the current synchronizations of any ownCloud account\r
+ Bundle bundle = new Bundle();\r
+ bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
+ ContentResolver.requestSync(\r
+ AccountUtils.getCurrentOwnCloudAccount(this),\r
+ "org.owncloud", bundle);\r
+ break;\r
+ }\r
+ case R.id.action_upload: {\r
+ Intent action = new Intent(Intent.ACTION_GET_CONTENT);\r
+ action = action.setType("*/*")\r
+ .addCategory(Intent.CATEGORY_OPENABLE);\r
+ startActivityForResult(\r
+ Intent.createChooser(action, getString(R.string.upload_chooser_title)),\r
+ ACTION_SELECT_FILE);\r
+ break;\r
+ }\r
+ case R.id.action_settings: {\r
+ Intent settingsIntent = new Intent(this, Preferences.class);\r
+ startActivity(settingsIntent);\r
+ break;\r
+ }\r
+ case R.id.about_app : {\r
+ showDialog(DIALOG_ABOUT_APP);\r
+ break;\r
+ }\r
+ case android.R.id.home: {\r
+ if(mCurrentDir != null && mCurrentDir.getParentId() != 0){\r
+ onBackPressed(); \r
+ }\r
+ break;\r
+ }\r
+ default:\r
+ retval = false;\r
+ }\r
+ return retval;\r
+ }\r
+\r
+ @Override\r
+ public boolean onNavigationItemSelected(int itemPosition, long itemId) {\r
+ int i = itemPosition;\r
+ while (i-- != 0) {\r
+ onBackPressed();\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Called, when the user selected something for uploading\r
+ */\r
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {\r
+ if (requestCode == ACTION_SELECT_FILE) {\r
+ if (resultCode == RESULT_OK) {\r
+ String filepath = null;\r
+ try {\r
+ Uri selectedImageUri = data.getData();\r
+ \r
+ String filemanagerstring = selectedImageUri.getPath();\r
+ String selectedImagePath = getPath(selectedImageUri);\r
+ \r
+ if (selectedImagePath != null)\r
+ filepath = selectedImagePath;\r
+ else\r
+ filepath = filemanagerstring;\r
+ \r
+ } catch (Exception e) {\r
+ Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);\r
+ e.printStackTrace();\r
+ \r
+ } finally {\r
+ if (filepath == null) {\r
+ Log.e("FileDisplay", "Couldnt resolve path to file");\r
+ Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);\r
+ t.show();\r
+ return;\r
+ }\r
+ }\r
+ \r
+ Intent i = new Intent(this, FileUploader.class);\r
+ i.putExtra(FileUploader.KEY_ACCOUNT,\r
+ AccountUtils.getCurrentOwnCloudAccount(this));\r
+ String remotepath = new String();\r
+ for (int j = mDirectories.getCount() - 2; j >= 0; --j) {\r
+ remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);\r
+ }\r
+ if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))\r
+ remotepath += OCFile.PATH_SEPARATOR;\r
+ remotepath += new File(filepath).getName();\r
+ \r
+ i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);\r
+ i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);\r
+ i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);\r
+ startService(i);\r
+ }\r
+ \r
+ }/* dvelasco: WIP - not working as expected ... yet :)\r
+ else if (requestCode == ACTION_CREATE_FIRST_ACCOUNT) {\r
+ if (resultCode != RESULT_OK) {\r
+ finish(); // the user cancelled the AuthenticatorActivity\r
+ }\r
+ }*/\r
+ }\r
+\r
+ @Override\r
+ public void onBackPressed() {\r
+ if (mDirectories == null || mDirectories.getCount() <= 1) {\r
+ finish();\r
+ return;\r
+ }\r
+ popDirname();\r
+ mFileList.onNavigateUp();\r
+ mCurrentDir = mFileList.getCurrentFile();\r
+ \r
+ if(mCurrentDir.getParentId() == 0){\r
+ ActionBar actionBar = getSupportActionBar(); \r
+ actionBar.setDisplayHomeAsUpEnabled(false);\r
+ } \r
+ }\r
+\r
+ @Override\r
+ protected void onSaveInstanceState(Bundle outState) {\r
+ // responsability of restore is prefered in onCreate() before than in onRestoreInstanceState when there are Fragments involved\r
+ Log.i(getClass().toString(), "onSaveInstanceState() start");\r
+ super.onSaveInstanceState(outState);\r
+ if(mDirectories != null && mDirectories.getCount() != 0){\r
+ mDirs = new String[mDirectories.getCount()-1];\r
+ for (int j = mDirectories.getCount() - 2, i = 0; j >= 0; --j, ++i) {\r
+ mDirs[i] = mDirectories.getItem(j);\r
+ }\r
+ }\r
+ outState.putStringArray(KEY_DIR_ARRAY, mDirs);\r
+ outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);\r
+ Log.i(getClass().toString(), "onSaveInstanceState() end");\r
+ }\r
+\r
+ @Override\r
+ protected void onResume() {\r
+ Log.i(getClass().toString(), "onResume() start");\r
+ super.onResume();\r
+\r
+ if (AccountUtils.accountsAreSetup(this)) {\r
+ // at least an account exist: normal operation\r
+ \r
+ // set the layout only if it couldn't be set in onCreate\r
+ if (mForcedLoginToCreateFirstAccount) {\r
+ initDelayedTilAccountAvailabe();\r
+ mForcedLoginToCreateFirstAccount = false;\r
+ }\r
+\r
+ // Listen for sync messages\r
+ IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE);\r
+ mSyncBroadcastReceiver = new SyncBroadcastReceiver();\r
+ registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);\r
+ \r
+ // Listen for upload messages\r
+ IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
+ mUploadFinishReceiver = new UploadFinishReceiver();\r
+ registerReceiver(mUploadFinishReceiver, uploadIntentFilter);\r
+ \r
+ // Listen for download messages\r
+ IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
+ mDownloadFinishReceiver = new DownloadFinishReceiver();\r
+ registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);\r
+ \r
+ // Storage manager initialization\r
+ mStorageManager = new FileDataStorageManager(\r
+ AccountUtils.getCurrentOwnCloudAccount(this),\r
+ getContentResolver());\r
+ \r
+ // File list fragments \r
+ mFileList = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
+ \r
+ \r
+ // Figure out what directory to list. \r
+ // Priority: Intent (here), savedInstanceState (onCreate), root dir (dir is null)\r
+ if(getIntent().hasExtra(FileDetailFragment.EXTRA_FILE)){\r
+ mCurrentDir = (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
+ if(mCurrentDir != null && !mCurrentDir.isDirectory()){\r
+ mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId());\r
+ }\r
+ \r
+ // Clear intent extra, so rotating the screen will not return us to this directory\r
+ getIntent().removeExtra(FileDetailFragment.EXTRA_FILE);\r
+ }\r
+ \r
+ if (mCurrentDir == null)\r
+ mCurrentDir = mStorageManager.getFileByPath("/");\r
+ \r
+ // Drop-Down navigation and file list restore\r
+ mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);\r
+ \r
+ \r
+ // Given the case we have a file to display:\r
+ if(mCurrentDir != null){\r
+ ArrayList<OCFile> files = new ArrayList<OCFile>();\r
+ OCFile currFile = mCurrentDir;\r
+ while(currFile != null){\r
+ files.add(currFile);\r
+ currFile = mStorageManager.getFileById(currFile.getParentId());\r
+ }\r
+ \r
+ // Insert in mDirs\r
+ mDirs = new String[files.size()];\r
+ for(int i = files.size() - 1; i >= 0; i--){\r
+ mDirs[i] = files.get(i).getFileName();\r
+ }\r
+ }\r
+ \r
+ if (mDirs != null) {\r
+ for (String s : mDirs)\r
+ mDirectories.add(s);\r
+ } else {\r
+ mDirectories.add(OCFile.PATH_SEPARATOR);\r
+ }\r
+ \r
+ // Actionbar setup\r
+ ActionBar action_bar = getSupportActionBar();\r
+ action_bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);\r
+ action_bar.setDisplayShowTitleEnabled(false);\r
+ action_bar.setListNavigationCallbacks(mDirectories, this);\r
+ if(mCurrentDir != null && mCurrentDir.getParentId() != 0){\r
+ action_bar.setDisplayHomeAsUpEnabled(true);\r
+ } else {\r
+ action_bar.setDisplayHomeAsUpEnabled(false);\r
+ }\r
+ \r
+ // List dir here\r
+ mFileList.listDirectory(mCurrentDir);\r
+ }\r
+ Log.i(getClass().toString(), "onResume() end");\r
+ }\r
+\r
+ @Override\r
+ protected void onPause() {\r
+ Log.i(getClass().toString(), "onPause() start");\r
+ super.onPause();\r
+ if (mSyncBroadcastReceiver != null) {\r
+ unregisterReceiver(mSyncBroadcastReceiver);\r
+ mSyncBroadcastReceiver = null;\r
+ }\r
+ if (mUploadFinishReceiver != null) {\r
+ unregisterReceiver(mUploadFinishReceiver);\r
+ mUploadFinishReceiver = null;\r
+ }\r
+ if (mDownloadFinishReceiver != null) {\r
+ unregisterReceiver(mDownloadFinishReceiver);\r
+ mDownloadFinishReceiver = null;\r
+ }\r
+ \r
+ getIntent().putExtra(FileDetailFragment.EXTRA_FILE, mCurrentDir);\r
+ Log.i(getClass().toString(), "onPause() end");\r
+ }\r
+\r
+ @Override\r
+ protected Dialog onCreateDialog(int id) {\r
+ Dialog dialog = null;\r
+ AlertDialog.Builder builder;\r
+ switch (id) {\r
+ case DIALOG_SETUP_ACCOUNT:\r
+ builder = new AlertDialog.Builder(this);\r
+ builder.setTitle(R.string.main_tit_accsetup);\r
+ builder.setMessage(R.string.main_wrn_accsetup);\r
+ builder.setCancelable(false);\r
+ builder.setPositiveButton(android.R.string.ok, this);\r
+ builder.setNegativeButton(android.R.string.cancel, this);\r
+ dialog = builder.create();\r
+ break;\r
+ case DIALOG_ABOUT_APP: {\r
+ builder = new AlertDialog.Builder(this);\r
+ builder.setTitle(getString(R.string.about_title));\r
+ PackageInfo pkg;\r
+ try {\r
+ pkg = getPackageManager().getPackageInfo(getPackageName(), 0);\r
+ builder.setMessage("ownCloud android client\n\nversion: " + pkg.versionName );\r
+ builder.setIcon(android.R.drawable.ic_menu_info_details);\r
+ dialog = builder.create();\r
+ } catch (NameNotFoundException e) {\r
+ builder = null;\r
+ dialog = null;\r
+ Log.e(TAG, "Error while showing about dialog", e);\r
+ }\r
+ break;\r
+ }\r
+ case DIALOG_CREATE_DIR: {\r
+ builder = new Builder(this);\r
+ final EditText dirNameInput = new EditText(getBaseContext());\r
+ final Account a = AccountUtils.getCurrentOwnCloudAccount(this);\r
+ builder.setView(dirNameInput);\r
+ builder.setTitle(R.string.uploader_info_dirname);\r
+ int typed_color = getResources().getColor(R.color.setup_text_typed);\r
+ dirNameInput.setTextColor(typed_color);\r
+ builder.setPositiveButton(android.R.string.ok,\r
+ new OnClickListener() {\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ String directoryName = dirNameInput.getText().toString();\r
+ if (directoryName.trim().length() == 0) {\r
+ dialog.cancel();\r
+ return;\r
+ }\r
+ \r
+ // Figure out the path where the dir needs to be created\r
+ String path;\r
+ if (mCurrentDir == null) {\r
+ // this is just a patch; we should ensure that mCurrentDir never is null\r
+ if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {\r
+ OCFile file = new OCFile(OCFile.PATH_SEPARATOR);\r
+ mStorageManager.saveFile(file);\r
+ }\r
+ mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);\r
+ }\r
+ path = FileDisplayActivity.this.mCurrentDir.getRemotePath();\r
+ \r
+ // Create directory\r
+ path += directoryName + OCFile.PATH_SEPARATOR;\r
+ Thread thread = new Thread(new DirectoryCreator(path, a, new Handler()));\r
+ thread.start();\r
+ \r
+ dialog.dismiss();\r
+ \r
+ showDialog(DIALOG_SHORT_WAIT);\r
+ }\r
+ });\r
+ builder.setNegativeButton(R.string.common_cancel,\r
+ new OnClickListener() {\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ dialog.cancel();\r
+ }\r
+ });\r
+ dialog = builder.create();\r
+ break;\r
+ }\r
+ case DIALOG_SHORT_WAIT: {\r
+ ProgressDialog working_dialog = new ProgressDialog(this);\r
+ working_dialog.setMessage(getResources().getString(\r
+ R.string.wait_a_moment));\r
+ working_dialog.setIndeterminate(true);\r
+ working_dialog.setCancelable(false);\r
+ dialog = working_dialog;\r
+ break;\r
+ }\r
+ default:\r
+ dialog = null;\r
+ }\r
+ \r
+ return dialog;\r
+ }\r
+\r
+ \r
+ /**\r
+ * Responds to the "There are no ownCloud Accounts setup" dialog\r
+ * TODO: Dialog is 100% useless -> Remove\r
+ */\r
+ @Override\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ // In any case - we won't need it anymore\r
+ dialog.dismiss();\r
+ switch (which) {\r
+ case DialogInterface.BUTTON_POSITIVE:\r
+ Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
+ intent.putExtra("authorities",\r
+ new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
+ startActivity(intent);\r
+ break;\r
+ case DialogInterface.BUTTON_NEGATIVE:\r
+ finish();\r
+ }\r
+ \r
+ }\r
+\r
+ /**\r
+ * Translates a content URI of an image to a physical path\r
+ * on the disk\r
+ * @param uri The URI to resolve\r
+ * @return The path to the image or null if it could not be found\r
+ */\r
+ public String getPath(Uri uri) {\r
+ String[] projection = { MediaStore.Images.Media.DATA };\r
+ Cursor cursor = managedQuery(uri, projection, null, null, null);\r
+ if (cursor != null) {\r
+ int column_index = cursor\r
+ .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);\r
+ cursor.moveToFirst();\r
+ return cursor.getString(column_index);\r
+ } \r
+ return null;\r
+ }\r
+ \r
+ /**\r
+ * Pushes a directory to the drop down list\r
+ * @param directory to push\r
+ * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false.\r
+ */\r
+ public void pushDirname(OCFile directory) {\r
+ if(!directory.isDirectory()){\r
+ throw new IllegalArgumentException("Only directories may be pushed!");\r
+ }\r
+ mDirectories.insert(directory.getFileName(), 0);\r
+ mCurrentDir = directory;\r
+ }\r
+\r
+ /**\r
+ * Pops a directory name from the drop down list\r
+ * @return True, unless the stack is empty\r
+ */\r
+ public boolean popDirname() {\r
+ mDirectories.remove(mDirectories.getItem(0));\r
+ return !mDirectories.isEmpty();\r
+ }\r
+\r
+ private class DirectoryCreator implements Runnable {\r
+ private String mTargetPath;\r
+ private Account mAccount;\r
+ private AccountManager mAm;\r
+ private Handler mHandler; \r
+ \r
+ public DirectoryCreator(String targetPath, Account account, Handler handler) {\r
+ mTargetPath = targetPath;\r
+ mAccount = account;\r
+ mAm = (AccountManager) getSystemService(ACCOUNT_SERVICE);\r
+ mHandler = handler;\r
+ }\r
+ \r
+ @Override\r
+ public void run() {\r
+ WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext());\r
+ \r
+ String username = mAccount.name.substring(0,\r
+ mAccount.name.lastIndexOf('@'));\r
+ String password = mAm.getPassword(mAccount);\r
+ \r
+ wdc.setCredentials(username, password);\r
+ wdc.allowSelfsignedCertificates();\r
+ boolean created = wdc.createDirectory(mTargetPath);\r
+ if (created) {\r
+ mHandler.post(new Runnable() {\r
+ @Override\r
+ public void run() { \r
+ dismissDialog(DIALOG_SHORT_WAIT);\r
+ \r
+ // Save new directory in local database\r
+ OCFile newDir = new OCFile(mTargetPath);\r
+ newDir.setMimetype("DIR");\r
+ newDir.setParentId(mCurrentDir.getFileId());\r
+ mStorageManager.saveFile(newDir);\r
+ \r
+ // Display the new folder right away\r
+ mFileList.listDirectory(mCurrentDir);\r
+ }\r
+ });\r
+ \r
+ } else {\r
+ mHandler.post(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ dismissDialog(DIALOG_SHORT_WAIT);\r
+ try {\r
+ Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); \r
+ msg.show();\r
+ \r
+ } catch (NotFoundException e) {\r
+ Log.e(TAG, "Error while trying to show fail message " , e);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+ \r
+ }\r
+\r
+ // Custom array adapter to override text colors\r
+ private class CustomArrayAdapter<T> extends ArrayAdapter<T> {\r
+ \r
+ public CustomArrayAdapter(FileDisplayActivity ctx, int view) {\r
+ super(ctx, view);\r
+ }\r
+ \r
+ public View getView(int position, View convertView, ViewGroup parent) {\r
+ View v = super.getView(position, convertView, parent);\r
+ \r
+ ((TextView) v).setTextColor(getResources().getColorStateList(\r
+ android.R.color.white));\r
+ return v;\r
+ }\r
+ \r
+ public View getDropDownView(int position, View convertView,\r
+ ViewGroup parent) {\r
+ View v = super.getDropDownView(position, convertView, parent);\r
+ \r
+ ((TextView) v).setTextColor(getResources().getColorStateList(\r
+ android.R.color.white));\r
+ \r
+ return v;\r
+ }\r
+ \r
+ }\r
+\r
+ private class SyncBroadcastReceiver extends BroadcastReceiver {\r
+ /**\r
+ * {@link BroadcastReceiver} to enable syncing feedback in UI\r
+ */\r
+ @Override\r
+ public void onReceive(Context context, Intent intent) {\r
+ boolean inProgress = intent.getBooleanExtra(\r
+ FileSyncService.IN_PROGRESS, false);\r
+ String accountName = intent\r
+ .getStringExtra(FileSyncService.ACCOUNT_NAME);\r
+\r
+ Log.d("FileDisplay", "sync of account " + accountName\r
+ + " is in_progress: " + inProgress);\r
+\r
+ if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { \r
+ \r
+ String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); \r
+ \r
+ boolean fillBlankRoot = false;\r
+ if (mCurrentDir == null) {\r
+ mCurrentDir = mStorageManager.getFileByPath("/");\r
+ fillBlankRoot = (mCurrentDir != null);\r
+ }\r
+\r
+ if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))\r
+ || fillBlankRoot ) {\r
+ if (!fillBlankRoot) \r
+ mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);\r
+ FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager()\r
+ .findFragmentById(R.id.fileList);\r
+ if (fileListFragment != null) {\r
+ fileListFragment.listDirectory(mCurrentDir); \r
+ }\r
+ }\r
+ \r
+ setSupportProgressBarIndeterminateVisibility(inProgress);\r
+ \r
+ }\r
+ }\r
+ }\r
+ \r
+\r
+ private class UploadFinishReceiver extends BroadcastReceiver {\r
+ /**\r
+ * Once the file upload has finished -> update view\r
+ * @author David A. Velasco\r
+ * {@link BroadcastReceiver} to enable upload feedback in UI\r
+ */\r
+ @Override\r
+ public void onReceive(Context context, Intent intent) {\r
+ long parentDirId = intent.getLongExtra(FileUploader.EXTRA_PARENT_DIR_ID, -1);\r
+ OCFile parentDir = mStorageManager.getFileById(parentDirId);\r
+ String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
+\r
+ if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&\r
+ parentDir != null && \r
+ ( (mCurrentDir == null && parentDir.getFileName().equals("/")) ||\r
+ parentDir.equals(mCurrentDir)\r
+ )\r
+ ) {\r
+ FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
+ if (fileListFragment != null) { \r
+ fileListFragment.listDirectory();\r
+ }\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ \r
+ /**\r
+ * Once the file download has finished -> update view\r
+ */\r
+ private class DownloadFinishReceiver extends BroadcastReceiver {\r
+ @Override\r
+ public void onReceive(Context context, Intent intent) {\r
+ String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
+ String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
+\r
+ if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&\r
+ mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) {\r
+ FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
+ if (fileListFragment != null) { \r
+ fileListFragment.listDirectory();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ \r
+ @Override\r
+ public void onClick(View v) {\r
+ if (v.getId() == R.id.setup_account) {\r
+ Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
+ intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
+ startActivity(intent); \r
+ mForcedLoginToCreateFirstAccount = true;\r
+ }\r
+ }\r
+\r
+ \r
+ \r
+ \r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public DataStorageManager getStorageManager() {\r
+ return mStorageManager;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onDirectoryClick(OCFile directory) {\r
+ pushDirname(directory);\r
+ ActionBar actionBar = getSupportActionBar();\r
+ actionBar.setDisplayHomeAsUpEnabled(true);\r
+ \r
+ if (mDualPane) {\r
+ // Resets the FileDetailsFragment on Tablets so that it always displays\r
+ FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+ if (fileDetails != null) {\r
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
+ transaction.remove(fileDetails);\r
+ transaction.add(R.id.file_details_container, new FileDetailFragment(null, null));\r
+ transaction.commit();\r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onFileClick(OCFile file) {\r
+ \r
+ // If we are on a large device -> update fragment\r
+ if (mDualPane) {\r
+ // 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'\r
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);\r
+ transaction.commit();\r
+ \r
+ } else { // small or medium screen device -> new Activity\r
+ Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);\r
+ showDetailsIntent.putExtra(FileDownloader.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));\r
+ startActivity(showDetailsIntent);\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onFileStateChanged() {\r
+ FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
+ if (fileListFragment != null) { \r
+ fileListFragment.listDirectory();\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Operations in this method should be preferably performed in onCreate to have a lighter onResume method. \r
+ * \r
+ * 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 \r
+ * put instead the ugly view that shows the 'Setup' button to restart the login activity. \r
+ * \r
+ * 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 \r
+ * FragmentList view empty).\r
+ * \r
+ * 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)\r
+ */\r
+ private void initDelayedTilAccountAvailabe() {\r
+ setContentView(mLayoutView); \r
+ mDualPane = (findViewById(R.id.file_details_container) != null);\r
+ if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {\r
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
+ transaction.commit();\r
+ }\r
+ setSupportProgressBarIndeterminateVisibility(false);\r
+ }\r
+ \r
+\r
+ /**\r
+ * Launch an intent to request the PIN code to the user before letting him use the app\r
+ */\r
+ private void requestPinCode() {\r
+ boolean pinStart = false;\r
+ SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\r
+ pinStart = appPrefs.getBoolean("set_pincode", false);\r
+ if (pinStart) {\r
+ Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);\r
+ i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");\r
+ startActivity(i);\r
+ }\r
+ }\r
+\r
+ \r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.activity;\r
+\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.ui.adapter.LandingScreenAdapter;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.content.DialogInterface;\r
+import android.content.DialogInterface.OnClickListener;\r
+import android.content.Intent;\r
+import android.os.Bundle;\r
+import android.view.View;\r
+import android.widget.AdapterView;\r
+import android.widget.AdapterView.OnItemClickListener;\r
+import android.widget.GridView;\r
+import android.widget.Toast;\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * This activity is used as a landing page when the user first opens this app.\r
+ * \r
+ * @author Lennart Rosam\r
+ * \r
+ */\r
+public class LandingActivity extends SherlockFragmentActivity implements\r
+ OnClickListener, OnItemClickListener {\r
+\r
+ public static final int DIALOG_SETUP_ACCOUNT = 1;\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ setContentView(R.layout.main);\r
+\r
+ // Fill the grid view of the landing screen with icons\r
+ GridView landingScreenItems = (GridView) findViewById(R.id.homeScreenGrid);\r
+ landingScreenItems.setAdapter(new LandingScreenAdapter(this));\r
+ landingScreenItems.setOnItemClickListener(this);\r
+\r
+ // Check, if there are ownCloud accounts\r
+ if (!accountsAreSetup()) {\r
+ showDialog(DIALOG_SETUP_ACCOUNT);\r
+ } else {\r
+ // Start device tracking service\r
+ Intent locationServiceIntent = new Intent();\r
+ locationServiceIntent\r
+ .setAction("eu.alefzero.owncloud.location.LocationLauncher");\r
+ sendBroadcast(locationServiceIntent);\r
+ }\r
+\r
+ }\r
+\r
+ @Override\r
+ protected void onRestart() {\r
+ super.onRestart();\r
+ // Check, if there are ownCloud accounts\r
+ if (!accountsAreSetup()) {\r
+ showDialog(DIALOG_SETUP_ACCOUNT);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {\r
+ super.onRestoreInstanceState(savedInstanceState);\r
+ // Check, if there are ownCloud accounts\r
+ if (!accountsAreSetup()) {\r
+ showDialog(DIALOG_SETUP_ACCOUNT);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected Dialog onCreateDialog(int id) {\r
+ Dialog dialog;\r
+ switch (id) {\r
+ case DIALOG_SETUP_ACCOUNT:\r
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
+ builder.setTitle(R.string.main_tit_accsetup);\r
+ builder.setMessage(R.string.main_wrn_accsetup);\r
+ builder.setCancelable(false);\r
+ builder.setPositiveButton(R.string.common_ok, this);\r
+ builder.setNegativeButton(R.string.common_cancel, this);\r
+ dialog = builder.create();\r
+ break;\r
+ default:\r
+ dialog = null;\r
+ }\r
+\r
+ return dialog;\r
+ }\r
+\r
+ public void onClick(DialogInterface dialog, int which) {\r
+ // In any case - we won't need it anymore\r
+ dialog.dismiss();\r
+ switch (which) {\r
+ case DialogInterface.BUTTON_POSITIVE:\r
+ Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
+ intent.putExtra("authorities",\r
+ new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
+ startActivity(intent);\r
+ break;\r
+ case DialogInterface.BUTTON_NEGATIVE:\r
+ finish();\r
+ }\r
+\r
+ }\r
+\r
+ @Override\r
+ /**\r
+ * Start an activity based on the selection\r
+ * the user made\r
+ */\r
+ public void onItemClick(AdapterView<?> parent, View view, int position,\r
+ long id) {\r
+ Intent intent;\r
+ intent = (Intent) parent.getAdapter().getItem(position);\r
+ if (intent != null) {\r
+ startActivity(intent);\r
+ } else {\r
+ // TODO: Implement all of this and make this text go away ;-)\r
+ Toast toast = Toast.makeText(this, "Not yet implemented!",\r
+ Toast.LENGTH_SHORT);\r
+ toast.show();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Checks, whether or not there are any ownCloud accounts setup.\r
+ * \r
+ * @return true, if there is at least one account.\r
+ */\r
+ private boolean accountsAreSetup() {\r
+ AccountManager accMan = AccountManager.get(this);\r
+ Account[] accounts = accMan\r
+ .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
+ return accounts.length > 0;\r
+ }\r
+\r
+}\r
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+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);
+ }
+
+
+
+
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.activity;\r
+\r
+import java.util.Vector;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.content.Intent;\r
+import android.content.SharedPreferences;\r
+import android.os.Bundle;\r
+import android.preference.CheckBoxPreference;\r
+import android.preference.ListPreference;\r
+import android.preference.Preference;\r
+import android.preference.PreferenceManager;\r
+import android.preference.Preference.OnPreferenceChangeListener;\r
+import android.preference.Preference.OnPreferenceClickListener;\r
+import android.util.Log;\r
+\r
+import com.actionbarsherlock.app.ActionBar;\r
+import com.actionbarsherlock.app.SherlockPreferenceActivity;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuItem;\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.OwnCloudSession;\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.db.DbHandler;\r
+\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * An Activity that allows the user to change the application's settings.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class Preferences extends SherlockPreferenceActivity implements\r
+ OnPreferenceChangeListener{\r
+ private static final String TAG = "OwnCloudPreferences";\r
+ private final int mNewSession = 47;\r
+ private final int mEditSession = 48;\r
+ private DbHandler mDbHandler;\r
+ private Vector<OwnCloudSession> mSessions;\r
+ //private Account[] mAccounts;\r
+ //private ListPreference mAccountList;\r
+ private ListPreference mTrackingUpdateInterval;\r
+ private CheckBoxPreference mDeviceTracking;\r
+ private CheckBoxPreference pCode;\r
+ private int mSelectedMenuItem;\r
+\r
+ @Override\r
+ public void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ mDbHandler = new DbHandler(getBaseContext());\r
+ mSessions = new Vector<OwnCloudSession>();\r
+ addPreferencesFromResource(R.xml.preferences);\r
+ //populateAccountList();\r
+ ActionBar actionBar = getSherlock().getActionBar();\r
+ actionBar.setDisplayHomeAsUpEnabled(true);\r
+ Preference p = findPreference("manage_account");\r
+ if (p != null)\r
+ p.setOnPreferenceClickListener(new OnPreferenceClickListener() {\r
+ @Override\r
+ public boolean onPreferenceClick(Preference preference) {\r
+ Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class);\r
+ startActivity(i);\r
+ return true;\r
+ }\r
+ });\r
+ \r
+ pCode = (CheckBoxPreference) findPreference("set_pincode");\r
+ \r
+ \r
+ if (pCode != null){\r
+ \r
+ pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {\r
+ @Override\r
+ public boolean onPreferenceChange(Preference preference, Object newValue) {\r
+ \r
+ Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);\r
+ i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences");\r
+ i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString());\r
+ \r
+ startActivity(i);\r
+ \r
+ return true;\r
+ }\r
+ }); \r
+ \r
+ }\r
+ \r
+ }\r
+\r
+\r
+ @Override\r
+ protected void onResume() {\r
+ // TODO Auto-generated method stub\r
+ SharedPreferences appPrefs = PreferenceManager\r
+ .getDefaultSharedPreferences(getApplicationContext());\r
+ \r
+ boolean state = appPrefs.getBoolean("set_pincode", false);\r
+ pCode.setChecked(state);\r
+ \r
+ super.onResume();\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ * Populates the account selector\r
+ *-/\r
+ private void populateAccountList() {\r
+ AccountManager accMan = AccountManager.get(this);\r
+ mAccounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
+ mAccountList = (ListPreference) findPreference("select_oc_account");\r
+ mAccountList.setOnPreferenceChangeListener(this);\r
+\r
+ // Display the name of the current account if there is any\r
+ Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
+ if (defaultAccount != null) {\r
+ mAccountList.setSummary(defaultAccount.name);\r
+ }\r
+ \r
+ // Transform accounts into array of string for preferences to use\r
+ String[] accNames = new String[mAccounts.length];\r
+ for (int i = 0; i < mAccounts.length; i++) {\r
+ Account account = mAccounts[i];\r
+ accNames[i] = account.name;\r
+ }\r
+\r
+ mAccountList.setEntries(accNames);\r
+ mAccountList.setEntryValues(accNames);\r
+ }*/\r
+\r
+ \r
+ \r
+ @Override\r
+ public boolean onCreateOptionsMenu(Menu menu) {\r
+ super.onCreateOptionsMenu(menu);\r
+ //MenuInflater inflater = getSherlock().getMenuInflater();\r
+ //inflater.inflate(R.menu.prefs_menu, menu);\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+ super.onMenuItemSelected(featureId, item);\r
+ Intent intent;\r
+\r
+ switch (item.getItemId()) {\r
+ //case R.id.addSessionItem:\r
+ case 1:\r
+ intent = new Intent(this, PreferencesNewSession.class);\r
+ startActivityForResult(intent, mNewSession);\r
+ break;\r
+ case R.id.SessionContextEdit:\r
+ intent = new Intent(this, PreferencesNewSession.class);\r
+ intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem)\r
+ .getEntryId());\r
+ intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem)\r
+ .getName());\r
+ intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem)\r
+ .getUrl());\r
+ startActivityForResult(intent, mEditSession);\r
+ break;\r
+ case android.R.id.home:\r
+ intent = new Intent(getBaseContext(), FileDisplayActivity.class);\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
+ startActivity(intent);\r
+ break;\r
+ default:\r
+ Log.w(TAG, "Unknown menu item triggered");\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
+ super.onActivityResult(requestCode, resultCode, data);\r
+ }\r
+\r
+ @Override\r
+ protected void onDestroy() {\r
+ mDbHandler.close();\r
+ super.onDestroy();\r
+ }\r
+\r
+ \r
+ \r
+ @Override\r
+ /**\r
+ * Updates various summaries after updates. Also starts and stops \r
+ * the\r
+ */\r
+ public boolean onPreferenceChange(Preference preference, Object newValue) {\r
+ // Update current account summary\r
+ /*if (preference.equals(mAccountList)) {\r
+ mAccountList.setSummary(newValue.toString());\r
+ }\r
+\r
+ // Update tracking interval summary\r
+ else*/ if (preference.equals(mTrackingUpdateInterval)) {\r
+ String trackingSummary = getResources().getString(\r
+ R.string.prefs_trackmydevice_interval_summary);\r
+ trackingSummary = String.format(trackingSummary,\r
+ newValue.toString());\r
+ mTrackingUpdateInterval.setSummary(trackingSummary);\r
+ }\r
+\r
+ // Start or stop tracking service\r
+ else if (preference.equals(mDeviceTracking)) {\r
+ Intent locationServiceIntent = new Intent();\r
+ locationServiceIntent\r
+ .setAction("eu.alefzero.owncloud.location.LocationLauncher");\r
+ locationServiceIntent.putExtra("TRACKING_SETTING",\r
+ (Boolean) newValue);\r
+ sendBroadcast(locationServiceIntent);\r
+ } \r
+ return true;\r
+ }\r
+ \r
+ \r
+\r
+}\r
--- /dev/null
+package com.owncloud.android.ui.activity;\r
+\r
+import android.accounts.AccountAuthenticatorActivity;\r
+import android.app.Activity;\r
+import android.os.Bundle;\r
+import android.view.View;\r
+import android.view.View.OnClickListener;\r
+\r
+public class PreferencesNewSession extends AccountAuthenticatorActivity\r
+ implements OnClickListener {\r
+ @Override\r
+ public void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ // setContentView(R.layout.add_new_session);\r
+ /*\r
+ * EditText et;// = (EditText)\r
+ * findViewById(R.id.newSession_sessionName);\r
+ * \r
+ * et = (EditText) findViewById(R.id.newSession_URL); if\r
+ * (getIntent().hasExtra("sessionURL")) { try { URI uri = new\r
+ * URI(getIntent().getStringExtra("sessionURL")); String url =\r
+ * uri.getHost(); if (uri.getPort() != -1) { url += ":" +\r
+ * String.valueOf(uri.getPort()); } if (uri.getPath() != null) { url +=\r
+ * uri.getPath(); } else { url += "/"; } et.setText(url); et =\r
+ * (EditText) findViewById(R.id.newSession_username); if\r
+ * (uri.getAuthority() != null) { if (uri.getUserInfo().indexOf(':') !=\r
+ * -1) { et.setText(uri.getUserInfo().substring(0,\r
+ * uri.getUserInfo().indexOf(':'))); et = (EditText)\r
+ * findViewById(R.id.newSession_password);\r
+ * et.setText(uri.getUserInfo().substring\r
+ * (uri.getUserInfo().indexOf(':')+1)); } else {\r
+ * et.setText(uri.getUserInfo()); } }\r
+ * \r
+ * } catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " +\r
+ * e.getLocalizedMessage()); } }\r
+ * \r
+ * mReturnData = new Intent(); setResult(Activity.RESULT_OK,\r
+ * mReturnData); ((Button)\r
+ * findViewById(R.id.button1)).setOnClickListener(this); ((Button)\r
+ * findViewById(R.id.button2)).setOnClickListener(this);\r
+ */\r
+ }\r
+\r
+ @Override\r
+ protected void onResume() {\r
+ super.onResume();\r
+ }\r
+\r
+ public void onClick(View v) {\r
+ /*\r
+ * switch (v.getId()) { case R.id.button1: Intent intent = new Intent();\r
+ * if (getIntent().hasExtra("sessionId")) { intent.putExtra("sessionId",\r
+ * getIntent().getIntExtra("sessionId", -1)); } //String sessionName =\r
+ * ((EditText)\r
+ * findViewById(R.id.newSession_sessionName)).getText().toString(); //\r
+ * if (sessionName.trim().equals("") || !isNameValid(sessionName)) { //\r
+ * Toast.makeText(this, R.string.new_session_session_name_error,\r
+ * Toast.LENGTH_LONG).show(); // break; // } URI uri = prepareURI(); if\r
+ * (uri != null) { //intent.putExtra("sessionName", sessionName);\r
+ * intent.putExtra("sessionURL", uri.toString());\r
+ * setResult(Activity.RESULT_OK, intent); AccountManager accMgr =\r
+ * AccountManager.get(this); Account a = new Account("OwnCloud",\r
+ * AccountAuthenticatorService.ACCOUNT_TYPE);\r
+ * accMgr.addAccountExplicitly(a, "asd", null); finish(); } break; case\r
+ * R.id.button2: setResult(Activity.RESULT_CANCELED); finish(); break; }\r
+ */\r
+ }\r
+\r
+ /*\r
+ * private URI prepareURI() { URI uri = null; String url = ""; try { String\r
+ * username = ((EditText)\r
+ * findViewById(R.id.newSession_username)).getText().toString().trim();\r
+ * String password = ((EditText)\r
+ * findViewById(R.id.newSession_password)).getText().toString().trim();\r
+ * String hostname = ((EditText)\r
+ * findViewById(R.id.newSession_URL)).getText().toString().trim(); String\r
+ * scheme; if (hostname.matches("[A-Za-z]://")) { scheme =\r
+ * hostname.substring(0, hostname.indexOf("://")+3); hostname =\r
+ * hostname.substring(hostname.indexOf("://")+3); } else { scheme =\r
+ * "http://"; } if (!username.equals("")) { if (!password.equals("")) {\r
+ * username += ":" + password + "@"; } else { username += "@"; } } url =\r
+ * scheme + username + hostname; Log.i(TAG, url); uri = new URI(url); }\r
+ * catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " +\r
+ * e.getLocalizedMessage()); Toast.makeText(this,\r
+ * R.string.new_session_uri_error, Toast.LENGTH_LONG).show(); } return uri;\r
+ * }\r
+ * \r
+ * private boolean isNameValid(String string) { return\r
+ * string.matches("[A-Za-z0-9 _-]*"); }\r
+ */\r
+\r
+ @Override\r
+ public void onBackPressed() {\r
+ setResult(Activity.RESULT_CANCELED);\r
+ super.onBackPressed();\r
+ }\r
+\r
+}\r
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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");
+ }
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.adapter;\r
+\r
+import java.util.Vector;\r
+\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.DisplayUtils;\r
+import com.owncloud.android.datamodel.DataStorageManager;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.files.services.FileDownloader;\r
+import com.owncloud.android.files.services.FileUploader;\r
+\r
+import com.owncloud.android.R;\r
+\r
+import android.accounts.Account;\r
+import android.content.Context;\r
+import android.database.DataSetObserver;\r
+import android.util.Log;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.ImageView;\r
+import android.widget.ListAdapter;\r
+import android.widget.TextView;\r
+\r
+/**\r
+ * This Adapter populates a ListView with all files and folders in an ownCloud\r
+ * instance.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class FileListListAdapter implements ListAdapter {\r
+ private Context mContext;\r
+ private OCFile mFile;\r
+ private Vector<OCFile> mFiles;\r
+ private DataStorageManager mStorageManager;\r
+ private Account mAccount;\r
+\r
+ public FileListListAdapter(OCFile file, DataStorageManager storage_man,\r
+ Context context) {\r
+ mFile = file;\r
+ mStorageManager = storage_man;\r
+ mFiles = mStorageManager.getDirectoryContent(mFile);\r
+ mContext = context;\r
+ mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
+ }\r
+\r
+ @Override\r
+ public boolean areAllItemsEnabled() {\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public boolean isEnabled(int position) {\r
+ // TODO Auto-generated method stub\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public int getCount() {\r
+ return mFiles != null ? mFiles.size() : 0;\r
+ }\r
+\r
+ @Override\r
+ public Object getItem(int position) {\r
+ if (mFiles.size() <= position)\r
+ return null;\r
+ return mFiles.get(position);\r
+ }\r
+\r
+ @Override\r
+ public long getItemId(int position) {\r
+ return mFiles != null ? mFiles.get(position).getFileId() : 0;\r
+ }\r
+\r
+ @Override\r
+ public int getItemViewType(int position) {\r
+ // TODO Auto-generated method stub\r
+ return 0;\r
+ }\r
+\r
+ @Override\r
+ public View getView(int position, View convertView, ViewGroup parent) {\r
+ View view = convertView;\r
+ if (view == null) {\r
+ LayoutInflater inflator = (LayoutInflater) mContext\r
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
+ view = inflator.inflate(R.layout.list_layout, null);\r
+ }\r
+ if (mFiles.size() > position) {\r
+ OCFile file = mFiles.get(position);\r
+ TextView fileName = (TextView) view.findViewById(R.id.Filename);\r
+ String name = file.getFileName();\r
+\r
+ fileName.setText(name);\r
+ ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);\r
+ if (file.getMimetype() == null || !file.getMimetype().equals("DIR")) {\r
+ fileIcon.setImageResource(R.drawable.file);\r
+ } else {\r
+ fileIcon.setImageResource(R.drawable.ic_menu_archive);\r
+ }\r
+ ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);\r
+ if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) {\r
+ localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
+ localStateView.setVisibility(View.VISIBLE);\r
+ } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) {\r
+ localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
+ localStateView.setVisibility(View.VISIBLE);\r
+ } else if (file.isDown()) {\r
+ localStateView.setImageResource(R.drawable.local_file_indicator);\r
+ localStateView.setVisibility(View.VISIBLE);\r
+ } else {\r
+ localStateView.setVisibility(View.INVISIBLE);\r
+ }\r
+ /*\r
+ ImageView down = (ImageView) view.findViewById(R.id.imageView2);\r
+ ImageView downloading = (ImageView) view.findViewById(R.id.imageView4);\r
+ ImageView uploading = (ImageView) view.findViewById(R.id.imageView5);\r
+ if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) {\r
+ down.setVisibility(View.INVISIBLE);\r
+ downloading.setVisibility(View.VISIBLE);\r
+ uploading.setVisibility(View.INVISIBLE);\r
+ } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) {\r
+ down.setVisibility(View.INVISIBLE);\r
+ downloading.setVisibility(View.INVISIBLE);\r
+ uploading.setVisibility(View.VISIBLE);\r
+ } else if (file.isDown()) {\r
+ down.setVisibility(View.VISIBLE);\r
+ downloading.setVisibility(View.INVISIBLE);\r
+ uploading.setVisibility(View.INVISIBLE);\r
+ } else {\r
+ down.setVisibility(View.INVISIBLE);\r
+ downloading.setVisibility(View.INVISIBLE);\r
+ uploading.setVisibility(View.INVISIBLE);\r
+ }*/\r
+ \r
+ if (!file.isDirectory()) {\r
+ view.findViewById(R.id.file_size).setVisibility(View.VISIBLE);\r
+ view.findViewById(R.id.last_mod).setVisibility(View.VISIBLE);\r
+ ((TextView)view.findViewById(R.id.file_size)).setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
+ ((TextView)view.findViewById(R.id.last_mod)).setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));\r
+ // this if-else is needed even thoe fav icon is visible by default\r
+ // because android reuses views in listview\r
+ if (!file.keepInSync()) {\r
+ view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
+ } else {\r
+ view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE);\r
+ }\r
+ } else {\r
+ view.findViewById(R.id.file_size).setVisibility(View.GONE);\r
+ view.findViewById(R.id.last_mod).setVisibility(View.GONE);\r
+ view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
+ }\r
+ }\r
+\r
+ return view;\r
+ }\r
+\r
+ @Override\r
+ public int getViewTypeCount() {\r
+ return 4;\r
+ }\r
+\r
+ @Override\r
+ public boolean hasStableIds() {\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public boolean isEmpty() {\r
+ return mFiles != null ? mFiles.isEmpty() : false;\r
+ }\r
+\r
+ @Override\r
+ public void registerDataSetObserver(DataSetObserver observer) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public void unregisterDataSetObserver(DataSetObserver observer) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.adapter;\r
+\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.ui.activity.FileDisplayActivity;\r
+import com.owncloud.android.ui.activity.Preferences;\r
+\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.BaseAdapter;\r
+import android.widget.ImageView;\r
+import android.widget.TextView;\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * Populates the landing screen icons.\r
+ * \r
+ * @author Lennart Rosam\r
+ * \r
+ */\r
+public class LandingScreenAdapter extends BaseAdapter {\r
+\r
+ private Context mContext;\r
+\r
+ private final Integer[] mLandingScreenIcons = { R.drawable.home,\r
+ R.drawable.music, R.drawable.contacts, R.drawable.calendar,\r
+ android.R.drawable.ic_menu_agenda, R.drawable.settings };\r
+\r
+ private final Integer[] mLandingScreenTexts = { R.string.main_files,\r
+ R.string.main_music, R.string.main_contacts,\r
+ R.string.main_calendar, R.string.main_bookmarks,\r
+ R.string.main_settings };\r
+\r
+ public LandingScreenAdapter(Context context) {\r
+ mContext = context;\r
+ }\r
+\r
+ @Override\r
+ public int getCount() {\r
+ return mLandingScreenIcons.length;\r
+ }\r
+\r
+ @Override\r
+ /**\r
+ * Returns the Intent associated with this object\r
+ * or null if the functionality is not yet implemented\r
+ */\r
+ public Object getItem(int position) {\r
+ Intent intent = new Intent();\r
+\r
+ switch (position) {\r
+ case 0:\r
+ /*\r
+ * The FileDisplayActivity requires the ownCloud account as an\r
+ * parcableExtra. We will put in the one that is selected in the\r
+ * preferences\r
+ */\r
+ intent.setClass(mContext, FileDisplayActivity.class);\r
+ intent.putExtra("ACCOUNT",\r
+ AccountUtils.getCurrentOwnCloudAccount(mContext));\r
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
+ break;\r
+ case 5:\r
+ intent.setClass(mContext, Preferences.class);\r
+ break;\r
+ default:\r
+ intent = null;\r
+ }\r
+ return intent;\r
+ }\r
+\r
+ @Override\r
+ public long getItemId(int position) {\r
+ return position;\r
+ }\r
+\r
+ @Override\r
+ public View getView(int position, View convertView, ViewGroup parent) {\r
+ if (convertView == null) {\r
+ LayoutInflater inflator = LayoutInflater.from(mContext);\r
+ convertView = inflator.inflate(R.layout.landing_page_item, null);\r
+\r
+ ImageView icon = (ImageView) convertView\r
+ .findViewById(R.id.gridImage);\r
+ TextView iconText = (TextView) convertView\r
+ .findViewById(R.id.gridText);\r
+\r
+ icon.setImageResource(mLandingScreenIcons[position]);\r
+ iconText.setText(mLandingScreenTexts[position]);\r
+ }\r
+ return convertView;\r
+ }\r
+}\r
--- /dev/null
+package com.owncloud.android.ui.fragment;
+
+import com.actionbarsherlock.app.SherlockFragment;
+
+public class AuthenticatorAccountDetailsFragment extends SherlockFragment {
+
+}
--- /dev/null
+package com.owncloud.android.ui.fragment;
+
+import com.actionbarsherlock.app.SherlockFragment;
+
+public class AuthenticatorGetStartedFragment extends SherlockFragment {
+
+}
--- /dev/null
+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);
+ }
+
+}
+
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.fragment;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.commons.httpclient.HttpException;\r
+import org.apache.commons.httpclient.methods.GetMethod;\r
+import org.apache.commons.httpclient.methods.PostMethod;\r
+import org.apache.commons.httpclient.methods.StringRequestEntity;\r
+import org.apache.commons.httpclient.params.HttpConnectionManagerParams;\r
+import org.apache.http.HttpStatus;\r
+import org.apache.http.NameValuePair;\r
+import org.apache.http.client.utils.URLEncodedUtils;\r
+import org.apache.http.message.BasicNameValuePair;\r
+import org.apache.http.protocol.HTTP;\r
+import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;\r
+import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
+import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountManager;\r
+import android.annotation.SuppressLint;\r
+import android.app.Activity;\r
+import android.content.ActivityNotFoundException;\r
+import android.content.BroadcastReceiver;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.content.IntentFilter;\r
+import android.content.res.Resources.NotFoundException;\r
+import android.graphics.Bitmap;\r
+import android.graphics.BitmapFactory;\r
+import android.graphics.BitmapFactory.Options;\r
+import android.graphics.Point;\r
+import android.net.Uri;\r
+import android.os.AsyncTask;\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.support.v4.app.FragmentTransaction;\r
+import android.util.Log;\r
+import android.view.Display;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.View.OnClickListener;\r
+import android.view.ViewGroup;\r
+import android.view.WindowManager.LayoutParams;\r
+import android.webkit.MimeTypeMap;\r
+import android.widget.Button;\r
+import android.widget.CheckBox;\r
+import android.widget.ImageView;\r
+import android.widget.TextView;\r
+import android.widget.Toast;\r
+\r
+import com.actionbarsherlock.app.SherlockDialogFragment;\r
+import com.actionbarsherlock.app.SherlockFragment;\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.DisplayUtils;\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.datamodel.FileDataStorageManager;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.files.services.FileDownloader;\r
+import com.owncloud.android.files.services.FileUploader;\r
+import com.owncloud.android.ui.activity.FileDetailActivity;\r
+import com.owncloud.android.ui.activity.FileDisplayActivity;\r
+import com.owncloud.android.utils.OwnCloudVersion;\r
+\r
+import com.owncloud.android.R;\r
+import eu.alefzero.webdav.WebdavClient;\r
+import eu.alefzero.webdav.WebdavUtils;\r
+\r
+/**\r
+ * This Fragment is used to display the details about a file.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class FileDetailFragment extends SherlockFragment implements\r
+ OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener {\r
+\r
+ public static final String EXTRA_FILE = "FILE";\r
+ public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
+\r
+ private FileDetailFragment.ContainerActivity mContainerActivity;\r
+ \r
+ private int mLayout;\r
+ private View mView;\r
+ private OCFile mFile;\r
+ private Account mAccount;\r
+ private ImageView mPreview;\r
+ \r
+ private DownloadFinishReceiver mDownloadFinishReceiver;\r
+ private UploadFinishReceiver mUploadFinishReceiver;\r
+\r
+ private static final String TAG = "FileDetailFragment";\r
+ public static final String FTAG = "FileDetails"; \r
+ public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
+\r
+ \r
+ /**\r
+ * Creates an empty details fragment.\r
+ * \r
+ * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. \r
+ */\r
+ public FileDetailFragment() {\r
+ mFile = null;\r
+ mAccount = null;\r
+ mLayout = R.layout.file_details_empty;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Creates a details fragment.\r
+ * \r
+ * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).\r
+ * \r
+ * @param fileToDetail An {@link OCFile} to show in the fragment\r
+ * @param ocAccount An ownCloud account; needed to start downloads\r
+ */\r
+ public FileDetailFragment(OCFile fileToDetail, Account ocAccount){\r
+ mFile = fileToDetail;\r
+ mAccount = ocAccount;\r
+ mLayout = R.layout.file_details_empty;\r
+ \r
+ if(fileToDetail != null && ocAccount != null) {\r
+ mLayout = R.layout.file_details_fragment;\r
+ }\r
+ }\r
+ \r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onAttach(Activity activity) {\r
+ super.onAttach(activity);\r
+ try {\r
+ mContainerActivity = (ContainerActivity) activity;\r
+ } catch (ClassCastException e) {\r
+ throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity");\r
+ }\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+ Bundle savedInstanceState) {\r
+ super.onCreateView(inflater, container, savedInstanceState);\r
+ \r
+ if (savedInstanceState != null) {\r
+ mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
+ mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);\r
+ }\r
+ \r
+ View view = null;\r
+ view = inflater.inflate(mLayout, container, false);\r
+ mView = view;\r
+ \r
+ if (mLayout == R.layout.file_details_fragment) {\r
+ mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);\r
+ mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);\r
+ mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);\r
+ mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);\r
+ mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);\r
+ //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);\r
+ mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
+ }\r
+ \r
+ updateFileDetails();\r
+ return view;\r
+ }\r
+ \r
+\r
+ @Override\r
+ public void onSaveInstanceState(Bundle outState) {\r
+ Log.i(getClass().toString(), "onSaveInstanceState() start");\r
+ super.onSaveInstanceState(outState);\r
+ outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);\r
+ outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
+ Log.i(getClass().toString(), "onSaveInstanceState() end");\r
+ }\r
+\r
+ \r
+ @Override\r
+ public void onResume() {\r
+ super.onResume();\r
+ \r
+ mDownloadFinishReceiver = new DownloadFinishReceiver();\r
+ IntentFilter filter = new IntentFilter(\r
+ FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
+ getActivity().registerReceiver(mDownloadFinishReceiver, filter);\r
+ \r
+ mUploadFinishReceiver = new UploadFinishReceiver();\r
+ filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
+ getActivity().registerReceiver(mUploadFinishReceiver, filter);\r
+ \r
+ mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
+ }\r
+\r
+ @Override\r
+ public void onPause() {\r
+ super.onPause();\r
+ \r
+ getActivity().unregisterReceiver(mDownloadFinishReceiver);\r
+ mDownloadFinishReceiver = null;\r
+ \r
+ getActivity().unregisterReceiver(mUploadFinishReceiver);\r
+ mUploadFinishReceiver = null;\r
+ \r
+ if (mPreview != null) {\r
+ mPreview = null;\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public View getView() {\r
+ return super.getView() == null ? mView : super.getView();\r
+ }\r
+\r
+ \r
+ \r
+ @Override\r
+ public void onClick(View v) {\r
+ switch (v.getId()) {\r
+ case R.id.fdDownloadBtn: {\r
+ Intent i = new Intent(getActivity(), FileDownloader.class);\r
+ i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);\r
+ i.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mFile.getRemotePath());\r
+ i.putExtra(FileDownloader.EXTRA_FILE_PATH, mFile.getRemotePath());\r
+ i.putExtra(FileDownloader.EXTRA_FILE_SIZE, mFile.getFileLength());\r
+ \r
+ // update ui \r
+ setButtonsForTransferring();\r
+ \r
+ getActivity().startService(i);\r
+ mContainerActivity.onFileStateChanged(); // this is not working; it is performed before the fileDownloadService registers it as 'in progress'\r
+ break;\r
+ }\r
+ case R.id.fdKeepInSync: {\r
+ CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);\r
+ mFile.setKeepInSync(cb.isChecked());\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
+ fdsm.saveFile(mFile);\r
+ if (mFile.keepInSync()) {\r
+ onClick(getView().findViewById(R.id.fdDownloadBtn));\r
+ } else { \r
+ mContainerActivity.onFileStateChanged(); // put inside 'else' to not call it twice (here, and in the virtual click on fdDownloadBtn)\r
+ }\r
+ break;\r
+ }\r
+ case R.id.fdRenameBtn: {\r
+ EditNameFragment dialog = EditNameFragment.newInstance(mFile.getFileName());\r
+ dialog.show(getFragmentManager(), "nameeditdialog");\r
+ dialog.setOnDismissListener(this);\r
+ break;\r
+ } \r
+ case R.id.fdRemoveBtn: {\r
+ ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(\r
+ R.string.confirmation_remove_alert,\r
+ new String[]{mFile.getFileName()},\r
+ mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,\r
+ mFile.isDown() ? R.string.confirmation_remove_local : -1,\r
+ R.string.common_cancel);\r
+ confDialog.setOnConfirmationListener(this);\r
+ confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
+ break;\r
+ }\r
+ case R.id.fdOpenBtn: {\r
+ String storagePath = mFile.getStoragePath();\r
+ String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
+ try {\r
+ Intent i = new Intent(Intent.ACTION_VIEW);\r
+ i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
+ i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
+ startActivity(i);\r
+ \r
+ } catch (Throwable t) {\r
+ Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
+ boolean toastIt = true; \r
+ String mimeType = "";\r
+ try {\r
+ Intent i = new Intent(Intent.ACTION_VIEW);\r
+ mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
+ if (mimeType != null && !mimeType.equals(mFile.getMimetype())) {\r
+ i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
+ i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
+ startActivity(i);\r
+ toastIt = false;\r
+ }\r
+ \r
+ } catch (IndexOutOfBoundsException e) {\r
+ Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
+ \r
+ } catch (ActivityNotFoundException e) {\r
+ Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
+ \r
+ } catch (Throwable th) {\r
+ Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
+ \r
+ } finally {\r
+ if (toastIt) {\r
+ Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
+ }\r
+ }\r
+ \r
+ }\r
+ break;\r
+ }\r
+ default:\r
+ Log.e(TAG, "Incorrect view clicked!");\r
+ }\r
+ \r
+ /* else if (v.getId() == R.id.fdShareBtn) {\r
+ Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));\r
+ t.start();\r
+ }*/\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void onConfirmation(String callerTag) {\r
+ if (callerTag.equals(FTAG_CONFIRMATION)) {\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
+ if (fdsm.getFileById(mFile.getFileId()) != null) {\r
+ new Thread(new RemoveRunnable(mFile, mAccount, new Handler())).start();\r
+ boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+ getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+ }\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void onNeutral(String callerTag) {\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
+ File f = null;\r
+ if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {\r
+ f.delete();\r
+ mFile.setStoragePath(null);\r
+ fdsm.saveFile(mFile);\r
+ updateFileDetails(mFile, mAccount);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void onCancel(String callerTag) {\r
+ Log.d(TAG, "REMOVAL CANCELED");\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.\r
+ * \r
+ * @return True when the fragment was created with the empty layout.\r
+ */\r
+ public boolean isEmpty() {\r
+ return mLayout == R.layout.file_details_empty;\r
+ }\r
+\r
+ \r
+ /**\r
+ * Can be used to get the file that is currently being displayed.\r
+ * @return The file on the screen.\r
+ */\r
+ public OCFile getDisplayedFile(){\r
+ return mFile;\r
+ }\r
+ \r
+ /**\r
+ * Use this method to signal this Activity that it shall update its view.\r
+ * \r
+ * @param file : An {@link OCFile}\r
+ */\r
+ public void updateFileDetails(OCFile file, Account ocAccount) {\r
+ mFile = file;\r
+ mAccount = ocAccount;\r
+ updateFileDetails();\r
+ }\r
+ \r
+\r
+ /**\r
+ * Updates the view with all relevant details about that file.\r
+ */\r
+ public void updateFileDetails() {\r
+\r
+ if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
+ \r
+ // set file details\r
+ setFilename(mFile.getFileName());\r
+ setFiletype(DisplayUtils.convertMIMEtoPrettyPrint(mFile\r
+ .getMimetype()));\r
+ setFilesize(mFile.getFileLength());\r
+ if(ocVersionSupportsTimeCreated()){\r
+ setTimeCreated(mFile.getCreationTimestamp());\r
+ }\r
+ \r
+ setTimeModified(mFile.getModificationTimestamp());\r
+ \r
+ CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);\r
+ cb.setChecked(mFile.keepInSync());\r
+\r
+ // configure UI for depending upon local state of the file\r
+ if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
+ setButtonsForTransferring();\r
+ \r
+ } else if (mFile.isDown()) {\r
+ // Update preview\r
+ if (mFile.getMimetype().startsWith("image/")) {\r
+ BitmapLoader bl = new BitmapLoader();\r
+ bl.execute(new String[]{mFile.getStoragePath()});\r
+ }\r
+ \r
+ setButtonsForDown();\r
+ \r
+ } else {\r
+ setButtonsForRemote();\r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Updates the filename in view\r
+ * @param filename to set\r
+ */\r
+ private void setFilename(String filename) {\r
+ TextView tv = (TextView) getView().findViewById(R.id.fdFilename);\r
+ if (tv != null)\r
+ tv.setText(filename);\r
+ }\r
+\r
+ /**\r
+ * Updates the MIME type in view\r
+ * @param mimetype to set\r
+ */\r
+ private void setFiletype(String mimetype) {\r
+ TextView tv = (TextView) getView().findViewById(R.id.fdType);\r
+ if (tv != null)\r
+ tv.setText(mimetype);\r
+ }\r
+\r
+ /**\r
+ * Updates the file size in view\r
+ * @param filesize in bytes to set\r
+ */\r
+ private void setFilesize(long filesize) {\r
+ TextView tv = (TextView) getView().findViewById(R.id.fdSize);\r
+ if (tv != null)\r
+ tv.setText(DisplayUtils.bytesToHumanReadable(filesize));\r
+ }\r
+ \r
+ /**\r
+ * Updates the time that the file was created in view\r
+ * @param milliseconds Unix time to set\r
+ */\r
+ private void setTimeCreated(long milliseconds){\r
+ TextView tv = (TextView) getView().findViewById(R.id.fdCreated);\r
+ TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);\r
+ if(tv != null){\r
+ tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
+ tv.setVisibility(View.VISIBLE);\r
+ tvLabel.setVisibility(View.VISIBLE);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Updates the time that the file was last modified\r
+ * @param milliseconds Unix time to set\r
+ */\r
+ private void setTimeModified(long milliseconds){\r
+ TextView tv = (TextView) getView().findViewById(R.id.fdModified);\r
+ if(tv != null){\r
+ tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Enables or disables buttons for a file being downloaded\r
+ */\r
+ private void setButtonsForTransferring() {\r
+ if (!isEmpty()) {\r
+ Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
+ //downloadButton.setText(R.string.filedetails_download_in_progress); // ugly\r
+ downloadButton.setEnabled(false); // TODO replace it with a 'cancel download' button\r
+ \r
+ // let's protect the user from himself ;)\r
+ ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
+ ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);\r
+ ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Enables or disables buttons for a file locally available \r
+ */\r
+ private void setButtonsForDown() {\r
+ if (!isEmpty()) {\r
+ Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
+ //downloadButton.setText(R.string.filedetails_redownload); // ugly\r
+ downloadButton.setEnabled(true);\r
+ \r
+ ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
+ ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
+ ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Enables or disables buttons for a file not locally available \r
+ */\r
+ private void setButtonsForRemote() {\r
+ if (!isEmpty()) {\r
+ Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
+ //downloadButton.setText(R.string.filedetails_download); // unnecessary\r
+ downloadButton.setEnabled(true);\r
+ \r
+ ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
+ ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
+ ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
+ }\r
+ }\r
+ \r
+\r
+ /**\r
+ * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return\r
+ * the time that the file was created. There is a chance that this will\r
+ * be fixed in future versions. Use this method to check if this version of\r
+ * ownCloud has this fix.\r
+ * @return True, if ownCloud the ownCloud version is supporting creation time\r
+ */\r
+ private boolean ocVersionSupportsTimeCreated(){\r
+ /*if(mAccount != null){\r
+ AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);\r
+ OwnCloudVersion ocVersion = new OwnCloudVersion(accManager\r
+ .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
+ if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {\r
+ return true;\r
+ }\r
+ }*/\r
+ return false;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Interface to implement by any Activity that includes some instance of FileDetailFragment\r
+ * \r
+ * @author David A. Velasco\r
+ */\r
+ public interface ContainerActivity {\r
+\r
+ /**\r
+ * Callback method invoked when the detail fragment wants to notice its container \r
+ * activity about a relevant state the file shown by the fragment.\r
+ * \r
+ * Added to notify to FileDisplayActivity about the need of refresh the files list. \r
+ * \r
+ * Currently called when:\r
+ * - a download is started;\r
+ * - a rename is completed;\r
+ * - a deletion is completed;\r
+ * - the 'inSync' flag is changed;\r
+ */\r
+ public void onFileStateChanged();\r
+ \r
+ }\r
+ \r
+\r
+ /**\r
+ * Once the file download has finished -> update view\r
+ * @author Bartek Przybylski\r
+ */\r
+ private class DownloadFinishReceiver extends BroadcastReceiver {\r
+ @Override\r
+ public void onReceive(Context context, Intent intent) {\r
+ String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
+\r
+ if (!isEmpty() && accountName.equals(mAccount.name)) {\r
+ boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);\r
+ String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
+ if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
+ if (downloadWasFine) {\r
+ mFile.setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH)); // updates the local object without accessing the database again\r
+ }\r
+ updateFileDetails(); // it updates the buttons; must be called although !downloadWasFine\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Once the file upload has finished -> update view\r
+ * \r
+ * Being notified about the finish of an upload is necessary for the next sequence:\r
+ * 1. Upload a big file.\r
+ * 2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list\r
+ * of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. \r
+ * 3. Click the file in the list to see its details.\r
+ * 4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.\r
+ */\r
+ private class UploadFinishReceiver extends BroadcastReceiver {\r
+ @Override\r
+ public void onReceive(Context context, Intent intent) {\r
+ String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
+\r
+ if (!isEmpty() && accountName.equals(mAccount.name)) {\r
+ boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
+ String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
+ if (mFile.getRemotePath().equals(uploadRemotePath)) {\r
+ if (uploadWasFine) {\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
+ mFile = fdsm.getFileByPath(mFile.getRemotePath());\r
+ }\r
+ updateFileDetails(); // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+\r
+ // this is a temporary class for sharing purposes, it need to be replaced in transfer service\r
+ private class ShareRunnable implements Runnable {\r
+ private String mPath;\r
+\r
+ public ShareRunnable(String path) {\r
+ mPath = path;\r
+ }\r
+ \r
+ public void run() {\r
+ AccountManager am = AccountManager.get(getActivity());\r
+ Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());\r
+ OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));\r
+ String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);\r
+\r
+ Log.d("share", "sharing for version " + ocv.toString());\r
+\r
+ if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {\r
+ String APPS_PATH = "/apps/files_sharing/";\r
+ String SHARE_PATH = "ajax/share.php";\r
+\r
+ String SHARED_PATH = "/apps/files_sharing/get.php?token=";\r
+ \r
+ final String WEBDAV_SCRIPT = "webdav.php";\r
+ final String WEBDAV_FILES_LOCATION = "/files/";\r
+ \r
+ WebdavClient wc = new WebdavClient();\r
+ HttpConnectionManagerParams params = new HttpConnectionManagerParams();\r
+ params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);\r
+\r
+ //wc.getParams().setParameter("http.protocol.single-cookie-header", true);\r
+ //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);\r
+\r
+ PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);\r
+\r
+ post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );\r
+ post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
+ List<NameValuePair> formparams = new ArrayList<NameValuePair>();\r
+ Log.d("share", mPath+"");\r
+ formparams.add(new BasicNameValuePair("sources",mPath));\r
+ formparams.add(new BasicNameValuePair("uid_shared_with", "public"));\r
+ formparams.add(new BasicNameValuePair("permissions", "0"));\r
+ post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));\r
+\r
+ int status;\r
+ try {\r
+ PropFindMethod find = new PropFindMethod(url+"/");\r
+ find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
+ Log.d("sharer", ""+ url+"/");\r
+ wc.setCredentials(account.name.substring(0, account.name.lastIndexOf('@')), am.getPassword(account));\r
+ \r
+ for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {\r
+ Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
+ }\r
+ \r
+ int status2 = wc.executeMethod(find);\r
+\r
+ Log.d("sharer", "propstatus "+status2);\r
+ \r
+ GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");\r
+ get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
+ \r
+ status2 = wc.executeMethod(get);\r
+\r
+ Log.d("sharer", "getstatus "+status2);\r
+ Log.d("sharer", "" + get.getResponseBodyAsString());\r
+ \r
+ for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {\r
+ Log.d("sharer", a.getName() + ":"+a.getValue());\r
+ }\r
+\r
+ status = wc.executeMethod(post);\r
+ for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {\r
+ Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
+ }\r
+ for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {\r
+ Log.d("sharer", a.getName() + ":"+a.getValue());\r
+ }\r
+ String resp = post.getResponseBodyAsString();\r
+ Log.d("share", ""+post.getURI().toString());\r
+ Log.d("share", "returned status " + status);\r
+ Log.d("share", " " +resp);\r
+ \r
+ if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {\r
+ return;\r
+ }\r
+\r
+ JSONObject jsonObject = new JSONObject (resp);\r
+ String jsonStatus = jsonObject.getString("status");\r
+ if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");\r
+ \r
+ String token = jsonObject.getString("data");\r
+ String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; \r
+ Log.d("Actions:shareFile ok", "url: " + uri); \r
+ \r
+ } catch (HttpException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (JSONException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (Exception e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ \r
+ } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {\r
+ \r
+ }\r
+ }\r
+ }\r
+ \r
+ public void onDismiss(EditNameFragment dialog) {\r
+ if (dialog instanceof EditNameFragment) {\r
+ if (((EditNameFragment)dialog).getResult()) {\r
+ String newFilename = ((EditNameFragment)dialog).getNewFilename();\r
+ Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
+ if (!newFilename.equals(mFile.getFileName())) {\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
+ if (fdsm.getFileById(mFile.getFileId()) != null) {\r
+ OCFile newFile = new OCFile(fdsm.getFileById(mFile.getParentId()).getRemotePath() + newFilename);\r
+ newFile.setCreationTimestamp(mFile.getCreationTimestamp());\r
+ newFile.setFileId(mFile.getFileId());\r
+ newFile.setFileLength(mFile.getFileLength());\r
+ newFile.setKeepInSync(mFile.keepInSync());\r
+ newFile.setLastSyncDate(mFile.getLastSyncDate());\r
+ newFile.setMimetype(mFile.getMimetype());\r
+ newFile.setModificationTimestamp(mFile.getModificationTimestamp());\r
+ newFile.setParentId(mFile.getParentId());\r
+ boolean localRenameFails = false;\r
+ if (mFile.isDown()) {\r
+ File f = new File(mFile.getStoragePath());\r
+ Log.e(TAG, f.getAbsolutePath());\r
+ localRenameFails = !(f.renameTo(new File(f.getParent() + File.separator + newFilename)));\r
+ Log.e(TAG, f.getParent() + File.separator + newFilename);\r
+ newFile.setStoragePath(f.getParent() + File.separator + newFilename);\r
+ }\r
+ \r
+ if (localRenameFails) {\r
+ Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
+ msg.show();\r
+ \r
+ } else {\r
+ new Thread(new RenameRunnable(mFile, newFile, mAccount, new Handler())).start();\r
+ boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+ getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ Log.e(TAG, "Unknown dialog instance passed to onDismissDalog: " + dialog.getClass().getCanonicalName());\r
+ }\r
+ \r
+ }\r
+ \r
+ private class RenameRunnable implements Runnable {\r
+ \r
+ Account mAccount;\r
+ OCFile mOld, mNew;\r
+ Handler mHandler;\r
+ \r
+ public RenameRunnable(OCFile oldFile, OCFile newFile, Account account, Handler handler) {\r
+ mOld = oldFile;\r
+ mNew = newFile;\r
+ mAccount = account;\r
+ mHandler = handler;\r
+ }\r
+ \r
+ public void run() {\r
+ WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext());\r
+ wc.allowSelfsignedCertificates();\r
+ AccountManager am = AccountManager.get(getSherlockActivity());\r
+ String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
+ OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
+ String webdav_path = AccountUtils.getWebdavPath(ocv);\r
+ Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath()));\r
+\r
+ Log.e("ASD", Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath()));\r
+ LocalMoveMethod move = new LocalMoveMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath()),\r
+ Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath()));\r
+ \r
+ boolean success = false;\r
+ try {\r
+ int status = wc.executeMethod(move);\r
+ success = move.succeeded();\r
+ Log.d(TAG, "Move returned status: " + status);\r
+ \r
+ } catch (HttpException e) {\r
+ Log.e(TAG, "HTTP Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e);\r
+ \r
+ } catch (IOException e) {\r
+ Log.e(TAG, "I/O Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e);\r
+ \r
+ } catch (Exception e) {\r
+ Log.e(TAG, "Unexpected exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e);\r
+ }\r
+ \r
+ if (success) {\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
+ fdsm.removeFile(mOld);\r
+ fdsm.saveFile(mNew);\r
+ mFile = mNew;\r
+ mHandler.post(new Runnable() {\r
+ @Override\r
+ public void run() { \r
+ boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+ getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+ updateFileDetails(mFile, mAccount);\r
+ mContainerActivity.onFileStateChanged();\r
+ }\r
+ });\r
+ \r
+ } else {\r
+ mHandler.post(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ // undo the local rename\r
+ if (mNew.isDown()) {\r
+ File f = new File(mNew.getStoragePath());\r
+ if (!f.renameTo(new File(mOld.getStoragePath()))) {\r
+ // the local rename undoing failed; last chance: save the new local storage path in the old file\r
+ mFile.setStoragePath(mNew.getStoragePath());\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
+ fdsm.saveFile(mFile);\r
+ }\r
+ }\r
+ boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+ getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+ try {\r
+ Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
+ msg.show();\r
+ \r
+ } catch (NotFoundException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+ private class LocalMoveMethod extends DavMethodBase {\r
+\r
+ public LocalMoveMethod(String uri, String dest) {\r
+ super(uri);\r
+ addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest));\r
+ }\r
+\r
+ @Override\r
+ public String getName() {\r
+ return "MOVE";\r
+ }\r
+\r
+ @Override\r
+ protected boolean isSuccess(int status) {\r
+ return status == 201 || status == 204;\r
+ }\r
+ \r
+ }\r
+ }\r
+ \r
+ private static class EditNameFragment extends SherlockDialogFragment implements OnClickListener {\r
+\r
+ private String mNewFilename;\r
+ private boolean mResult;\r
+ private FileDetailFragment mListener;\r
+ \r
+ static public EditNameFragment newInstance(String filename) {\r
+ EditNameFragment f = new EditNameFragment();\r
+ Bundle args = new Bundle();\r
+ args.putString("filename", filename);\r
+ f.setArguments(args);\r
+ return f;\r
+ }\r
+ \r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
+ View v = inflater.inflate(R.layout.edit_box_dialog, container, false);\r
+\r
+ String currentName = getArguments().getString("filename");\r
+ if (currentName == null)\r
+ currentName = "";\r
+ \r
+ ((Button)v.findViewById(R.id.cancel)).setOnClickListener(this);\r
+ ((Button)v.findViewById(R.id.ok)).setOnClickListener(this);\r
+ ((TextView)v.findViewById(R.id.user_input)).setText(currentName);\r
+ ((TextView)v.findViewById(R.id.user_input)).requestFocus();\r
+ getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);\r
+\r
+ mResult = false;\r
+ return v;\r
+ }\r
+ \r
+ @Override\r
+ public void onClick(View view) {\r
+ switch (view.getId()) {\r
+ case R.id.ok: {\r
+ mNewFilename = ((TextView)getView().findViewById(R.id.user_input)).getText().toString();\r
+ mResult = true;\r
+ }\r
+ case R.id.cancel: { // fallthought\r
+ dismiss();\r
+ mListener.onDismiss(this);\r
+ }\r
+ }\r
+ }\r
+ \r
+ void setOnDismissListener(FileDetailFragment listener) {\r
+ mListener = listener;\r
+ }\r
+ \r
+ public String getNewFilename() {\r
+ return mNewFilename;\r
+ }\r
+ \r
+ // true if user click ok\r
+ public boolean getResult() {\r
+ return mResult;\r
+ }\r
+ \r
+ }\r
+ \r
+ private class RemoveRunnable implements Runnable {\r
+ \r
+ Account mAccount;\r
+ OCFile mFileToRemove;\r
+ Handler mHandler;\r
+ \r
+ public RemoveRunnable(OCFile fileToRemove, Account account, Handler handler) {\r
+ mFileToRemove = fileToRemove;\r
+ mAccount = account;\r
+ mHandler = handler;\r
+ }\r
+ \r
+ public void run() {\r
+ WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext());\r
+ wc.allowSelfsignedCertificates();\r
+ AccountManager am = AccountManager.get(getSherlockActivity());\r
+ String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
+ OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
+ String webdav_path = AccountUtils.getWebdavPath(ocv);\r
+ Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath()));\r
+\r
+ DeleteMethod delete = new DeleteMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath()));\r
+ \r
+ boolean success = false;\r
+ int status = -1;\r
+ try {\r
+ status = wc.executeMethod(delete);\r
+ success = (delete.succeeded());\r
+ Log.d(TAG, "Delete: returned status " + status);\r
+ \r
+ } catch (HttpException e) {\r
+ Log.e(TAG, "HTTP Exception removing file " + mFileToRemove.getRemotePath(), e);\r
+ \r
+ } catch (IOException e) {\r
+ Log.e(TAG, "I/O Exception removing file " + mFileToRemove.getRemotePath(), e);\r
+ \r
+ } catch (Exception e) {\r
+ Log.e(TAG, "Unexpected exception removing file " + mFileToRemove.getRemotePath(), e);\r
+ }\r
+ \r
+ if (success) {\r
+ FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
+ fdsm.removeFile(mFileToRemove);\r
+ mHandler.post(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+ getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+ try {\r
+ Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);\r
+ msg.show();\r
+ if (inDisplayActivity) {\r
+ // double pane\r
+ FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
+ transaction.commit();\r
+ mContainerActivity.onFileStateChanged();\r
+ \r
+ } else {\r
+ getActivity().finish();\r
+ }\r
+ \r
+ } catch (NotFoundException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ });\r
+ \r
+ } else {\r
+ mHandler.post(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+ getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+ try {\r
+ Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
+ msg.show();\r
+ \r
+ } catch (NotFoundException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ class BitmapLoader extends AsyncTask<String, Void, Bitmap> {\r
+ @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20\r
+ @Override\r
+ protected Bitmap doInBackground(String... params) {\r
+ Bitmap result = null;\r
+ if (params.length != 1) return result;\r
+ String storagePath = params[0];\r
+ try {\r
+\r
+ BitmapFactory.Options options = new Options();\r
+ options.inScaled = true;\r
+ options.inPurgeable = true;\r
+ options.inJustDecodeBounds = true;\r
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {\r
+ options.inPreferQualityOverSpeed = false;\r
+ }\r
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {\r
+ options.inMutable = false;\r
+ }\r
+\r
+ result = BitmapFactory.decodeFile(storagePath, options);\r
+ options.inJustDecodeBounds = false;\r
+\r
+ int width = options.outWidth;\r
+ int height = options.outHeight;\r
+ int scale = 1;\r
+ if (width >= 2048 || height >= 2048) {\r
+ scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));\r
+ options.inSampleSize = scale;\r
+ }\r
+ Display display = getActivity().getWindowManager().getDefaultDisplay();\r
+ Point size = new Point();\r
+ int screenwidth;\r
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {\r
+ display.getSize(size);\r
+ screenwidth = size.x;\r
+ } else {\r
+ screenwidth = display.getWidth();\r
+ }\r
+\r
+ Log.e("ASD", "W " + width + " SW " + screenwidth);\r
+\r
+ if (width > screenwidth) {\r
+ scale = (int) Math.ceil((float)width / screenwidth);\r
+ options.inSampleSize = scale;\r
+ }\r
+\r
+ result = BitmapFactory.decodeFile(storagePath, options);\r
+\r
+ Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight);\r
+\r
+ } catch (OutOfMemoryError e) {\r
+ result = null;\r
+ Log.e(TAG, "Out of memory occured for file with size " + storagePath);\r
+ \r
+ } catch (NoSuchFieldError e) {\r
+ result = null;\r
+ Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);\r
+ \r
+ } catch (Throwable t) {\r
+ result = null;\r
+ Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);\r
+ }\r
+ return result;\r
+ }\r
+ @Override\r
+ protected void onPostExecute(Bitmap result) {\r
+ if (result != null && mPreview != null) {\r
+ mPreview.setImageBitmap(result);\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.fragment;\r
+\r
+import java.util.Vector;\r
+\r
+import com.owncloud.android.datamodel.DataStorageManager;\r
+import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.ui.FragmentListView;\r
+import com.owncloud.android.ui.adapter.FileListListAdapter;\r
+\r
+import android.app.Activity;\r
+import android.os.Bundle;\r
+import android.util.Log;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.AdapterView;\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * A Fragment that lists all files and folders in a given path.\r
+ * \r
+ * @author Bartek Przybylski\r
+ * \r
+ */\r
+public class FileListFragment extends FragmentListView {\r
+ private static final String TAG = "FileListFragment";\r
+ \r
+ private FileListFragment.ContainerActivity mContainerActivity;\r
+ \r
+ private OCFile mFile = null;\r
+ private FileListListAdapter mAdapter;\r
+\r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void onAttach(Activity activity) {\r
+ super.onAttach(activity);\r
+ try {\r
+ mContainerActivity = (ContainerActivity) activity;\r
+ } catch (ClassCastException e) {\r
+ throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity");\r
+ }\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+ Bundle savedInstanceState) {\r
+ Log.i(getClass().toString(), "onCreateView() start");\r
+ super.onCreateView(inflater, container, savedInstanceState);\r
+ getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));\r
+ getListView().setDividerHeight(1);\r
+ \r
+ Log.i(getClass().toString(), "onCreateView() end");\r
+ return getListView();\r
+ } \r
+\r
+\r
+ @Override\r
+ public void onActivityCreated(Bundle savedInstanceState) {\r
+ Log.i(getClass().toString(), "onActivityCreated() start");\r
+ \r
+ super.onCreate(savedInstanceState);\r
+ //mAdapter = new FileListListAdapter();\r
+ \r
+ Log.i(getClass().toString(), "onActivityCreated() stop");\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void onItemClick(AdapterView<?> l, View v, int position, long id) {\r
+ OCFile file = (OCFile) mAdapter.getItem(position);\r
+ if (file != null) {\r
+ /// Click on a directory\r
+ if (file.getMimetype().equals("DIR")) {\r
+ // just local updates\r
+ mFile = file;\r
+ listDirectory(file);\r
+ // any other updates are let to the container Activity\r
+ mContainerActivity.onDirectoryClick(file);\r
+ \r
+ } else { /// Click on a file\r
+ mContainerActivity.onFileClick(file);\r
+ }\r
+ \r
+ } else {\r
+ Log.d(TAG, "Null object in ListAdapter!!");\r
+ }\r
+ \r
+ }\r
+\r
+ /**\r
+ * Call this, when the user presses the up button\r
+ */\r
+ public void onNavigateUp() {\r
+ OCFile parentDir = null;\r
+ \r
+ if(mFile != null){\r
+ DataStorageManager storageManager = mContainerActivity.getStorageManager();\r
+ parentDir = storageManager.getFileById(mFile.getParentId());\r
+ mFile = parentDir;\r
+ }\r
+ listDirectory(parentDir);\r
+ }\r
+\r
+ /**\r
+ * Use this to query the {@link OCFile} that is currently\r
+ * being displayed by this fragment\r
+ * @return The currently viewed OCFile\r
+ */\r
+ public OCFile getCurrentFile(){\r
+ return mFile;\r
+ }\r
+ \r
+ /**\r
+ * Calls {@link FileListFragment#listDirectory(OCFile)} with a null parameter\r
+ */\r
+ public void listDirectory(){\r
+ listDirectory(null);\r
+ }\r
+ \r
+ /**\r
+ * Lists the given directory on the view. When the input parameter is null,\r
+ * it will either refresh the last known directory, or list the root\r
+ * if there never was a directory.\r
+ * \r
+ * @param directory File to be listed\r
+ */\r
+ public void listDirectory(OCFile directory) {\r
+ \r
+ DataStorageManager storageManager = mContainerActivity.getStorageManager();\r
+\r
+ // Check input parameters for null\r
+ if(directory == null){\r
+ if(mFile != null){\r
+ directory = mFile;\r
+ } else {\r
+ directory = storageManager.getFileByPath("/");\r
+ if (directory == null) return; // no files, wait for sync\r
+ }\r
+ }\r
+ \r
+ \r
+ // If that's not a directory -> List its parent\r
+ if(!directory.isDirectory()){\r
+ Log.w(TAG, "You see, that is not a directory -> " + directory.toString());\r
+ directory = storageManager.getFileById(directory.getParentId());\r
+ }\r
+\r
+ mFile = directory;\r
+ \r
+ mAdapter = new FileListListAdapter(directory, storageManager, getActivity());\r
+ setListAdapter(mAdapter);\r
+ }\r
+ \r
+ \r
+ \r
+ /**\r
+ * Interface to implement by any Activity that includes some instance of FileListFragment\r
+ * \r
+ * @author David A. Velasco\r
+ */\r
+ public interface ContainerActivity {\r
+\r
+ /**\r
+ * Callback method invoked when a directory is clicked by the user on the files list\r
+ * \r
+ * @param file\r
+ */\r
+ public void onDirectoryClick(OCFile file);\r
+ \r
+ /**\r
+ * Callback method invoked when a file (non directory) is clicked by the user on the files list\r
+ * \r
+ * @param file\r
+ */\r
+ public void onFileClick(OCFile file);\r
+\r
+ /**\r
+ * Getter for the current DataStorageManager in the container activity\r
+ */\r
+ public DataStorageManager getStorageManager();\r
+ \r
+ }\r
+\r
+}\r
--- /dev/null
+/* ownCloud Android client application\r
+ * Copyright (C) 2011 Bartek Przybylski\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.ui.fragment;\r
+\r
+import com.actionbarsherlock.app.SherlockFragment;\r
+import com.owncloud.android.ui.activity.LandingActivity;\r
+import com.owncloud.android.ui.adapter.LandingScreenAdapter;\r
+\r
+import android.os.Bundle;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.ListView;\r
+import com.owncloud.android.R;\r
+\r
+/**\r
+ * Used on the Landing page to display what Components of the ownCloud there\r
+ * are. Like Files, Music, Contacts, etc.\r
+ * \r
+ * @author Lennart Rosam\r
+ * \r
+ */\r
+public class LandingPageFragment extends SherlockFragment {\r
+\r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+ Bundle savedInstanceState) {\r
+ View root = inflater.inflate(R.layout.landing_page_fragment, container);\r
+ return root;\r
+ }\r
+\r
+ @Override\r
+ public void onActivityCreated(Bundle savedInstanceState) {\r
+ super.onActivityCreated(savedInstanceState);\r
+\r
+ ListView landingScreenItems = (ListView) getView().findViewById(\r
+ R.id.homeScreenList);\r
+ landingScreenItems.setAdapter(new LandingScreenAdapter(getActivity()));\r
+ landingScreenItems\r
+ .setOnItemClickListener((LandingActivity) getActivity());\r
+ }\r
+\r
+}\r
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.utils;
+
+public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
+ 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;
+ }
+ }
+}
--- /dev/null
+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);
+ }
+
+}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud;\r
-\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.utils.OwnCloudVersion;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.content.Context;\r
-import android.content.SharedPreferences;\r
-import android.preference.PreferenceManager;\r
-\r
-public class AccountUtils {\r
- public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";\r
- public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";\r
- public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";\r
- public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";\r
- public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";\r
- public static final String STATUS_PATH = "/status.php";\r
-\r
- /**\r
- * Can be used to get the currently selected ownCloud account in the\r
- * preferences\r
- * \r
- * @param context The current appContext\r
- * @return The current account or first available, if none is available,\r
- * then null.\r
- */\r
- public static Account getCurrentOwnCloudAccount(Context context) {\r
- Account[] ocAccounts = AccountManager.get(context).getAccountsByType(\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- Account defaultAccount = null;\r
-\r
- SharedPreferences appPreferences = PreferenceManager\r
- .getDefaultSharedPreferences(context);\r
- String accountName = appPreferences\r
- .getString("select_oc_account", null);\r
-\r
- if (accountName != null) {\r
- for (Account account : ocAccounts) {\r
- if (account.name.equals(accountName)) {\r
- defaultAccount = account;\r
- break;\r
- }\r
- }\r
- } else if (ocAccounts.length != 0) {\r
- // we at least need to take first account as fallback\r
- defaultAccount = ocAccounts[0];\r
- }\r
-\r
- return defaultAccount;\r
- }\r
-\r
- \r
-\r
- /**\r
- * Checks, whether or not there are any ownCloud accounts setup.\r
- * \r
- * @return true, if there is at least one account.\r
- */\r
- public static boolean accountsAreSetup(Context context) {\r
- AccountManager accMan = AccountManager.get(context);\r
- Account[] accounts = accMan\r
- .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
- return accounts.length > 0;\r
- }\r
- \r
- \r
- public static void setCurrentOwnCloudAccount(Context context, String name) {\r
- SharedPreferences.Editor appPrefs = PreferenceManager\r
- .getDefaultSharedPreferences(context).edit();\r
- appPrefs.putString("select_oc_account", name);\r
- appPrefs.commit();\r
- }\r
-\r
- /**\r
- * \r
- * @param version version of owncloud\r
- * @return webdav path for given OC version, null if OC version unknown\r
- */\r
- public static String getWebdavPath(OwnCloudVersion version) {\r
- if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
- return WEBDAV_PATH_4_0;\r
- if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0\r
- || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0)\r
- return WEBDAV_PATH_2_0;\r
- if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0)\r
- return WEBDAV_PATH_1_2;\r
- return null;\r
- }\r
-\r
-}\r
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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<String> TAGS;
- private UncaughtExceptionHandler defaultUEH;
-
- // TODO: create base activity which will register for crashlog tag automaticly
- static {
- TAGS = new LinkedList<String>();
- 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;
- }
- }
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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();
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud;\r
-\r
-import java.util.Date;\r
-import java.util.HashMap;\r
-\r
-/**\r
- * A helper class for some string operations.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class DisplayUtils {\r
-\r
- private static final String[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };\r
-\r
- private static HashMap<String, String> mimeType2HUmanReadable;\r
- static {\r
- mimeType2HUmanReadable = new HashMap<String, String>();\r
- // images\r
- mimeType2HUmanReadable.put("image/jpeg", "JPEG image");\r
- mimeType2HUmanReadable.put("image/jpg", "JPEG image");\r
- mimeType2HUmanReadable.put("image/png", "PNG image");\r
- mimeType2HUmanReadable.put("image/bmp", "Bitmap image");\r
- mimeType2HUmanReadable.put("image/gif", "GIF image");\r
- mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");\r
- mimeType2HUmanReadable.put("image/tiff", "TIFF image");\r
- // music\r
- mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");\r
- mimeType2HUmanReadable.put("application/ogg", "OGG music file");\r
-\r
- }\r
-\r
- /**\r
- * Converts the file size in bytes to human readable output.\r
- * \r
- * @param bytes Input file size\r
- * @return Like something readable like "12 MB"\r
- */\r
- public static String bytesToHumanReadable(long bytes) {\r
- double result = bytes;\r
- int attachedsuff = 0;\r
- while (result > 1024 && attachedsuff < suffixes.length) {\r
- result /= 1024.;\r
- attachedsuff++;\r
- }\r
- result = ((int) (result * 100)) / 100.;\r
- return result + " " + suffixes[attachedsuff];\r
- }\r
-\r
- /**\r
- * Removes special HTML entities from a string\r
- * \r
- * @param s Input string\r
- * @return A cleaned version of the string\r
- */\r
- public static String HtmlDecode(String s) {\r
- /*\r
- * TODO: Perhaps we should use something more proven like:\r
- * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29\r
- */\r
-\r
- String ret = "";\r
- for (int i = 0; i < s.length(); ++i) {\r
- if (s.charAt(i) == '%') {\r
- ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16);\r
- i += 2;\r
- } else {\r
- ret += s.charAt(i);\r
- }\r
- }\r
- return ret;\r
- }\r
-\r
- /**\r
- * Converts MIME types like "image/jpg" to more end user friendly output\r
- * like "JPG image".\r
- * \r
- * @param mimetype MIME type to convert\r
- * @return A human friendly version of the MIME type\r
- */\r
- public static String convertMIMEtoPrettyPrint(String mimetype) {\r
- if (mimeType2HUmanReadable.containsKey(mimetype)) {\r
- return mimeType2HUmanReadable.get(mimetype);\r
- }\r
- if (mimetype.split("/").length >= 2)\r
- return mimetype.split("/")[1].toUpperCase() + " file";\r
- return "Unknown type";\r
- }\r
-\r
- /**\r
- * Converts Unix time to human readable format\r
- * @param miliseconds that have passed since 01/01/1970\r
- * @return The human readable time for the users locale\r
- */\r
- public static String unixTimeToHumanReadable(long milliseconds) {\r
- Date date = new Date(milliseconds);\r
- return date.toLocaleString();\r
- }\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud;\r
-\r
-/**\r
- * Represents a session to an ownCloud instance\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class OwnCloudSession {\r
- private String mSessionName;\r
- private String mSessionUrl;\r
- private int mEntryId;\r
-\r
- public OwnCloudSession(String name, String url, int entryId) {\r
- mSessionName = name;\r
- mSessionUrl = url;\r
- mEntryId = entryId;\r
- }\r
-\r
- public void setName(String name) {\r
- mSessionName = name;\r
- }\r
-\r
- public String getName() {\r
- return mSessionName;\r
- }\r
-\r
- public void setUrl(String url) {\r
- mSessionUrl = url;\r
- }\r
-\r
- public String getUrl() {\r
- return mSessionUrl;\r
- }\r
-\r
- public int getEntryId() {\r
- return mEntryId;\r
- }\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud;\r
-\r
-import java.io.File;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Stack;\r
-import java.util.Vector;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.AlertDialog.Builder;\r
-import android.app.Dialog;\r
-import android.app.ListActivity;\r
-import android.app.ProgressDialog;\r
-import android.content.Context;\r
-import android.content.DialogInterface;\r
-import android.content.DialogInterface.OnCancelListener;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.content.Intent;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Parcelable;\r
-import android.provider.MediaStore.Images.Media;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.Window;\r
-import android.widget.AdapterView;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.SimpleAdapter;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.datamodel.DataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.FileDataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.files.services.FileUploader;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * This can be used to upload things to an ownCloud instance.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
- private static final String TAG = "ownCloudUploader";\r
-\r
- private Account mAccount;\r
- private AccountManager mAccountManager;\r
- private Stack<String> mParents;\r
- private ArrayList<Parcelable> mStreamsToUpload;\r
- private boolean mCreateDir;\r
- private String mUploadPath;\r
- private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };\r
- private DataStorageManager mStorageManager;\r
- private OCFile mFile;\r
-\r
- private final static int DIALOG_NO_ACCOUNT = 0;\r
- private final static int DIALOG_WAITING = 1;\r
- private final static int DIALOG_NO_STREAM = 2;\r
- private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
- private final static int DIALOG_GET_DIRNAME = 4;\r
-\r
- private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
- mParents = new Stack<String>();\r
- mParents.add("");\r
- if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
- prepareStreamsToUpload();\r
- mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);\r
- Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
- if (accounts.length == 0) {\r
- Log.i(TAG, "No ownCloud account is available");\r
- showDialog(DIALOG_NO_ACCOUNT);\r
- } else if (accounts.length > 1) {\r
- Log.i(TAG, "More then one ownCloud is available");\r
- showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
- } else {\r
- mAccount = accounts[0];\r
- setContentView(R.layout.uploader_layout);\r
- mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
- populateDirectoryList();\r
- }\r
- } else {\r
- showDialog(DIALOG_NO_STREAM);\r
- }\r
- }\r
- \r
- @Override\r
- protected Dialog onCreateDialog(final int id) {\r
- final AlertDialog.Builder builder = new Builder(this);\r
- switch (id) {\r
- case DIALOG_WAITING:\r
- ProgressDialog pDialog = new ProgressDialog(this);\r
- pDialog.setIndeterminate(false);\r
- pDialog.setCancelable(false);\r
- pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
- return pDialog;\r
- case DIALOG_NO_ACCOUNT:\r
- builder.setIcon(android.R.drawable.ic_dialog_alert);\r
- builder.setTitle(R.string.uploader_wrn_no_account_title);\r
- builder.setMessage(R.string.uploader_wrn_no_account_text);\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
- // using string value since in API7 this\r
- // constatn is not defined\r
- // in API7 < this constatant is defined in\r
- // Settings.ADD_ACCOUNT_SETTINGS\r
- // and Settings.EXTRA_AUTHORITIES\r
- Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
- intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
- startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
- } else {\r
- // since in API7 there is no direct call for\r
- // account setup, so we need to\r
- // show our own AccountSetupAcricity, get\r
- // desired results and setup\r
- // everything for ourself\r
- Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
- startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
- }\r
- }\r
- });\r
- builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- /*case DIALOG_GET_DIRNAME:\r
- final EditText dirName = new EditText(getBaseContext());\r
- builder.setView(dirName);\r
- builder.setTitle(R.string.uploader_info_dirname);\r
- String pathToUpload;\r
- if (mParents.empty()) {\r
- pathToUpload = "/";\r
- } else {\r
- mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,\r
- null, null, null);\r
- mCursor.moveToFirst();\r
- pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))\r
- + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); // TODO don't make this ; use WebdavUtils.encode in the right moment\r
- }\r
- a a = new a(pathToUpload, dirName);\r
- builder.setPositiveButton(R.string.common_ok, a);\r
- builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- dialog.cancel();\r
- }\r
- });\r
- return builder.create();*/\r
- case DIALOG_MULTIPLE_ACCOUNT:\r
- CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
- for (int i = 0; i < ac.length; ++i) {\r
- ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
- }\r
- builder.setTitle(R.string.common_choose_account);\r
- builder.setItems(ac, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
- mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
- populateDirectoryList();\r
- }\r
- });\r
- builder.setCancelable(true);\r
- builder.setOnCancelListener(new OnCancelListener() {\r
- public void onCancel(DialogInterface dialog) {\r
- dialog.cancel();\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- default:\r
- throw new IllegalArgumentException("Unknown dialog id: " + id);\r
- }\r
- }\r
-\r
- class a implements OnClickListener {\r
- String mPath;\r
- EditText mDirname;\r
-\r
- public a(String path, EditText dirname) {\r
- mPath = path; \r
- mDirname = dirname;\r
- }\r
-\r
- public void onClick(DialogInterface dialog, int which) {\r
- Uploader.this.mUploadPath = mPath + mDirname.getText().toString();\r
- Uploader.this.mCreateDir = true;\r
- uploadFiles();\r
- }\r
- }\r
-\r
- @Override\r
- public void onBackPressed() {\r
-\r
- if (mParents.size() <= 1) {\r
- super.onBackPressed();\r
- return;\r
- } else {\r
- mParents.pop();\r
- populateDirectoryList();\r
- }\r
- }\r
-\r
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
- // click on folder in the list\r
- Log.d(TAG, "on item click");\r
- Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);\r
- if (tmpfiles == null) return;\r
- // filter on dirtype\r
- Vector<OCFile> files = new Vector<OCFile>();\r
- for (OCFile f : tmpfiles)\r
- if (f.isDirectory())\r
- files.add(f);\r
- if (files.size() < position) {\r
- throw new IndexOutOfBoundsException("Incorrect item selected");\r
- }\r
- mParents.push(files.get(position).getFileName());\r
- populateDirectoryList();\r
- }\r
-\r
- public void onClick(View v) {\r
- // click on button\r
- switch (v.getId()) {\r
- case R.id.uploader_choose_folder:\r
- mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix\r
- for (String p : mParents)\r
- mUploadPath += p + OCFile.PATH_SEPARATOR;\r
- Log.d(TAG, "Uploading file to dir " + mUploadPath);\r
-\r
- uploadFiles();\r
-\r
- break;\r
- case android.R.id.button1: // dynamic action for create aditional dir\r
- showDialog(DIALOG_GET_DIRNAME);\r
- break;\r
- default:\r
- throw new IllegalArgumentException("Wrong element clicked");\r
- }\r
- }\r
-\r
- @Override\r
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
- super.onActivityResult(requestCode, resultCode, data);\r
- Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
- if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
- dismissDialog(DIALOG_NO_ACCOUNT);\r
- if (resultCode == RESULT_CANCELED) {\r
- finish();\r
- }\r
- Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
- if (accounts.length == 0) {\r
- showDialog(DIALOG_NO_ACCOUNT);\r
- } else {\r
- // there is no need for checking for is there more then one\r
- // account at this point\r
- // since account setup can set only one account at time\r
- mAccount = accounts[0];\r
- populateDirectoryList();\r
- }\r
- }\r
- }\r
-\r
- private void populateDirectoryList() {\r
- setContentView(R.layout.uploader_layout);\r
-\r
- String full_path = "";\r
- for (String a : mParents)\r
- full_path += a + "/";\r
- \r
- Log.d(TAG, "Populating view with content of : " + full_path);\r
- \r
- mFile = mStorageManager.getFileByPath(full_path);\r
- if (mFile != null) {\r
- Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);\r
- if (files != null) {\r
- List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();\r
- for (OCFile f : files) {\r
- HashMap<String, Object> h = new HashMap<String, Object>();\r
- if (f.isDirectory()) {\r
- h.put("dirname", f.getFileName());\r
- data.add(h);\r
- }\r
- }\r
- SimpleAdapter sa = new SimpleAdapter(this,\r
- data,\r
- R.layout.uploader_list_item_layout,\r
- new String[] {"dirname"},\r
- new int[] {R.id.textView1});\r
- setListAdapter(sa);\r
- Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
- btn.setOnClickListener(this);\r
- getListView().setOnItemClickListener(this);\r
- }\r
- }\r
- /*\r
- mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, null, ProviderTableMeta.FILE_NAME\r
- + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", new String[] { "/", mAccount.name }, null);\r
-\r
- if (mCursor.moveToFirst()) {\r
- mCursor = managedQuery(\r
- ProviderMeta.ProviderTableMeta.CONTENT_URI,\r
- null,\r
- ProviderTableMeta.FILE_CONTENT_TYPE + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND "\r
- + ProviderTableMeta.FILE_PARENT + "=?",\r
- new String[] { "DIR", mAccount.name,\r
- mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)) }, null);\r
-\r
- ListView lv = getListView();\r
- lv.setOnItemClickListener(this);\r
- SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, mCursor,\r
- new String[] { ProviderTableMeta.FILE_NAME }, new int[] { R.id.textView1 });\r
- setListAdapter(sca);\r
- Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
- btn.setOnClickListener(this);\r
- /*\r
- * disable this until new server interaction service wont be created\r
- * // insert create new directory for multiple items uploading if\r
- * (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
- * Button createDirBtn = new Button(this);\r
- * createDirBtn.setId(android.R.id.button1);\r
- * createDirBtn.setText(R.string.uploader_btn_create_dir_text);\r
- * createDirBtn.setOnClickListener(this); ((LinearLayout)\r
- * findViewById(R.id.linearLayout1)).addView( createDirBtn,\r
- * LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); }\r
- *\r
- }*/\r
- }\r
-\r
- private void prepareStreamsToUpload() {\r
- if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
- mStreamsToUpload = new ArrayList<Parcelable>();\r
- mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
- } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
- mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
- } else {\r
- // unknow action inserted\r
- throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());\r
- }\r
- }\r
-\r
- public void uploadFiles() {\r
- WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext());\r
- wdc.allowSelfsignedCertificates();\r
-\r
- // create last directory in path if nessesary\r
- if (mCreateDir) {\r
- wdc.createDirectory(mUploadPath);\r
- }\r
-\r
- String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
-\r
- for (int i = 0; i < mStreamsToUpload.size(); ++i) {\r
- Uri uri = (Uri) mStreamsToUpload.get(i);\r
- if (uri.getScheme().equals("content")) {\r
- Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),\r
- CONTENT_PROJECTION,\r
- null,\r
- null,\r
- null);\r
-\r
- if (!c.moveToFirst())\r
- continue;\r
-\r
- final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
- data = c.getString(c.getColumnIndex(Media.DATA));\r
- local[i] = data;\r
- remote[i] = mUploadPath + display_name;\r
- } else if (uri.getScheme().equals("file")) {\r
- final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));\r
- local[i] = file.getAbsolutePath();\r
- remote[i] = mUploadPath + file.getName();\r
- }\r
-\r
- }\r
- Intent intent = new Intent(getApplicationContext(), FileUploader.class);\r
- intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
- intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);\r
- intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);\r
- intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);\r
- startService(intent);\r
- finish();\r
- }\r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud.authenticator;\r
-\r
-import eu.alefzero.owncloud.ui.activity.AuthenticatorActivity;\r
-import android.accounts.*;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-\r
-public class AccountAuthenticator extends AbstractAccountAuthenticator {\r
- /**\r
- * Is used by android system to assign accounts to authenticators. Should be\r
- * used by application and all extensions.\r
- */\r
- public static final String ACCOUNT_TYPE = "owncloud";\r
- public static final String AUTH_TOKEN_TYPE = "org.owncloud";\r
-\r
- public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";\r
- public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";\r
- public static final String KEY_LOGIN_OPTIONS = "loginOptions";\r
- public static final String KEY_ACCOUNT = "account";\r
- /**\r
- * Value under this key should handle path to webdav php script. Will be\r
- * removed and usage should be replaced by combining\r
- * {@link eu.alefzero.owncloud.authenticator.KEY_OC_BASE_URL} and\r
- * {@link eu.alefzero.owncloud.utils.OwnCloudVersion}\r
- * \r
- * @deprecated\r
- */\r
- public static final String KEY_OC_URL = "oc_url";\r
- /**\r
- * Version should be 3 numbers separated by dot so it can be parsed by\r
- * {@link eu.alefzero.owncloud.utils.OwnCloudVersion}\r
- */\r
- public static final String KEY_OC_VERSION = "oc_version";\r
- /**\r
- * Base url should point to owncloud installation without trailing / ie:\r
- * http://server/path or https://owncloud.server\r
- */\r
- public static final String KEY_OC_BASE_URL = "oc_base_url";\r
-\r
- private static final String TAG = "AccountAuthenticator";\r
- private Context mContext;\r
-\r
- public AccountAuthenticator(Context context) {\r
- super(context);\r
- mContext = context;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public Bundle addAccount(AccountAuthenticatorResponse response,\r
- String accountType, String authTokenType,\r
- String[] requiredFeatures, Bundle options)\r
- throws NetworkErrorException {\r
- Log.i(TAG, "Adding account with type " + accountType\r
- + " and auth token " + authTokenType);\r
- try {\r
- validateAccountType(accountType);\r
- } catch (AuthenticatorException e) {\r
- Log.e(TAG, "Failed to validate account type " + accountType + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
- intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
- setIntentFlags(intent);\r
- final Bundle bundle = new Bundle();\r
- bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return bundle;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
- Account account, Bundle options) throws NetworkErrorException {\r
- try {\r
- validateAccountType(account.type);\r
- } catch (AuthenticatorException e) {\r
- Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_ACCOUNT, account);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
- setIntentFlags(intent);\r
-\r
- Bundle resultBundle = new Bundle();\r
- resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return resultBundle;\r
- }\r
-\r
- @Override\r
- public Bundle editProperties(AccountAuthenticatorResponse response,\r
- String accountType) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public Bundle getAuthToken(AccountAuthenticatorResponse response,\r
- Account account, String authTokenType, Bundle options)\r
- throws NetworkErrorException {\r
- try {\r
- validateAccountType(account.type);\r
- validateAuthTokenType(authTokenType);\r
- } catch (AuthenticatorException e) {\r
- Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- final AccountManager am = AccountManager.get(mContext);\r
- final String password = am.getPassword(account);\r
- if (password != null) {\r
- final Bundle result = new Bundle();\r
- result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
- result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);\r
- result.putString(AccountManager.KEY_AUTHTOKEN, password);\r
- return result;\r
- }\r
-\r
- final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
- intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);\r
-\r
- final Bundle bundle = new Bundle();\r
- bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return bundle;\r
- }\r
-\r
- @Override\r
- public String getAuthTokenLabel(String authTokenType) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public Bundle hasFeatures(AccountAuthenticatorResponse response,\r
- Account account, String[] features) throws NetworkErrorException {\r
- final Bundle result = new Bundle();\r
- result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);\r
- return result;\r
- }\r
-\r
- @Override\r
- public Bundle updateCredentials(AccountAuthenticatorResponse response,\r
- Account account, String authTokenType, Bundle options)\r
- throws NetworkErrorException {\r
- final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_ACCOUNT, account);\r
- intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
- setIntentFlags(intent);\r
-\r
- final Bundle bundle = new Bundle();\r
- bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return bundle;\r
- }\r
-\r
- @Override\r
- public Bundle getAccountRemovalAllowed(\r
- AccountAuthenticatorResponse response, Account account)\r
- throws NetworkErrorException {\r
- return super.getAccountRemovalAllowed(response, account);\r
- }\r
-\r
- private void setIntentFlags(Intent intent) {\r
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
- intent.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
- }\r
-\r
- private void validateAccountType(String type)\r
- throws UnsupportedAccountTypeException {\r
- if (!type.equals(ACCOUNT_TYPE)) {\r
- throw new UnsupportedAccountTypeException();\r
- }\r
- }\r
-\r
- private void validateAuthTokenType(String authTokenType)\r
- throws UnsupportedAuthTokenTypeException {\r
- if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {\r
- throw new UnsupportedAuthTokenTypeException();\r
- }\r
- }\r
-\r
- public static class AuthenticatorException extends Exception {\r
- private static final long serialVersionUID = 1L;\r
- private Bundle mFailureBundle;\r
-\r
- public AuthenticatorException(int code, String errorMsg) {\r
- mFailureBundle = new Bundle();\r
- mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
- mFailureBundle\r
- .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
- }\r
-\r
- public Bundle getFailureBundle() {\r
- return mFailureBundle;\r
- }\r
- }\r
-\r
- public static class UnsupportedAccountTypeException extends\r
- AuthenticatorException {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedAccountTypeException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported account type");\r
- }\r
- }\r
-\r
- public static class UnsupportedAuthTokenTypeException extends\r
- AuthenticatorException {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedAuthTokenTypeException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported auth token type");\r
- }\r
- }\r
-\r
- public static class UnsupportedFeaturesException extends\r
- AuthenticatorException {\r
- public static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedFeaturesException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported features");\r
- }\r
- }\r
-\r
- public static class AccessDeniedException extends AuthenticatorException {\r
- public AccessDeniedException(int code, String errorMsg) {\r
- super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
- }\r
-\r
- private static final long serialVersionUID = 1L;\r
-\r
- }\r
-}\r
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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();
- }
-
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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);
- }
- });
- }
- }
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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);
- }
- });
- }
- }
-
-}
+++ /dev/null
-/*
- * $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
- * <http://www.apache.org/>.
- *
- */
-
-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;
-
-/**
- * <p>
- * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s that
- * accept self-signed certificates.
- * </p>
- * <p>
- * 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
- * </p>
- *
- * <p>
- * Example of using custom protocol socket factory for a specific host:
- *
- * <pre>
- * 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);
- * </pre>
- *
- * </p>
- * <p>
- * Example of using custom protocol socket factory per default instead of the
- * standard one:
- *
- * <pre>
- * 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);
- * </pre>
- *
- * </p>
- *
- * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
- *
- * <p>
- * 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.
- * </p>
- */
-
-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.
- * <p>
- * 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}
- * </p>
- *
- * @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
+++ /dev/null
-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
+++ /dev/null
-package eu.alefzero.owncloud.authenticator;
-
-public interface OnAuthenticationResultListener {
-
- public void onAuthenticationResult(boolean success, String message);
-
-}
+++ /dev/null
-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);
-
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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<OCFile> files);
-
- public Vector<OCFile> getDirectoryContent(OCFile f);
-
- public void removeFile(OCFile file);
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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<OCFile> files) {
-
- Iterator<OCFile> filesIt = files.iterator();
- ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(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<results.length; i++) {
- if (results[i].uri != null) {
- newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
- files.get(i).setFileId(newId);
- //Log.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
- }
- }
- }
-
- for (OCFile aFile : files) {
- if (aFile.isDirectory() && aFile.needsUpdatingWhileSaving())
- saveFiles(getDirectoryContent(aFile));
- }
-
- }
-
- public void setAccount(Account account) {
- mAccount = account;
- }
-
- public Account getAccount() {
- return mAccount;
- }
-
- public void setContentResolver(ContentResolver cr) {
- mContentResolver = cr;
- }
-
- public ContentResolver getContentResolver() {
- return mContentResolver;
- }
-
- public void setContentProvider(ContentProviderClient cp) {
- mContentProvider = cp;
- }
-
- public ContentProviderClient getContentProvider() {
- return mContentProvider;
- }
-
- public Vector<OCFile> getDirectoryContent(OCFile f) {
- if (f != null && f.isDirectory() && f.getFileId() != -1) {
- Vector<OCFile> ret = new Vector<OCFile>();
-
- 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();
- }
- }
-
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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<OCFile> {
-
- public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
- @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;
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.db;\r
-\r
-import java.util.Vector;\r
-\r
-import eu.alefzero.owncloud.OwnCloudSession;\r
-\r
-import android.content.ContentValues;\r
-import android.content.Context;\r
-import android.database.Cursor;\r
-import android.database.sqlite.SQLiteDatabase;\r
-import android.database.sqlite.SQLiteOpenHelper;\r
-\r
-/**\r
- * Custom database helper for ownCloud\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class DbHandler {\r
- private SQLiteDatabase mDB;\r
- private OpenerHepler mHelper;\r
- private final String mDatabaseName = "ownCloud";\r
- private final String TABLE_SESSIONS = "sessions";\r
- private final int mDatabaseVersion = 1;\r
- \r
- private final String TABLE_INSTANT_UPLOAD = "instant_upload";\r
-\r
- public DbHandler(Context context) {\r
- mHelper = new OpenerHepler(context);\r
- mDB = mHelper.getWritableDatabase();\r
- }\r
-\r
- public void close() {\r
- mDB.close();\r
- }\r
-\r
- public boolean putFileForLater(String filepath, String account) {\r
- ContentValues cv = new ContentValues();\r
- cv.put("path", filepath);\r
- cv.put("account", account);\r
- return mDB.insert(TABLE_INSTANT_UPLOAD, null, cv) != -1;\r
- }\r
- \r
- public Cursor getAwaitingFiles() {\r
- return mDB.query(TABLE_INSTANT_UPLOAD, null, null, null, null, null, null);\r
- }\r
- \r
- public void clearFiles() {\r
- mDB.delete(TABLE_INSTANT_UPLOAD, null, null);\r
- }\r
- \r
- private class OpenerHepler extends SQLiteOpenHelper {\r
- public OpenerHepler(Context context) {\r
- super(context, mDatabaseName, null, mDatabaseVersion);\r
- }\r
-\r
- @Override\r
- public void onCreate(SQLiteDatabase db) {\r
- db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " ("\r
- + " _id INTEGET PRIMARY KEY, "\r
- + " path TEXT,"\r
- + " account TEXT);");\r
- }\r
-\r
- @Override\r
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
- }\r
- }\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.db;\r
-\r
-import android.net.Uri;\r
-import android.provider.BaseColumns;\r
-\r
-/**\r
- * Meta-Class that holds various static field information\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class ProviderMeta {\r
-\r
- public static final String AUTHORITY_FILES = "org.owncloud";\r
- public static final String DB_FILE = "owncloud.db";\r
- public static final String DB_NAME = "filelist";\r
- public static final int DB_VERSION = 2;\r
-\r
- private ProviderMeta() {\r
- }\r
-\r
- static public class ProviderTableMeta implements BaseColumns {\r
- public static final String DB_NAME = "filelist";\r
- public static final Uri CONTENT_URI = Uri.parse("content://"\r
- + AUTHORITY_FILES + "/");\r
- public static final Uri CONTENT_URI_FILE = Uri.parse("content://"\r
- + AUTHORITY_FILES + "/file");\r
- public static final Uri CONTENT_URI_DIR = Uri.parse("content://"\r
- + AUTHORITY_FILES + "/dir");\r
-\r
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";\r
- public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";\r
-\r
- public static final String FILE_PARENT = "parent";\r
- public static final String FILE_NAME = "filename";\r
- public static final String FILE_CREATION = "created";\r
- public static final String FILE_MODIFIED = "modified";\r
- public static final String FILE_CONTENT_LENGTH = "content_length";\r
- public static final String FILE_CONTENT_TYPE = "content_type";\r
- public static final String FILE_STORAGE_PATH = "media_path";\r
- public static final String FILE_PATH = "path";\r
- public static final String FILE_ACCOUNT_OWNER = "file_owner";\r
- public static final String FILE_LAST_SYNC_DATE = "last_sync_date";\r
- public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";\r
-\r
- public static final String DEFAULT_SORT_ORDER = FILE_NAME\r
- + " collate nocase asc";\r
-\r
- }\r
-}\r
+++ /dev/null
-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");
- }
-}
+++ /dev/null
-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());
- }
- }
-
-}
+++ /dev/null
-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<HashMap<String, String>> ll = new LinkedList<HashMap<String, String>>();
- for (int i = 0; i < a.length(); ++i) {
- try {
- ExtensionApplicationEntry ela = new ExtensionApplicationEntry(
- ((JSONObject) a.get(i)));
- HashMap<String, String> ss = new HashMap<String, String>();
- 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;
- }
- }
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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();
- }
-
-}
+++ /dev/null
-package eu.alefzero.owncloud.files.interfaces;
-
-public interface OnDatatransferProgressListener {
- void transferProgress(long progressRate);
-
-}
+++ /dev/null
-package eu.alefzero.owncloud.files.services;\r
-\r
-import java.io.File;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.Notification;\r
-import android.app.NotificationManager;\r
-import android.app.PendingIntent;\r
-import android.app.Service;\r
-import android.content.ContentValues;\r
-import android.content.Intent;\r
-import android.net.Uri;\r
-import android.os.Environment;\r
-import android.os.Handler;\r
-import android.os.HandlerThread;\r
-import android.os.IBinder;\r
-import android.os.Looper;\r
-import android.os.Message;\r
-import android.os.Process;\r
-import android.util.Log;\r
-import android.widget.RemoteViews;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;\r
-import eu.alefzero.owncloud.files.interfaces.OnDatatransferProgressListener;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-public class FileDownloader extends Service implements OnDatatransferProgressListener {\r
- public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";\r
- public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; \r
- public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
- public static final String EXTRA_FILE_PATH = "FILE_PATH";\r
- public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";\r
- public static final String EXTRA_FILE_SIZE = "FILE_SIZE";\r
- public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
- \r
- private static final String TAG = "FileDownloader";\r
-\r
- private NotificationManager mNotificationMngr;\r
- private Looper mServiceLooper;\r
- private ServiceHandler mServiceHandler;\r
- private Account mAccount;\r
- private String mFilePath;\r
- private String mRemotePath;\r
- private int mLastPercent;\r
- private long mTotalDownloadSize;\r
- private long mCurrentDownloadSize;\r
- private Notification mNotification;\r
- \r
- /**\r
- * Static map with the files being download and the path to the temporal file were are download\r
- */\r
- private static Map<String, String> mDownloadsInProgress = Collections.synchronizedMap(new HashMap<String, String>());\r
- \r
- /**\r
- * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading\r
- */\r
- public static boolean isDownloading(Account account, String remotePath) {\r
- return (mDownloadsInProgress.get(buildRemoteName(account.name, remotePath)) != null);\r
- }\r
- \r
- /**\r
- * Builds a key for mDownloadsInProgress from the accountName and remotePath\r
- */\r
- private static String buildRemoteName(String accountName, String remotePath) {\r
- return accountName + remotePath;\r
- }\r
-\r
- \r
- private final class ServiceHandler extends Handler {\r
- public ServiceHandler(Looper looper) {\r
- super(looper);\r
- }\r
-\r
- @Override\r
- public void handleMessage(Message msg) {\r
- downloadFile();\r
- stopSelf(msg.arg1);\r
- }\r
- }\r
- \r
- public static final String getSavePath(String accountName) {\r
- File sdCard = Environment.getExternalStorageDirectory();\r
- return sdCard.getAbsolutePath() + "/owncloud/" + Uri.encode(accountName, "@"); \r
- // 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\r
- }\r
- \r
- public static final String getTemporalPath(String accountName) {\r
- File sdCard = Environment.getExternalStorageDirectory();\r
- return sdCard.getAbsolutePath() + "/owncloud/tmp/" + Uri.encode(accountName, "@");\r
- // 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\r
- }\r
-\r
- @Override\r
- public void onCreate() {\r
- super.onCreate();\r
- mNotificationMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);\r
- HandlerThread thread = new HandlerThread("FileDownladerThread",\r
- Process.THREAD_PRIORITY_BACKGROUND);\r
- thread.start();\r
- mServiceLooper = thread.getLooper();\r
- mServiceHandler = new ServiceHandler(mServiceLooper);\r
- }\r
-\r
- @Override\r
- public IBinder onBind(Intent arg0) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public int onStartCommand(Intent intent, int flags, int startId) {\r
- if ( !intent.hasExtra(EXTRA_ACCOUNT) ||\r
- !intent.hasExtra(EXTRA_FILE_PATH) ||\r
- !intent.hasExtra(EXTRA_REMOTE_PATH)\r
- ) {\r
- Log.e(TAG, "Not enough information provided in intent");\r
- return START_NOT_STICKY;\r
- }\r
- mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT);\r
- mFilePath = intent.getStringExtra(EXTRA_FILE_PATH);\r
- mRemotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);\r
- mTotalDownloadSize = intent.getLongExtra(EXTRA_FILE_SIZE, -1);\r
- mCurrentDownloadSize = mLastPercent = 0;\r
-\r
- Message msg = mServiceHandler.obtainMessage();\r
- msg.arg1 = startId;\r
- mServiceHandler.sendMessage(msg);\r
-\r
- return START_NOT_STICKY;\r
- }\r
-\r
- /**\r
- * Core download method: requests the file to download and stores it.\r
- */\r
- private void downloadFile() {\r
- boolean downloadResult = false;\r
-\r
- /// prepare client object to send the request to the ownCloud server\r
- AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);\r
- WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext());\r
- String username = mAccount.name.split("@")[0];\r
- String password = null;\r
- try {\r
- password = am.blockingGetAuthToken(mAccount,\r
- AccountAuthenticator.AUTH_TOKEN_TYPE, true);\r
- } catch (Exception e) {\r
- Log.e(TAG, "Access to account credentials failed", e);\r
- sendFinalBroadcast(downloadResult, null);\r
- return;\r
- }\r
- wdc.setCredentials(username, password);\r
- wdc.allowSelfsignedCertificates();\r
- wdc.setDataTransferProgressListener(this);\r
-\r
- \r
- /// download will be in a temporal file\r
- File tmpFile = new File(getTemporalPath(mAccount.name) + mFilePath);\r
- \r
- /// create status notification to show the download progress\r
- mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());\r
- mNotification.flags |= Notification.FLAG_ONGOING_EVENT;\r
- mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);\r
- mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, mTotalDownloadSize == -1);\r
- mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, tmpFile.getName()));\r
- mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);\r
- // TODO put something smart in the contentIntent below\r
- mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);\r
- mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
- \r
-\r
- /// perform the download\r
- tmpFile.getParentFile().mkdirs();\r
- mDownloadsInProgress.put(buildRemoteName(mAccount.name, mRemotePath), tmpFile.getAbsolutePath());\r
- File newFile = null;\r
- try {\r
- if (wdc.downloadFile(mRemotePath, tmpFile)) {\r
- newFile = new File(getSavePath(mAccount.name) + mFilePath);\r
- newFile.getParentFile().mkdirs();\r
- boolean moved = tmpFile.renameTo(newFile);\r
- \r
- if (moved) {\r
- ContentValues cv = new ContentValues();\r
- cv.put(ProviderTableMeta.FILE_STORAGE_PATH, newFile.getAbsolutePath());\r
- getContentResolver().update(\r
- ProviderTableMeta.CONTENT_URI,\r
- cv,\r
- ProviderTableMeta.FILE_NAME + "=? AND "\r
- + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",\r
- new String[] {\r
- mFilePath.substring(mFilePath.lastIndexOf('/') + 1),\r
- mAccount.name });\r
- downloadResult = true;\r
- }\r
- }\r
- } finally {\r
- mDownloadsInProgress.remove(buildRemoteName(mAccount.name, mRemotePath));\r
- }\r
-\r
- \r
- /// notify result\r
- mNotificationMngr.cancel(R.string.downloader_download_in_progress_ticker);\r
- int tickerId = (downloadResult) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;\r
- int contentId = (downloadResult) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;\r
- Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());\r
- finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;\r
- // TODO put something smart in the contentIntent below\r
- finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);\r
- finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), tmpFile.getName()), finalNotification.contentIntent);\r
- mNotificationMngr.notify(tickerId, finalNotification);\r
- \r
- sendFinalBroadcast(downloadResult, (downloadResult)?newFile.getAbsolutePath():null);\r
- }\r
-\r
- /**\r
- * Callback method to update the progress bar in the status notification.\r
- */\r
- @Override\r
- public void transferProgress(long progressRate) {\r
- mCurrentDownloadSize += progressRate;\r
- int percent = (int)(100.0*((double)mCurrentDownloadSize)/((double)mTotalDownloadSize));\r
- if (percent != mLastPercent) {\r
- mNotification.contentView.setProgressBar(R.id.status_progress, 100, (int)(100*mCurrentDownloadSize/mTotalDownloadSize), mTotalDownloadSize == -1);\r
- mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), percent, new File(mFilePath).getName()));\r
- mNotificationMngr.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
- }\r
- \r
- mLastPercent = percent;\r
- }\r
- \r
-\r
- /**\r
- * Sends a broadcast in order to the interested activities can update their view\r
- * \r
- * @param downloadResult 'True' if the download was successful\r
- * @param newFilePath Absolute path to the download file\r
- */\r
- private void sendFinalBroadcast(boolean downloadResult, String newFilePath) {\r
- Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);\r
- end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult);\r
- end.putExtra(ACCOUNT_NAME, mAccount.name);\r
- end.putExtra(EXTRA_REMOTE_PATH, mRemotePath);\r
- if (downloadResult) {\r
- end.putExtra(EXTRA_FILE_PATH, newFilePath);\r
- }\r
- sendBroadcast(end);\r
- }\r
-\r
-}\r
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-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;
- }
-
-}
+++ /dev/null
-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<String, String> mUploadsInProgress = Collections.synchronizedMap(new HashMap<String, String>());
-
- /**
- * 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;
- }
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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<HashMap<String, Object>> mHashMapList;
-
- public UploaderRunnable() {
- mHashMapList = new LinkedList<HashMap<String, Object>>();
- mLock = new Object();
- }
-
- public void addElementToQueue(String filename,
- String filepath,
- String mimetype,
- long length,
- Account account) {
- HashMap<String, Object> new_map = new HashMap<String, Object>();
- 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<String, Object> getFirstObject() {
- synchronized (mLock) {
- if (mHashMapList.size() == 0)
- return null;
- HashMap<String, Object> ret = mHashMapList.get(0);
- mHashMapList.remove(0);
- return ret;
- }
- }
-
- public void run() {
- HashMap<String, Object> 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();
- }
- }
- }
- }
-
-}
+++ /dev/null
-package eu.alefzero.owncloud.files.services;
-
-public interface OnUploadCompletedListener extends Runnable {
-
- public boolean getUploadResult();
-
- public void setUploadResult(boolean result);
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-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;
- }
-
-}
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-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
-
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud.providers;\r
-\r
-import java.util.HashMap;\r
-\r
-import eu.alefzero.owncloud.db.ProviderMeta;\r
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;\r
-\r
-import android.content.ContentProvider;\r
-import android.content.ContentUris;\r
-import android.content.ContentValues;\r
-import android.content.Context;\r
-import android.content.UriMatcher;\r
-import android.database.Cursor;\r
-import android.database.SQLException;\r
-import android.database.sqlite.SQLiteDatabase;\r
-import android.database.sqlite.SQLiteOpenHelper;\r
-import android.database.sqlite.SQLiteQueryBuilder;\r
-import android.net.Uri;\r
-import android.text.TextUtils;\r
-import android.util.Log;\r
-\r
-/**\r
- * The ContentProvider for the ownCloud App.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileContentProvider extends ContentProvider {\r
-\r
- private DataBaseHelper mDbHelper;\r
-\r
- private static HashMap<String, String> mProjectionMap;\r
- static {\r
- mProjectionMap = new HashMap<String, String>();\r
- mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);\r
- mProjectionMap.put(ProviderTableMeta.FILE_PARENT,\r
- ProviderTableMeta.FILE_PARENT);\r
- mProjectionMap.put(ProviderTableMeta.FILE_PATH,\r
- ProviderTableMeta.FILE_PATH);\r
- mProjectionMap.put(ProviderTableMeta.FILE_NAME,\r
- ProviderTableMeta.FILE_NAME);\r
- mProjectionMap.put(ProviderTableMeta.FILE_CREATION,\r
- ProviderTableMeta.FILE_CREATION);\r
- mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,\r
- ProviderTableMeta.FILE_MODIFIED);\r
- mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,\r
- ProviderTableMeta.FILE_CONTENT_LENGTH);\r
- mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,\r
- ProviderTableMeta.FILE_CONTENT_TYPE);\r
- mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,\r
- ProviderTableMeta.FILE_STORAGE_PATH);\r
- mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,\r
- ProviderTableMeta.FILE_LAST_SYNC_DATE);\r
- mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,\r
- ProviderTableMeta.FILE_KEEP_IN_SYNC);\r
- }\r
-\r
- private static final int SINGLE_FILE = 1;\r
- private static final int DIRECTORY = 2;\r
- private static final int ROOT_DIRECTORY = 3;\r
- private static final UriMatcher mUriMatcher;\r
- static {\r
- mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);\r
- mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);\r
- }\r
-\r
- @Override\r
- public int delete(Uri uri, String where, String[] whereArgs) {\r
- SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
- int count = 0;\r
- switch (mUriMatcher.match(uri)) {\r
- case SINGLE_FILE:\r
- count = db.delete(ProviderTableMeta.DB_NAME,\r
- ProviderTableMeta._ID\r
- + "="\r
- + uri.getPathSegments().get(1)\r
- + (!TextUtils.isEmpty(where) ? " AND (" + where\r
- + ")" : ""), whereArgs);\r
- break;\r
- case ROOT_DIRECTORY:\r
- count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);\r
- break;\r
- default:\r
- throw new IllegalArgumentException("Unknown uri: " + uri.toString());\r
- }\r
- getContext().getContentResolver().notifyChange(uri, null);\r
- return count;\r
- }\r
-\r
- @Override\r
- public String getType(Uri uri) {\r
- switch (mUriMatcher.match(uri)) {\r
- case ROOT_DIRECTORY:\r
- return ProviderTableMeta.CONTENT_TYPE;\r
- case SINGLE_FILE:\r
- return ProviderTableMeta.CONTENT_TYPE_ITEM;\r
- default:\r
- throw new IllegalArgumentException("Unknown Uri id."\r
- + uri.toString());\r
- }\r
- }\r
-\r
- @Override\r
- public Uri insert(Uri uri, ContentValues values) {\r
- if (mUriMatcher.match(uri) != SINGLE_FILE &&\r
- mUriMatcher.match(uri) != ROOT_DIRECTORY) {\r
- \r
- throw new IllegalArgumentException("Unknown uri id: " + uri);\r
- }\r
-\r
- SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
- long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);\r
- if (rowId > 0) {\r
- Uri insertedFileUri = ContentUris.withAppendedId(\r
- ProviderTableMeta.CONTENT_URI_FILE, rowId);\r
- getContext().getContentResolver().notifyChange(insertedFileUri,\r
- null);\r
- return insertedFileUri;\r
- }\r
- throw new SQLException("ERROR " + uri);\r
- }\r
-\r
- @Override\r
- public boolean onCreate() {\r
- mDbHelper = new DataBaseHelper(getContext());\r
- return true;\r
- }\r
-\r
- @Override\r
- public Cursor query(Uri uri, String[] projection, String selection,\r
- String[] selectionArgs, String sortOrder) {\r
- SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();\r
-\r
- sqlQuery.setTables(ProviderTableMeta.DB_NAME);\r
- sqlQuery.setProjectionMap(mProjectionMap);\r
-\r
- switch (mUriMatcher.match(uri)) {\r
- case ROOT_DIRECTORY:\r
- break;\r
- case DIRECTORY:\r
- sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="\r
- + uri.getPathSegments().get(1));\r
- break;\r
- case SINGLE_FILE:\r
- if (uri.getPathSegments().size() > 1) {\r
- sqlQuery.appendWhere(ProviderTableMeta._ID + "="\r
- + uri.getPathSegments().get(1));\r
- }\r
- break;\r
- default:\r
- throw new IllegalArgumentException("Unknown uri id: " + uri);\r
- }\r
-\r
- String order;\r
- if (TextUtils.isEmpty(sortOrder)) {\r
- order = ProviderTableMeta.DEFAULT_SORT_ORDER;\r
- } else {\r
- order = sortOrder;\r
- }\r
-\r
- SQLiteDatabase db = mDbHelper.getReadableDatabase();\r
- Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,\r
- null, null, order);\r
-\r
- c.setNotificationUri(getContext().getContentResolver(), uri);\r
-\r
- return c;\r
- }\r
-\r
- @Override\r
- public int update(Uri uri, ContentValues values, String selection,\r
- String[] selectionArgs) {\r
- return mDbHelper.getWritableDatabase().update(\r
- ProviderTableMeta.DB_NAME, values, selection, selectionArgs);\r
- }\r
-\r
- class DataBaseHelper extends SQLiteOpenHelper {\r
-\r
- public DataBaseHelper(Context context) {\r
- super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);\r
-\r
- }\r
-\r
- @Override\r
- public void onCreate(SQLiteDatabase db) {\r
- // files table\r
- Log.i("SQL", "Entering in onCreate");\r
- db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("\r
- + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "\r
- + ProviderTableMeta.FILE_NAME + " TEXT, "\r
- + ProviderTableMeta.FILE_PATH + " TEXT, "\r
- + ProviderTableMeta.FILE_PARENT + " INTEGER, "\r
- + ProviderTableMeta.FILE_CREATION + " INTEGER, "\r
- + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "\r
- + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "\r
- + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "\r
- + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "\r
- + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "\r
- + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "\r
- + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER );");\r
- }\r
-\r
- @Override\r
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
- Log.i("SQL", "Entering in onUpgrade");\r
- if (oldVersion == 1 && newVersion >= 2) {\r
- Log.i("SQL", "Entering in the ADD in onUpgrade");\r
- db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
- " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +\r
- " DEFAULT 0");\r
- } else Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);\r
- }\r
-\r
- }\r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud.syncadapter;\r
-\r
-import java.io.IOException;\r
-import java.net.UnknownHostException;\r
-import java.util.Date;\r
-\r
-import org.apache.http.HttpRequest;\r
-import org.apache.http.HttpResponse;\r
-import org.apache.http.client.ClientProtocolException;\r
-import org.apache.http.conn.ConnectionKeepAliveStrategy;\r
-import org.apache.http.protocol.HttpContext;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.accounts.AuthenticatorException;\r
-import android.accounts.OperationCanceledException;\r
-import android.content.AbstractThreadedSyncAdapter;\r
-import android.content.ContentProviderClient;\r
-import android.content.Context;\r
-import android.net.Uri;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.datamodel.DataStorageManager;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * Base SyncAdapter for OwnCloud Designed to be subclassed for the concrete\r
- * SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc..\r
- * \r
- * @author sassman\r
- * \r
- */\r
-public abstract class AbstractOwnCloudSyncAdapter extends\r
- AbstractThreadedSyncAdapter {\r
-\r
- private AccountManager accountManager;\r
- private Account account;\r
- private ContentProviderClient contentProvider;\r
- private Date lastUpdated;\r
- private DataStorageManager mStoreManager;\r
-\r
- private WebdavClient mClient = null;\r
-\r
- public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) {\r
- super(context, autoInitialize);\r
- this.setAccountManager(AccountManager.get(context));\r
- }\r
-\r
- public AccountManager getAccountManager() {\r
- return accountManager;\r
- }\r
-\r
- public void setAccountManager(AccountManager accountManager) {\r
- this.accountManager = accountManager;\r
- }\r
-\r
- public Account getAccount() {\r
- return account;\r
- }\r
-\r
- public void setAccount(Account account) {\r
- this.account = account;\r
- }\r
-\r
- public ContentProviderClient getContentProvider() {\r
- return contentProvider;\r
- }\r
-\r
- public void setContentProvider(ContentProviderClient contentProvider) {\r
- this.contentProvider = contentProvider;\r
- }\r
-\r
- public Date getLastUpdated() {\r
- return lastUpdated;\r
- }\r
-\r
- public void setLastUpdated(Date lastUpdated) {\r
- this.lastUpdated = lastUpdated;\r
- }\r
-\r
- public void setStorageManager(DataStorageManager storage_manager) {\r
- mStoreManager = storage_manager;\r
- }\r
-\r
- public DataStorageManager getStorageManager() {\r
- return mStoreManager;\r
- }\r
-\r
- protected ConnectionKeepAliveStrategy getKeepAliveStrategy() {\r
- return new ConnectionKeepAliveStrategy() {\r
- public long getKeepAliveDuration(HttpResponse response,\r
- HttpContext context) {\r
- // Change keep alive straategy basing on response: ie\r
- // forbidden/not found/etc\r
- // should have keep alive 0\r
- // default return: 5s\r
- int statusCode = response.getStatusLine().getStatusCode();\r
-\r
- // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed\r
- // out\r
- if ((statusCode >= 400 && statusCode <= 418)\r
- || (statusCode >= 421 && statusCode <= 426)\r
- || (statusCode >= 500 && statusCode <= 510)\r
- || statusCode == 118) {\r
- return 0;\r
- }\r
-\r
- return 5 * 1000;\r
- }\r
- };\r
- }\r
-\r
- protected HttpResponse fireRawRequest(HttpRequest query)\r
- throws ClientProtocolException, OperationCanceledException,\r
- AuthenticatorException, IOException {\r
- /*\r
- * BasicHttpContext httpContext = new BasicHttpContext(); BasicScheme\r
- * basicAuth = new BasicScheme();\r
- * httpContext.setAttribute("preemptive-auth", basicAuth);\r
- * \r
- * HttpResponse response = getClient().execute(mHost, query,\r
- * httpContext);\r
- */\r
- return null;\r
- }\r
-\r
- protected Uri getUri() {\r
- return Uri.parse(this.getAccountManager().getUserData(getAccount(),\r
- AccountAuthenticator.KEY_OC_URL));\r
- }\r
-\r
- protected WebdavClient getClient() throws OperationCanceledException,\r
- AuthenticatorException, IOException {\r
- if (mClient == null) {\r
- if (this.getAccountManager().getUserData(getAccount(),\r
- AccountAuthenticator.KEY_OC_URL) == null) {\r
- throw new UnknownHostException();\r
- }\r
- mClient = new WebdavClient(account, getContext());\r
- mClient.allowSelfsignedCertificates();\r
- // mHost = mClient.getTargetHost();\r
- }\r
-\r
- return mClient;\r
- }\r
-}
\ No newline at end of file
+++ /dev/null
-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");
- }
-
-}
+++ /dev/null
-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();
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud.syncadapter;\r
-\r
-import java.io.IOException;\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import org.apache.jackrabbit.webdav.DavException;\r
-import org.apache.jackrabbit.webdav.MultiStatus;\r
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AuthenticatorException;\r
-import android.accounts.OperationCanceledException;\r
-import android.content.ContentProviderClient;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.SyncResult;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-import eu.alefzero.owncloud.datamodel.FileDataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.files.services.FileDownloader;\r
-import eu.alefzero.webdav.WebdavEntry;\r
-import eu.alefzero.webdav.WebdavUtils;\r
-\r
-/**\r
- * SyncAdapter implementation for syncing sample SyncAdapter contacts to the\r
- * platform ContactOperations provider.\r
- * \r
- * @author Bartek Przybylski\r
- */\r
-public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {\r
-\r
- private final static String TAG = "FileSyncAdapter"; \r
- \r
- /* Commented code for ugly performance tests\r
- private final static int MAX_DELAYS = 100;\r
- private static long[] mResponseDelays = new long[MAX_DELAYS]; \r
- private static long[] mSaveDelays = new long[MAX_DELAYS];\r
- private int mDelaysIndex = 0;\r
- private int mDelaysCount = 0;\r
- */\r
- \r
- private long mCurrentSyncTime;\r
- private boolean mCancellation;\r
- private Account mAccount;\r
- \r
- public FileSyncAdapter(Context context, boolean autoInitialize) {\r
- super(context, autoInitialize);\r
- }\r
-\r
- @Override\r
- public synchronized void onPerformSync(Account account, Bundle extras,\r
- String authority, ContentProviderClient provider,\r
- SyncResult syncResult) {\r
-\r
- mCancellation = false;\r
- mAccount = account;\r
- \r
- this.setAccount(mAccount);\r
- this.setContentProvider(provider);\r
- this.setStorageManager(new FileDataStorageManager(mAccount,\r
- getContentProvider()));\r
- \r
- /* Commented code for ugly performance tests\r
- mDelaysIndex = 0;\r
- mDelaysCount = 0;\r
- */\r
- \r
- \r
- Log.d(TAG, "syncing owncloud account " + mAccount.name);\r
-\r
- sendStickyBroadcast(true, null); // message to signal the start to the UI\r
-\r
- PropFindMethod query;\r
- try {\r
- mCurrentSyncTime = System.currentTimeMillis();\r
- query = new PropFindMethod(getUri().toString() + "/");\r
- getClient().executeMethod(query);\r
- MultiStatus resp = null;\r
- resp = query.getResponseBodyAsMultiStatus();\r
-\r
- if (resp.getResponses().length > 0) {\r
- WebdavEntry we = new WebdavEntry(resp.getResponses()[0], getUri().getPath());\r
- OCFile file = fillOCFile(we);\r
- file.setParentId(0);\r
- getStorageManager().saveFile(file);\r
- if (!mCancellation) {\r
- fetchData(getUri().toString(), syncResult, file.getFileId());\r
- }\r
- }\r
- } catch (OperationCanceledException e) {\r
- e.printStackTrace();\r
- } catch (AuthenticatorException e) {\r
- syncResult.stats.numAuthExceptions++;\r
- e.printStackTrace();\r
- } catch (IOException e) {\r
- syncResult.stats.numIoExceptions++;\r
- e.printStackTrace();\r
- } catch (DavException e) {\r
- syncResult.stats.numIoExceptions++;\r
- e.printStackTrace();\r
- } catch (Throwable t) {\r
- // TODO update syncResult\r
- Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t);\r
- t.printStackTrace();\r
- }\r
- \r
- /* Commented code for ugly performance tests\r
- long sum = 0, mean = 0, max = 0, min = Long.MAX_VALUE;\r
- for (int i=0; i<MAX_DELAYS && i<mDelaysCount; i++) {\r
- sum += mResponseDelays[i];\r
- max = Math.max(max, mResponseDelays[i]);\r
- min = Math.min(min, mResponseDelays[i]);\r
- }\r
- mean = sum / mDelaysCount;\r
- Log.e(TAG, "SYNC STATS - response: mean time = " + mean + " ; max time = " + max + " ; min time = " + min);\r
- \r
- sum = 0; max = 0; min = Long.MAX_VALUE;\r
- for (int i=0; i<MAX_DELAYS && i<mDelaysCount; i++) {\r
- sum += mSaveDelays[i];\r
- max = Math.max(max, mSaveDelays[i]);\r
- min = Math.min(min, mSaveDelays[i]);\r
- }\r
- mean = sum / mDelaysCount;\r
- Log.e(TAG, "SYNC STATS - save: mean time = " + mean + " ; max time = " + max + " ; min time = " + min);\r
- Log.e(TAG, "SYNC STATS - folders measured: " + mDelaysCount);\r
- */\r
- \r
- sendStickyBroadcast(false, null); \r
- }\r
-\r
- private void fetchData(String uri, SyncResult syncResult, long parentId) {\r
- try {\r
- Log.d(TAG, "fetching " + uri);\r
- \r
- // remote request \r
- PropFindMethod query = new PropFindMethod(uri);\r
- /* Commented code for ugly performance tests\r
- long responseDelay = System.currentTimeMillis();\r
- */\r
- getClient().executeMethod(query);\r
- /* Commented code for ugly performance tests\r
- responseDelay = System.currentTimeMillis() - responseDelay;\r
- Log.e(TAG, "syncing: RESPONSE TIME for " + uri + " contents, " + responseDelay + "ms");\r
- */\r
- MultiStatus resp = null;\r
- resp = query.getResponseBodyAsMultiStatus();\r
- \r
- // insertion or update of files\r
- List<OCFile> updatedFiles = new Vector<OCFile>(resp.getResponses().length - 1);\r
- for (int i = 1; i < resp.getResponses().length; ++i) {\r
- WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath());\r
- OCFile file = fillOCFile(we);\r
- file.setParentId(parentId);\r
- if (getStorageManager().getFileByPath(file.getRemotePath()) != null &&\r
- getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() &&\r
- file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath())\r
- .getModificationTimestamp()) {\r
- Intent intent = new Intent(this.getContext(), FileDownloader.class);\r
- intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());\r
- intent.putExtra(FileDownloader.EXTRA_FILE_PATH, file.getRemotePath());\r
- intent.putExtra(FileDownloader.EXTRA_REMOTE_PATH, file.getRemotePath());\r
- intent.putExtra(FileDownloader.EXTRA_FILE_SIZE, file.getFileLength());\r
- file.setKeepInSync(true);\r
- getContext().startService(intent);\r
- }\r
- if (getStorageManager().getFileByPath(file.getRemotePath()) != null)\r
- file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync());\r
- \r
- //Log.v(TAG, "adding file: " + file);\r
- updatedFiles.add(file);\r
- if (parentId == 0)\r
- parentId = file.getFileId();\r
- }\r
- /* Commented code for ugly performance tests\r
- long saveDelay = System.currentTimeMillis();\r
- */ \r
- getStorageManager().saveFiles(updatedFiles); // all "at once" ; trying to get a best performance in database update\r
- /* Commented code for ugly performance tests\r
- saveDelay = System.currentTimeMillis() - saveDelay;\r
- Log.e(TAG, "syncing: SAVE TIME for " + uri + " contents, " + mSaveDelays[mDelaysIndex] + "ms");\r
- */\r
- \r
- // removal of obsolete files\r
- Vector<OCFile> files = getStorageManager().getDirectoryContent(\r
- getStorageManager().getFileById(parentId));\r
- OCFile file;\r
- for (int i=0; i < files.size(); ) {\r
- file = files.get(i);\r
- if (file.getLastSyncDate() != mCurrentSyncTime) {\r
- Log.v(TAG, "removing file: " + file);\r
- getStorageManager().removeFile(file);\r
- files.remove(i);\r
- } else {\r
- i++;\r
- }\r
- }\r
- \r
- // synchronized folder -> notice to UI\r
- sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath());\r
-\r
- // recursive fetch\r
- for (int i=0; i < files.size() && !mCancellation; i++) {\r
- OCFile newFile = files.get(i);\r
- if (newFile.getMimetype().equals("DIR")) {\r
- fetchData(getUri().toString() + WebdavUtils.encodePath(newFile.getRemotePath()), syncResult, newFile.getFileId());\r
- }\r
- }\r
- if (mCancellation) Log.d(TAG, "Leaving " + uri + " because cancelation request");\r
- \r
- /* Commented code for ugly performance tests\r
- mResponseDelays[mDelaysIndex] = responseDelay;\r
- mSaveDelays[mDelaysIndex] = saveDelay;\r
- mDelaysCount++;\r
- mDelaysIndex++;\r
- if (mDelaysIndex >= MAX_DELAYS)\r
- mDelaysIndex = 0;\r
- */\r
- \r
-\r
-\r
- } catch (OperationCanceledException e) {\r
- e.printStackTrace();\r
- } catch (AuthenticatorException e) {\r
- syncResult.stats.numAuthExceptions++;\r
- e.printStackTrace();\r
- } catch (IOException e) {\r
- syncResult.stats.numIoExceptions++;\r
- e.printStackTrace();\r
- } catch (DavException e) {\r
- syncResult.stats.numIoExceptions++;\r
- e.printStackTrace();\r
- } catch (Throwable t) {\r
- // TODO update syncResult\r
- Log.e(TAG, "problem while synchronizing owncloud account " + mAccount.name, t);\r
- t.printStackTrace();\r
- }\r
- }\r
-\r
- private OCFile fillOCFile(WebdavEntry we) {\r
- OCFile file = new OCFile(we.decodedPath());\r
- file.setCreationTimestamp(we.createTimestamp());\r
- file.setFileLength(we.contentLength());\r
- file.setMimetype(we.contentType());\r
- file.setModificationTimestamp(we.modifiedTimesamp());\r
- file.setLastSyncDate(mCurrentSyncTime);\r
- return file;\r
- }\r
- \r
- \r
- private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) {\r
- Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
- i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
- i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
- if (dirRemotePath != null) {\r
- i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
- }\r
- getContext().sendStickyBroadcast(i);\r
- }\r
- \r
- /**\r
- * Called by system SyncManager when a synchronization is required to be cancelled.\r
- * \r
- * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder\r
- * fetched will be still saved in the database. See onPerformSync implementation.\r
- */\r
- @Override\r
- public void onSyncCanceled() {\r
- Log.d(TAG, "Synchronization of " + mAccount.name + " has been requested to cancell");\r
- mCancellation = true;\r
- super.onSyncCanceled();\r
- }\r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.syncadapter;\r
-\r
-import android.app.Service;\r
-import android.content.Intent;\r
-import android.os.IBinder;\r
-\r
-/**\r
- * Background service for syncing files to our local Database\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileSyncService extends Service {\r
- public static final String SYNC_MESSAGE = "ACCOUNT_SYNC";\r
- public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH";\r
- public static final String IN_PROGRESS = "SYNC_IN_PROGRESS";\r
- public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
-\r
- /*\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onCreate() {\r
- }\r
-\r
- /*\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public IBinder onBind(Intent intent) {\r
- return new FileSyncAdapter(getApplicationContext(), true).getSyncAdapterBinder();\r
- }\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui;\r
-\r
-import android.graphics.drawable.Drawable;\r
-import android.view.View.OnClickListener;\r
-\r
-/**\r
- * Represents an Item on the ActionBar.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class ActionItem {\r
- private Drawable mIcon;\r
- private String mTitle;\r
- private OnClickListener mClickListener;\r
-\r
- public ActionItem() {\r
- }\r
-\r
- public void setTitle(String title) {\r
- mTitle = title;\r
- }\r
-\r
- public String getTitle() {\r
- return mTitle;\r
- }\r
-\r
- public void setIcon(Drawable icon) {\r
- mIcon = icon;\r
- }\r
-\r
- public Drawable getIcon() {\r
- return mIcon;\r
- }\r
-\r
- public void setOnClickListener(OnClickListener listener) {\r
- mClickListener = listener;\r
- }\r
-\r
- public OnClickListener getOnClickListerner() {\r
- return mClickListener;\r
- }\r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui;\r
-\r
-import android.content.Context;\r
-import android.graphics.Rect;\r
-import android.graphics.drawable.BitmapDrawable;\r
-import android.graphics.drawable.Drawable;\r
-import android.view.Gravity;\r
-import android.view.LayoutInflater;\r
-import android.view.MotionEvent;\r
-import android.view.View;\r
-import android.view.WindowManager;\r
-import android.view.View.OnTouchListener;\r
-import android.view.ViewGroup.LayoutParams;\r
-import android.widget.PopupWindow;\r
-\r
-/**\r
- * Represents a custom PopupWindows\r
- * \r
- * @author Lorensius. W. T\r
- * \r
- */\r
-public class CustomPopup {\r
- protected final View mAnchor;\r
- protected final PopupWindow mWindow;\r
- private View root;\r
- private Drawable background = null;\r
- protected final WindowManager mWManager;\r
-\r
- public CustomPopup(View anchor) {\r
- mAnchor = anchor;\r
- mWindow = new PopupWindow(anchor.getContext());\r
-\r
- mWindow.setTouchInterceptor(new OnTouchListener() {\r
-\r
- public boolean onTouch(View v, MotionEvent event) {\r
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {\r
- CustomPopup.this.dismiss();\r
- return true;\r
- }\r
- return false;\r
- }\r
- });\r
-\r
- mWManager = (WindowManager) anchor.getContext().getSystemService(\r
- Context.WINDOW_SERVICE);\r
- onCreate();\r
- }\r
-\r
- public void onCreate() {\r
- }\r
-\r
- public void onShow() {\r
- }\r
-\r
- public void preShow() {\r
- if (root == null) {\r
- throw new IllegalStateException(\r
- "setContentView called with a view to display");\r
- }\r
-\r
- onShow();\r
-\r
- if (background == null) {\r
- mWindow.setBackgroundDrawable(new BitmapDrawable());\r
- } else {\r
- mWindow.setBackgroundDrawable(background);\r
- }\r
-\r
- mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);\r
- mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);\r
- mWindow.setTouchable(true);\r
- mWindow.setFocusable(true);\r
- mWindow.setOutsideTouchable(true);\r
-\r
- mWindow.setContentView(root);\r
- }\r
-\r
- public void setBackgroundDrawable(Drawable background) {\r
- this.background = background;\r
- }\r
-\r
- public void setContentView(View root) {\r
- this.root = root;\r
- mWindow.setContentView(root);\r
- }\r
-\r
- public void setContentView(int layoutResId) {\r
- LayoutInflater inflater = (LayoutInflater) mAnchor.getContext()\r
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
- setContentView(inflater.inflate(layoutResId, null));\r
- }\r
-\r
- public void showDropDown() {\r
- showDropDown(0, 0);\r
- }\r
-\r
- public void showDropDown(int x, int y) {\r
- preShow();\r
- mWindow.setAnimationStyle(android.R.style.Animation_Dialog);\r
- mWindow.showAsDropDown(mAnchor, x, y);\r
- }\r
-\r
- public void showLikeQuickAction() {\r
- showLikeQuickAction(0, 0);\r
- }\r
-\r
- public void showLikeQuickAction(int x, int y) {\r
- preShow();\r
-\r
- mWindow.setAnimationStyle(android.R.style.Animation_Dialog);\r
- int[] location = new int[2];\r
- mAnchor.getLocationOnScreen(location);\r
-\r
- Rect anchorRect = new Rect(location[0], location[1], location[0]\r
- + mAnchor.getWidth(), location[1] + mAnchor.getHeight());\r
-\r
- root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,\r
- LayoutParams.WRAP_CONTENT));\r
- root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\r
-\r
- int rootW = root.getWidth(), rootH = root.getHeight();\r
- int screenW = mWManager.getDefaultDisplay().getWidth();\r
-\r
- int xpos = ((screenW - rootW) / 2) + x;\r
- int ypos = anchorRect.top - rootH + y;\r
-\r
- if (rootH > anchorRect.top) {\r
- ypos = anchorRect.bottom + y;\r
- }\r
- mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos);\r
- }\r
-\r
- public void dismiss() {\r
- mWindow.dismiss();\r
- }\r
-\r
-}\r
+++ /dev/null
-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;
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui;\r
-\r
-import android.content.Context;\r
-\r
-import android.graphics.Rect;\r
-import android.graphics.drawable.Drawable;\r
-\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import android.widget.LinearLayout;\r
-import android.widget.ScrollView;\r
-\r
-import android.view.Gravity;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.ViewGroup.LayoutParams;\r
-import android.view.ViewGroup;\r
-\r
-import java.util.ArrayList;\r
-\r
-import eu.alefzero.owncloud.R;\r
-\r
-/**\r
- * Popup window, shows action list as icon and text like the one in Gallery3D\r
- * app.\r
- * \r
- * @author Lorensius. W. T\r
- */\r
-public class QuickAction extends CustomPopup {\r
- private final View root;\r
- private final ImageView mArrowUp;\r
- private final ImageView mArrowDown;\r
- private final LayoutInflater inflater;\r
- private final Context context;\r
-\r
- protected static final int ANIM_GROW_FROM_LEFT = 1;\r
- protected static final int ANIM_GROW_FROM_RIGHT = 2;\r
- protected static final int ANIM_GROW_FROM_CENTER = 3;\r
- protected static final int ANIM_REFLECT = 4;\r
- protected static final int ANIM_AUTO = 5;\r
-\r
- private int animStyle;\r
- private ViewGroup mTrack;\r
- private ScrollView scroller;\r
- private ArrayList<ActionItem> actionList;\r
-\r
- /**\r
- * Constructor\r
- * \r
- * @param anchor {@link View} on where the popup window should be displayed\r
- */\r
- public QuickAction(View anchor) {\r
- super(anchor);\r
-\r
- actionList = new ArrayList<ActionItem>();\r
- context = anchor.getContext();\r
- inflater = (LayoutInflater) context\r
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
-\r
- root = (ViewGroup) inflater.inflate(R.layout.popup, null);\r
-\r
- mArrowDown = (ImageView) root.findViewById(R.id.arrow_down);\r
- mArrowUp = (ImageView) root.findViewById(R.id.arrow_up);\r
-\r
- setContentView(root);\r
-\r
- mTrack = (ViewGroup) root.findViewById(R.id.tracks);\r
- scroller = (ScrollView) root.findViewById(R.id.scroller);\r
- animStyle = ANIM_AUTO;\r
- }\r
-\r
- /**\r
- * Set animation style\r
- * \r
- * @param animStyle animation style, default is set to ANIM_AUTO\r
- */\r
- public void setAnimStyle(int animStyle) {\r
- this.animStyle = animStyle;\r
- }\r
-\r
- /**\r
- * Add action item\r
- * \r
- * @param action {@link ActionItem} object\r
- */\r
- public void addActionItem(ActionItem action) {\r
- actionList.add(action);\r
- }\r
-\r
- /**\r
- * Show popup window. Popup is automatically positioned, on top or bottom of\r
- * anchor view.\r
- * \r
- */\r
- public void show() {\r
- preShow();\r
-\r
- int xPos, yPos;\r
-\r
- int[] location = new int[2];\r
-\r
- mAnchor.getLocationOnScreen(location);\r
-\r
- Rect anchorRect = new Rect(location[0], location[1], location[0]\r
- + mAnchor.getWidth(), location[1] + mAnchor.getHeight());\r
-\r
- createActionList();\r
-\r
- root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,\r
- LayoutParams.WRAP_CONTENT));\r
- root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\r
-\r
- int rootHeight = root.getMeasuredHeight();\r
- int rootWidth = root.getMeasuredWidth();\r
-\r
- int screenWidth = mWManager.getDefaultDisplay().getWidth();\r
- int screenHeight = mWManager.getDefaultDisplay().getHeight();\r
-\r
- // automatically get X coord of popup (top left)\r
- if ((anchorRect.left + rootWidth) > screenWidth) {\r
- xPos = anchorRect.left - (rootWidth - mAnchor.getWidth());\r
- } else {\r
- if (mAnchor.getWidth() > rootWidth) {\r
- xPos = anchorRect.centerX() - (rootWidth / 2);\r
- } else {\r
- xPos = anchorRect.left;\r
- }\r
- }\r
-\r
- int dyTop = anchorRect.top;\r
- int dyBottom = screenHeight - anchorRect.bottom;\r
-\r
- boolean onTop = (dyTop > dyBottom) ? true : false;\r
-\r
- if (onTop) {\r
- if (rootHeight > dyTop) {\r
- yPos = 15;\r
- LayoutParams l = scroller.getLayoutParams();\r
- l.height = dyTop - mAnchor.getHeight();\r
- } else {\r
- yPos = anchorRect.top - rootHeight;\r
- }\r
- } else {\r
- yPos = anchorRect.bottom;\r
-\r
- if (rootHeight > dyBottom) {\r
- LayoutParams l = scroller.getLayoutParams();\r
- l.height = dyBottom;\r
- }\r
- }\r
-\r
- showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up),\r
- anchorRect.centerX() - xPos);\r
-\r
- setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);\r
-\r
- mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos);\r
- }\r
-\r
- /**\r
- * Set animation style\r
- * \r
- * @param screenWidth screen width\r
- * @param requestedX distance from left edge\r
- * @param onTop flag to indicate where the popup should be displayed. Set\r
- * TRUE if displayed on top of anchor view and vice versa\r
- */\r
- private void setAnimationStyle(int screenWidth, int requestedX,\r
- boolean onTop) {\r
- int arrowPos = requestedX - mArrowUp.getMeasuredWidth() / 2;\r
-\r
- switch (animStyle) {\r
- case ANIM_GROW_FROM_LEFT:\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left\r
- : R.style.Animations_PopDownMenu_Left);\r
- break;\r
-\r
- case ANIM_GROW_FROM_RIGHT:\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right\r
- : R.style.Animations_PopDownMenu_Right);\r
- break;\r
-\r
- case ANIM_GROW_FROM_CENTER:\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center\r
- : R.style.Animations_PopDownMenu_Center);\r
- break;\r
-\r
- case ANIM_REFLECT:\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect\r
- : R.style.Animations_PopDownMenu_Reflect);\r
- break;\r
-\r
- case ANIM_AUTO:\r
- if (arrowPos <= screenWidth / 4) {\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left\r
- : R.style.Animations_PopDownMenu_Left);\r
- } else if (arrowPos > screenWidth / 4\r
- && arrowPos < 3 * (screenWidth / 4)) {\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center\r
- : R.style.Animations_PopDownMenu_Center);\r
- } else {\r
- mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right\r
- : R.style.Animations_PopDownMenu_Right);\r
- }\r
-\r
- break;\r
- }\r
- }\r
-\r
- /**\r
- * Create action list\r
- */\r
- private void createActionList() {\r
- View view;\r
- String title;\r
- Drawable icon;\r
- OnClickListener listener;\r
-\r
- for (int i = 0; i < actionList.size(); i++) {\r
- title = actionList.get(i).getTitle();\r
- icon = actionList.get(i).getIcon();\r
- listener = actionList.get(i).getOnClickListerner();\r
-\r
- view = getActionItem(title, icon, listener);\r
-\r
- view.setFocusable(true);\r
- view.setClickable(true);\r
-\r
- mTrack.addView(view);\r
- }\r
- }\r
-\r
- /**\r
- * Get action item {@link View}\r
- * \r
- * @param title action item title\r
- * @param icon {@link Drawable} action item icon\r
- * @param listener {@link View.OnClickListener} action item listener\r
- * @return action item {@link View}\r
- */\r
- private View getActionItem(String title, Drawable icon,\r
- OnClickListener listener) {\r
- LinearLayout container = (LinearLayout) inflater.inflate(\r
- R.layout.action_item, null);\r
-\r
- ImageView img = (ImageView) container.findViewById(R.id.icon);\r
- TextView text = (TextView) container.findViewById(R.id.title);\r
-\r
- if (icon != null) {\r
- img.setImageDrawable(icon);\r
- }\r
-\r
- if (title != null) {\r
- text.setText(title);\r
- }\r
-\r
- if (listener != null) {\r
- container.setOnClickListener(listener);\r
- }\r
-\r
- return container;\r
- }\r
-\r
- /**\r
- * Show arrow\r
- * \r
- * @param whichArrow arrow type resource id\r
- * @param requestedX distance from left screen\r
- */\r
- private void showArrow(int whichArrow, int requestedX) {\r
- final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp\r
- : mArrowDown;\r
- final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown\r
- : mArrowUp;\r
-\r
- final int arrowWidth = mArrowUp.getMeasuredWidth();\r
-\r
- showArrow.setVisibility(View.VISIBLE);\r
-\r
- ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow\r
- .getLayoutParams();\r
-\r
- param.leftMargin = requestedX - arrowWidth / 2;\r
-\r
- hideArrow.setVisibility(View.INVISIBLE);\r
- }\r
-}
\ No newline at end of file
+++ /dev/null
-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<Boolean> {
-
- 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<String, String> map = (HashMap<String, String>) 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<HashMap<String, String>> ll = new LinkedList<HashMap<String, String>>();
- for (Account a : accounts) {
- HashMap<String, String> h = new HashMap<String, String>();
- 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<Boolean> 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<? extends Map<String, ?>> mPrivateData;
-
- public AccountCheckedSimpleAdepter(Context context,
- List<? extends Map<String, ?>> 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;
- }
-
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2012 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud.ui.activity;\r
-\r
-import java.net.MalformedURLException;\r
-import java.net.URL;\r
-import java.net.URLEncoder;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountAuthenticatorActivity;\r
-import android.accounts.AccountManager;\r
-import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.ContentResolver;\r
-import android.content.DialogInterface;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.preference.PreferenceManager;\r
-import android.text.InputType;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.View.OnFocusChangeListener;\r
-import android.view.Window;\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.authenticator.AuthenticationRunnable;\r
-import eu.alefzero.owncloud.authenticator.ConnectionCheckerRunnable;\r
-import eu.alefzero.owncloud.authenticator.OnAuthenticationResultListener;\r
-import eu.alefzero.owncloud.authenticator.OnConnectCheckListener;\r
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;\r
-import eu.alefzero.owncloud.extensions.ExtensionsAvailableActivity;\r
-import eu.alefzero.owncloud.utils.OwnCloudVersion;\r
-\r
-/**\r
- * This Activity is used to add an ownCloud account to the App\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
- implements OnAuthenticationResultListener, OnConnectCheckListener,\r
- OnFocusChangeListener, OnClickListener {\r
- private static final int DIALOG_LOGIN_PROGRESS = 0;\r
-\r
- private static final String TAG = "AuthActivity";\r
-\r
- private Thread mAuthThread;\r
- private AuthenticationRunnable mAuthRunnable;\r
- private ConnectionCheckerRunnable mConnChkRunnable;\r
- private final Handler mHandler = new Handler();\r
- private String mBaseUrl;\r
-\r
- private static final String STATUS_TEXT = "STATUS_TEXT";\r
- private static final String STATUS_ICON = "STATUS_ICON";\r
- private static final String STATUS_CORRECT = "STATUS_CORRECT";\r
- private static final String IS_SSL_CONN = "IS_SSL_CONN";\r
- private int mStatusText, mStatusIcon;\r
- private boolean mStatusCorrect, mIsSslConn;\r
-\r
- public static final String PARAM_USERNAME = "param_Username";\r
- public static final String PARAM_HOSTNAME = "param_Hostname";\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
- setContentView(R.layout.account_setup);\r
- ImageView iv = (ImageView) findViewById(R.id.refreshButton);\r
- ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);\r
- TextView tv = (TextView) findViewById(R.id.host_URL);\r
- TextView tv2 = (TextView) findViewById(R.id.account_password);\r
-\r
- if (savedInstanceState != null) {\r
- mStatusIcon = savedInstanceState.getInt(STATUS_ICON);\r
- mStatusText = savedInstanceState.getInt(STATUS_TEXT);\r
- mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);\r
- mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);\r
- setResultIconAndText(mStatusIcon, mStatusText);\r
- findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
- if (!mStatusCorrect)\r
- iv.setVisibility(View.VISIBLE);\r
- else\r
- iv.setVisibility(View.INVISIBLE);\r
-\r
- } else {\r
- mStatusText = mStatusIcon = 0;\r
- mStatusCorrect = false;\r
- mIsSslConn = false;\r
- }\r
- iv.setOnClickListener(this);\r
- iv2.setOnClickListener(this);\r
- tv.setOnFocusChangeListener(this);\r
- tv2.setOnFocusChangeListener(this);\r
- }\r
-\r
- @Override\r
- protected void onSaveInstanceState(Bundle outState) {\r
- outState.putInt(STATUS_ICON, mStatusIcon);\r
- outState.putInt(STATUS_TEXT, mStatusText);\r
- outState.putBoolean(STATUS_CORRECT, mStatusCorrect);\r
- super.onSaveInstanceState(outState);\r
- }\r
-\r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog = null;\r
- switch (id) {\r
- case DIALOG_LOGIN_PROGRESS: {\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(getResources().getString(\r
- R.string.auth_trying_to_login));\r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(true);\r
- working_dialog\r
- .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
- @Override\r
- public void onCancel(DialogInterface dialog) {\r
- Log.i(TAG, "Login canceled");\r
- if (mAuthThread != null) {\r
- mAuthThread.interrupt();\r
- finish();\r
- }\r
- }\r
- });\r
- dialog = working_dialog;\r
- break;\r
- }\r
- default:\r
- Log.e(TAG, "Incorrect dialog called with id = " + id);\r
- }\r
- return dialog;\r
- }\r
-\r
- public void onAuthenticationResult(boolean success, String message) {\r
- if (success) {\r
- TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);\r
-\r
- URL url;\r
- try {\r
- url = new URL(message);\r
- } catch (MalformedURLException e) {\r
- // should never happen\r
- Log.e(getClass().getName(), "Malformed URL: " + message);\r
- return;\r
- }\r
-\r
- String username = username_text.getText().toString().trim();\r
- String accountName = username + "@" + url.getHost();\r
- if (url.getPort() >= 0) {\r
- accountName += ":" + url.getPort();\r
- }\r
- Account account = new Account(accountName,\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- AccountManager accManager = AccountManager.get(this);\r
- accManager.addAccountExplicitly(account, password_text.getText()\r
- .toString(), null);\r
-\r
- // Add this account as default in the preferences, if there is none\r
- // already\r
- Account defaultAccount = AccountUtils\r
- .getCurrentOwnCloudAccount(this);\r
- if (defaultAccount == null) {\r
- SharedPreferences.Editor editor = PreferenceManager\r
- .getDefaultSharedPreferences(this).edit();\r
- editor.putString("select_oc_account", accountName);\r
- editor.commit();\r
- }\r
-\r
- final Intent intent = new Intent();\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
- intent.putExtra(AccountManager.KEY_AUTHTOKEN,\r
- AccountAuthenticator.ACCOUNT_TYPE);\r
- intent.putExtra(AccountManager.KEY_USERDATA, username);\r
-\r
- accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL,\r
- url.toString());\r
- accManager.setUserData(account,\r
- AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable\r
- .getDiscoveredVersion().toString());\r
- accManager.setUserData(account,\r
- AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);\r
-\r
- setAccountAuthenticatorResult(intent.getExtras());\r
- setResult(RESULT_OK, intent);\r
- Bundle bundle = new Bundle();\r
- bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
- //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,\r
- // bundle);\r
- ContentResolver.requestSync(account, "org.owncloud", bundle);\r
-\r
- /*\r
- * if\r
- * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion\r
- * .owncloud_v2) >= 0) { Intent i = new Intent(this,\r
- * ExtensionsAvailableActivity.class); startActivity(i); }\r
- */\r
-\r
- finish();\r
- } else {\r
- dismissDialog(DIALOG_LOGIN_PROGRESS);\r
- TextView tv = (TextView) findViewById(R.id.account_username);\r
- tv.setError(message);\r
- }\r
- }\r
- public void onCancelClick(View view) {\r
- finish();\r
- }\r
- \r
- public void onOkClick(View view) {\r
- String prefix = "";\r
- String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString();\r
- if (mIsSslConn) {\r
- prefix = "https://";\r
- } else {\r
- prefix = "http://";\r
- }\r
- if (url.toLowerCase().startsWith("http://")\r
- || url.toLowerCase().startsWith("https://")) {\r
- prefix = "";\r
- }\r
- continueConnection(prefix);\r
- }\r
-\r
- private void continueConnection(String prefix) {\r
- String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString();\r
- String username = ((TextView) findViewById(R.id.account_username))\r
- .getText().toString();\r
- String password = ((TextView) findViewById(R.id.account_password))\r
- .getText().toString();\r
- if (url.endsWith("/"))\r
- url = url.substring(0, url.length() - 1);\r
-\r
- URL uri = null;\r
- String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable\r
- .getDiscoveredVersion());\r
-\r
- try {\r
- mBaseUrl = prefix + url;\r
- String url_str = prefix + url + webdav_path;\r
- uri = new URL(url_str);\r
- } catch (MalformedURLException e) {\r
- // should not happend\r
- e.printStackTrace();\r
- }\r
-\r
- showDialog(DIALOG_LOGIN_PROGRESS);\r
- mAuthRunnable = new AuthenticationRunnable(uri, username, password);\r
- mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);\r
- mAuthThread = new Thread(mAuthRunnable);\r
- mAuthThread.start();\r
- }\r
-\r
- @Override\r
- public void onConnectionCheckResult(ResultType type) {\r
- mStatusText = mStatusIcon = 0;\r
- mStatusCorrect = false;\r
- String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
- .toString().toLowerCase();\r
-\r
- switch (type) {\r
- case OK_SSL:\r
- mIsSslConn = true;\r
- mStatusIcon = android.R.drawable.ic_secure;\r
- mStatusText = R.string.auth_secure_connection;\r
- mStatusCorrect = true;\r
- break;\r
- case OK_NO_SSL:\r
- mIsSslConn = false;\r
- mStatusCorrect = true;\r
- if (t_url.startsWith("http://") ) {\r
- mStatusText = R.string.auth_connection_established;\r
- mStatusIcon = R.drawable.ic_ok;\r
- } else {\r
- mStatusText = R.string.auth_nossl_plain_ok_title;\r
- mStatusIcon = android.R.drawable.ic_partial_secure;\r
- }\r
- break;\r
- case TIMEOUT:\r
- case INORRECT_ADDRESS:\r
- case SSL_INIT_ERROR:\r
- case HOST_NOT_AVAILABLE:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_unknow_host_title;\r
- break;\r
- case NO_NETWORK_CONNECTION:\r
- mStatusIcon = R.drawable.no_network;\r
- mStatusText = R.string.auth_no_net_conn_title;\r
- break;\r
- case INSTANCE_NOT_CONFIGURED:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_not_configured_title;\r
- break;\r
- case UNKNOWN_ERROR:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_unknow_error;\r
- break;\r
- case FILE_NOT_FOUND:\r
- mStatusIcon = R.drawable.common_error;\r
- mStatusText = R.string.auth_incorrect_path_title;\r
- break;\r
- default:\r
- Log.e(TAG, "Incorrect connection checker result type: " + type);\r
- }\r
- setResultIconAndText(mStatusIcon, mStatusText);\r
- if (!mStatusCorrect)\r
- findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
- else\r
- findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
- findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
- }\r
-\r
- @Override\r
- public void onFocusChange(View view, boolean hasFocus) {\r
- if (view.getId() == R.id.host_URL) {\r
- if (!hasFocus) {\r
- TextView tv = ((TextView) findViewById(R.id.host_URL));\r
- String uri = tv.getText().toString();\r
- if (uri.length() != 0) {\r
- setResultIconAndText(R.drawable.progress_small,\r
- R.string.auth_testing_connection);\r
- findViewById(R.id.buttonOK).setEnabled(false); // avoid connect can be clicked if the test was previously passed\r
- mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);\r
- mConnChkRunnable.setListener(this, mHandler);\r
- mAuthThread = new Thread(mConnChkRunnable);\r
- mAuthThread.start();\r
- } else {\r
- findViewById(R.id.refreshButton).setVisibility(\r
- View.INVISIBLE);\r
- setResultIconAndText(0, 0);\r
- }\r
- }\r
- } else if (view.getId() == R.id.account_password) {\r
- ImageView iv = (ImageView) findViewById(R.id.viewPassword);\r
- if (hasFocus) {\r
- iv.setVisibility(View.VISIBLE);\r
- } else {\r
- TextView v = (TextView) findViewById(R.id.account_password);\r
- int input_type = InputType.TYPE_CLASS_TEXT\r
- | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
- v.setInputType(input_type);\r
- iv.setVisibility(View.INVISIBLE);\r
- }\r
- }\r
- }\r
-\r
- private void setResultIconAndText(int drawable_id, int text_id) {\r
- ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
- TextView tv = (TextView) findViewById(R.id.status_text);\r
-\r
- if (drawable_id == 0 && text_id == 0) {\r
- iv.setVisibility(View.INVISIBLE);\r
- tv.setVisibility(View.INVISIBLE);\r
- } else {\r
- iv.setImageResource(drawable_id);\r
- tv.setText(text_id);\r
- iv.setVisibility(View.VISIBLE);\r
- tv.setVisibility(View.VISIBLE);\r
- }\r
- }\r
-\r
- @Override\r
- public void onClick(View v) {\r
- if (v.getId() == R.id.refreshButton) {\r
- onFocusChange(findViewById(R.id.host_URL), false);\r
- } else if (v.getId() == R.id.viewPassword) {\r
- TextView view = (TextView) findViewById(R.id.account_password);\r
- int input_type = InputType.TYPE_CLASS_TEXT\r
- | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
- view.setInputType(input_type);\r
- }\r
- }\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.activity;\r
-\r
-import android.accounts.Account;\r
-import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.Intent;\r
-import android.content.res.Configuration;\r
-import android.os.Bundle;\r
-import android.support.v4.app.FragmentTransaction;\r
-\r
-import com.actionbarsherlock.app.ActionBar;\r
-import com.actionbarsherlock.app.SherlockFragmentActivity;\r
-import com.actionbarsherlock.view.MenuItem;\r
-\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.files.services.FileDownloader;\r
-import eu.alefzero.owncloud.ui.fragment.FileDetailFragment;\r
-\r
-/**\r
- * This activity displays the details of a file like its name, its size and so\r
- * on.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity {\r
- \r
- public static final int DIALOG_SHORT_WAIT = 0;\r
- \r
- private boolean mConfigurationChangedToLandscape = false;\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
-\r
- // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity \r
- Configuration conf = getResources().getConfiguration();\r
- mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && \r
- (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE\r
- );\r
-\r
- if (!mConfigurationChangedToLandscape) {\r
- setContentView(R.layout.file_activity_details);\r
- \r
- ActionBar actionBar = getSupportActionBar();\r
- actionBar.setDisplayHomeAsUpEnabled(true);\r
- \r
- OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
- Account account = getIntent().getParcelableExtra(FileDownloader.EXTRA_ACCOUNT);\r
- FileDetailFragment mFileDetail = new FileDetailFragment(file, account);\r
- \r
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
- ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG);\r
- ft.commit();\r
- \r
- } else {\r
- backToDisplayActivity(); // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
- }\r
- \r
- \r
- }\r
-\r
- @Override\r
- public boolean onOptionsItemSelected(MenuItem item) {\r
- boolean returnValue = false;\r
- \r
- switch(item.getItemId()){\r
- case android.R.id.home:\r
- backToDisplayActivity();\r
- returnValue = true;\r
- }\r
- \r
- return returnValue;\r
- }\r
-\r
-\r
-\r
- @Override\r
- protected void onResume() {\r
- \r
- super.onResume();\r
- if (!mConfigurationChangedToLandscape) { \r
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
- fragment.updateFileDetails();\r
- }\r
- }\r
- \r
-\r
- private void backToDisplayActivity() {\r
- Intent intent = new Intent(this, FileDisplayActivity.class);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
- intent.putExtra(FileDetailFragment.EXTRA_FILE, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE));\r
- startActivity(intent);\r
- finish();\r
- }\r
- \r
- \r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog = null;\r
- switch (id) {\r
- case DIALOG_SHORT_WAIT: {\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(getResources().getString(\r
- R.string.wait_a_moment));\r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(false);\r
- dialog = working_dialog;\r
- break;\r
- }\r
- default:\r
- dialog = null;\r
- }\r
- return dialog;\r
- }\r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onFileStateChanged() {\r
- // nothing to do here!\r
- }\r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package eu.alefzero.owncloud.ui.activity;\r
-\r
-import java.io.File;\r
-import java.util.ArrayList;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.ProgressDialog;\r
-import android.app.AlertDialog.Builder;\r
-import android.app.Dialog;\r
-import android.content.BroadcastReceiver;\r
-import android.content.ContentResolver;\r
-import android.content.Context;\r
-import android.content.DialogInterface;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.content.Intent;\r
-import android.content.IntentFilter;\r
-import android.content.SharedPreferences;\r
-import android.content.pm.PackageInfo;\r
-import android.content.pm.PackageManager.NameNotFoundException;\r
-import android.content.res.Resources.NotFoundException;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.preference.PreferenceManager;\r
-import android.provider.MediaStore;\r
-import android.support.v4.app.FragmentTransaction;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.ArrayAdapter;\r
-import android.widget.EditText;\r
-import android.widget.TextView;\r
-import android.widget.Toast;\r
-\r
-import com.actionbarsherlock.app.ActionBar;\r
-import com.actionbarsherlock.app.ActionBar.OnNavigationListener;\r
-import com.actionbarsherlock.app.SherlockFragmentActivity;\r
-import com.actionbarsherlock.view.Menu;\r
-import com.actionbarsherlock.view.MenuInflater;\r
-import com.actionbarsherlock.view.MenuItem;\r
-import com.actionbarsherlock.view.Window;\r
-\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.CrashHandler;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.datamodel.DataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.FileDataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.files.services.FileDownloader;\r
-import eu.alefzero.owncloud.files.services.FileUploader;\r
-import eu.alefzero.owncloud.syncadapter.FileSyncService;\r
-import eu.alefzero.owncloud.ui.fragment.FileDetailFragment;\r
-import eu.alefzero.owncloud.ui.fragment.FileListFragment;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * Displays, what files the user has available in his ownCloud.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-\r
-public class FileDisplayActivity extends SherlockFragmentActivity implements\r
- FileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnClickListener, android.view.View.OnClickListener {\r
- \r
- private ArrayAdapter<String> mDirectories;\r
- private OCFile mCurrentDir;\r
- private String[] mDirs = null;\r
-\r
- private DataStorageManager mStorageManager;\r
- private SyncBroadcastReceiver mSyncBroadcastReceiver;\r
- private UploadFinishReceiver mUploadFinishReceiver;\r
- private DownloadFinishReceiver mDownloadFinishReceiver;\r
- \r
- private View mLayoutView = null;\r
- private FileListFragment mFileList;\r
- \r
- private boolean mDualPane;\r
- \r
- private boolean mForcedLoginToCreateFirstAccount = false;\r
- \r
- private static final String KEY_DIR_ARRAY = "DIR_ARRAY";\r
- private static final String KEY_CURRENT_DIR = "DIR";\r
- \r
- private static final int DIALOG_SETUP_ACCOUNT = 0;\r
- private static final int DIALOG_CREATE_DIR = 1;\r
- private static final int DIALOG_ABOUT_APP = 2;\r
- public static final int DIALOG_SHORT_WAIT = 3;\r
- \r
- private static final int ACTION_SELECT_FILE = 1;\r
- \r
- private static final String TAG = "FileDisplayActivity";\r
- \r
- \r
- @Override\r
- public void onCreate(Bundle savedInstanceState) {\r
- Log.i(getClass().toString(), "onCreate() start");\r
- super.onCreate(savedInstanceState);\r
-\r
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);\r
-\r
- Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(getApplicationContext()));\r
-\r
- if(savedInstanceState != null) {\r
- mDirs = savedInstanceState.getStringArray(KEY_DIR_ARRAY);\r
- mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);\r
- mDirectories.add(OCFile.PATH_SEPARATOR);\r
- if (mDirs != null)\r
- for (String s : mDirs)\r
- mDirectories.insert(s, 0);\r
- mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
- }\r
- \r
- mLayoutView = getLayoutInflater().inflate(R.layout.files, null); // always inflate this at onCreate() ; just once!\r
- \r
- if (AccountUtils.accountsAreSetup(this)) {\r
- \r
- initDelayedTilAccountAvailabe();\r
- \r
- // PIN CODE request ; best location is to decide, let's try this first\r
- //if (savedInstanceState == null) {\r
- if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {\r
- requestPinCode();\r
- }\r
- \r
- \r
- } else {\r
- \r
- setContentView(R.layout.no_account_available);\r
- getSupportActionBar().setNavigationMode(ActionBar.DISPLAY_SHOW_TITLE);\r
- findViewById(R.id.setup_account).setOnClickListener(this);\r
-\r
- setSupportProgressBarIndeterminateVisibility(false);\r
-\r
- Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
- intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
- startActivity(intent); // although the code is here, the activity won't be created until this.onStart() and this.onResume() are finished;\r
- mForcedLoginToCreateFirstAccount = true;\r
- }\r
- \r
- Log.i(getClass().toString(), "onCreate() end");\r
- }\r
-\r
- @Override\r
- public boolean onCreateOptionsMenu(Menu menu) {\r
- MenuInflater inflater = getSherlock().getMenuInflater();\r
- inflater.inflate(R.menu.menu, menu);\r
- return true;\r
- }\r
-\r
- @Override\r
- public boolean onOptionsItemSelected(MenuItem item) {\r
- boolean retval = true;\r
- switch (item.getItemId()) {\r
- case R.id.createDirectoryItem: {\r
- showDialog(DIALOG_CREATE_DIR);\r
- break;\r
- }\r
- case R.id.startSync: {\r
- ContentResolver.cancelSync(null, "org.owncloud"); // cancel the current synchronizations of any ownCloud account\r
- Bundle bundle = new Bundle();\r
- bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
- ContentResolver.requestSync(\r
- AccountUtils.getCurrentOwnCloudAccount(this),\r
- "org.owncloud", bundle);\r
- break;\r
- }\r
- case R.id.action_upload: {\r
- Intent action = new Intent(Intent.ACTION_GET_CONTENT);\r
- action = action.setType("*/*")\r
- .addCategory(Intent.CATEGORY_OPENABLE);\r
- startActivityForResult(\r
- Intent.createChooser(action, getString(R.string.upload_chooser_title)),\r
- ACTION_SELECT_FILE);\r
- break;\r
- }\r
- case R.id.action_settings: {\r
- Intent settingsIntent = new Intent(this, Preferences.class);\r
- startActivity(settingsIntent);\r
- break;\r
- }\r
- case R.id.about_app : {\r
- showDialog(DIALOG_ABOUT_APP);\r
- break;\r
- }\r
- case android.R.id.home: {\r
- if(mCurrentDir != null && mCurrentDir.getParentId() != 0){\r
- onBackPressed(); \r
- }\r
- break;\r
- }\r
- default:\r
- retval = false;\r
- }\r
- return retval;\r
- }\r
-\r
- @Override\r
- public boolean onNavigationItemSelected(int itemPosition, long itemId) {\r
- int i = itemPosition;\r
- while (i-- != 0) {\r
- onBackPressed();\r
- }\r
- return true;\r
- }\r
-\r
- /**\r
- * Called, when the user selected something for uploading\r
- */\r
- public void onActivityResult(int requestCode, int resultCode, Intent data) {\r
- if (requestCode == ACTION_SELECT_FILE) {\r
- if (resultCode == RESULT_OK) {\r
- String filepath = null;\r
- try {\r
- Uri selectedImageUri = data.getData();\r
- \r
- String filemanagerstring = selectedImageUri.getPath();\r
- String selectedImagePath = getPath(selectedImageUri);\r
- \r
- if (selectedImagePath != null)\r
- filepath = selectedImagePath;\r
- else\r
- filepath = filemanagerstring;\r
- \r
- } catch (Exception e) {\r
- Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);\r
- e.printStackTrace();\r
- \r
- } finally {\r
- if (filepath == null) {\r
- Log.e("FileDisplay", "Couldnt resolve path to file");\r
- Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);\r
- t.show();\r
- return;\r
- }\r
- }\r
- \r
- Intent i = new Intent(this, FileUploader.class);\r
- i.putExtra(FileUploader.KEY_ACCOUNT,\r
- AccountUtils.getCurrentOwnCloudAccount(this));\r
- String remotepath = new String();\r
- for (int j = mDirectories.getCount() - 2; j >= 0; --j) {\r
- remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);\r
- }\r
- if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))\r
- remotepath += OCFile.PATH_SEPARATOR;\r
- remotepath += new File(filepath).getName();\r
- \r
- i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);\r
- i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);\r
- i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);\r
- startService(i);\r
- }\r
- \r
- }/* dvelasco: WIP - not working as expected ... yet :)\r
- else if (requestCode == ACTION_CREATE_FIRST_ACCOUNT) {\r
- if (resultCode != RESULT_OK) {\r
- finish(); // the user cancelled the AuthenticatorActivity\r
- }\r
- }*/\r
- }\r
-\r
- @Override\r
- public void onBackPressed() {\r
- if (mDirectories == null || mDirectories.getCount() <= 1) {\r
- finish();\r
- return;\r
- }\r
- popDirname();\r
- mFileList.onNavigateUp();\r
- mCurrentDir = mFileList.getCurrentFile();\r
- \r
- if(mCurrentDir.getParentId() == 0){\r
- ActionBar actionBar = getSupportActionBar(); \r
- actionBar.setDisplayHomeAsUpEnabled(false);\r
- } \r
- }\r
-\r
- @Override\r
- protected void onSaveInstanceState(Bundle outState) {\r
- // responsability of restore is prefered in onCreate() before than in onRestoreInstanceState when there are Fragments involved\r
- Log.i(getClass().toString(), "onSaveInstanceState() start");\r
- super.onSaveInstanceState(outState);\r
- if(mDirectories != null && mDirectories.getCount() != 0){\r
- mDirs = new String[mDirectories.getCount()-1];\r
- for (int j = mDirectories.getCount() - 2, i = 0; j >= 0; --j, ++i) {\r
- mDirs[i] = mDirectories.getItem(j);\r
- }\r
- }\r
- outState.putStringArray(KEY_DIR_ARRAY, mDirs);\r
- outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);\r
- Log.i(getClass().toString(), "onSaveInstanceState() end");\r
- }\r
-\r
- @Override\r
- protected void onResume() {\r
- Log.i(getClass().toString(), "onResume() start");\r
- super.onResume();\r
-\r
- if (AccountUtils.accountsAreSetup(this)) {\r
- // at least an account exist: normal operation\r
- \r
- // set the layout only if it couldn't be set in onCreate\r
- if (mForcedLoginToCreateFirstAccount) {\r
- initDelayedTilAccountAvailabe();\r
- mForcedLoginToCreateFirstAccount = false;\r
- }\r
-\r
- // Listen for sync messages\r
- IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE);\r
- mSyncBroadcastReceiver = new SyncBroadcastReceiver();\r
- registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);\r
- \r
- // Listen for upload messages\r
- IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
- mUploadFinishReceiver = new UploadFinishReceiver();\r
- registerReceiver(mUploadFinishReceiver, uploadIntentFilter);\r
- \r
- // Listen for download messages\r
- IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
- mDownloadFinishReceiver = new DownloadFinishReceiver();\r
- registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);\r
- \r
- // Storage manager initialization\r
- mStorageManager = new FileDataStorageManager(\r
- AccountUtils.getCurrentOwnCloudAccount(this),\r
- getContentResolver());\r
- \r
- // File list fragments \r
- mFileList = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
- \r
- \r
- // Figure out what directory to list. \r
- // Priority: Intent (here), savedInstanceState (onCreate), root dir (dir is null)\r
- if(getIntent().hasExtra(FileDetailFragment.EXTRA_FILE)){\r
- mCurrentDir = (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
- if(mCurrentDir != null && !mCurrentDir.isDirectory()){\r
- mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId());\r
- }\r
- \r
- // Clear intent extra, so rotating the screen will not return us to this directory\r
- getIntent().removeExtra(FileDetailFragment.EXTRA_FILE);\r
- }\r
- \r
- if (mCurrentDir == null)\r
- mCurrentDir = mStorageManager.getFileByPath("/");\r
- \r
- // Drop-Down navigation and file list restore\r
- mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);\r
- \r
- \r
- // Given the case we have a file to display:\r
- if(mCurrentDir != null){\r
- ArrayList<OCFile> files = new ArrayList<OCFile>();\r
- OCFile currFile = mCurrentDir;\r
- while(currFile != null){\r
- files.add(currFile);\r
- currFile = mStorageManager.getFileById(currFile.getParentId());\r
- }\r
- \r
- // Insert in mDirs\r
- mDirs = new String[files.size()];\r
- for(int i = files.size() - 1; i >= 0; i--){\r
- mDirs[i] = files.get(i).getFileName();\r
- }\r
- }\r
- \r
- if (mDirs != null) {\r
- for (String s : mDirs)\r
- mDirectories.add(s);\r
- } else {\r
- mDirectories.add(OCFile.PATH_SEPARATOR);\r
- }\r
- \r
- // Actionbar setup\r
- ActionBar action_bar = getSupportActionBar();\r
- action_bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);\r
- action_bar.setDisplayShowTitleEnabled(false);\r
- action_bar.setListNavigationCallbacks(mDirectories, this);\r
- if(mCurrentDir != null && mCurrentDir.getParentId() != 0){\r
- action_bar.setDisplayHomeAsUpEnabled(true);\r
- } else {\r
- action_bar.setDisplayHomeAsUpEnabled(false);\r
- }\r
- \r
- // List dir here\r
- mFileList.listDirectory(mCurrentDir);\r
- }\r
- Log.i(getClass().toString(), "onResume() end");\r
- }\r
-\r
- @Override\r
- protected void onPause() {\r
- Log.i(getClass().toString(), "onPause() start");\r
- super.onPause();\r
- if (mSyncBroadcastReceiver != null) {\r
- unregisterReceiver(mSyncBroadcastReceiver);\r
- mSyncBroadcastReceiver = null;\r
- }\r
- if (mUploadFinishReceiver != null) {\r
- unregisterReceiver(mUploadFinishReceiver);\r
- mUploadFinishReceiver = null;\r
- }\r
- if (mDownloadFinishReceiver != null) {\r
- unregisterReceiver(mDownloadFinishReceiver);\r
- mDownloadFinishReceiver = null;\r
- }\r
- \r
- getIntent().putExtra(FileDetailFragment.EXTRA_FILE, mCurrentDir);\r
- Log.i(getClass().toString(), "onPause() end");\r
- }\r
-\r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog = null;\r
- AlertDialog.Builder builder;\r
- switch (id) {\r
- case DIALOG_SETUP_ACCOUNT:\r
- builder = new AlertDialog.Builder(this);\r
- builder.setTitle(R.string.main_tit_accsetup);\r
- builder.setMessage(R.string.main_wrn_accsetup);\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(android.R.string.ok, this);\r
- builder.setNegativeButton(android.R.string.cancel, this);\r
- dialog = builder.create();\r
- break;\r
- case DIALOG_ABOUT_APP: {\r
- builder = new AlertDialog.Builder(this);\r
- builder.setTitle(getString(R.string.about_title));\r
- PackageInfo pkg;\r
- try {\r
- pkg = getPackageManager().getPackageInfo(getPackageName(), 0);\r
- builder.setMessage("ownCloud android client\n\nversion: " + pkg.versionName );\r
- builder.setIcon(android.R.drawable.ic_menu_info_details);\r
- dialog = builder.create();\r
- } catch (NameNotFoundException e) {\r
- builder = null;\r
- dialog = null;\r
- Log.e(TAG, "Error while showing about dialog", e);\r
- }\r
- break;\r
- }\r
- case DIALOG_CREATE_DIR: {\r
- builder = new Builder(this);\r
- final EditText dirNameInput = new EditText(getBaseContext());\r
- final Account a = AccountUtils.getCurrentOwnCloudAccount(this);\r
- builder.setView(dirNameInput);\r
- builder.setTitle(R.string.uploader_info_dirname);\r
- int typed_color = getResources().getColor(R.color.setup_text_typed);\r
- dirNameInput.setTextColor(typed_color);\r
- builder.setPositiveButton(android.R.string.ok,\r
- new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- String directoryName = dirNameInput.getText().toString();\r
- if (directoryName.trim().length() == 0) {\r
- dialog.cancel();\r
- return;\r
- }\r
- \r
- // Figure out the path where the dir needs to be created\r
- String path;\r
- if (mCurrentDir == null) {\r
- // this is just a patch; we should ensure that mCurrentDir never is null\r
- if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {\r
- OCFile file = new OCFile(OCFile.PATH_SEPARATOR);\r
- mStorageManager.saveFile(file);\r
- }\r
- mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);\r
- }\r
- path = FileDisplayActivity.this.mCurrentDir.getRemotePath();\r
- \r
- // Create directory\r
- path += directoryName + OCFile.PATH_SEPARATOR;\r
- Thread thread = new Thread(new DirectoryCreator(path, a, new Handler()));\r
- thread.start();\r
- \r
- dialog.dismiss();\r
- \r
- showDialog(DIALOG_SHORT_WAIT);\r
- }\r
- });\r
- builder.setNegativeButton(R.string.common_cancel,\r
- new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- dialog.cancel();\r
- }\r
- });\r
- dialog = builder.create();\r
- break;\r
- }\r
- case DIALOG_SHORT_WAIT: {\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(getResources().getString(\r
- R.string.wait_a_moment));\r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(false);\r
- dialog = working_dialog;\r
- break;\r
- }\r
- default:\r
- dialog = null;\r
- }\r
- \r
- return dialog;\r
- }\r
-\r
- \r
- /**\r
- * Responds to the "There are no ownCloud Accounts setup" dialog\r
- * TODO: Dialog is 100% useless -> Remove\r
- */\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- // In any case - we won't need it anymore\r
- dialog.dismiss();\r
- switch (which) {\r
- case DialogInterface.BUTTON_POSITIVE:\r
- Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
- intent.putExtra("authorities",\r
- new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
- startActivity(intent);\r
- break;\r
- case DialogInterface.BUTTON_NEGATIVE:\r
- finish();\r
- }\r
- \r
- }\r
-\r
- /**\r
- * Translates a content URI of an image to a physical path\r
- * on the disk\r
- * @param uri The URI to resolve\r
- * @return The path to the image or null if it could not be found\r
- */\r
- public String getPath(Uri uri) {\r
- String[] projection = { MediaStore.Images.Media.DATA };\r
- Cursor cursor = managedQuery(uri, projection, null, null, null);\r
- if (cursor != null) {\r
- int column_index = cursor\r
- .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);\r
- cursor.moveToFirst();\r
- return cursor.getString(column_index);\r
- } \r
- return null;\r
- }\r
- \r
- /**\r
- * Pushes a directory to the drop down list\r
- * @param directory to push\r
- * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false.\r
- */\r
- public void pushDirname(OCFile directory) {\r
- if(!directory.isDirectory()){\r
- throw new IllegalArgumentException("Only directories may be pushed!");\r
- }\r
- mDirectories.insert(directory.getFileName(), 0);\r
- mCurrentDir = directory;\r
- }\r
-\r
- /**\r
- * Pops a directory name from the drop down list\r
- * @return True, unless the stack is empty\r
- */\r
- public boolean popDirname() {\r
- mDirectories.remove(mDirectories.getItem(0));\r
- return !mDirectories.isEmpty();\r
- }\r
-\r
- private class DirectoryCreator implements Runnable {\r
- private String mTargetPath;\r
- private Account mAccount;\r
- private AccountManager mAm;\r
- private Handler mHandler; \r
- \r
- public DirectoryCreator(String targetPath, Account account, Handler handler) {\r
- mTargetPath = targetPath;\r
- mAccount = account;\r
- mAm = (AccountManager) getSystemService(ACCOUNT_SERVICE);\r
- mHandler = handler;\r
- }\r
- \r
- @Override\r
- public void run() {\r
- WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext());\r
- \r
- String username = mAccount.name.substring(0,\r
- mAccount.name.lastIndexOf('@'));\r
- String password = mAm.getPassword(mAccount);\r
- \r
- wdc.setCredentials(username, password);\r
- wdc.allowSelfsignedCertificates();\r
- boolean created = wdc.createDirectory(mTargetPath);\r
- if (created) {\r
- mHandler.post(new Runnable() {\r
- @Override\r
- public void run() { \r
- dismissDialog(DIALOG_SHORT_WAIT);\r
- \r
- // Save new directory in local database\r
- OCFile newDir = new OCFile(mTargetPath);\r
- newDir.setMimetype("DIR");\r
- newDir.setParentId(mCurrentDir.getFileId());\r
- mStorageManager.saveFile(newDir);\r
- \r
- // Display the new folder right away\r
- mFileList.listDirectory(mCurrentDir);\r
- }\r
- });\r
- \r
- } else {\r
- mHandler.post(new Runnable() {\r
- @Override\r
- public void run() {\r
- dismissDialog(DIALOG_SHORT_WAIT);\r
- try {\r
- Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- \r
- } catch (NotFoundException e) {\r
- Log.e(TAG, "Error while trying to show fail message " , e);\r
- }\r
- }\r
- });\r
- }\r
- }\r
- \r
- }\r
-\r
- // Custom array adapter to override text colors\r
- private class CustomArrayAdapter<T> extends ArrayAdapter<T> {\r
- \r
- public CustomArrayAdapter(FileDisplayActivity ctx, int view) {\r
- super(ctx, view);\r
- }\r
- \r
- public View getView(int position, View convertView, ViewGroup parent) {\r
- View v = super.getView(position, convertView, parent);\r
- \r
- ((TextView) v).setTextColor(getResources().getColorStateList(\r
- android.R.color.white));\r
- return v;\r
- }\r
- \r
- public View getDropDownView(int position, View convertView,\r
- ViewGroup parent) {\r
- View v = super.getDropDownView(position, convertView, parent);\r
- \r
- ((TextView) v).setTextColor(getResources().getColorStateList(\r
- android.R.color.white));\r
- \r
- return v;\r
- }\r
- \r
- }\r
-\r
- private class SyncBroadcastReceiver extends BroadcastReceiver {\r
- /**\r
- * {@link BroadcastReceiver} to enable syncing feedback in UI\r
- */\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- boolean inProgress = intent.getBooleanExtra(\r
- FileSyncService.IN_PROGRESS, false);\r
- String accountName = intent\r
- .getStringExtra(FileSyncService.ACCOUNT_NAME);\r
-\r
- Log.d("FileDisplay", "sync of account " + accountName\r
- + " is in_progress: " + inProgress);\r
-\r
- if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { \r
- \r
- String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); \r
- \r
- boolean fillBlankRoot = false;\r
- if (mCurrentDir == null) {\r
- mCurrentDir = mStorageManager.getFileByPath("/");\r
- fillBlankRoot = (mCurrentDir != null);\r
- }\r
-\r
- if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))\r
- || fillBlankRoot ) {\r
- if (!fillBlankRoot) \r
- mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);\r
- FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager()\r
- .findFragmentById(R.id.fileList);\r
- if (fileListFragment != null) {\r
- fileListFragment.listDirectory(mCurrentDir); \r
- }\r
- }\r
- \r
- setSupportProgressBarIndeterminateVisibility(inProgress);\r
- \r
- }\r
- }\r
- }\r
- \r
-\r
- private class UploadFinishReceiver extends BroadcastReceiver {\r
- /**\r
- * Once the file upload has finished -> update view\r
- * @author David A. Velasco\r
- * {@link BroadcastReceiver} to enable upload feedback in UI\r
- */\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- long parentDirId = intent.getLongExtra(FileUploader.EXTRA_PARENT_DIR_ID, -1);\r
- OCFile parentDir = mStorageManager.getFileById(parentDirId);\r
- String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
-\r
- if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&\r
- parentDir != null && \r
- ( (mCurrentDir == null && parentDir.getFileName().equals("/")) ||\r
- parentDir.equals(mCurrentDir)\r
- )\r
- ) {\r
- FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
- if (fileListFragment != null) { \r
- fileListFragment.listDirectory();\r
- }\r
- }\r
- }\r
- \r
- }\r
- \r
- \r
- /**\r
- * Once the file download has finished -> update view\r
- */\r
- private class DownloadFinishReceiver extends BroadcastReceiver {\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
- String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-\r
- if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&\r
- mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) {\r
- FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
- if (fileListFragment != null) { \r
- fileListFragment.listDirectory();\r
- }\r
- }\r
- }\r
- }\r
-\r
- \r
- @Override\r
- public void onClick(View v) {\r
- if (v.getId() == R.id.setup_account) {\r
- Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
- intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
- startActivity(intent); \r
- mForcedLoginToCreateFirstAccount = true;\r
- }\r
- }\r
-\r
- \r
- \r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public DataStorageManager getStorageManager() {\r
- return mStorageManager;\r
- }\r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onDirectoryClick(OCFile directory) {\r
- pushDirname(directory);\r
- ActionBar actionBar = getSupportActionBar();\r
- actionBar.setDisplayHomeAsUpEnabled(true);\r
- \r
- if (mDualPane) {\r
- // Resets the FileDetailsFragment on Tablets so that it always displays\r
- FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
- if (fileDetails != null) {\r
- FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
- transaction.remove(fileDetails);\r
- transaction.add(R.id.file_details_container, new FileDetailFragment(null, null));\r
- transaction.commit();\r
- }\r
- }\r
- }\r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onFileClick(OCFile file) {\r
- \r
- // If we are on a large device -> update fragment\r
- if (mDualPane) {\r
- // 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'\r
- FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
- transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
- transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);\r
- transaction.commit();\r
- \r
- } else { // small or medium screen device -> new Activity\r
- Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
- showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);\r
- showDetailsIntent.putExtra(FileDownloader.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));\r
- startActivity(showDetailsIntent);\r
- }\r
- }\r
- \r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onFileStateChanged() {\r
- FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
- if (fileListFragment != null) { \r
- fileListFragment.listDirectory();\r
- }\r
- }\r
- \r
- \r
- /**\r
- * Operations in this method should be preferably performed in onCreate to have a lighter onResume method. \r
- * \r
- * 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 \r
- * put instead the ugly view that shows the 'Setup' button to restart the login activity. \r
- * \r
- * 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 \r
- * FragmentList view empty).\r
- * \r
- * 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)\r
- */\r
- private void initDelayedTilAccountAvailabe() {\r
- setContentView(mLayoutView); \r
- mDualPane = (findViewById(R.id.file_details_container) != null);\r
- if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {\r
- FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
- transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
- transaction.commit();\r
- }\r
- setSupportProgressBarIndeterminateVisibility(false);\r
- }\r
- \r
-\r
- /**\r
- * Launch an intent to request the PIN code to the user before letting him use the app\r
- */\r
- private void requestPinCode() {\r
- boolean pinStart = false;\r
- SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\r
- pinStart = appPrefs.getBoolean("set_pincode", false);\r
- if (pinStart) {\r
- Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);\r
- i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");\r
- startActivity(i);\r
- }\r
- }\r
-\r
- \r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.activity;\r
-\r
-import com.actionbarsherlock.app.SherlockFragmentActivity;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.Dialog;\r
-import android.content.DialogInterface;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.content.Intent;\r
-import android.os.Bundle;\r
-import android.view.View;\r
-import android.widget.AdapterView;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import android.widget.GridView;\r
-import android.widget.Toast;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.ui.adapter.LandingScreenAdapter;\r
-\r
-/**\r
- * This activity is used as a landing page when the user first opens this app.\r
- * \r
- * @author Lennart Rosam\r
- * \r
- */\r
-public class LandingActivity extends SherlockFragmentActivity implements\r
- OnClickListener, OnItemClickListener {\r
-\r
- public static final int DIALOG_SETUP_ACCOUNT = 1;\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- setContentView(R.layout.main);\r
-\r
- // Fill the grid view of the landing screen with icons\r
- GridView landingScreenItems = (GridView) findViewById(R.id.homeScreenGrid);\r
- landingScreenItems.setAdapter(new LandingScreenAdapter(this));\r
- landingScreenItems.setOnItemClickListener(this);\r
-\r
- // Check, if there are ownCloud accounts\r
- if (!accountsAreSetup()) {\r
- showDialog(DIALOG_SETUP_ACCOUNT);\r
- } else {\r
- // Start device tracking service\r
- Intent locationServiceIntent = new Intent();\r
- locationServiceIntent\r
- .setAction("eu.alefzero.owncloud.location.LocationLauncher");\r
- sendBroadcast(locationServiceIntent);\r
- }\r
-\r
- }\r
-\r
- @Override\r
- protected void onRestart() {\r
- super.onRestart();\r
- // Check, if there are ownCloud accounts\r
- if (!accountsAreSetup()) {\r
- showDialog(DIALOG_SETUP_ACCOUNT);\r
- }\r
- }\r
-\r
- @Override\r
- protected void onRestoreInstanceState(Bundle savedInstanceState) {\r
- super.onRestoreInstanceState(savedInstanceState);\r
- // Check, if there are ownCloud accounts\r
- if (!accountsAreSetup()) {\r
- showDialog(DIALOG_SETUP_ACCOUNT);\r
- }\r
- }\r
-\r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog;\r
- switch (id) {\r
- case DIALOG_SETUP_ACCOUNT:\r
- AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
- builder.setTitle(R.string.main_tit_accsetup);\r
- builder.setMessage(R.string.main_wrn_accsetup);\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(R.string.common_ok, this);\r
- builder.setNegativeButton(R.string.common_cancel, this);\r
- dialog = builder.create();\r
- break;\r
- default:\r
- dialog = null;\r
- }\r
-\r
- return dialog;\r
- }\r
-\r
- public void onClick(DialogInterface dialog, int which) {\r
- // In any case - we won't need it anymore\r
- dialog.dismiss();\r
- switch (which) {\r
- case DialogInterface.BUTTON_POSITIVE:\r
- Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
- intent.putExtra("authorities",\r
- new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
- startActivity(intent);\r
- break;\r
- case DialogInterface.BUTTON_NEGATIVE:\r
- finish();\r
- }\r
-\r
- }\r
-\r
- @Override\r
- /**\r
- * Start an activity based on the selection\r
- * the user made\r
- */\r
- public void onItemClick(AdapterView<?> parent, View view, int position,\r
- long id) {\r
- Intent intent;\r
- intent = (Intent) parent.getAdapter().getItem(position);\r
- if (intent != null) {\r
- startActivity(intent);\r
- } else {\r
- // TODO: Implement all of this and make this text go away ;-)\r
- Toast toast = Toast.makeText(this, "Not yet implemented!",\r
- Toast.LENGTH_SHORT);\r
- toast.show();\r
- }\r
- }\r
-\r
- /**\r
- * Checks, whether or not there are any ownCloud accounts setup.\r
- * \r
- * @return true, if there is at least one account.\r
- */\r
- private boolean accountsAreSetup() {\r
- AccountManager accMan = AccountManager.get(this);\r
- Account[] accounts = accMan\r
- .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
- return accounts.length > 0;\r
- }\r
-\r
-}\r
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-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);
- }
-
-
-
-
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.activity;\r
-\r
-import java.util.Vector;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.os.Bundle;\r
-import android.preference.CheckBoxPreference;\r
-import android.preference.ListPreference;\r
-import android.preference.Preference;\r
-import android.preference.PreferenceManager;\r
-import android.preference.Preference.OnPreferenceChangeListener;\r
-import android.preference.Preference.OnPreferenceClickListener;\r
-import android.util.Log;\r
-\r
-import com.actionbarsherlock.app.ActionBar;\r
-import com.actionbarsherlock.app.SherlockPreferenceActivity;\r
-import com.actionbarsherlock.view.Menu;\r
-import com.actionbarsherlock.view.MenuItem;\r
-\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.OwnCloudSession;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.db.DbHandler;\r
-\r
-/**\r
- * An Activity that allows the user to change the application's settings.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class Preferences extends SherlockPreferenceActivity implements\r
- OnPreferenceChangeListener{\r
- private static final String TAG = "OwnCloudPreferences";\r
- private final int mNewSession = 47;\r
- private final int mEditSession = 48;\r
- private DbHandler mDbHandler;\r
- private Vector<OwnCloudSession> mSessions;\r
- //private Account[] mAccounts;\r
- //private ListPreference mAccountList;\r
- private ListPreference mTrackingUpdateInterval;\r
- private CheckBoxPreference mDeviceTracking;\r
- private CheckBoxPreference pCode;\r
- private int mSelectedMenuItem;\r
-\r
- @Override\r
- public void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- mDbHandler = new DbHandler(getBaseContext());\r
- mSessions = new Vector<OwnCloudSession>();\r
- addPreferencesFromResource(R.xml.preferences);\r
- //populateAccountList();\r
- ActionBar actionBar = getSherlock().getActionBar();\r
- actionBar.setDisplayHomeAsUpEnabled(true);\r
- Preference p = findPreference("manage_account");\r
- if (p != null)\r
- p.setOnPreferenceClickListener(new OnPreferenceClickListener() {\r
- @Override\r
- public boolean onPreferenceClick(Preference preference) {\r
- Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class);\r
- startActivity(i);\r
- return true;\r
- }\r
- });\r
- \r
- pCode = (CheckBoxPreference) findPreference("set_pincode");\r
- \r
- \r
- if (pCode != null){\r
- \r
- pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {\r
- @Override\r
- public boolean onPreferenceChange(Preference preference, Object newValue) {\r
- \r
- Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);\r
- i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences");\r
- i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString());\r
- \r
- startActivity(i);\r
- \r
- return true;\r
- }\r
- }); \r
- \r
- }\r
- \r
- }\r
-\r
-\r
- @Override\r
- protected void onResume() {\r
- // TODO Auto-generated method stub\r
- SharedPreferences appPrefs = PreferenceManager\r
- .getDefaultSharedPreferences(getApplicationContext());\r
- \r
- boolean state = appPrefs.getBoolean("set_pincode", false);\r
- pCode.setChecked(state);\r
- \r
- super.onResume();\r
- }\r
-\r
-\r
-\r
- /**\r
- * Populates the account selector\r
- *-/\r
- private void populateAccountList() {\r
- AccountManager accMan = AccountManager.get(this);\r
- mAccounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
- mAccountList = (ListPreference) findPreference("select_oc_account");\r
- mAccountList.setOnPreferenceChangeListener(this);\r
-\r
- // Display the name of the current account if there is any\r
- Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
- if (defaultAccount != null) {\r
- mAccountList.setSummary(defaultAccount.name);\r
- }\r
- \r
- // Transform accounts into array of string for preferences to use\r
- String[] accNames = new String[mAccounts.length];\r
- for (int i = 0; i < mAccounts.length; i++) {\r
- Account account = mAccounts[i];\r
- accNames[i] = account.name;\r
- }\r
-\r
- mAccountList.setEntries(accNames);\r
- mAccountList.setEntryValues(accNames);\r
- }*/\r
-\r
- \r
- \r
- @Override\r
- public boolean onCreateOptionsMenu(Menu menu) {\r
- super.onCreateOptionsMenu(menu);\r
- //MenuInflater inflater = getSherlock().getMenuInflater();\r
- //inflater.inflate(R.menu.prefs_menu, menu);\r
- return true;\r
- }\r
-\r
- @Override\r
- public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
- super.onMenuItemSelected(featureId, item);\r
- Intent intent;\r
-\r
- switch (item.getItemId()) {\r
- //case R.id.addSessionItem:\r
- case 1:\r
- intent = new Intent(this, PreferencesNewSession.class);\r
- startActivityForResult(intent, mNewSession);\r
- break;\r
- case R.id.SessionContextEdit:\r
- intent = new Intent(this, PreferencesNewSession.class);\r
- intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem)\r
- .getEntryId());\r
- intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem)\r
- .getName());\r
- intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem)\r
- .getUrl());\r
- startActivityForResult(intent, mEditSession);\r
- break;\r
- case android.R.id.home:\r
- intent = new Intent(getBaseContext(), FileDisplayActivity.class);\r
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
- startActivity(intent);\r
- break;\r
- default:\r
- Log.w(TAG, "Unknown menu item triggered");\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- @Override\r
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
- super.onActivityResult(requestCode, resultCode, data);\r
- }\r
-\r
- @Override\r
- protected void onDestroy() {\r
- mDbHandler.close();\r
- super.onDestroy();\r
- }\r
-\r
- \r
- \r
- @Override\r
- /**\r
- * Updates various summaries after updates. Also starts and stops \r
- * the\r
- */\r
- public boolean onPreferenceChange(Preference preference, Object newValue) {\r
- // Update current account summary\r
- /*if (preference.equals(mAccountList)) {\r
- mAccountList.setSummary(newValue.toString());\r
- }\r
-\r
- // Update tracking interval summary\r
- else*/ if (preference.equals(mTrackingUpdateInterval)) {\r
- String trackingSummary = getResources().getString(\r
- R.string.prefs_trackmydevice_interval_summary);\r
- trackingSummary = String.format(trackingSummary,\r
- newValue.toString());\r
- mTrackingUpdateInterval.setSummary(trackingSummary);\r
- }\r
-\r
- // Start or stop tracking service\r
- else if (preference.equals(mDeviceTracking)) {\r
- Intent locationServiceIntent = new Intent();\r
- locationServiceIntent\r
- .setAction("eu.alefzero.owncloud.location.LocationLauncher");\r
- locationServiceIntent.putExtra("TRACKING_SETTING",\r
- (Boolean) newValue);\r
- sendBroadcast(locationServiceIntent);\r
- } \r
- return true;\r
- }\r
- \r
- \r
-\r
-}\r
+++ /dev/null
-package eu.alefzero.owncloud.ui.activity;\r
-\r
-import android.accounts.AccountAuthenticatorActivity;\r
-import android.app.Activity;\r
-import android.os.Bundle;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-\r
-public class PreferencesNewSession extends AccountAuthenticatorActivity\r
- implements OnClickListener {\r
- @Override\r
- public void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- // setContentView(R.layout.add_new_session);\r
- /*\r
- * EditText et;// = (EditText)\r
- * findViewById(R.id.newSession_sessionName);\r
- * \r
- * et = (EditText) findViewById(R.id.newSession_URL); if\r
- * (getIntent().hasExtra("sessionURL")) { try { URI uri = new\r
- * URI(getIntent().getStringExtra("sessionURL")); String url =\r
- * uri.getHost(); if (uri.getPort() != -1) { url += ":" +\r
- * String.valueOf(uri.getPort()); } if (uri.getPath() != null) { url +=\r
- * uri.getPath(); } else { url += "/"; } et.setText(url); et =\r
- * (EditText) findViewById(R.id.newSession_username); if\r
- * (uri.getAuthority() != null) { if (uri.getUserInfo().indexOf(':') !=\r
- * -1) { et.setText(uri.getUserInfo().substring(0,\r
- * uri.getUserInfo().indexOf(':'))); et = (EditText)\r
- * findViewById(R.id.newSession_password);\r
- * et.setText(uri.getUserInfo().substring\r
- * (uri.getUserInfo().indexOf(':')+1)); } else {\r
- * et.setText(uri.getUserInfo()); } }\r
- * \r
- * } catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " +\r
- * e.getLocalizedMessage()); } }\r
- * \r
- * mReturnData = new Intent(); setResult(Activity.RESULT_OK,\r
- * mReturnData); ((Button)\r
- * findViewById(R.id.button1)).setOnClickListener(this); ((Button)\r
- * findViewById(R.id.button2)).setOnClickListener(this);\r
- */\r
- }\r
-\r
- @Override\r
- protected void onResume() {\r
- super.onResume();\r
- }\r
-\r
- public void onClick(View v) {\r
- /*\r
- * switch (v.getId()) { case R.id.button1: Intent intent = new Intent();\r
- * if (getIntent().hasExtra("sessionId")) { intent.putExtra("sessionId",\r
- * getIntent().getIntExtra("sessionId", -1)); } //String sessionName =\r
- * ((EditText)\r
- * findViewById(R.id.newSession_sessionName)).getText().toString(); //\r
- * if (sessionName.trim().equals("") || !isNameValid(sessionName)) { //\r
- * Toast.makeText(this, R.string.new_session_session_name_error,\r
- * Toast.LENGTH_LONG).show(); // break; // } URI uri = prepareURI(); if\r
- * (uri != null) { //intent.putExtra("sessionName", sessionName);\r
- * intent.putExtra("sessionURL", uri.toString());\r
- * setResult(Activity.RESULT_OK, intent); AccountManager accMgr =\r
- * AccountManager.get(this); Account a = new Account("OwnCloud",\r
- * AccountAuthenticatorService.ACCOUNT_TYPE);\r
- * accMgr.addAccountExplicitly(a, "asd", null); finish(); } break; case\r
- * R.id.button2: setResult(Activity.RESULT_CANCELED); finish(); break; }\r
- */\r
- }\r
-\r
- /*\r
- * private URI prepareURI() { URI uri = null; String url = ""; try { String\r
- * username = ((EditText)\r
- * findViewById(R.id.newSession_username)).getText().toString().trim();\r
- * String password = ((EditText)\r
- * findViewById(R.id.newSession_password)).getText().toString().trim();\r
- * String hostname = ((EditText)\r
- * findViewById(R.id.newSession_URL)).getText().toString().trim(); String\r
- * scheme; if (hostname.matches("[A-Za-z]://")) { scheme =\r
- * hostname.substring(0, hostname.indexOf("://")+3); hostname =\r
- * hostname.substring(hostname.indexOf("://")+3); } else { scheme =\r
- * "http://"; } if (!username.equals("")) { if (!password.equals("")) {\r
- * username += ":" + password + "@"; } else { username += "@"; } } url =\r
- * scheme + username + hostname; Log.i(TAG, url); uri = new URI(url); }\r
- * catch (URISyntaxException e) { Log.e(TAG, "Incorrect URI syntax " +\r
- * e.getLocalizedMessage()); Toast.makeText(this,\r
- * R.string.new_session_uri_error, Toast.LENGTH_LONG).show(); } return uri;\r
- * }\r
- * \r
- * private boolean isNameValid(String string) { return\r
- * string.matches("[A-Za-z0-9 _-]*"); }\r
- */\r
-\r
- @Override\r
- public void onBackPressed() {\r
- setResult(Activity.RESULT_CANCELED);\r
- super.onBackPressed();\r
- }\r
-\r
-}\r
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-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");
- }
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.adapter;\r
-\r
-import java.util.Vector;\r
-\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.DisplayUtils;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.datamodel.DataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.files.services.FileDownloader;\r
-import eu.alefzero.owncloud.files.services.FileUploader;\r
-\r
-import android.accounts.Account;\r
-import android.content.Context;\r
-import android.database.DataSetObserver;\r
-import android.util.Log;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.ImageView;\r
-import android.widget.ListAdapter;\r
-import android.widget.TextView;\r
-\r
-/**\r
- * This Adapter populates a ListView with all files and folders in an ownCloud\r
- * instance.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileListListAdapter implements ListAdapter {\r
- private Context mContext;\r
- private OCFile mFile;\r
- private Vector<OCFile> mFiles;\r
- private DataStorageManager mStorageManager;\r
- private Account mAccount;\r
-\r
- public FileListListAdapter(OCFile file, DataStorageManager storage_man,\r
- Context context) {\r
- mFile = file;\r
- mStorageManager = storage_man;\r
- mFiles = mStorageManager.getDirectoryContent(mFile);\r
- mContext = context;\r
- mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
- }\r
-\r
- @Override\r
- public boolean areAllItemsEnabled() {\r
- return true;\r
- }\r
-\r
- @Override\r
- public boolean isEnabled(int position) {\r
- // TODO Auto-generated method stub\r
- return true;\r
- }\r
-\r
- @Override\r
- public int getCount() {\r
- return mFiles != null ? mFiles.size() : 0;\r
- }\r
-\r
- @Override\r
- public Object getItem(int position) {\r
- if (mFiles.size() <= position)\r
- return null;\r
- return mFiles.get(position);\r
- }\r
-\r
- @Override\r
- public long getItemId(int position) {\r
- return mFiles != null ? mFiles.get(position).getFileId() : 0;\r
- }\r
-\r
- @Override\r
- public int getItemViewType(int position) {\r
- // TODO Auto-generated method stub\r
- return 0;\r
- }\r
-\r
- @Override\r
- public View getView(int position, View convertView, ViewGroup parent) {\r
- View view = convertView;\r
- if (view == null) {\r
- LayoutInflater inflator = (LayoutInflater) mContext\r
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
- view = inflator.inflate(R.layout.list_layout, null);\r
- }\r
- if (mFiles.size() > position) {\r
- OCFile file = mFiles.get(position);\r
- TextView fileName = (TextView) view.findViewById(R.id.Filename);\r
- String name = file.getFileName();\r
-\r
- fileName.setText(name);\r
- ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);\r
- if (file.getMimetype() == null || !file.getMimetype().equals("DIR")) {\r
- fileIcon.setImageResource(R.drawable.file);\r
- } else {\r
- fileIcon.setImageResource(R.drawable.ic_menu_archive);\r
- }\r
- ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);\r
- if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) {\r
- localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
- localStateView.setVisibility(View.VISIBLE);\r
- } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) {\r
- localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
- localStateView.setVisibility(View.VISIBLE);\r
- } else if (file.isDown()) {\r
- localStateView.setImageResource(R.drawable.local_file_indicator);\r
- localStateView.setVisibility(View.VISIBLE);\r
- } else {\r
- localStateView.setVisibility(View.INVISIBLE);\r
- }\r
- /*\r
- ImageView down = (ImageView) view.findViewById(R.id.imageView2);\r
- ImageView downloading = (ImageView) view.findViewById(R.id.imageView4);\r
- ImageView uploading = (ImageView) view.findViewById(R.id.imageView5);\r
- if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) {\r
- down.setVisibility(View.INVISIBLE);\r
- downloading.setVisibility(View.VISIBLE);\r
- uploading.setVisibility(View.INVISIBLE);\r
- } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) {\r
- down.setVisibility(View.INVISIBLE);\r
- downloading.setVisibility(View.INVISIBLE);\r
- uploading.setVisibility(View.VISIBLE);\r
- } else if (file.isDown()) {\r
- down.setVisibility(View.VISIBLE);\r
- downloading.setVisibility(View.INVISIBLE);\r
- uploading.setVisibility(View.INVISIBLE);\r
- } else {\r
- down.setVisibility(View.INVISIBLE);\r
- downloading.setVisibility(View.INVISIBLE);\r
- uploading.setVisibility(View.INVISIBLE);\r
- }*/\r
- \r
- if (!file.isDirectory()) {\r
- view.findViewById(R.id.file_size).setVisibility(View.VISIBLE);\r
- view.findViewById(R.id.last_mod).setVisibility(View.VISIBLE);\r
- ((TextView)view.findViewById(R.id.file_size)).setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
- ((TextView)view.findViewById(R.id.last_mod)).setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));\r
- // this if-else is needed even thoe fav icon is visible by default\r
- // because android reuses views in listview\r
- if (!file.keepInSync()) {\r
- view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
- } else {\r
- view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE);\r
- }\r
- } else {\r
- view.findViewById(R.id.file_size).setVisibility(View.GONE);\r
- view.findViewById(R.id.last_mod).setVisibility(View.GONE);\r
- view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
- }\r
- }\r
-\r
- return view;\r
- }\r
-\r
- @Override\r
- public int getViewTypeCount() {\r
- return 4;\r
- }\r
-\r
- @Override\r
- public boolean hasStableIds() {\r
- return true;\r
- }\r
-\r
- @Override\r
- public boolean isEmpty() {\r
- return mFiles != null ? mFiles.isEmpty() : false;\r
- }\r
-\r
- @Override\r
- public void registerDataSetObserver(DataSetObserver observer) {\r
- // TODO Auto-generated method stub\r
-\r
- }\r
-\r
- @Override\r
- public void unregisterDataSetObserver(DataSetObserver observer) {\r
- // TODO Auto-generated method stub\r
-\r
- }\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.adapter;\r
-\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.BaseAdapter;\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.ui.activity.FileDisplayActivity;\r
-import eu.alefzero.owncloud.ui.activity.Preferences;\r
-\r
-/**\r
- * Populates the landing screen icons.\r
- * \r
- * @author Lennart Rosam\r
- * \r
- */\r
-public class LandingScreenAdapter extends BaseAdapter {\r
-\r
- private Context mContext;\r
-\r
- private final Integer[] mLandingScreenIcons = { R.drawable.home,\r
- R.drawable.music, R.drawable.contacts, R.drawable.calendar,\r
- android.R.drawable.ic_menu_agenda, R.drawable.settings };\r
-\r
- private final Integer[] mLandingScreenTexts = { R.string.main_files,\r
- R.string.main_music, R.string.main_contacts,\r
- R.string.main_calendar, R.string.main_bookmarks,\r
- R.string.main_settings };\r
-\r
- public LandingScreenAdapter(Context context) {\r
- mContext = context;\r
- }\r
-\r
- @Override\r
- public int getCount() {\r
- return mLandingScreenIcons.length;\r
- }\r
-\r
- @Override\r
- /**\r
- * Returns the Intent associated with this object\r
- * or null if the functionality is not yet implemented\r
- */\r
- public Object getItem(int position) {\r
- Intent intent = new Intent();\r
-\r
- switch (position) {\r
- case 0:\r
- /*\r
- * The FileDisplayActivity requires the ownCloud account as an\r
- * parcableExtra. We will put in the one that is selected in the\r
- * preferences\r
- */\r
- intent.setClass(mContext, FileDisplayActivity.class);\r
- intent.putExtra("ACCOUNT",\r
- AccountUtils.getCurrentOwnCloudAccount(mContext));\r
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
- break;\r
- case 5:\r
- intent.setClass(mContext, Preferences.class);\r
- break;\r
- default:\r
- intent = null;\r
- }\r
- return intent;\r
- }\r
-\r
- @Override\r
- public long getItemId(int position) {\r
- return position;\r
- }\r
-\r
- @Override\r
- public View getView(int position, View convertView, ViewGroup parent) {\r
- if (convertView == null) {\r
- LayoutInflater inflator = LayoutInflater.from(mContext);\r
- convertView = inflator.inflate(R.layout.landing_page_item, null);\r
-\r
- ImageView icon = (ImageView) convertView\r
- .findViewById(R.id.gridImage);\r
- TextView iconText = (TextView) convertView\r
- .findViewById(R.id.gridText);\r
-\r
- icon.setImageResource(mLandingScreenIcons[position]);\r
- iconText.setText(mLandingScreenTexts[position]);\r
- }\r
- return convertView;\r
- }\r
-}\r
+++ /dev/null
-package eu.alefzero.owncloud.ui.fragment;
-
-import com.actionbarsherlock.app.SherlockFragment;
-
-public class AuthenticatorAccountDetailsFragment extends SherlockFragment {
-
-}
+++ /dev/null
-package eu.alefzero.owncloud.ui.fragment;
-
-import com.actionbarsherlock.app.SherlockFragment;
-
-public class AuthenticatorGetStartedFragment extends SherlockFragment {
-
-}
+++ /dev/null
-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);
- }
-
-}
-
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.fragment;\r
-\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.apache.commons.httpclient.HttpException;\r
-import org.apache.commons.httpclient.methods.GetMethod;\r
-import org.apache.commons.httpclient.methods.PostMethod;\r
-import org.apache.commons.httpclient.methods.StringRequestEntity;\r
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;\r
-import org.apache.http.HttpStatus;\r
-import org.apache.http.NameValuePair;\r
-import org.apache.http.client.utils.URLEncodedUtils;\r
-import org.apache.http.message.BasicNameValuePair;\r
-import org.apache.http.protocol.HTTP;\r
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;\r
-import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.annotation.SuppressLint;\r
-import android.app.Activity;\r
-import android.content.ActivityNotFoundException;\r
-import android.content.BroadcastReceiver;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.IntentFilter;\r
-import android.content.res.Resources.NotFoundException;\r
-import android.graphics.Bitmap;\r
-import android.graphics.BitmapFactory;\r
-import android.graphics.BitmapFactory.Options;\r
-import android.graphics.Point;\r
-import android.net.Uri;\r
-import android.os.AsyncTask;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.support.v4.app.FragmentTransaction;\r
-import android.util.Log;\r
-import android.view.Display;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.ViewGroup;\r
-import android.view.WindowManager.LayoutParams;\r
-import android.webkit.MimeTypeMap;\r
-import android.widget.Button;\r
-import android.widget.CheckBox;\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import android.widget.Toast;\r
-\r
-import com.actionbarsherlock.app.SherlockDialogFragment;\r
-import com.actionbarsherlock.app.SherlockFragment;\r
-\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.DisplayUtils;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.datamodel.FileDataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.files.services.FileDownloader;\r
-import eu.alefzero.owncloud.files.services.FileUploader;\r
-import eu.alefzero.owncloud.ui.activity.FileDetailActivity;\r
-import eu.alefzero.owncloud.ui.activity.FileDisplayActivity;\r
-import eu.alefzero.owncloud.utils.OwnCloudVersion;\r
-import eu.alefzero.webdav.WebdavClient;\r
-import eu.alefzero.webdav.WebdavUtils;\r
-\r
-/**\r
- * This Fragment is used to display the details about a file.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileDetailFragment extends SherlockFragment implements\r
- OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener {\r
-\r
- public static final String EXTRA_FILE = "FILE";\r
- public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
-\r
- private FileDetailFragment.ContainerActivity mContainerActivity;\r
- \r
- private int mLayout;\r
- private View mView;\r
- private OCFile mFile;\r
- private Account mAccount;\r
- private ImageView mPreview;\r
- \r
- private DownloadFinishReceiver mDownloadFinishReceiver;\r
- private UploadFinishReceiver mUploadFinishReceiver;\r
-\r
- private static final String TAG = "FileDetailFragment";\r
- public static final String FTAG = "FileDetails"; \r
- public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
-\r
- \r
- /**\r
- * Creates an empty details fragment.\r
- * \r
- * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. \r
- */\r
- public FileDetailFragment() {\r
- mFile = null;\r
- mAccount = null;\r
- mLayout = R.layout.file_details_empty;\r
- }\r
- \r
- \r
- /**\r
- * Creates a details fragment.\r
- * \r
- * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).\r
- * \r
- * @param fileToDetail An {@link OCFile} to show in the fragment\r
- * @param ocAccount An ownCloud account; needed to start downloads\r
- */\r
- public FileDetailFragment(OCFile fileToDetail, Account ocAccount){\r
- mFile = fileToDetail;\r
- mAccount = ocAccount;\r
- mLayout = R.layout.file_details_empty;\r
- \r
- if(fileToDetail != null && ocAccount != null) {\r
- mLayout = R.layout.file_details_fragment;\r
- }\r
- }\r
- \r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onAttach(Activity activity) {\r
- super.onAttach(activity);\r
- try {\r
- mContainerActivity = (ContainerActivity) activity;\r
- } catch (ClassCastException e) {\r
- throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity");\r
- }\r
- }\r
- \r
- \r
- @Override\r
- public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
- Bundle savedInstanceState) {\r
- super.onCreateView(inflater, container, savedInstanceState);\r
- \r
- if (savedInstanceState != null) {\r
- mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
- mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);\r
- }\r
- \r
- View view = null;\r
- view = inflater.inflate(mLayout, container, false);\r
- mView = view;\r
- \r
- if (mLayout == R.layout.file_details_fragment) {\r
- mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);\r
- mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);\r
- mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);\r
- mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);\r
- mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);\r
- //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);\r
- mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
- }\r
- \r
- updateFileDetails();\r
- return view;\r
- }\r
- \r
-\r
- @Override\r
- public void onSaveInstanceState(Bundle outState) {\r
- Log.i(getClass().toString(), "onSaveInstanceState() start");\r
- super.onSaveInstanceState(outState);\r
- outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);\r
- outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
- Log.i(getClass().toString(), "onSaveInstanceState() end");\r
- }\r
-\r
- \r
- @Override\r
- public void onResume() {\r
- super.onResume();\r
- \r
- mDownloadFinishReceiver = new DownloadFinishReceiver();\r
- IntentFilter filter = new IntentFilter(\r
- FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
- getActivity().registerReceiver(mDownloadFinishReceiver, filter);\r
- \r
- mUploadFinishReceiver = new UploadFinishReceiver();\r
- filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
- getActivity().registerReceiver(mUploadFinishReceiver, filter);\r
- \r
- mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
- }\r
-\r
- @Override\r
- public void onPause() {\r
- super.onPause();\r
- \r
- getActivity().unregisterReceiver(mDownloadFinishReceiver);\r
- mDownloadFinishReceiver = null;\r
- \r
- getActivity().unregisterReceiver(mUploadFinishReceiver);\r
- mUploadFinishReceiver = null;\r
- \r
- if (mPreview != null) {\r
- mPreview = null;\r
- }\r
- }\r
-\r
- @Override\r
- public View getView() {\r
- return super.getView() == null ? mView : super.getView();\r
- }\r
-\r
- \r
- \r
- @Override\r
- public void onClick(View v) {\r
- switch (v.getId()) {\r
- case R.id.fdDownloadBtn: {\r
- Intent i = new Intent(getActivity(), FileDownloader.class);\r
- i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);\r
- i.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mFile.getRemotePath());\r
- i.putExtra(FileDownloader.EXTRA_FILE_PATH, mFile.getRemotePath());\r
- i.putExtra(FileDownloader.EXTRA_FILE_SIZE, mFile.getFileLength());\r
- \r
- // update ui \r
- setButtonsForTransferring();\r
- \r
- getActivity().startService(i);\r
- mContainerActivity.onFileStateChanged(); // this is not working; it is performed before the fileDownloadService registers it as 'in progress'\r
- break;\r
- }\r
- case R.id.fdKeepInSync: {\r
- CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);\r
- mFile.setKeepInSync(cb.isChecked());\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
- fdsm.saveFile(mFile);\r
- if (mFile.keepInSync()) {\r
- onClick(getView().findViewById(R.id.fdDownloadBtn));\r
- } else { \r
- mContainerActivity.onFileStateChanged(); // put inside 'else' to not call it twice (here, and in the virtual click on fdDownloadBtn)\r
- }\r
- break;\r
- }\r
- case R.id.fdRenameBtn: {\r
- EditNameFragment dialog = EditNameFragment.newInstance(mFile.getFileName());\r
- dialog.show(getFragmentManager(), "nameeditdialog");\r
- dialog.setOnDismissListener(this);\r
- break;\r
- } \r
- case R.id.fdRemoveBtn: {\r
- ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(\r
- R.string.confirmation_remove_alert,\r
- new String[]{mFile.getFileName()},\r
- mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,\r
- mFile.isDown() ? R.string.confirmation_remove_local : -1,\r
- R.string.common_cancel);\r
- confDialog.setOnConfirmationListener(this);\r
- confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
- break;\r
- }\r
- case R.id.fdOpenBtn: {\r
- String storagePath = mFile.getStoragePath();\r
- String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
- try {\r
- Intent i = new Intent(Intent.ACTION_VIEW);\r
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
- i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
- startActivity(i);\r
- \r
- } catch (Throwable t) {\r
- Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
- boolean toastIt = true; \r
- String mimeType = "";\r
- try {\r
- Intent i = new Intent(Intent.ACTION_VIEW);\r
- mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
- if (mimeType != null && !mimeType.equals(mFile.getMimetype())) {\r
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
- i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
- startActivity(i);\r
- toastIt = false;\r
- }\r
- \r
- } catch (IndexOutOfBoundsException e) {\r
- Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
- \r
- } catch (ActivityNotFoundException e) {\r
- Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
- \r
- } catch (Throwable th) {\r
- Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
- \r
- } finally {\r
- if (toastIt) {\r
- Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
- }\r
- }\r
- \r
- }\r
- break;\r
- }\r
- default:\r
- Log.e(TAG, "Incorrect view clicked!");\r
- }\r
- \r
- /* else if (v.getId() == R.id.fdShareBtn) {\r
- Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));\r
- t.start();\r
- }*/\r
- }\r
- \r
- \r
- @Override\r
- public void onConfirmation(String callerTag) {\r
- if (callerTag.equals(FTAG_CONFIRMATION)) {\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
- if (fdsm.getFileById(mFile.getFileId()) != null) {\r
- new Thread(new RemoveRunnable(mFile, mAccount, new Handler())).start();\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- }\r
- }\r
- }\r
- \r
- @Override\r
- public void onNeutral(String callerTag) {\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
- File f = null;\r
- if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {\r
- f.delete();\r
- mFile.setStoragePath(null);\r
- fdsm.saveFile(mFile);\r
- updateFileDetails(mFile, mAccount);\r
- }\r
- }\r
- \r
- @Override\r
- public void onCancel(String callerTag) {\r
- Log.d(TAG, "REMOVAL CANCELED");\r
- }\r
- \r
- \r
- /**\r
- * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.\r
- * \r
- * @return True when the fragment was created with the empty layout.\r
- */\r
- public boolean isEmpty() {\r
- return mLayout == R.layout.file_details_empty;\r
- }\r
-\r
- \r
- /**\r
- * Can be used to get the file that is currently being displayed.\r
- * @return The file on the screen.\r
- */\r
- public OCFile getDisplayedFile(){\r
- return mFile;\r
- }\r
- \r
- /**\r
- * Use this method to signal this Activity that it shall update its view.\r
- * \r
- * @param file : An {@link OCFile}\r
- */\r
- public void updateFileDetails(OCFile file, Account ocAccount) {\r
- mFile = file;\r
- mAccount = ocAccount;\r
- updateFileDetails();\r
- }\r
- \r
-\r
- /**\r
- * Updates the view with all relevant details about that file.\r
- */\r
- public void updateFileDetails() {\r
-\r
- if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
- \r
- // set file details\r
- setFilename(mFile.getFileName());\r
- setFiletype(DisplayUtils.convertMIMEtoPrettyPrint(mFile\r
- .getMimetype()));\r
- setFilesize(mFile.getFileLength());\r
- if(ocVersionSupportsTimeCreated()){\r
- setTimeCreated(mFile.getCreationTimestamp());\r
- }\r
- \r
- setTimeModified(mFile.getModificationTimestamp());\r
- \r
- CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);\r
- cb.setChecked(mFile.keepInSync());\r
-\r
- // configure UI for depending upon local state of the file\r
- if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
- setButtonsForTransferring();\r
- \r
- } else if (mFile.isDown()) {\r
- // Update preview\r
- if (mFile.getMimetype().startsWith("image/")) {\r
- BitmapLoader bl = new BitmapLoader();\r
- bl.execute(new String[]{mFile.getStoragePath()});\r
- }\r
- \r
- setButtonsForDown();\r
- \r
- } else {\r
- setButtonsForRemote();\r
- }\r
- }\r
- }\r
- \r
- \r
- /**\r
- * Updates the filename in view\r
- * @param filename to set\r
- */\r
- private void setFilename(String filename) {\r
- TextView tv = (TextView) getView().findViewById(R.id.fdFilename);\r
- if (tv != null)\r
- tv.setText(filename);\r
- }\r
-\r
- /**\r
- * Updates the MIME type in view\r
- * @param mimetype to set\r
- */\r
- private void setFiletype(String mimetype) {\r
- TextView tv = (TextView) getView().findViewById(R.id.fdType);\r
- if (tv != null)\r
- tv.setText(mimetype);\r
- }\r
-\r
- /**\r
- * Updates the file size in view\r
- * @param filesize in bytes to set\r
- */\r
- private void setFilesize(long filesize) {\r
- TextView tv = (TextView) getView().findViewById(R.id.fdSize);\r
- if (tv != null)\r
- tv.setText(DisplayUtils.bytesToHumanReadable(filesize));\r
- }\r
- \r
- /**\r
- * Updates the time that the file was created in view\r
- * @param milliseconds Unix time to set\r
- */\r
- private void setTimeCreated(long milliseconds){\r
- TextView tv = (TextView) getView().findViewById(R.id.fdCreated);\r
- TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);\r
- if(tv != null){\r
- tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
- tv.setVisibility(View.VISIBLE);\r
- tvLabel.setVisibility(View.VISIBLE);\r
- }\r
- }\r
- \r
- /**\r
- * Updates the time that the file was last modified\r
- * @param milliseconds Unix time to set\r
- */\r
- private void setTimeModified(long milliseconds){\r
- TextView tv = (TextView) getView().findViewById(R.id.fdModified);\r
- if(tv != null){\r
- tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
- }\r
- }\r
- \r
- /**\r
- * Enables or disables buttons for a file being downloaded\r
- */\r
- private void setButtonsForTransferring() {\r
- if (!isEmpty()) {\r
- Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
- //downloadButton.setText(R.string.filedetails_download_in_progress); // ugly\r
- downloadButton.setEnabled(false); // TODO replace it with a 'cancel download' button\r
- \r
- // let's protect the user from himself ;)\r
- ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
- ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);\r
- ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);\r
- }\r
- }\r
- \r
- /**\r
- * Enables or disables buttons for a file locally available \r
- */\r
- private void setButtonsForDown() {\r
- if (!isEmpty()) {\r
- Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
- //downloadButton.setText(R.string.filedetails_redownload); // ugly\r
- downloadButton.setEnabled(true);\r
- \r
- ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
- ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
- ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
- }\r
- }\r
-\r
- /**\r
- * Enables or disables buttons for a file not locally available \r
- */\r
- private void setButtonsForRemote() {\r
- if (!isEmpty()) {\r
- Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
- //downloadButton.setText(R.string.filedetails_download); // unnecessary\r
- downloadButton.setEnabled(true);\r
- \r
- ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
- ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
- ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
- }\r
- }\r
- \r
-\r
- /**\r
- * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return\r
- * the time that the file was created. There is a chance that this will\r
- * be fixed in future versions. Use this method to check if this version of\r
- * ownCloud has this fix.\r
- * @return True, if ownCloud the ownCloud version is supporting creation time\r
- */\r
- private boolean ocVersionSupportsTimeCreated(){\r
- /*if(mAccount != null){\r
- AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);\r
- OwnCloudVersion ocVersion = new OwnCloudVersion(accManager\r
- .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
- if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {\r
- return true;\r
- }\r
- }*/\r
- return false;\r
- }\r
- \r
- \r
- /**\r
- * Interface to implement by any Activity that includes some instance of FileDetailFragment\r
- * \r
- * @author David A. Velasco\r
- */\r
- public interface ContainerActivity {\r
-\r
- /**\r
- * Callback method invoked when the detail fragment wants to notice its container \r
- * activity about a relevant state the file shown by the fragment.\r
- * \r
- * Added to notify to FileDisplayActivity about the need of refresh the files list. \r
- * \r
- * Currently called when:\r
- * - a download is started;\r
- * - a rename is completed;\r
- * - a deletion is completed;\r
- * - the 'inSync' flag is changed;\r
- */\r
- public void onFileStateChanged();\r
- \r
- }\r
- \r
-\r
- /**\r
- * Once the file download has finished -> update view\r
- * @author Bartek Przybylski\r
- */\r
- private class DownloadFinishReceiver extends BroadcastReceiver {\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-\r
- if (!isEmpty() && accountName.equals(mAccount.name)) {\r
- boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);\r
- String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
- if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
- if (downloadWasFine) {\r
- mFile.setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH)); // updates the local object without accessing the database again\r
- }\r
- updateFileDetails(); // it updates the buttons; must be called although !downloadWasFine\r
- }\r
- }\r
- }\r
- }\r
- \r
- \r
- /**\r
- * Once the file upload has finished -> update view\r
- * \r
- * Being notified about the finish of an upload is necessary for the next sequence:\r
- * 1. Upload a big file.\r
- * 2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list\r
- * of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. \r
- * 3. Click the file in the list to see its details.\r
- * 4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.\r
- */\r
- private class UploadFinishReceiver extends BroadcastReceiver {\r
- @Override\r
- public void onReceive(Context context, Intent intent) {\r
- String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
-\r
- if (!isEmpty() && accountName.equals(mAccount.name)) {\r
- boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
- String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
- if (mFile.getRemotePath().equals(uploadRemotePath)) {\r
- if (uploadWasFine) {\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
- mFile = fdsm.getFileByPath(mFile.getRemotePath());\r
- }\r
- updateFileDetails(); // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
- }\r
- }\r
- }\r
- }\r
- \r
-\r
- // this is a temporary class for sharing purposes, it need to be replaced in transfer service\r
- private class ShareRunnable implements Runnable {\r
- private String mPath;\r
-\r
- public ShareRunnable(String path) {\r
- mPath = path;\r
- }\r
- \r
- public void run() {\r
- AccountManager am = AccountManager.get(getActivity());\r
- Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());\r
- OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));\r
- String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);\r
-\r
- Log.d("share", "sharing for version " + ocv.toString());\r
-\r
- if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {\r
- String APPS_PATH = "/apps/files_sharing/";\r
- String SHARE_PATH = "ajax/share.php";\r
-\r
- String SHARED_PATH = "/apps/files_sharing/get.php?token=";\r
- \r
- final String WEBDAV_SCRIPT = "webdav.php";\r
- final String WEBDAV_FILES_LOCATION = "/files/";\r
- \r
- WebdavClient wc = new WebdavClient();\r
- HttpConnectionManagerParams params = new HttpConnectionManagerParams();\r
- params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);\r
-\r
- //wc.getParams().setParameter("http.protocol.single-cookie-header", true);\r
- //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);\r
-\r
- PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);\r
-\r
- post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );\r
- post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
- List<NameValuePair> formparams = new ArrayList<NameValuePair>();\r
- Log.d("share", mPath+"");\r
- formparams.add(new BasicNameValuePair("sources",mPath));\r
- formparams.add(new BasicNameValuePair("uid_shared_with", "public"));\r
- formparams.add(new BasicNameValuePair("permissions", "0"));\r
- post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));\r
-\r
- int status;\r
- try {\r
- PropFindMethod find = new PropFindMethod(url+"/");\r
- find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
- Log.d("sharer", ""+ url+"/");\r
- wc.setCredentials(account.name.substring(0, account.name.lastIndexOf('@')), am.getPassword(account));\r
- \r
- for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {\r
- Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
- }\r
- \r
- int status2 = wc.executeMethod(find);\r
-\r
- Log.d("sharer", "propstatus "+status2);\r
- \r
- GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");\r
- get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
- \r
- status2 = wc.executeMethod(get);\r
-\r
- Log.d("sharer", "getstatus "+status2);\r
- Log.d("sharer", "" + get.getResponseBodyAsString());\r
- \r
- for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {\r
- Log.d("sharer", a.getName() + ":"+a.getValue());\r
- }\r
-\r
- status = wc.executeMethod(post);\r
- for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {\r
- Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
- }\r
- for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {\r
- Log.d("sharer", a.getName() + ":"+a.getValue());\r
- }\r
- String resp = post.getResponseBodyAsString();\r
- Log.d("share", ""+post.getURI().toString());\r
- Log.d("share", "returned status " + status);\r
- Log.d("share", " " +resp);\r
- \r
- if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {\r
- return;\r
- }\r
-\r
- JSONObject jsonObject = new JSONObject (resp);\r
- String jsonStatus = jsonObject.getString("status");\r
- if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");\r
- \r
- String token = jsonObject.getString("data");\r
- String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; \r
- Log.d("Actions:shareFile ok", "url: " + uri); \r
- \r
- } catch (HttpException e) {\r
- // TODO Auto-generated catch block\r
- e.printStackTrace();\r
- } catch (IOException e) {\r
- // TODO Auto-generated catch block\r
- e.printStackTrace();\r
- } catch (JSONException e) {\r
- // TODO Auto-generated catch block\r
- e.printStackTrace();\r
- } catch (Exception e) {\r
- // TODO Auto-generated catch block\r
- e.printStackTrace();\r
- }\r
- \r
- } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {\r
- \r
- }\r
- }\r
- }\r
- \r
- public void onDismiss(EditNameFragment dialog) {\r
- if (dialog instanceof EditNameFragment) {\r
- if (((EditNameFragment)dialog).getResult()) {\r
- String newFilename = ((EditNameFragment)dialog).getNewFilename();\r
- Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
- if (!newFilename.equals(mFile.getFileName())) {\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
- if (fdsm.getFileById(mFile.getFileId()) != null) {\r
- OCFile newFile = new OCFile(fdsm.getFileById(mFile.getParentId()).getRemotePath() + newFilename);\r
- newFile.setCreationTimestamp(mFile.getCreationTimestamp());\r
- newFile.setFileId(mFile.getFileId());\r
- newFile.setFileLength(mFile.getFileLength());\r
- newFile.setKeepInSync(mFile.keepInSync());\r
- newFile.setLastSyncDate(mFile.getLastSyncDate());\r
- newFile.setMimetype(mFile.getMimetype());\r
- newFile.setModificationTimestamp(mFile.getModificationTimestamp());\r
- newFile.setParentId(mFile.getParentId());\r
- boolean localRenameFails = false;\r
- if (mFile.isDown()) {\r
- File f = new File(mFile.getStoragePath());\r
- Log.e(TAG, f.getAbsolutePath());\r
- localRenameFails = !(f.renameTo(new File(f.getParent() + File.separator + newFilename)));\r
- Log.e(TAG, f.getParent() + File.separator + newFilename);\r
- newFile.setStoragePath(f.getParent() + File.separator + newFilename);\r
- }\r
- \r
- if (localRenameFails) {\r
- Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- \r
- } else {\r
- new Thread(new RenameRunnable(mFile, newFile, mAccount, new Handler())).start();\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- }\r
-\r
- }\r
- }\r
- }\r
- } else {\r
- Log.e(TAG, "Unknown dialog instance passed to onDismissDalog: " + dialog.getClass().getCanonicalName());\r
- }\r
- \r
- }\r
- \r
- private class RenameRunnable implements Runnable {\r
- \r
- Account mAccount;\r
- OCFile mOld, mNew;\r
- Handler mHandler;\r
- \r
- public RenameRunnable(OCFile oldFile, OCFile newFile, Account account, Handler handler) {\r
- mOld = oldFile;\r
- mNew = newFile;\r
- mAccount = account;\r
- mHandler = handler;\r
- }\r
- \r
- public void run() {\r
- WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext());\r
- wc.allowSelfsignedCertificates();\r
- AccountManager am = AccountManager.get(getSherlockActivity());\r
- String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
- OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
- String webdav_path = AccountUtils.getWebdavPath(ocv);\r
- Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath()));\r
-\r
- Log.e("ASD", Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath()));\r
- LocalMoveMethod move = new LocalMoveMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mOld.getRemotePath()),\r
- Uri.parse(baseUrl).getPath() == null ? "" : Uri.parse(baseUrl).getPath() + webdav_path + WebdavUtils.encodePath(mNew.getRemotePath()));\r
- \r
- boolean success = false;\r
- try {\r
- int status = wc.executeMethod(move);\r
- success = move.succeeded();\r
- Log.d(TAG, "Move returned status: " + status);\r
- \r
- } catch (HttpException e) {\r
- Log.e(TAG, "HTTP Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e);\r
- \r
- } catch (IOException e) {\r
- Log.e(TAG, "I/O Exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e);\r
- \r
- } catch (Exception e) {\r
- Log.e(TAG, "Unexpected exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e);\r
- }\r
- \r
- if (success) {\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
- fdsm.removeFile(mOld);\r
- fdsm.saveFile(mNew);\r
- mFile = mNew;\r
- mHandler.post(new Runnable() {\r
- @Override\r
- public void run() { \r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- updateFileDetails(mFile, mAccount);\r
- mContainerActivity.onFileStateChanged();\r
- }\r
- });\r
- \r
- } else {\r
- mHandler.post(new Runnable() {\r
- @Override\r
- public void run() {\r
- // undo the local rename\r
- if (mNew.isDown()) {\r
- File f = new File(mNew.getStoragePath());\r
- if (!f.renameTo(new File(mOld.getStoragePath()))) {\r
- // the local rename undoing failed; last chance: save the new local storage path in the old file\r
- mFile.setStoragePath(mNew.getStoragePath());\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
- fdsm.saveFile(mFile);\r
- }\r
- }\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- try {\r
- Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- \r
- } catch (NotFoundException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
- }\r
- private class LocalMoveMethod extends DavMethodBase {\r
-\r
- public LocalMoveMethod(String uri, String dest) {\r
- super(uri);\r
- addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest));\r
- }\r
-\r
- @Override\r
- public String getName() {\r
- return "MOVE";\r
- }\r
-\r
- @Override\r
- protected boolean isSuccess(int status) {\r
- return status == 201 || status == 204;\r
- }\r
- \r
- }\r
- }\r
- \r
- private static class EditNameFragment extends SherlockDialogFragment implements OnClickListener {\r
-\r
- private String mNewFilename;\r
- private boolean mResult;\r
- private FileDetailFragment mListener;\r
- \r
- static public EditNameFragment newInstance(String filename) {\r
- EditNameFragment f = new EditNameFragment();\r
- Bundle args = new Bundle();\r
- args.putString("filename", filename);\r
- f.setArguments(args);\r
- return f;\r
- }\r
- \r
- @Override\r
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
- View v = inflater.inflate(R.layout.edit_box_dialog, container, false);\r
-\r
- String currentName = getArguments().getString("filename");\r
- if (currentName == null)\r
- currentName = "";\r
- \r
- ((Button)v.findViewById(R.id.cancel)).setOnClickListener(this);\r
- ((Button)v.findViewById(R.id.ok)).setOnClickListener(this);\r
- ((TextView)v.findViewById(R.id.user_input)).setText(currentName);\r
- ((TextView)v.findViewById(R.id.user_input)).requestFocus();\r
- getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);\r
-\r
- mResult = false;\r
- return v;\r
- }\r
- \r
- @Override\r
- public void onClick(View view) {\r
- switch (view.getId()) {\r
- case R.id.ok: {\r
- mNewFilename = ((TextView)getView().findViewById(R.id.user_input)).getText().toString();\r
- mResult = true;\r
- }\r
- case R.id.cancel: { // fallthought\r
- dismiss();\r
- mListener.onDismiss(this);\r
- }\r
- }\r
- }\r
- \r
- void setOnDismissListener(FileDetailFragment listener) {\r
- mListener = listener;\r
- }\r
- \r
- public String getNewFilename() {\r
- return mNewFilename;\r
- }\r
- \r
- // true if user click ok\r
- public boolean getResult() {\r
- return mResult;\r
- }\r
- \r
- }\r
- \r
- private class RemoveRunnable implements Runnable {\r
- \r
- Account mAccount;\r
- OCFile mFileToRemove;\r
- Handler mHandler;\r
- \r
- public RemoveRunnable(OCFile fileToRemove, Account account, Handler handler) {\r
- mFileToRemove = fileToRemove;\r
- mAccount = account;\r
- mHandler = handler;\r
- }\r
- \r
- public void run() {\r
- WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext());\r
- wc.allowSelfsignedCertificates();\r
- AccountManager am = AccountManager.get(getSherlockActivity());\r
- String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
- OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
- String webdav_path = AccountUtils.getWebdavPath(ocv);\r
- Log.d("ASD", ""+baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath()));\r
-\r
- DeleteMethod delete = new DeleteMethod(baseUrl + webdav_path + WebdavUtils.encodePath(mFileToRemove.getRemotePath()));\r
- \r
- boolean success = false;\r
- int status = -1;\r
- try {\r
- status = wc.executeMethod(delete);\r
- success = (delete.succeeded());\r
- Log.d(TAG, "Delete: returned status " + status);\r
- \r
- } catch (HttpException e) {\r
- Log.e(TAG, "HTTP Exception removing file " + mFileToRemove.getRemotePath(), e);\r
- \r
- } catch (IOException e) {\r
- Log.e(TAG, "I/O Exception removing file " + mFileToRemove.getRemotePath(), e);\r
- \r
- } catch (Exception e) {\r
- Log.e(TAG, "Unexpected exception removing file " + mFileToRemove.getRemotePath(), e);\r
- }\r
- \r
- if (success) {\r
- FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
- fdsm.removeFile(mFileToRemove);\r
- mHandler.post(new Runnable() {\r
- @Override\r
- public void run() {\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- try {\r
- Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);\r
- msg.show();\r
- if (inDisplayActivity) {\r
- // double pane\r
- FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
- transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
- transaction.commit();\r
- mContainerActivity.onFileStateChanged();\r
- \r
- } else {\r
- getActivity().finish();\r
- }\r
- \r
- } catch (NotFoundException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- });\r
- \r
- } else {\r
- mHandler.post(new Runnable() {\r
- @Override\r
- public void run() {\r
- boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
- getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
- try {\r
- Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
- msg.show();\r
- \r
- } catch (NotFoundException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
- }\r
- \r
- }\r
- \r
- class BitmapLoader extends AsyncTask<String, Void, Bitmap> {\r
- @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20\r
- @Override\r
- protected Bitmap doInBackground(String... params) {\r
- Bitmap result = null;\r
- if (params.length != 1) return result;\r
- String storagePath = params[0];\r
- try {\r
-\r
- BitmapFactory.Options options = new Options();\r
- options.inScaled = true;\r
- options.inPurgeable = true;\r
- options.inJustDecodeBounds = true;\r
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {\r
- options.inPreferQualityOverSpeed = false;\r
- }\r
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {\r
- options.inMutable = false;\r
- }\r
-\r
- result = BitmapFactory.decodeFile(storagePath, options);\r
- options.inJustDecodeBounds = false;\r
-\r
- int width = options.outWidth;\r
- int height = options.outHeight;\r
- int scale = 1;\r
- if (width >= 2048 || height >= 2048) {\r
- scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));\r
- options.inSampleSize = scale;\r
- }\r
- Display display = getActivity().getWindowManager().getDefaultDisplay();\r
- Point size = new Point();\r
- int screenwidth;\r
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {\r
- display.getSize(size);\r
- screenwidth = size.x;\r
- } else {\r
- screenwidth = display.getWidth();\r
- }\r
-\r
- Log.e("ASD", "W " + width + " SW " + screenwidth);\r
-\r
- if (width > screenwidth) {\r
- scale = (int) Math.ceil((float)width / screenwidth);\r
- options.inSampleSize = scale;\r
- }\r
-\r
- result = BitmapFactory.decodeFile(storagePath, options);\r
-\r
- Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight);\r
-\r
- } catch (OutOfMemoryError e) {\r
- result = null;\r
- Log.e(TAG, "Out of memory occured for file with size " + storagePath);\r
- \r
- } catch (NoSuchFieldError e) {\r
- result = null;\r
- Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);\r
- \r
- } catch (Throwable t) {\r
- result = null;\r
- Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);\r
- }\r
- return result;\r
- }\r
- @Override\r
- protected void onPostExecute(Bitmap result) {\r
- if (result != null && mPreview != null) {\r
- mPreview.setImageBitmap(result);\r
- }\r
- }\r
- \r
- }\r
- \r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.fragment;\r
-\r
-import java.util.Vector;\r
-\r
-import android.app.Activity;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.AdapterView;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.datamodel.DataStorageManager;\r
-import eu.alefzero.owncloud.datamodel.OCFile;\r
-import eu.alefzero.owncloud.ui.FragmentListView;\r
-import eu.alefzero.owncloud.ui.adapter.FileListListAdapter;\r
-\r
-/**\r
- * A Fragment that lists all files and folders in a given path.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileListFragment extends FragmentListView {\r
- private static final String TAG = "FileListFragment";\r
- \r
- private FileListFragment.ContainerActivity mContainerActivity;\r
- \r
- private OCFile mFile = null;\r
- private FileListListAdapter mAdapter;\r
-\r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public void onAttach(Activity activity) {\r
- super.onAttach(activity);\r
- try {\r
- mContainerActivity = (ContainerActivity) activity;\r
- } catch (ClassCastException e) {\r
- throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity");\r
- }\r
- }\r
- \r
- \r
- @Override\r
- public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
- Bundle savedInstanceState) {\r
- Log.i(getClass().toString(), "onCreateView() start");\r
- super.onCreateView(inflater, container, savedInstanceState);\r
- getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));\r
- getListView().setDividerHeight(1);\r
- \r
- Log.i(getClass().toString(), "onCreateView() end");\r
- return getListView();\r
- } \r
-\r
-\r
- @Override\r
- public void onActivityCreated(Bundle savedInstanceState) {\r
- Log.i(getClass().toString(), "onActivityCreated() start");\r
- \r
- super.onCreate(savedInstanceState);\r
- //mAdapter = new FileListListAdapter();\r
- \r
- Log.i(getClass().toString(), "onActivityCreated() stop");\r
- }\r
- \r
- \r
- @Override\r
- public void onItemClick(AdapterView<?> l, View v, int position, long id) {\r
- OCFile file = (OCFile) mAdapter.getItem(position);\r
- if (file != null) {\r
- /// Click on a directory\r
- if (file.getMimetype().equals("DIR")) {\r
- // just local updates\r
- mFile = file;\r
- listDirectory(file);\r
- // any other updates are let to the container Activity\r
- mContainerActivity.onDirectoryClick(file);\r
- \r
- } else { /// Click on a file\r
- mContainerActivity.onFileClick(file);\r
- }\r
- \r
- } else {\r
- Log.d(TAG, "Null object in ListAdapter!!");\r
- }\r
- \r
- }\r
-\r
- /**\r
- * Call this, when the user presses the up button\r
- */\r
- public void onNavigateUp() {\r
- OCFile parentDir = null;\r
- \r
- if(mFile != null){\r
- DataStorageManager storageManager = mContainerActivity.getStorageManager();\r
- parentDir = storageManager.getFileById(mFile.getParentId());\r
- mFile = parentDir;\r
- }\r
- listDirectory(parentDir);\r
- }\r
-\r
- /**\r
- * Use this to query the {@link OCFile} that is currently\r
- * being displayed by this fragment\r
- * @return The currently viewed OCFile\r
- */\r
- public OCFile getCurrentFile(){\r
- return mFile;\r
- }\r
- \r
- /**\r
- * Calls {@link FileListFragment#listDirectory(OCFile)} with a null parameter\r
- */\r
- public void listDirectory(){\r
- listDirectory(null);\r
- }\r
- \r
- /**\r
- * Lists the given directory on the view. When the input parameter is null,\r
- * it will either refresh the last known directory, or list the root\r
- * if there never was a directory.\r
- * \r
- * @param directory File to be listed\r
- */\r
- public void listDirectory(OCFile directory) {\r
- \r
- DataStorageManager storageManager = mContainerActivity.getStorageManager();\r
-\r
- // Check input parameters for null\r
- if(directory == null){\r
- if(mFile != null){\r
- directory = mFile;\r
- } else {\r
- directory = storageManager.getFileByPath("/");\r
- if (directory == null) return; // no files, wait for sync\r
- }\r
- }\r
- \r
- \r
- // If that's not a directory -> List its parent\r
- if(!directory.isDirectory()){\r
- Log.w(TAG, "You see, that is not a directory -> " + directory.toString());\r
- directory = storageManager.getFileById(directory.getParentId());\r
- }\r
-\r
- mFile = directory;\r
- \r
- mAdapter = new FileListListAdapter(directory, storageManager, getActivity());\r
- setListAdapter(mAdapter);\r
- }\r
- \r
- \r
- \r
- /**\r
- * Interface to implement by any Activity that includes some instance of FileListFragment\r
- * \r
- * @author David A. Velasco\r
- */\r
- public interface ContainerActivity {\r
-\r
- /**\r
- * Callback method invoked when a directory is clicked by the user on the files list\r
- * \r
- * @param file\r
- */\r
- public void onDirectoryClick(OCFile file);\r
- \r
- /**\r
- * Callback method invoked when a file (non directory) is clicked by the user on the files list\r
- * \r
- * @param file\r
- */\r
- public void onFileClick(OCFile file);\r
-\r
- /**\r
- * Getter for the current DataStorageManager in the container activity\r
- */\r
- public DataStorageManager getStorageManager();\r
- \r
- }\r
-\r
-}\r
+++ /dev/null
-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud.ui.fragment;\r
-\r
-import com.actionbarsherlock.app.SherlockFragment;\r
-\r
-import android.os.Bundle;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.ListView;\r
-import eu.alefzero.owncloud.R;\r
-import eu.alefzero.owncloud.ui.activity.LandingActivity;\r
-import eu.alefzero.owncloud.ui.adapter.LandingScreenAdapter;\r
-\r
-/**\r
- * Used on the Landing page to display what Components of the ownCloud there\r
- * are. Like Files, Music, Contacts, etc.\r
- * \r
- * @author Lennart Rosam\r
- * \r
- */\r
-public class LandingPageFragment extends SherlockFragment {\r
-\r
- @Override\r
- public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
- Bundle savedInstanceState) {\r
- View root = inflater.inflate(R.layout.landing_page_fragment, container);\r
- return root;\r
- }\r
-\r
- @Override\r
- public void onActivityCreated(Bundle savedInstanceState) {\r
- super.onActivityCreated(savedInstanceState);\r
-\r
- ListView landingScreenItems = (ListView) getView().findViewById(\r
- R.id.homeScreenList);\r
- landingScreenItems.setAdapter(new LandingScreenAdapter(getActivity()));\r
- landingScreenItems\r
- .setOnItemClickListener((LandingActivity) getActivity());\r
- }\r
-\r
-}\r
+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.owncloud.utils;
-
-public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
- 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;
- }
- }
-}
+++ /dev/null
-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);
- }
-
-}
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.
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;\r
\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.authenticator.EasySSLSocketFactory;\r
+import com.owncloud.android.files.interfaces.OnDatatransferProgressListener;\r
+import com.owncloud.android.utils.OwnCloudVersion;\r
+\r
import android.accounts.Account;\r
import android.accounts.AccountManager;\r
import android.content.Context;\r
import android.net.Uri;\r
import android.util.Log;\r
-import eu.alefzero.owncloud.AccountUtils;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory;\r
-import eu.alefzero.owncloud.files.interfaces.OnDatatransferProgressListener;\r
-import eu.alefzero.owncloud.utils.OwnCloudVersion;\r
\r
public class WebdavClient extends HttpClient {\r
private Uri mUri;\r