From: Lennart Rosam Date: Sat, 4 Feb 2012 16:41:28 +0000 (+0100) Subject: Refactoring: Added comments to every class, as well as a copyright X-Git-Tag: oc-android-1.4.3~489 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/dc8c32fb3f7033d6fdfa7e1b64eaa77884da678a?ds=inline Refactoring: Added comments to every class, as well as a copyright notice. Also, some classes were moved to packages where they make sense --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2500eaa5..d2bf5866 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,77 +1,76 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/action_bar.xml b/res/layout/action_bar.xml index 4d69c6a2..4500adbd 100644 --- a/res/layout/action_bar.xml +++ b/res/layout/action_bar.xml @@ -1,39 +1,39 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/ActionItem.java b/src/eu/alefzero/owncloud/ActionItem.java deleted file mode 100644 index 5f97c559..00000000 --- a/src/eu/alefzero/owncloud/ActionItem.java +++ /dev/null @@ -1,37 +0,0 @@ -package eu.alefzero.owncloud; - -import android.graphics.drawable.Drawable; -import android.view.View.OnClickListener; - -public class ActionItem { - private Drawable mIcon; - private String mTitle; - private OnClickListener mClickListener; - - public ActionItem() { } - - public void setTitle(String title) { - mTitle = title; - } - - public String getTitle() { - return mTitle; - } - - public void setIcon(Drawable icon) { - mIcon = icon; - } - - public Drawable getIcon() { - return mIcon; - } - - public void setOnClickListener(OnClickListener listener) { - mClickListener = listener; - } - - public OnClickListener getOnClickListerner() { - return mClickListener; - } - -} diff --git a/src/eu/alefzero/owncloud/CustomPopup.java b/src/eu/alefzero/owncloud/CustomPopup.java deleted file mode 100644 index 7c919700..00000000 --- a/src/eu/alefzero/owncloud/CustomPopup.java +++ /dev/null @@ -1,126 +0,0 @@ -package eu.alefzero.owncloud; - -import android.content.Context; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.view.View.OnTouchListener; -import android.view.ViewGroup.LayoutParams; -import android.widget.PopupWindow; - -public class CustomPopup { - protected final View mAnchor; - protected final PopupWindow mWindow; - private View root; - private Drawable background = null; - protected final WindowManager mWManager; - - public CustomPopup(View anchor) { - mAnchor = anchor; - mWindow = new PopupWindow(anchor.getContext()); - - mWindow.setTouchInterceptor(new OnTouchListener() { - - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { - CustomPopup.this.dismiss(); - return true; - } - return false; - } - }); - - mWManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE); - onCreate(); - } - - - public void onCreate() {} - public void onShow() {} - - public void preShow() { - if (root == null) { - throw new IllegalStateException("setContentView called with a view to display"); - } - - onShow(); - - if (background == null) { - mWindow.setBackgroundDrawable(new BitmapDrawable()); - } else { - mWindow.setBackgroundDrawable(background); - } - - mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); - mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); - mWindow.setTouchable(true); - mWindow.setFocusable(true); - mWindow.setOutsideTouchable(true); - - mWindow.setContentView(root); - } - - public void setBackgroundDrawable(Drawable background) { - this.background = background; - } - - public void setContentView(View root) { - this.root = root; - mWindow.setContentView(root); - } - - public void setContentView(int layoutResId) { - LayoutInflater inflater = - (LayoutInflater) mAnchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - setContentView(inflater.inflate(layoutResId, null)); - } - - public void showDropDown() { - showDropDown(0, 0); - } - - public void showDropDown(int x, int y) { - preShow(); - mWindow.setAnimationStyle(android.R.style.Animation_Dialog); - mWindow.showAsDropDown(mAnchor, x, y); - } - - public void showLikeQuickAction() { - showLikeQuickAction(0, 0); - } - - public void showLikeQuickAction(int x, int y) { - preShow(); - - mWindow.setAnimationStyle(android.R.style.Animation_Dialog); - int[] location = new int[2]; - mAnchor.getLocationOnScreen(location); - - Rect anchorRect = - new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); - - root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - int rootW = root.getWidth(), rootH = root.getHeight(); - int screenW = mWManager.getDefaultDisplay().getWidth(); - - int xpos = ((screenW-rootW)/2) + x; - int ypos = anchorRect.top - rootH + y; - - if (rootH > anchorRect.top) { - ypos = anchorRect.bottom + y; - } - mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos); - } - - public void dismiss() { - mWindow.dismiss(); - } - -} diff --git a/src/eu/alefzero/owncloud/DbHandler.java b/src/eu/alefzero/owncloud/DbHandler.java deleted file mode 100644 index c47bd439..00000000 --- a/src/eu/alefzero/owncloud/DbHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -package eu.alefzero.owncloud; - -import java.util.Vector; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -public class DbHandler { - private SQLiteDatabase mDB; - private OpenerHepler mHelper; - private final String mDatabaseName = "ownCloud"; - private final String TABLE_SESSIONS = "sessions"; - private final int mDatabaseVersion = 1; - - public DbHandler(Context context) { - mHelper = new OpenerHepler(context); - mDB = mHelper.getWritableDatabase(); - } - - public Vector getSessionList() { - Cursor c = mDB.query(TABLE_SESSIONS, null, null, null, null, null, null); - Vector v = new Vector(); - if (!c.moveToFirst()) { - return v; - } - while (!c.isAfterLast()) { - v.add(new OwnCloudSession(c.getString(c.getColumnIndex("sessionName")), - c.getString(c.getColumnIndex("sessionUrl")), - c.getInt(c.getColumnIndex("_id")))); - c.moveToNext(); - } - c.close(); - return v; - } - - public void addSession(String sessionName, String uri) { - ContentValues cv = new ContentValues(); - cv.put("sessionName", sessionName); - cv.put("sessionUrl", uri); - mDB.insert(TABLE_SESSIONS, null, cv); - } - - public void removeSessionWithId(int sessionId) { - mDB.delete(TABLE_SESSIONS, "_id = ?", new String[] {String.valueOf(sessionId)}); - } - - public void changeSessionFields(int id, String hostname, String uri) { - ContentValues cv = new ContentValues(); - cv.put("sessionName", hostname); - cv.put("sessionUrl", uri); - mDB.update(TABLE_SESSIONS, cv, "_id = ?", new String[] {String.valueOf(id)}); - } - - public void close() { - mDB.close(); - } - - private class OpenerHepler extends SQLiteOpenHelper { - public OpenerHepler(Context context) { - super(context, mDatabaseName, null, mDatabaseVersion); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TABLE_SESSIONS + " (" + - " _id INTEGER PRIMARY KEY, " + - " sessionName TEXT, " + - " sessionUrl TEXT);"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } - } -} diff --git a/src/eu/alefzero/owncloud/DisplayUtils.java b/src/eu/alefzero/owncloud/DisplayUtils.java index 3f278b31..bea19acb 100644 --- a/src/eu/alefzero/owncloud/DisplayUtils.java +++ b/src/eu/alefzero/owncloud/DisplayUtils.java @@ -1,75 +1,80 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud; - -import java.util.HashMap; - -import android.util.Log; - -public class DisplayUtils { - public static String bitsToHumanReadable(long bitsLen) { - double result = bitsLen; - int attachedsuff = 0; - while (result > 1024 && attachedsuff < suffixes.length) { - result /= 1024.; - attachedsuff++; - } - result = ((int)(result * 100))/100.; - return result+suffixes[attachedsuff]; - } - - public static String HtmlDecode(String s) { - String ret = ""; - for (int i = 0; i < s.length(); ++i) { - if (s.charAt(i) == '%') { - ret += (char)Integer.parseInt(s.substring(i+1, i+3), 16); - i+=2; - } else { - ret += s.charAt(i); - } - } - return ret; - } - - public static String convertMIMEtoPrettyPrint(String mimetype) { - if (mimeType2HUmanReadable.containsKey(mimetype)) { - return mimeType2HUmanReadable.get(mimetype); - } - return mimetype.split("/")[1].toUpperCase() + " file"; - } - - private static final String[] suffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; - - private static HashMap mimeType2HUmanReadable; - static { - mimeType2HUmanReadable = new HashMap(); - // images - mimeType2HUmanReadable.put("image/jpeg", "JPEG image"); - mimeType2HUmanReadable.put("image/jpg", "JPEG image"); - mimeType2HUmanReadable.put("image/png", "PNG image"); - mimeType2HUmanReadable.put("image/bmp", "Bitmap image"); - mimeType2HUmanReadable.put("image/gif", "GIF image"); - mimeType2HUmanReadable.put("image/svg+xml", "JPEG image"); - mimeType2HUmanReadable.put("image/tiff", "TIFF image"); - // music - mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file"); - mimeType2HUmanReadable.put("application/ogg", "OGG music file"); - - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package eu.alefzero.owncloud; + +import java.util.HashMap; + +import android.util.Log; + +/** + * A helper class for some string operations. + * @author Bartek Przybylski + * + */ +public class DisplayUtils { + public static String bitsToHumanReadable(long bitsLen) { + double result = bitsLen; + int attachedsuff = 0; + while (result > 1024 && attachedsuff < suffixes.length) { + result /= 1024.; + attachedsuff++; + } + result = ((int)(result * 100))/100.; + return result+suffixes[attachedsuff]; + } + + public static String HtmlDecode(String s) { + String ret = ""; + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '%') { + ret += (char)Integer.parseInt(s.substring(i+1, i+3), 16); + i+=2; + } else { + ret += s.charAt(i); + } + } + return ret; + } + + public static String convertMIMEtoPrettyPrint(String mimetype) { + if (mimeType2HUmanReadable.containsKey(mimetype)) { + return mimeType2HUmanReadable.get(mimetype); + } + return mimetype.split("/")[1].toUpperCase() + " file"; + } + + private static final String[] suffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; + + private static HashMap mimeType2HUmanReadable; + static { + mimeType2HUmanReadable = new HashMap(); + // images + mimeType2HUmanReadable.put("image/jpeg", "JPEG image"); + mimeType2HUmanReadable.put("image/jpg", "JPEG image"); + mimeType2HUmanReadable.put("image/png", "PNG image"); + mimeType2HUmanReadable.put("image/bmp", "Bitmap image"); + mimeType2HUmanReadable.put("image/gif", "GIF image"); + mimeType2HUmanReadable.put("image/svg+xml", "JPEG image"); + mimeType2HUmanReadable.put("image/tiff", "TIFF image"); + // music + mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file"); + mimeType2HUmanReadable.put("application/ogg", "OGG music file"); + + } +} diff --git a/src/eu/alefzero/owncloud/FileDownloader.java b/src/eu/alefzero/owncloud/FileDownloader.java index 7d3605e4..121e1472 100644 --- a/src/eu/alefzero/owncloud/FileDownloader.java +++ b/src/eu/alefzero/owncloud/FileDownloader.java @@ -1,76 +1,77 @@ -package eu.alefzero.owncloud; - -import java.io.File; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Intent; -import android.net.Uri; -import android.os.Environment; -import android.os.IBinder; -import android.util.Log; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.ui.FileDisplayActivity; - -public class FileDownloader extends Service { - static final String EXTRA_ACCOUNT = "ACCOUNT"; - static final String EXTRA_FILE_PATH = "FILE_PATH"; - static final String TAG = "OC_FileDownloader"; - - NotificationManager nm; - - @Override - public IBinder onBind(Intent arg0) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_FILE_PATH)) { - Log.e(TAG, "Not enough information provided in intent"); - return START_NOT_STICKY; - } - - nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - - Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); - String file_path = intent.getStringExtra(EXTRA_FILE_PATH); - AccountManager am = (AccountManager)getSystemService(ACCOUNT_SERVICE); - Uri oc_url = Uri.parse(am.getUserData(account, AccountAuthenticator.KEY_OC_URL)); - - WebdavClient wdc = new WebdavClient(oc_url); - - String username = account.name.split("@")[0]; - String password = ""; - try { - password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE, true); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return START_NOT_STICKY; - } - - wdc.setCredentials(username, password); - wdc.allowUnsignedCertificates(); - - Notification n = new Notification(R.drawable.icon, "Downloading file", System.currentTimeMillis()); - PendingIntent pi = PendingIntent.getActivity(this, 1, new Intent(this, FileDisplayActivity.class), 0); - n.setLatestEventInfo(this, "A", "B", pi); - nm.notify(1, n); - - File sdCard = Environment.getExternalStorageDirectory(); - File dir = new File (sdCard.getAbsolutePath() + "/owncloud"); - dir.mkdirs(); - File file = new File(dir, file_path.replace('/', '.')); - - wdc.downloadFile(file_path, file); - - return START_NOT_STICKY; - } - - -} +package eu.alefzero.owncloud; + +import java.io.File; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.os.IBinder; +import android.util.Log; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.owncloud.ui.activity.FileDisplayActivity; +import eu.alefzero.webdav.WebdavClient; + +public class FileDownloader extends Service { + static final String EXTRA_ACCOUNT = "ACCOUNT"; + static final String EXTRA_FILE_PATH = "FILE_PATH"; + static final String TAG = "OC_FileDownloader"; + + NotificationManager nm; + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_FILE_PATH)) { + Log.e(TAG, "Not enough information provided in intent"); + return START_NOT_STICKY; + } + + nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + + Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); + String file_path = intent.getStringExtra(EXTRA_FILE_PATH); + AccountManager am = (AccountManager)getSystemService(ACCOUNT_SERVICE); + Uri oc_url = Uri.parse(am.getUserData(account, AccountAuthenticator.KEY_OC_URL)); + + WebdavClient wdc = new WebdavClient(oc_url); + + String username = account.name.split("@")[0]; + String password = ""; + try { + password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE, true); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return START_NOT_STICKY; + } + + wdc.setCredentials(username, password); + wdc.allowUnsignedCertificates(); + + Notification n = new Notification(R.drawable.icon, "Downloading file", System.currentTimeMillis()); + PendingIntent pi = PendingIntent.getActivity(this, 1, new Intent(this, FileDisplayActivity.class), 0); + n.setLatestEventInfo(this, "A", "B", pi); + nm.notify(1, n); + + File sdCard = Environment.getExternalStorageDirectory(); + File dir = new File (sdCard.getAbsolutePath() + "/owncloud"); + dir.mkdirs(); + File file = new File(dir, file_path.replace('/', '.')); + + wdc.downloadFile(file_path, file); + + return START_NOT_STICKY; + } + + +} diff --git a/src/eu/alefzero/owncloud/OwnCloudSession.java b/src/eu/alefzero/owncloud/OwnCloudSession.java index c7caae50..0b9fc39e 100644 --- a/src/eu/alefzero/owncloud/OwnCloudSession.java +++ b/src/eu/alefzero/owncloud/OwnCloudSession.java @@ -1,33 +1,55 @@ -package eu.alefzero.owncloud; - -public class OwnCloudSession { - private String mSessionName; - private String mSessionUrl; - private int mEntryId; - - public OwnCloudSession(String name, String url, int entryId) { - mSessionName = name; - mSessionUrl = url; - mEntryId = entryId; - } - - public void setName(String name) { - mSessionName = name; - } - - public String getName() { - return mSessionName; - } - - public void setUrl(String url) { - mSessionUrl = url; - } - - public String getUrl() { - return mSessionUrl; - } - - public int getEntryId() { - return mEntryId; - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud; + +/** + * Represents a session to an ownCloud instance + * @author Bartek Przybylski + * + */ +public class OwnCloudSession { + private String mSessionName; + private String mSessionUrl; + private int mEntryId; + + public OwnCloudSession(String name, String url, int entryId) { + mSessionName = name; + mSessionUrl = url; + mEntryId = entryId; + } + + public void setName(String name) { + mSessionName = name; + } + + public String getName() { + return mSessionName; + } + + public void setUrl(String url) { + mSessionUrl = url; + } + + public String getUrl() { + return mSessionUrl; + } + + public int getEntryId() { + return mEntryId; + } +} diff --git a/src/eu/alefzero/owncloud/PathLayout.java b/src/eu/alefzero/owncloud/PathLayout.java deleted file mode 100644 index 3f5a4930..00000000 --- a/src/eu/alefzero/owncloud/PathLayout.java +++ /dev/null @@ -1,92 +0,0 @@ -package eu.alefzero.owncloud; - -import java.util.LinkedList; -import java.util.Stack; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.HorizontalScrollView; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ScrollView; -import android.widget.TextView; - -public class PathLayout extends LinearLayout { - - private LinkedList paths; - ScrollView internalScroll; - LinearLayout view; - - public PathLayout(Context context) { - super(context); - initialize(); - } - - public PathLayout(Context context, AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - public String pop() { - if (paths.size() == 0) { - return null; - } - int start = paths.size()*2-2; - int count = 2; - if (paths.size() == 1) { - start++; - count--; - } - view.removeViews(start, count); - return paths.removeLast(); - } - - public void addPath(String path) { - for (String s : path.split("/")) if (s.length() != 0) push(s); - } - - public void push(String path) { - // its weird that we cannot declare static imgView as path separator - if (paths.size() != 0) { - ImageView iv = new ImageView(getContext()); - iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb)); - iv.setPadding(2, 0, 2, 0); - view.addView(iv); - } - TextView tv = new TextView(getContext()); - tv.setLayoutParams(getLayoutParams()); - tv.setText(path); - view.addView(tv); - HorizontalScrollView hsv = (HorizontalScrollView) internalScroll.getChildAt(0); - hsv.smoothScrollTo(hsv.getMaxScrollAmount()*2, 0); - paths.addLast(path); - } - - public String peek() { - return paths.peek(); - } - - public String getFullPath() { - String ret = new String(); - for (int i = 0; i < paths.size(); i++) { - ret += "/" + paths.get(i); - } - return ret; - } - - private void initialize() { - paths = new LinkedList(); - internalScroll = new ScrollView(getContext()); - internalScroll.setFillViewport(true); - HorizontalScrollView hsv = new HorizontalScrollView(getContext()); - hsv.setSmoothScrollingEnabled(true); - internalScroll.addView(hsv); - view = new LinearLayout(getContext()); - addView(internalScroll); - hsv.addView(view); - ImageView iv = new ImageView(getContext()); - iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb)); - view.addView(iv); - } - -} diff --git a/src/eu/alefzero/owncloud/QuickAction.java b/src/eu/alefzero/owncloud/QuickAction.java deleted file mode 100644 index d1974230..00000000 --- a/src/eu/alefzero/owncloud/QuickAction.java +++ /dev/null @@ -1,267 +0,0 @@ -package eu.alefzero.owncloud; - -import android.content.Context; - -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.LinearLayout; -import android.widget.ScrollView; - -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup; - -import java.util.ArrayList; - -/** - * Popup window, shows action list as icon and text like the one in Gallery3D app. - * - * @author Lorensius. W. T - */ -public class QuickAction extends CustomPopup { - private final View root; - private final ImageView mArrowUp; - private final ImageView mArrowDown; - private final LayoutInflater inflater; - private final Context context; - - protected static final int ANIM_GROW_FROM_LEFT = 1; - protected static final int ANIM_GROW_FROM_RIGHT = 2; - protected static final int ANIM_GROW_FROM_CENTER = 3; - protected static final int ANIM_REFLECT = 4; - protected static final int ANIM_AUTO = 5; - - private int animStyle; - private ViewGroup mTrack; - private ScrollView scroller; - private ArrayList actionList; - - /** - * Constructor - * - * @param anchor {@link View} on where the popup window should be displayed - */ - public QuickAction(View anchor) { - super(anchor); - - actionList = new ArrayList(); - context = anchor.getContext(); - inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - root = (ViewGroup) inflater.inflate(R.layout.popup, null); - - mArrowDown = (ImageView) root.findViewById(R.id.arrow_down); - mArrowUp = (ImageView) root.findViewById(R.id.arrow_up); - - setContentView(root); - - mTrack = (ViewGroup) root.findViewById(R.id.tracks); - scroller = (ScrollView) root.findViewById(R.id.scroller); - animStyle = ANIM_AUTO; - } - - /** - * Set animation style - * - * @param animStyle animation style, default is set to ANIM_AUTO - */ - public void setAnimStyle(int animStyle) { - this.animStyle = animStyle; - } - - /** - * Add action item - * - * @param action {@link ActionItem} object - */ - public void addActionItem(ActionItem action) { - actionList.add(action); - } - - /** - * Show popup window. Popup is automatically positioned, on top or bottom of anchor view. - * - */ - public void show () { - preShow(); - - int xPos, yPos; - - int[] location = new int[2]; - - mAnchor.getLocationOnScreen(location); - - Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] - + mAnchor.getHeight()); - - createActionList(); - - root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - int rootHeight = root.getMeasuredHeight(); - int rootWidth = root.getMeasuredWidth(); - - int screenWidth = mWManager.getDefaultDisplay().getWidth(); - int screenHeight = mWManager.getDefaultDisplay().getHeight(); - - //automatically get X coord of popup (top left) - if ((anchorRect.left + rootWidth) > screenWidth) { - xPos = anchorRect.left - (rootWidth-mAnchor.getWidth()); - } else { - if (mAnchor.getWidth() > rootWidth) { - xPos = anchorRect.centerX() - (rootWidth/2); - } else { - xPos = anchorRect.left; - } - } - - int dyTop = anchorRect.top; - int dyBottom = screenHeight - anchorRect.bottom; - - boolean onTop = (dyTop > dyBottom) ? true : false; - - if (onTop) { - if (rootHeight > dyTop) { - yPos = 15; - LayoutParams l = scroller.getLayoutParams(); - l.height = dyTop - mAnchor.getHeight(); - } else { - yPos = anchorRect.top - rootHeight; - } - } else { - yPos = anchorRect.bottom; - - if (rootHeight > dyBottom) { - LayoutParams l = scroller.getLayoutParams(); - l.height = dyBottom; - } - } - - showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), anchorRect.centerX()-xPos); - - setAnimationStyle(screenWidth, anchorRect.centerX(), onTop); - - mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos); - } - - /** - * Set animation style - * - * @param screenWidth screen width - * @param requestedX distance from left edge - * @param onTop flag to indicate where the popup should be displayed. Set TRUE if displayed on top of anchor view - * and vice versa - */ - private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) { - int arrowPos = requestedX - mArrowUp.getMeasuredWidth()/2; - - switch (animStyle) { - case ANIM_GROW_FROM_LEFT: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left); - break; - - case ANIM_GROW_FROM_RIGHT: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right); - break; - - case ANIM_GROW_FROM_CENTER: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center); - break; - - case ANIM_REFLECT: - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect); - break; - - case ANIM_AUTO: - if (arrowPos <= screenWidth/4) { - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left); - } else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) { - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center); - } else { - mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right); - } - - break; - } - } - - /** - * Create action list - */ - private void createActionList() { - View view; - String title; - Drawable icon; - OnClickListener listener; - - for (int i = 0; i < actionList.size(); i++) { - title = actionList.get(i).getTitle(); - icon = actionList.get(i).getIcon(); - listener = actionList.get(i).getOnClickListerner(); - - view = getActionItem(title, icon, listener); - - view.setFocusable(true); - view.setClickable(true); - - mTrack.addView(view); - } - } - - /** - * Get action item {@link View} - * - * @param title action item title - * @param icon {@link Drawable} action item icon - * @param listener {@link View.OnClickListener} action item listener - * @return action item {@link View} - */ - private View getActionItem(String title, Drawable icon, OnClickListener listener) { - LinearLayout container = (LinearLayout) inflater.inflate(R.layout.action_item, null); - - ImageView img = (ImageView) container.findViewById(R.id.icon); - TextView text = (TextView) container.findViewById(R.id.title); - - if (icon != null) { - img.setImageDrawable(icon); - } - - if (title != null) { - text.setText(title); - } - - if (listener != null) { - container.setOnClickListener(listener); - } - - return container; - } - - /** - * Show arrow - * - * @param whichArrow arrow type resource id - * @param requestedX distance from left screen - */ - private void showArrow(int whichArrow, int requestedX) { - final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown; - final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp; - - final int arrowWidth = mArrowUp.getMeasuredWidth(); - - showArrow.setVisibility(View.VISIBLE); - - ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams(); - - param.leftMargin = requestedX - arrowWidth / 2; - - hideArrow.setVisibility(View.INVISIBLE); - } -} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/Uploader.java b/src/eu/alefzero/owncloud/Uploader.java index 5a6a4a22..b15cab97 100644 --- a/src/eu/alefzero/owncloud/Uploader.java +++ b/src/eu/alefzero/owncloud/Uploader.java @@ -1,445 +1,468 @@ -package eu.alefzero.owncloud; - -import java.io.File; -import java.net.FileNameMap; -import java.net.URI; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Stack; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ListActivity; -import android.app.ProgressDialog; -import android.app.AlertDialog.Builder; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; -import android.provider.MediaStore.Images.Media; -import android.util.Log; -import android.view.View; -import android.view.Window; -import android.view.ViewGroup.LayoutParams; -import android.widget.AdapterView; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.SimpleCursorAdapter; -import android.widget.Toast; -import android.widget.AdapterView.OnItemClickListener; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.webdav.WebdavUtils; - -public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { - private static final String TAG = "ownCloudUploader"; - - private Account mAccount; - private AccountManager mAccountManager; - private String mUsername, mPassword; - private Cursor mCursor; - private Stack mParents; - private Thread mUploadThread; - private Handler mHandler; - private ArrayList mStreamsToUpload; - - private final static int DIALOG_NO_ACCOUNT = 0; - private final static int DIALOG_WAITING = 1; - private final static int DIALOG_NO_STREAM = 2; - private final static int DIALOG_MULTIPLE_ACCOUNT = 3; - private final static int DIALOG_GET_DIRNAME = 4; - - private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - mParents = new Stack(); - mHandler = new Handler(); - if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { - prepareStreamsToUpload(); - mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE); - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - if (accounts.length == 0) { - Log.i(TAG, "No ownCloud account is available"); - showDialog(DIALOG_NO_ACCOUNT); - } else if (accounts.length > 1) { - Log.i(TAG, "More then one ownCloud is available"); - showDialog(DIALOG_MULTIPLE_ACCOUNT); - } else { - mAccount = accounts[0]; - setContentView(R.layout.uploader_layout); - populateDirectoryList(); - } - } else { - showDialog(DIALOG_NO_STREAM); - } - } - - @Override - protected Dialog onCreateDialog(final int id) { - final AlertDialog.Builder builder = new Builder(this); - switch (id) { - case DIALOG_WAITING: - ProgressDialog pDialog = new ProgressDialog(this); - pDialog.setIndeterminate(false); - pDialog.setCancelable(false); - pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading)); - return pDialog; - case DIALOG_NO_ACCOUNT: - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.uploader_wrn_no_account_title); - builder.setMessage(R.string.uploader_wrn_no_account_text); - builder.setCancelable(false); - builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) { - // using string value since in API7 this constatn is not defined - // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS - // and Settings.EXTRA_AUTHORITIES - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE}); - startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); - } else { - // since in API7 there is no direct call for account setup, so we need to - // show our own AccountSetupAcricity, get desired results and setup - // everything for ourself - Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class); - startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); - } - } - }); - builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - return builder.create(); - case DIALOG_GET_DIRNAME: - final EditText dirName = new EditText(getBaseContext()); - builder.setView(dirName); - builder.setTitle(R.string.uploader_info_dirname); - String pathToUpload; - if (mParents.empty()) { - pathToUpload = "/"; - } else { - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), - null, - null, - null, - null); - mCursor.moveToFirst(); - pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + - mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); - } - a a = new a(pathToUpload, dirName); - builder.setPositiveButton(R.string.common_ok, a); - builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - return builder.create(); - case DIALOG_MULTIPLE_ACCOUNT: - CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; - for (int i = 0; i < ac.length; ++i) { - ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; - } - builder.setTitle(R.string.common_choose_account); - builder.setItems(ac, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; - populateDirectoryList(); - } - }); - builder.setCancelable(true); - builder.setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - dialog.cancel(); - finish(); - } - }); - return builder.create(); - default: - throw new IllegalArgumentException("Unknown dialog id: " + id); - } - } - - class a implements OnClickListener { - String mPath; - EditText mDirname; - public a(String path, EditText dirname) { - mPath = path; mDirname = dirname; - } - public void onClick(DialogInterface dialog, int which) { - showDialog(DIALOG_WAITING); - mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true)); - mUploadThread.start(); - } - } - - @Override - public void onBackPressed() { - - if (mParents.size()==0) { - super.onBackPressed(); - return; - } else if (mParents.size() == 1) { - mParents.pop(); - mCursor = managedQuery(ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=?", - new String[]{"DIR"}, - null); - } else { - mParents.pop(); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=?", - new String[]{"DIR"}, - null); - } - - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, - mCursor, - new String[]{ProviderTableMeta.FILE_NAME}, - new int[]{R.id.textView1}); - setListAdapter(sca); - } - - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (!mCursor.moveToPosition(position)) { - throw new IndexOutOfBoundsException("Incorrect item selected"); - } - String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); - mParents.push(_id); - - mCursor.close(); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id), - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=?", - new String[]{"DIR"}, - null); - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, - mCursor, - new String[]{ProviderTableMeta.FILE_NAME}, - new int[]{R.id.textView1}); - setListAdapter(sca); - getListView().invalidate(); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.uploader_choose_folder: - String pathToUpload = null; - if (mParents.empty()) { - pathToUpload = "/"; - } else { - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), - null, - null, - null, - null); - mCursor.moveToFirst(); - pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + - mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); - } - - showDialog(DIALOG_WAITING); - mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler)); - mUploadThread.start(); - - break; - case android.R.id.button1: // dynamic action for create aditional dir - showDialog(DIALOG_GET_DIRNAME); - break; - default: - throw new IllegalArgumentException("Wrong element clicked"); - } - } - - public void onUploadComplete(boolean uploadSucc, String message) { - dismissDialog(DIALOG_WAITING); - Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message); - if (uploadSucc) { - Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show(); - } - finish(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); - if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { - dismissDialog(DIALOG_NO_ACCOUNT); - if (resultCode == RESULT_CANCELED) { - finish(); - } - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); - if (accounts.length == 0) { - showDialog(DIALOG_NO_ACCOUNT); - } else { - // there is no need for checking for is there more then one account at this point - // since account setup can set only one account at time - mAccount = accounts[0]; - populateDirectoryList(); - } - } - } - - private void populateDirectoryList() { - mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@')); - mPassword = mAccountManager.getPassword(mAccount); - setContentView(R.layout.uploader_layout); - mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[]{"DIR", mAccount.name}, - null); - - ListView lv = getListView(); - lv.setOnItemClickListener(this); - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, - R.layout.uploader_list_item_layout, - mCursor, - new String[]{ProviderTableMeta.FILE_NAME}, - new int[]{R.id.textView1}); - setListAdapter(sca); - Button btn = (Button) findViewById(R.id.uploader_choose_folder); - btn.setOnClickListener(this); - // insert create new directory for multiple items uploading - if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - Button createDirBtn = new Button(this); - createDirBtn.setId(android.R.id.button1); - createDirBtn.setText(R.string.uploader_btn_create_dir_text); - createDirBtn.setOnClickListener(this); - ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - } - } - - private void prepareStreamsToUpload() { - if (getIntent().getAction().equals(Intent.ACTION_SEND)) { - mStreamsToUpload = new ArrayList(); - mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); - } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); - } else { - // unknow action inserted - throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction()); - } - } - - public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) { - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_NAME, filename); - cv.put(ProviderTableMeta.FILE_PATH, filepath); - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath); - cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date())); - cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength); - cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); - Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath); - if (!mParents.empty()) { - Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), - null, - null, - null, - null); - c.moveToFirst(); - cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); - c.close(); - } - getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); - } - - class BackgroundUploader implements Runnable { - private ArrayList mUploadStreams; - private Handler mHandler; - private String mUploadPath; - private boolean mCreateDir; - - public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, - Handler handler) { - mUploadStreams = streamsToUpload; - mHandler = handler; - mUploadPath = pathToUpload.replace(" ", "%20"); - mCreateDir = false; - } - - public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, - Handler handler, boolean createDir) { - mUploadStreams = streamsToUpload; - mHandler = handler; - mUploadPath = pathToUpload.replace(" ", "%20"); - mCreateDir = createDir; - } - - public void run() { - WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount, - AccountAuthenticator.KEY_OC_URL))); - wdc.setCredentials(mUsername, mPassword); - wdc.allowUnsignedCertificates(); - - // create last directory in path if nessesary - if (mCreateDir) { - wdc.createDirectory(mUploadPath); - } - - for (int i = 0; i < mUploadStreams.size(); ++i) { - Uri uri = (Uri) mUploadStreams.get(i); - if (uri.getScheme().equals("content")) { - final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null); - c.moveToFirst(); - - if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)), - mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), - c.getString(c.getColumnIndex(Media.MIME_TYPE)))) { - mHandler.post(new Runnable() { - public void run() { - Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME))); - } - }); - } - } else if (uri.getScheme().equals("file")) { - final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme()+"://", "")); - FileNameMap fileNameMap = URLConnection.getFileNameMap(); - String contentType = fileNameMap.getContentTypeFor(uri.toString()); - if (contentType == null) { - contentType = "text/plain"; - } - if (!wdc.putFile(file.getAbsolutePath(), mUploadPath+"/"+file.getName(), contentType)) { - mHandler.post(new Runnable() { - public void run() { - Uploader.this.onUploadComplete(false, "Error while uploading file: " + file.getName()); - } - }); - } - } - - } - mHandler.post(new Runnable() { - public void run() { - Uploader.this.onUploadComplete(true, 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 . + * + */ +package eu.alefzero.owncloud; + +import java.io.File; +import java.net.FileNameMap; +import java.net.URI; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Stack; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.app.AlertDialog.Builder; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.DialogInterface.OnCancelListener; +import android.content.DialogInterface.OnClickListener; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Parcelable; +import android.provider.MediaStore.Images.Media; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.ViewGroup.LayoutParams; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; +import android.widget.Toast; +import android.widget.AdapterView.OnItemClickListener; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.owncloud.db.ProviderMeta; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; +import eu.alefzero.webdav.WebdavClient; +import eu.alefzero.webdav.WebdavUtils; + +/** + * This can be used to upload things to an ownCloud instance. + * @author Bartek Przybylski + * + */ +public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { + private static final String TAG = "ownCloudUploader"; + + private Account mAccount; + private AccountManager mAccountManager; + private String mUsername, mPassword; + private Cursor mCursor; + private Stack mParents; + private Thread mUploadThread; + private Handler mHandler; + private ArrayList mStreamsToUpload; + + private final static int DIALOG_NO_ACCOUNT = 0; + private final static int DIALOG_WAITING = 1; + private final static int DIALOG_NO_STREAM = 2; + private final static int DIALOG_MULTIPLE_ACCOUNT = 3; + private final static int DIALOG_GET_DIRNAME = 4; + + private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + mParents = new Stack(); + mHandler = new Handler(); + if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { + prepareStreamsToUpload(); + mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE); + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + if (accounts.length == 0) { + Log.i(TAG, "No ownCloud account is available"); + showDialog(DIALOG_NO_ACCOUNT); + } else if (accounts.length > 1) { + Log.i(TAG, "More then one ownCloud is available"); + showDialog(DIALOG_MULTIPLE_ACCOUNT); + } else { + mAccount = accounts[0]; + setContentView(R.layout.uploader_layout); + populateDirectoryList(); + } + } else { + showDialog(DIALOG_NO_STREAM); + } + } + + @Override + protected Dialog onCreateDialog(final int id) { + final AlertDialog.Builder builder = new Builder(this); + switch (id) { + case DIALOG_WAITING: + ProgressDialog pDialog = new ProgressDialog(this); + pDialog.setIndeterminate(false); + pDialog.setCancelable(false); + pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading)); + return pDialog; + case DIALOG_NO_ACCOUNT: + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.uploader_wrn_no_account_title); + builder.setMessage(R.string.uploader_wrn_no_account_text); + builder.setCancelable(false); + builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) { + // using string value since in API7 this constatn is not defined + // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS + // and Settings.EXTRA_AUTHORITIES + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE}); + startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); + } else { + // since in API7 there is no direct call for account setup, so we need to + // show our own AccountSetupAcricity, get desired results and setup + // everything for ourself + Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class); + startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); + } + } + }); + builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + return builder.create(); + case DIALOG_GET_DIRNAME: + final EditText dirName = new EditText(getBaseContext()); + builder.setView(dirName); + builder.setTitle(R.string.uploader_info_dirname); + String pathToUpload; + if (mParents.empty()) { + pathToUpload = "/"; + } else { + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), + null, + null, + null, + null); + mCursor.moveToFirst(); + pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); + } + a a = new a(pathToUpload, dirName); + builder.setPositiveButton(R.string.common_ok, a); + builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + return builder.create(); + case DIALOG_MULTIPLE_ACCOUNT: + CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; + for (int i = 0; i < ac.length; ++i) { + ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; + } + builder.setTitle(R.string.common_choose_account); + builder.setItems(ac, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; + populateDirectoryList(); + } + }); + builder.setCancelable(true); + builder.setOnCancelListener(new OnCancelListener() { + public void onCancel(DialogInterface dialog) { + dialog.cancel(); + finish(); + } + }); + return builder.create(); + default: + throw new IllegalArgumentException("Unknown dialog id: " + id); + } + } + + class a implements OnClickListener { + String mPath; + EditText mDirname; + public a(String path, EditText dirname) { + mPath = path; mDirname = dirname; + } + public void onClick(DialogInterface dialog, int which) { + showDialog(DIALOG_WAITING); + mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true)); + mUploadThread.start(); + } + } + + @Override + public void onBackPressed() { + + if (mParents.size()==0) { + super.onBackPressed(); + return; + } else if (mParents.size() == 1) { + mParents.pop(); + mCursor = managedQuery(ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=?", + new String[]{"DIR"}, + null); + } else { + mParents.pop(); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=?", + new String[]{"DIR"}, + null); + } + + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, + mCursor, + new String[]{ProviderTableMeta.FILE_NAME}, + new int[]{R.id.textView1}); + setListAdapter(sca); + } + + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (!mCursor.moveToPosition(position)) { + throw new IndexOutOfBoundsException("Incorrect item selected"); + } + String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); + mParents.push(_id); + + mCursor.close(); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id), + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=?", + new String[]{"DIR"}, + null); + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, + mCursor, + new String[]{ProviderTableMeta.FILE_NAME}, + new int[]{R.id.textView1}); + setListAdapter(sca); + getListView().invalidate(); + } + + public void onClick(View v) { + switch (v.getId()) { + case R.id.uploader_choose_folder: + String pathToUpload = null; + if (mParents.empty()) { + pathToUpload = "/"; + } else { + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), + null, + null, + null, + null); + mCursor.moveToFirst(); + pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); + } + + showDialog(DIALOG_WAITING); + mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler)); + mUploadThread.start(); + + break; + case android.R.id.button1: // dynamic action for create aditional dir + showDialog(DIALOG_GET_DIRNAME); + break; + default: + throw new IllegalArgumentException("Wrong element clicked"); + } + } + + public void onUploadComplete(boolean uploadSucc, String message) { + dismissDialog(DIALOG_WAITING); + Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message); + if (uploadSucc) { + Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show(); + } + finish(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); + if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { + dismissDialog(DIALOG_NO_ACCOUNT); + if (resultCode == RESULT_CANCELED) { + finish(); + } + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); + if (accounts.length == 0) { + showDialog(DIALOG_NO_ACCOUNT); + } else { + // there is no need for checking for is there more then one account at this point + // since account setup can set only one account at time + mAccount = accounts[0]; + populateDirectoryList(); + } + } + } + + private void populateDirectoryList() { + mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@')); + mPassword = mAccountManager.getPassword(mAccount); + setContentView(R.layout.uploader_layout); + mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[]{"DIR", mAccount.name}, + null); + + ListView lv = getListView(); + lv.setOnItemClickListener(this); + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, + R.layout.uploader_list_item_layout, + mCursor, + new String[]{ProviderTableMeta.FILE_NAME}, + new int[]{R.id.textView1}); + setListAdapter(sca); + Button btn = (Button) findViewById(R.id.uploader_choose_folder); + btn.setOnClickListener(this); + // insert create new directory for multiple items uploading + if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + Button createDirBtn = new Button(this); + createDirBtn.setId(android.R.id.button1); + createDirBtn.setText(R.string.uploader_btn_create_dir_text); + createDirBtn.setOnClickListener(this); + ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + } + } + + private void prepareStreamsToUpload() { + if (getIntent().getAction().equals(Intent.ACTION_SEND)) { + mStreamsToUpload = new ArrayList(); + mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); + } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); + } else { + // unknow action inserted + throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction()); + } + } + + public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_NAME, filename); + cv.put(ProviderTableMeta.FILE_PATH, filepath); + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath); + cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date())); + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength); + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); + Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath); + if (!mParents.empty()) { + Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), + null, + null, + null, + null); + c.moveToFirst(); + cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); + c.close(); + } + getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); + } + + class BackgroundUploader implements Runnable { + private ArrayList mUploadStreams; + private Handler mHandler; + private String mUploadPath; + private boolean mCreateDir; + + public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, + Handler handler) { + mUploadStreams = streamsToUpload; + mHandler = handler; + mUploadPath = pathToUpload.replace(" ", "%20"); + mCreateDir = false; + } + + public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, + Handler handler, boolean createDir) { + mUploadStreams = streamsToUpload; + mHandler = handler; + mUploadPath = pathToUpload.replace(" ", "%20"); + mCreateDir = createDir; + } + + public void run() { + WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount, + AccountAuthenticator.KEY_OC_URL))); + wdc.setCredentials(mUsername, mPassword); + wdc.allowUnsignedCertificates(); + + // create last directory in path if nessesary + if (mCreateDir) { + wdc.createDirectory(mUploadPath); + } + + for (int i = 0; i < mUploadStreams.size(); ++i) { + Uri uri = (Uri) mUploadStreams.get(i); + if (uri.getScheme().equals("content")) { + final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null); + c.moveToFirst(); + + if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)), + mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), + c.getString(c.getColumnIndex(Media.MIME_TYPE)))) { + mHandler.post(new Runnable() { + public void run() { + Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME))); + } + }); + } + } else if (uri.getScheme().equals("file")) { + final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme()+"://", "")); + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + String contentType = fileNameMap.getContentTypeFor(uri.toString()); + if (contentType == null) { + contentType = "text/plain"; + } + if (!wdc.putFile(file.getAbsolutePath(), mUploadPath+"/"+file.getName(), contentType)) { + mHandler.post(new Runnable() { + public void run() { + Uploader.this.onUploadComplete(false, "Error while uploading file: " + file.getName()); + } + }); + } + } + + } + mHandler.post(new Runnable() { + public void run() { + Uploader.this.onUploadComplete(true, null); + } + }); + } + + } + +} diff --git a/src/eu/alefzero/owncloud/WebdavClient.java b/src/eu/alefzero/owncloud/WebdavClient.java deleted file mode 100644 index 84598037..00000000 --- a/src/eu/alefzero/owncloud/WebdavClient.java +++ /dev/null @@ -1,175 +0,0 @@ -package eu.alefzero.owncloud; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.HttpVersion; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.params.ConnManagerPNames; -import org.apache.http.conn.params.ConnPerRouteBean; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.entity.FileEntity; -import org.apache.http.entity.mime.content.FileBody; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.BasicHttpContext; - -import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory; -import eu.alefzero.webdav.HttpMkCol; - -import android.net.Uri; -import android.util.Log; - -public class WebdavClient { - private DefaultHttpClient mHttpClient; - private BasicHttpContext mHttpContext; - private HttpHost mTargetHost; - private SchemeRegistry mSchemeRegistry; - private Uri mUri; - final private static String TAG = "WebdavClient"; - - WebdavClient(Uri uri) { - mUri = uri; - mSchemeRegistry = new SchemeRegistry(); - setupHttpClient(); - } - - void setCredentials(String username, String password) { - // determine default port for http or https - int targetPort = mTargetHost.getPort() == -1 ? - ( mUri.getScheme().equals("https") ? 443 : 80) - : mUri.getPort(); - - mHttpClient.getCredentialsProvider().setCredentials( - new AuthScope(mUri.getHost(), targetPort), - new UsernamePasswordCredentials(username, password)); - BasicScheme basicAuth = new BasicScheme(); - mHttpContext.setAttribute("preemptive-auth", basicAuth); - } - - void allowUnsignedCertificates() { - // https - mSchemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); - } - - boolean downloadFile(String filepath, File targetPath) { - HttpGet get = new HttpGet(mUri.toString() + filepath.replace(" ", "%20")); - get.setHeader("Host", mUri.getHost()); - get.setHeader("User-Agent", "Android-ownCloud"); - - try { - HttpResponse response = mHttpClient.execute(mTargetHost, get, mHttpContext); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - return false; - } - BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent()); - FileOutputStream fos = new FileOutputStream(targetPath); - - byte[] bytes = new byte[512]; - int readResult; - while ((readResult = bis.read(bytes)) != -1) fos.write(bytes, 0, readResult); - - } catch (IOException e) { - e.printStackTrace(); - return false; - } - return true; - } - - void getFileList(String dirPath) { - - } - - boolean putFile(String localFile, - String remoteTarget, - String contentType) { - boolean result = true; - HttpPut method = new HttpPut(mUri.toString() + remoteTarget.replace(" ", "%20")); - method.setHeader("Content-type", contentType); - method.setHeader("Host", mUri.getHost()); - method.setHeader("User-Agent", "Android-ownCloud"); - - try { - FileBody fb = new FileBody(new File(localFile, contentType)); - final FileEntity fileEntity = new FileEntity(new File(localFile), contentType); - - method.setEntity(fileEntity); - Log.i(TAG, "executing:" + method.getRequestLine().toString()); - - mHttpClient.execute(mTargetHost, method, mHttpContext); - /*mHandler.post(new Runnable() { - public void run() { - Uploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)), - c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), - mUploadPath + (mUploadPath.equals("/")?"":"/"), - fileEntity.getContentType().getValue(), - fileEntity.getContentLength()+""); - } - }); - Log.i(TAG, "Uploading, done"); -*/ - Log.i(TAG, "Uploading, done"); - } catch (final Exception e) { - Log.i(TAG, ""+e.getMessage()); - result = false; - } - - return result; - } - - public boolean createDirectory(String path) { - HttpMkCol method = new HttpMkCol(mUri.toString() + path + "/"); - method.setHeader("User-Agent", "Android-ownCloud"); - - try { - mHttpClient.execute(mTargetHost, method, mHttpContext); - Log.i(TAG, "Creating dir completed"); - } catch (final Exception e) { - e.printStackTrace(); - return false; - } - return true; - } - - private void setupHttpClient() { - // http scheme - mSchemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - mSchemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); - - HttpParams params = new BasicHttpParams(); - params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); - params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); - params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); - HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); - - mHttpContext = new BasicHttpContext(); - ClientConnectionManager cm = new ThreadSafeClientConnManager(params, mSchemeRegistry); - - int port = mUri.getPort() == -1 ? - mUri.getScheme().equals("https") ? 443 : 80 - : mUri.getPort(); - - mTargetHost = new HttpHost(mUri.getHost(), port, mUri.getScheme()); - - mHttpClient = new DefaultHttpClient(cm, params); - } -} diff --git a/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java b/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java index e4b118c5..b688a2d2 100644 --- a/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java +++ b/src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java @@ -1,235 +1,235 @@ -package eu.alefzero.owncloud.authenticator; - -import eu.alefzero.owncloud.ui.AuthenticatorActivity; -import android.accounts.*; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; - -public class AccountAuthenticator extends AbstractAccountAuthenticator { - public static final String OPTIONS_USERNAME = "username"; - public static final String OPTIONS_PASSWORD = "password"; - public static final String OPTIONS_FILE_LIST_SYNC_ENABLED = "filelist"; - public static final String OPTIONS_PINNED_FILE_SYNC_ENABLED = "pinned"; - - public static final String ACCOUNT_TYPE = "owncloud"; - public static final String AUTH_TOKEN_TYPE = "org.owncloud"; - - public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType"; - public static final String KEY_REQUIRED_FEATURES = "requiredFeatures"; - public static final String KEY_LOGIN_OPTIONS = "loginOptions"; - public static final String KEY_ACCOUNT = "account"; - public static final String KEY_OC_URL = "oc_url"; - public static final String KEY_CONTACT_URL = "oc_contact_url"; - - private Context mContext; - - public AccountAuthenticator(Context context) { - super(context); - mContext = context; - } - - /** - * {@inheritDoc} - */ - @Override - public Bundle addAccount(AccountAuthenticatorResponse response, - String accountType, String authTokenType, String[] requiredFeatures, - Bundle options) throws NetworkErrorException { - Log.i(getClass().getName(), "Adding account with type " + accountType + - " and auth token " + authTokenType); - try { - validateAccountType(accountType); - //validateAuthTokenType(authTokenType); - validateRequiredFeatures(requiredFeatures); - } catch (AuthenticatorException e) { - e.printStackTrace(); - return e.getFailureBundle(); - } - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - - setIntentFlags(intent); - Log.i(getClass().getName(), intent.toString()); - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - /** - * {@inheritDoc} - */ - @Override - public Bundle confirmCredentials(AccountAuthenticatorResponse response, - Account account, Bundle options) throws NetworkErrorException { - try { - validateAccountType(account.type); - } catch (AuthenticatorException e) { - return e.getFailureBundle(); - } - Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); - intent.putExtra(KEY_ACCOUNT, account); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - - setIntentFlags(intent); - - Bundle resultBundle = new Bundle(); - resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); - return resultBundle; - } - - @Override - public Bundle editProperties(AccountAuthenticatorResponse response, - String accountType) { - throw new UnsupportedOperationException(); - } - - @Override - public Bundle getAuthToken(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle options) - throws NetworkErrorException { - Log.i(getClass().getName(), "Getting authToken"); - try { - validateAccountType(account.type); - validateAuthTokenType(authTokenType); - } catch (AuthenticatorException e) { - Log.w(getClass().getName(), "Validating failded in getAuthToken"); - return e.getFailureBundle(); - } - final AccountManager am = AccountManager.get(mContext); - final String password = am.getPassword(account); - if (password != null) { - final Bundle result = new Bundle(); - result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); - result.putString(AccountManager.KEY_AUTHTOKEN, password); - return result; - } - - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); - - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - @Override - public String getAuthTokenLabel(String authTokenType) { - return null; - } - - @Override - public Bundle hasFeatures(AccountAuthenticatorResponse response, - Account account, String[] features) throws NetworkErrorException { - final Bundle result = new Bundle(); - result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); - return result; - } - - @Override - public Bundle updateCredentials(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle options) - throws NetworkErrorException { - final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); - intent.putExtra(KEY_ACCOUNT, account); - intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); - intent.putExtra(KEY_LOGIN_OPTIONS, options); - setIntentFlags(intent); - - final Bundle bundle = new Bundle(); - bundle.putParcelable(AccountManager.KEY_INTENT, intent); - return bundle; - } - - @Override - public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, - Account account) throws NetworkErrorException { - return super.getAccountRemovalAllowed(response, account); - } - - private void setIntentFlags(Intent intent) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.addFlags(Intent.FLAG_FROM_BACKGROUND); - } - - private void validateAccountType(String type) throws UnsupportedAccountTypeException { - if (!type.equals(ACCOUNT_TYPE)) { - throw new UnsupportedAccountTypeException(); - } - } - - private void validateAuthTokenType(String authTokenType) throws UnsupportedAuthTokenTypeException { - if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { - throw new UnsupportedAuthTokenTypeException(); - } - } - - private void validateRequiredFeatures(String[] requiredFeatures) throws UnsupportedFeaturesException { - // TODO - } - - private void validateCreaditials(String username, String password, String path) throws AccessDeniedException { - - } - - public static class AuthenticatorException extends Exception { - private static final long serialVersionUID = 1L; - private Bundle mFailureBundle; - - public AuthenticatorException(int code, String errorMsg) { - mFailureBundle = new Bundle(); - mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code); - mFailureBundle.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg); - } - - public Bundle getFailureBundle() { - return mFailureBundle; - } - } - - public static class UnsupportedAccountTypeException extends AuthenticatorException { - private static final long serialVersionUID = 1L; - - public UnsupportedAccountTypeException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported account type"); - } - } - - public static class UnsupportedAuthTokenTypeException extends AuthenticatorException { - private static final long serialVersionUID = 1L; - - public UnsupportedAuthTokenTypeException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported auth token type"); - } - } - - public static class UnsupportedFeaturesException extends AuthenticatorException { - public static final long serialVersionUID = 1L; - - public UnsupportedFeaturesException() { - super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported features"); - } - } - - public static class AccessDeniedException extends AuthenticatorException { - public AccessDeniedException(int code, String errorMsg) { - super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied"); - } - - private static final long serialVersionUID = 1L; - - } -} +package eu.alefzero.owncloud.authenticator; + +import eu.alefzero.owncloud.ui.activity.AuthenticatorActivity; +import android.accounts.*; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +public class AccountAuthenticator extends AbstractAccountAuthenticator { + public static final String OPTIONS_USERNAME = "username"; + public static final String OPTIONS_PASSWORD = "password"; + public static final String OPTIONS_FILE_LIST_SYNC_ENABLED = "filelist"; + public static final String OPTIONS_PINNED_FILE_SYNC_ENABLED = "pinned"; + + public static final String ACCOUNT_TYPE = "owncloud"; + public static final String AUTH_TOKEN_TYPE = "org.owncloud"; + + public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType"; + public static final String KEY_REQUIRED_FEATURES = "requiredFeatures"; + public static final String KEY_LOGIN_OPTIONS = "loginOptions"; + public static final String KEY_ACCOUNT = "account"; + public static final String KEY_OC_URL = "oc_url"; + public static final String KEY_CONTACT_URL = "oc_contact_url"; + + private Context mContext; + + public AccountAuthenticator(Context context) { + super(context); + mContext = context; + } + + /** + * {@inheritDoc} + */ + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, + String accountType, String authTokenType, String[] requiredFeatures, + Bundle options) throws NetworkErrorException { + Log.i(getClass().getName(), "Adding account with type " + accountType + + " and auth token " + authTokenType); + try { + validateAccountType(accountType); + //validateAuthTokenType(authTokenType); + validateRequiredFeatures(requiredFeatures); + } catch (AuthenticatorException e) { + e.printStackTrace(); + return e.getFailureBundle(); + } + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + + setIntentFlags(intent); + Log.i(getClass().getName(), intent.toString()); + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + /** + * {@inheritDoc} + */ + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, + Account account, Bundle options) throws NetworkErrorException { + try { + validateAccountType(account.type); + } catch (AuthenticatorException e) { + return e.getFailureBundle(); + } + Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); + intent.putExtra(KEY_ACCOUNT, account); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + + setIntentFlags(intent); + + Bundle resultBundle = new Bundle(); + resultBundle.putParcelable(AccountManager.KEY_INTENT, intent); + return resultBundle; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, + String accountType) { + throw new UnsupportedOperationException(); + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + Log.i(getClass().getName(), "Getting authToken"); + try { + validateAccountType(account.type); + validateAuthTokenType(authTokenType); + } catch (AuthenticatorException e) { + Log.w(getClass().getName(), "Validating failded in getAuthToken"); + return e.getFailureBundle(); + } + final AccountManager am = AccountManager.get(mContext); + final String password = am.getPassword(account); + if (password != null) { + final Bundle result = new Bundle(); + result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); + result.putString(AccountManager.KEY_AUTHTOKEN, password); + return result; + } + + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); + + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, + Account account, String[] features) throws NetworkErrorException { + final Bundle result = new Bundle(); + result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); + return result; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); + intent.putExtra(KEY_ACCOUNT, account); + intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType); + intent.putExtra(KEY_LOGIN_OPTIONS, options); + setIntentFlags(intent); + + final Bundle bundle = new Bundle(); + bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return bundle; + } + + @Override + public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, + Account account) throws NetworkErrorException { + return super.getAccountRemovalAllowed(response, account); + } + + private void setIntentFlags(Intent intent) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.addFlags(Intent.FLAG_FROM_BACKGROUND); + } + + private void validateAccountType(String type) throws UnsupportedAccountTypeException { + if (!type.equals(ACCOUNT_TYPE)) { + throw new UnsupportedAccountTypeException(); + } + } + + private void validateAuthTokenType(String authTokenType) throws UnsupportedAuthTokenTypeException { + if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { + throw new UnsupportedAuthTokenTypeException(); + } + } + + private void validateRequiredFeatures(String[] requiredFeatures) throws UnsupportedFeaturesException { + // TODO + } + + private void validateCreaditials(String username, String password, String path) throws AccessDeniedException { + + } + + public static class AuthenticatorException extends Exception { + private static final long serialVersionUID = 1L; + private Bundle mFailureBundle; + + public AuthenticatorException(int code, String errorMsg) { + mFailureBundle = new Bundle(); + mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code); + mFailureBundle.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg); + } + + public Bundle getFailureBundle() { + return mFailureBundle; + } + } + + public static class UnsupportedAccountTypeException extends AuthenticatorException { + private static final long serialVersionUID = 1L; + + public UnsupportedAccountTypeException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported account type"); + } + } + + public static class UnsupportedAuthTokenTypeException extends AuthenticatorException { + private static final long serialVersionUID = 1L; + + public UnsupportedAuthTokenTypeException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported auth token type"); + } + } + + public static class UnsupportedFeaturesException extends AuthenticatorException { + public static final long serialVersionUID = 1L; + + public UnsupportedFeaturesException() { + super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported features"); + } + } + + public static class AccessDeniedException extends AuthenticatorException { + public AccessDeniedException(int code, String errorMsg) { + super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied"); + } + + private static final long serialVersionUID = 1L; + + } +} diff --git a/src/eu/alefzero/owncloud/authenticator/AuthUtils.java b/src/eu/alefzero/owncloud/authenticator/AuthUtils.java index e444824a..7e6c813d 100644 --- a/src/eu/alefzero/owncloud/authenticator/AuthUtils.java +++ b/src/eu/alefzero/owncloud/authenticator/AuthUtils.java @@ -1,243 +1,243 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.authenticator; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.UnrecoverableKeyException; - -import javax.net.SocketFactory; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import javax.security.cert.CertificateException; -import javax.security.cert.X509Certificate; - -import org.apache.http.client.HttpClient; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; - -import org.apache.http.impl.client.DefaultHttpClient; - -import org.apache.commons.httpclient.auth.BasicScheme; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.HttpVersion; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.conn.params.ConnManagerPNames; -import org.apache.http.conn.params.ConnPerRouteBean; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.conn.SingleClientConnManager; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.BasicHttpContext; - -import eu.alefzero.owncloud.ui.AuthenticatorActivity; - - -import android.content.Context; -import android.os.Handler; -import android.util.Log; - -public class AuthUtils { - public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; - public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; - public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php"; - - private static String mResultMsg = ""; - - public static boolean authenticate(URL url, String username, String password, - Handler handler, Context context) { - String strippedPath = url.toString().endsWith("/") ? - url.toString().substring(0, url.toString().length()-1) : - url.toString(); - String webdatPath = strippedPath + WEBDAV_PATH_2_0; - URL complete_url = null; - try { - complete_url = new URL(webdatPath); - } catch (MalformedURLException e) { - // should never happend - sendResult(false, handler, context, "URL error"); - return false; - } - - // version 2.0 success - if (tryGetWebdav(complete_url, username, password, handler, context)) { - sendResult(true, handler, context, complete_url.toString()); - return true; - } - - if (mResultMsg.equals("401")) { - sendResult(false, handler, context, "Invalid login or/and password"); - return false; - } - - if (!mResultMsg.equals("404")) { - sendResult(false, handler, context, "Server error: " + mResultMsg); - return false; - } - - webdatPath = strippedPath + WEBDAV_PATH_1_2; - try { - complete_url = new URL(webdatPath); - } catch (MalformedURLException e) { - // should never happend - sendResult(false, handler, context, "URL error"); - return false; - } - - // version 1.2 success - if (tryGetWebdav(complete_url, username, password, handler, context)) { - sendResult(true, handler, context, complete_url.toString()); - return true; - } - - if (mResultMsg.equals("401")) { - sendResult(false, handler, context, "Invalid login or/and password"); - return false; - } - - if (mResultMsg.equals("404")) { - sendResult(false, handler, context, "Wrong path given"); - return false; - } - - sendResult(false, handler, context, "Server error: " + mResultMsg); - return false; - } - - public static boolean tryGetWebdav(URL url, String username, String pwd, - Handler handler, Context context) { - SchemeRegistry schemeRegistry = new SchemeRegistry(); - // http scheme - schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - // https scheme - schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); - - HttpParams params = new BasicHttpParams(); - params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); - params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); - params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); - HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); - - ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); - - DefaultHttpClient c = new DefaultHttpClient(cm, params); - - c.getCredentialsProvider().setCredentials( - new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()), - new UsernamePasswordCredentials(username, pwd)); - - BasicHttpContext localcontext = new BasicHttpContext(); - BasicScheme basicAuth = new BasicScheme(); - - localcontext.setAttribute("preemptive-auth", basicAuth); - HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1) - ? 80 - : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http"); - HttpHead httpget = new HttpHead(url.toString()); - httpget.setHeader("Host", url.getHost()); - HttpResponse response = null; - try { - response = c.execute(targetHost, httpget, localcontext); - } catch (ClientProtocolException e1) { - sendResult(false, handler, context, "Protocol error: " - + e1.getLocalizedMessage()); - return false; - } catch (UnknownHostException e1) { - mResultMsg = "Unknowh host: " + e1.getLocalizedMessage(); - return false; - } catch (IOException e1) { - mResultMsg = "Error: " + e1.getLocalizedMessage(); - return false; - } - String status = response.getStatusLine().toString(); - - status = status.split(" ")[1]; - Log.i("AuthUtils", "Status returned: " + status); - if (status.equals("200")) { - return true; - } else if (status.equals("404")) { - mResultMsg = "404"; - return false; - } else if (status.equals("401")) { - mResultMsg = "401"; - return false; - } - mResultMsg = status; - return false; - } - - public static Thread performOnBackgroundThread(final Runnable r) { - final Thread t = new Thread() { - @Override - public void run() { - try { - r.run(); - } finally {} - } - }; - t.start(); - return t; - } - - public static void sendResult(final Boolean result, - final Handler handler, - final Context context, - final String message) { - if (handler == null || context == null) { - return; - } - handler.post(new Runnable() { - public void run() { - ((AuthenticatorActivity) context).onAuthenticationResult(result, message); - } - }); - } - - public static Thread attemptAuth(final URL url, final String username, - final String password, final Handler handler, - final Context context) { - final Runnable r = new Runnable() { - - public void run() { - authenticate(url, username, password, handler, context); - } - }; - return performOnBackgroundThread(r); - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package eu.alefzero.owncloud.authenticator; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; + +import javax.net.SocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; + +import org.apache.http.impl.client.DefaultHttpClient; + +import org.apache.commons.httpclient.auth.BasicScheme; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.conn.params.ConnManagerPNames; +import org.apache.http.conn.params.ConnPerRouteBean; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.conn.SingleClientConnManager; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.BasicHttpContext; + +import eu.alefzero.owncloud.ui.activity.AuthenticatorActivity; + + +import android.content.Context; +import android.os.Handler; +import android.util.Log; + +public class AuthUtils { + public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; + public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; + public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php"; + + private static String mResultMsg = ""; + + public static boolean authenticate(URL url, String username, String password, + Handler handler, Context context) { + String strippedPath = url.toString().endsWith("/") ? + url.toString().substring(0, url.toString().length()-1) : + url.toString(); + String webdatPath = strippedPath + WEBDAV_PATH_2_0; + URL complete_url = null; + try { + complete_url = new URL(webdatPath); + } catch (MalformedURLException e) { + // should never happend + sendResult(false, handler, context, "URL error"); + return false; + } + + // version 2.0 success + if (tryGetWebdav(complete_url, username, password, handler, context)) { + sendResult(true, handler, context, complete_url.toString()); + return true; + } + + if (mResultMsg.equals("401")) { + sendResult(false, handler, context, "Invalid login or/and password"); + return false; + } + + if (!mResultMsg.equals("404")) { + sendResult(false, handler, context, "Server error: " + mResultMsg); + return false; + } + + webdatPath = strippedPath + WEBDAV_PATH_1_2; + try { + complete_url = new URL(webdatPath); + } catch (MalformedURLException e) { + // should never happend + sendResult(false, handler, context, "URL error"); + return false; + } + + // version 1.2 success + if (tryGetWebdav(complete_url, username, password, handler, context)) { + sendResult(true, handler, context, complete_url.toString()); + return true; + } + + if (mResultMsg.equals("401")) { + sendResult(false, handler, context, "Invalid login or/and password"); + return false; + } + + if (mResultMsg.equals("404")) { + sendResult(false, handler, context, "Wrong path given"); + return false; + } + + sendResult(false, handler, context, "Server error: " + mResultMsg); + return false; + } + + public static boolean tryGetWebdav(URL url, String username, String pwd, + Handler handler, Context context) { + SchemeRegistry schemeRegistry = new SchemeRegistry(); + // http scheme + schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + // https scheme + schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); + + HttpParams params = new BasicHttpParams(); + params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); + params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); + params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + + ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); + + DefaultHttpClient c = new DefaultHttpClient(cm, params); + + c.getCredentialsProvider().setCredentials( + new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()), + new UsernamePasswordCredentials(username, pwd)); + + BasicHttpContext localcontext = new BasicHttpContext(); + BasicScheme basicAuth = new BasicScheme(); + + localcontext.setAttribute("preemptive-auth", basicAuth); + HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1) + ? 80 + : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http"); + HttpHead httpget = new HttpHead(url.toString()); + httpget.setHeader("Host", url.getHost()); + HttpResponse response = null; + try { + response = c.execute(targetHost, httpget, localcontext); + } catch (ClientProtocolException e1) { + sendResult(false, handler, context, "Protocol error: " + + e1.getLocalizedMessage()); + return false; + } catch (UnknownHostException e1) { + mResultMsg = "Unknowh host: " + e1.getLocalizedMessage(); + return false; + } catch (IOException e1) { + mResultMsg = "Error: " + e1.getLocalizedMessage(); + return false; + } + String status = response.getStatusLine().toString(); + + status = status.split(" ")[1]; + Log.i("AuthUtils", "Status returned: " + status); + if (status.equals("200")) { + return true; + } else if (status.equals("404")) { + mResultMsg = "404"; + return false; + } else if (status.equals("401")) { + mResultMsg = "401"; + return false; + } + mResultMsg = status; + return false; + } + + public static Thread performOnBackgroundThread(final Runnable r) { + final Thread t = new Thread() { + @Override + public void run() { + try { + r.run(); + } finally {} + } + }; + t.start(); + return t; + } + + public static void sendResult(final Boolean result, + final Handler handler, + final Context context, + final String message) { + if (handler == null || context == null) { + return; + } + handler.post(new Runnable() { + public void run() { + ((AuthenticatorActivity) context).onAuthenticationResult(result, message); + } + }); + } + + public static Thread attemptAuth(final URL url, final String username, + final String password, final Handler handler, + final Context context) { + final Runnable r = new Runnable() { + + public void run() { + authenticate(url, username, password, handler, context); + } + }; + return performOnBackgroundThread(r); + } +} diff --git a/src/eu/alefzero/owncloud/cp.java b/src/eu/alefzero/owncloud/cp.java index bb66bfcf..e4436012 100644 --- a/src/eu/alefzero/owncloud/cp.java +++ b/src/eu/alefzero/owncloud/cp.java @@ -1,210 +1,215 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud; - -import java.util.HashMap; - -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; - -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.text.TextUtils; - -public class cp extends ContentProvider { - - private DataBaseHelper mDbHelper; - - private static HashMap mProjectionMap; - static { - mProjectionMap = new HashMap(); - mProjectionMap.put(ProviderTableMeta._ID, - ProviderTableMeta._ID); - mProjectionMap.put(ProviderTableMeta.FILE_PARENT, - ProviderTableMeta.FILE_PARENT); - mProjectionMap.put(ProviderTableMeta.FILE_PATH, - ProviderTableMeta.FILE_PATH); - mProjectionMap.put(ProviderTableMeta.FILE_NAME, - ProviderTableMeta.FILE_NAME); - mProjectionMap.put(ProviderTableMeta.FILE_CREATION, - ProviderTableMeta.FILE_CREATION); - mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, - ProviderTableMeta.FILE_MODIFIED); - mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH, - ProviderTableMeta.FILE_CONTENT_LENGTH); - mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE, - ProviderTableMeta.FILE_CONTENT_TYPE); - mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH, - ProviderTableMeta.FILE_STORAGE_PATH); - } - - private static final int SINGLE_FILE = 1; - private static final int DIRECTORY = 2; - private static final int ROOT_DIRECTORY = 3; - private static final UriMatcher mUriMatcher; - static { - mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); - } - - private static final String TAG = "OC_ContentProvider"; - - @Override - public int delete(Uri uri, String where, String[] whereArgs) { - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - int count = 0; - switch (mUriMatcher.match(uri)) { - case SINGLE_FILE: - count = db.delete(ProviderTableMeta.DB_NAME, - ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1) - + (!TextUtils.isEmpty(where)?" AND (" + where +")" : ""), - whereArgs); - break; - case ROOT_DIRECTORY: - count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); - break; - default: - throw new IllegalArgumentException("Unknown uri: " + uri.toString()); - } - getContext().getContentResolver().notifyChange(uri, null); - return count; - } - - @Override - public String getType(Uri uri) { - switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - return ProviderTableMeta.CONTENT_TYPE; - case SINGLE_FILE: - return ProviderTableMeta.CONTENT_TYPE_ITEM; - default: - throw new IllegalArgumentException("Unknown Uri id." + uri.toString()); - } - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - if (mUriMatcher.match(uri) != SINGLE_FILE) { - throw new IllegalArgumentException("Unknown uri id: " + uri); - } - - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - long rowId = db.insert(ProviderTableMeta.DB_NAME, ProviderTableMeta.FILE_NAME, values); - if (rowId > 0) { - Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); - getContext().getContentResolver().notifyChange(insertedFileUri, null); - return insertedFileUri; - } - throw new SQLException("ERROR " + uri); - } - - @Override - public boolean onCreate() { - mDbHelper = new DataBaseHelper(getContext()); - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); - - sqlQuery.setTables(ProviderTableMeta.DB_NAME); - sqlQuery.setProjectionMap(mProjectionMap); - - switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + " is null"); - break; - case DIRECTORY: - sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="+uri.getPathSegments().get(1)); - break; - case SINGLE_FILE: - if (uri.getPathSegments().size() > 1) { - sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + - uri.getPathSegments().get(1)); - } - break; - default: - throw new IllegalArgumentException("Unknown uri id: " + uri); - } - - String order; - if (TextUtils.isEmpty(sortOrder)) { - order = ProviderTableMeta.DEFAULT_SORT_ORDER; - } else { - order = sortOrder; - } - - SQLiteDatabase db = mDbHelper.getReadableDatabase(); - Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order); - - c.setNotificationUri(getContext().getContentResolver(), uri); - - return c; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - return mDbHelper.getWritableDatabase().update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs); - } - - class DataBaseHelper extends SQLiteOpenHelper { - - public DataBaseHelper(Context context) { - super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION); - - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" + - ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + - ProviderTableMeta.FILE_NAME + " TEXT, " + - ProviderTableMeta.FILE_PATH + " TEXT, " + - ProviderTableMeta.FILE_PARENT + " INTEGER, " + - ProviderTableMeta.FILE_CREATION + " INTEGER, " + - ProviderTableMeta.FILE_MODIFIED + " INTEGER, " + - ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " + - ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " + - ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " + - ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT);"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - - } - - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package eu.alefzero.owncloud; + +import java.util.HashMap; + +import eu.alefzero.owncloud.db.ProviderMeta; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.text.TextUtils; + +/** +* The ContentProvider for the ownCloud App. +* @author Bartek Przybylski +* +*/ +public class cp extends ContentProvider { + + private DataBaseHelper mDbHelper; + + private static HashMap mProjectionMap; + static { + mProjectionMap = new HashMap(); + mProjectionMap.put(ProviderTableMeta._ID, + ProviderTableMeta._ID); + mProjectionMap.put(ProviderTableMeta.FILE_PARENT, + ProviderTableMeta.FILE_PARENT); + mProjectionMap.put(ProviderTableMeta.FILE_PATH, + ProviderTableMeta.FILE_PATH); + mProjectionMap.put(ProviderTableMeta.FILE_NAME, + ProviderTableMeta.FILE_NAME); + mProjectionMap.put(ProviderTableMeta.FILE_CREATION, + ProviderTableMeta.FILE_CREATION); + mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, + ProviderTableMeta.FILE_MODIFIED); + mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH, + ProviderTableMeta.FILE_CONTENT_LENGTH); + mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE, + ProviderTableMeta.FILE_CONTENT_TYPE); + mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH, + ProviderTableMeta.FILE_STORAGE_PATH); + } + + private static final int SINGLE_FILE = 1; + private static final int DIRECTORY = 2; + private static final int ROOT_DIRECTORY = 3; + private static final UriMatcher mUriMatcher; + static { + mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); + mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); + } + + private static final String TAG = "OC_ContentProvider"; + + @Override + public int delete(Uri uri, String where, String[] whereArgs) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + int count = 0; + switch (mUriMatcher.match(uri)) { + case SINGLE_FILE: + count = db.delete(ProviderTableMeta.DB_NAME, + ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1) + + (!TextUtils.isEmpty(where)?" AND (" + where +")" : ""), + whereArgs); + break; + case ROOT_DIRECTORY: + count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); + break; + default: + throw new IllegalArgumentException("Unknown uri: " + uri.toString()); + } + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + @Override + public String getType(Uri uri) { + switch (mUriMatcher.match(uri)) { + case ROOT_DIRECTORY: + return ProviderTableMeta.CONTENT_TYPE; + case SINGLE_FILE: + return ProviderTableMeta.CONTENT_TYPE_ITEM; + default: + throw new IllegalArgumentException("Unknown Uri id." + uri.toString()); + } + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + if (mUriMatcher.match(uri) != SINGLE_FILE) { + throw new IllegalArgumentException("Unknown uri id: " + uri); + } + + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + long rowId = db.insert(ProviderTableMeta.DB_NAME, ProviderTableMeta.FILE_NAME, values); + if (rowId > 0) { + Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); + getContext().getContentResolver().notifyChange(insertedFileUri, null); + return insertedFileUri; + } + throw new SQLException("ERROR " + uri); + } + + @Override + public boolean onCreate() { + mDbHelper = new DataBaseHelper(getContext()); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); + + sqlQuery.setTables(ProviderTableMeta.DB_NAME); + sqlQuery.setProjectionMap(mProjectionMap); + + switch (mUriMatcher.match(uri)) { + case ROOT_DIRECTORY: + sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + " is null"); + break; + case DIRECTORY: + sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="+uri.getPathSegments().get(1)); + break; + case SINGLE_FILE: + if (uri.getPathSegments().size() > 1) { + sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + + uri.getPathSegments().get(1)); + } + break; + default: + throw new IllegalArgumentException("Unknown uri id: " + uri); + } + + String order; + if (TextUtils.isEmpty(sortOrder)) { + order = ProviderTableMeta.DEFAULT_SORT_ORDER; + } else { + order = sortOrder; + } + + SQLiteDatabase db = mDbHelper.getReadableDatabase(); + Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order); + + c.setNotificationUri(getContext().getContentResolver(), uri); + + return c; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, + String[] selectionArgs) { + return mDbHelper.getWritableDatabase().update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs); + } + + class DataBaseHelper extends SQLiteOpenHelper { + + public DataBaseHelper(Context context) { + super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION); + + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + + ProviderTableMeta.FILE_NAME + " TEXT, " + + ProviderTableMeta.FILE_PATH + " TEXT, " + + ProviderTableMeta.FILE_PARENT + " INTEGER, " + + ProviderTableMeta.FILE_CREATION + " INTEGER, " + + ProviderTableMeta.FILE_MODIFIED + " INTEGER, " + + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " + + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " + + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " + + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT);"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + + } + +} diff --git a/src/eu/alefzero/owncloud/db/DbHandler.java b/src/eu/alefzero/owncloud/db/DbHandler.java new file mode 100644 index 00000000..d2e0b118 --- /dev/null +++ b/src/eu/alefzero/owncloud/db/DbHandler.java @@ -0,0 +1,103 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.db; + +import java.util.Vector; + +import eu.alefzero.owncloud.OwnCloudSession; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +/** + * Custom database helper for ownCloud + * @author Bartek Przybylski + * + */ +public class DbHandler { + private SQLiteDatabase mDB; + private OpenerHepler mHelper; + private final String mDatabaseName = "ownCloud"; + private final String TABLE_SESSIONS = "sessions"; + private final int mDatabaseVersion = 1; + + public DbHandler(Context context) { + mHelper = new OpenerHepler(context); + mDB = mHelper.getWritableDatabase(); + } + + public Vector getSessionList() { + Cursor c = mDB.query(TABLE_SESSIONS, null, null, null, null, null, null); + Vector v = new Vector(); + if (!c.moveToFirst()) { + return v; + } + while (!c.isAfterLast()) { + v.add(new OwnCloudSession(c.getString(c.getColumnIndex("sessionName")), + c.getString(c.getColumnIndex("sessionUrl")), + c.getInt(c.getColumnIndex("_id")))); + c.moveToNext(); + } + c.close(); + return v; + } + + public void addSession(String sessionName, String uri) { + ContentValues cv = new ContentValues(); + cv.put("sessionName", sessionName); + cv.put("sessionUrl", uri); + mDB.insert(TABLE_SESSIONS, null, cv); + } + + public void removeSessionWithId(int sessionId) { + mDB.delete(TABLE_SESSIONS, "_id = ?", new String[] {String.valueOf(sessionId)}); + } + + public void changeSessionFields(int id, String hostname, String uri) { + ContentValues cv = new ContentValues(); + cv.put("sessionName", hostname); + cv.put("sessionUrl", uri); + mDB.update(TABLE_SESSIONS, cv, "_id = ?", new String[] {String.valueOf(id)}); + } + + public void close() { + mDB.close(); + } + + private class OpenerHepler extends SQLiteOpenHelper { + public OpenerHepler(Context context) { + super(context, mDatabaseName, null, mDatabaseVersion); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_SESSIONS + " (" + + " _id INTEGER PRIMARY KEY, " + + " sessionName TEXT, " + + " sessionUrl TEXT);"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + } + } +} diff --git a/src/eu/alefzero/owncloud/db/ProviderMeta.java b/src/eu/alefzero/owncloud/db/ProviderMeta.java index d5d86ca6..591edaf8 100644 --- a/src/eu/alefzero/owncloud/db/ProviderMeta.java +++ b/src/eu/alefzero/owncloud/db/ProviderMeta.java @@ -1,59 +1,64 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.db; - -import android.net.Uri; -import android.provider.BaseColumns; - -public class ProviderMeta { - - public static final String AUTHORITY_FILES = "org.owncloud"; - public static final String DB_FILE = "owncloud.db"; - public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 1; - - private ProviderMeta() { } - - static public class ProviderTableMeta implements BaseColumns { - public static final String DB_NAME = "filelist"; - public static final Uri CONTENT_URI = - Uri.parse("content://" + AUTHORITY_FILES + "/"); - public static final Uri CONTENT_URI_FILE = - Uri.parse("content://" + AUTHORITY_FILES + "/file"); - public static final Uri CONTENT_URI_DIR = - Uri.parse("content://" + AUTHORITY_FILES + "/dir"); - - public static final String CONTENT_TYPE = - "vnd.android.cursor.dir/vnd.owncloud.file"; - public static final String CONTENT_TYPE_ITEM = - "vnd.android.cursor.item/vnd.owncloud.file"; - - public static final String FILE_PARENT = "parent"; - public static final String FILE_NAME = "filename"; - public static final String FILE_CREATION = "created"; - public static final String FILE_MODIFIED = "modified"; - public static final String FILE_CONTENT_LENGTH = "content_length"; - public static final String FILE_CONTENT_TYPE = "content_type"; - public static final String FILE_STORAGE_PATH = "media_path"; - public static final String FILE_PATH = "path"; - public static final String FILE_ACCOUNT_OWNER = "file_owner"; - - public static final String DEFAULT_SORT_ORDER = FILE_NAME + " asc"; - - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.db; + +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * Meta-Class that holds various static field information + * @author Bartek Przybylski + * + */ +public class ProviderMeta { + + public static final String AUTHORITY_FILES = "org.owncloud"; + public static final String DB_FILE = "owncloud.db"; + public static final String DB_NAME = "filelist"; + public static final int DB_VERSION = 1; + + private ProviderMeta() { } + + static public class ProviderTableMeta implements BaseColumns { + public static final String DB_NAME = "filelist"; + public static final Uri CONTENT_URI = + Uri.parse("content://" + AUTHORITY_FILES + "/"); + public static final Uri CONTENT_URI_FILE = + Uri.parse("content://" + AUTHORITY_FILES + "/file"); + public static final Uri CONTENT_URI_DIR = + Uri.parse("content://" + AUTHORITY_FILES + "/dir"); + + public static final String CONTENT_TYPE = + "vnd.android.cursor.dir/vnd.owncloud.file"; + public static final String CONTENT_TYPE_ITEM = + "vnd.android.cursor.item/vnd.owncloud.file"; + + public static final String FILE_PARENT = "parent"; + public static final String FILE_NAME = "filename"; + public static final String FILE_CREATION = "created"; + public static final String FILE_MODIFIED = "modified"; + public static final String FILE_CONTENT_LENGTH = "content_length"; + public static final String FILE_CONTENT_TYPE = "content_type"; + public static final String FILE_STORAGE_PATH = "media_path"; + public static final String FILE_PATH = "path"; + public static final String FILE_ACCOUNT_OWNER = "file_owner"; + + public static final String DEFAULT_SORT_ORDER = FILE_NAME + " asc"; + + } +} diff --git a/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java index 524904f3..3c1caf95 100644 --- a/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java +++ b/src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java @@ -1,171 +1,188 @@ -package eu.alefzero.owncloud.syncadapter; - -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.Date; -import java.util.LinkedList; - -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.AbstractThreadedSyncAdapter; -import android.content.ContentProviderClient; -import android.content.Context; -import android.net.Uri; -import android.text.TextUtils; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.webdav.HttpPropFind; -import eu.alefzero.webdav.TreeNode; -import eu.alefzero.webdav.TreeNode.NodeProperty; -import eu.alefzero.webdav.WebdavUtils; - -/** - * Base SyncAdapter for OwnCloud - * Designed to be subclassed for the concreete SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc.. - * - * @author sassman - * - */ -public abstract class AbstractOwnCloudSyncAdapter extends AbstractThreadedSyncAdapter { - - private AccountManager accountManager; - private Account account; - private ContentProviderClient contentProvider; - private Date lastUpdated; - - private DefaultHttpClient client = null; - private HttpHost host; - - public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - this.setAccountManager(AccountManager.get(context)); - } - - public AccountManager getAccountManager() { - return accountManager; - } - - public void setAccountManager(AccountManager accountManager) { - this.accountManager = accountManager; - } - - public Account getAccount() { - return account; - } - - public void setAccount(Account account) { - this.account = account; - } - - public ContentProviderClient getContentProvider() { - return contentProvider; - } - - public void setContentProvider(ContentProviderClient contentProvider) { - this.contentProvider = contentProvider; - } - - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - - protected ConnectionKeepAliveStrategy getKeepAliveStrategy() { - return new ConnectionKeepAliveStrategy() { - public long getKeepAliveDuration(HttpResponse response, HttpContext context) { - // TODO: change keep alive straategy basing on response: ie forbidden/not found/etc - // should have keep alive 0 - // default return: 5s - return 5 * 1000; - } - }; - } - - protected HttpPropFind getPropFindQuery() throws OperationCanceledException, AuthenticatorException, IOException { - HttpPropFind query = new HttpPropFind(getUri().toString()); - query.setHeader("Content-type", "text/xml"); - query.setHeader("User-Agent", "Android-ownCloud"); - return query; - } - - protected HttpResponse fireRawRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException { - BasicHttpContext httpContext = new BasicHttpContext(); - BasicScheme basicAuth = new BasicScheme(); - httpContext.setAttribute("preemptive-auth", basicAuth); - - HttpResponse response = getClient().execute(this.host, query, httpContext); - return response; - } - - protected TreeNode fireRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException { - HttpResponse response = fireRawRequest(query); - - TreeNode root = new TreeNode(); - root.setProperty(TreeNode.NodeProperty.NAME, "/"); - this.parseResponse(response, getUri(), getClient(), this.host, root.getChildList()); - return root; - } - - protected Uri getUri() { - return Uri.parse(this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL)); - } - - private DefaultHttpClient getClient() throws OperationCanceledException, AuthenticatorException, IOException { - if(this.client == null) { - String username = getAccount().name.split("@")[0]; - String password = this.getAccountManager().blockingGetAuthToken(getAccount(), AccountAuthenticator.AUTH_TOKEN_TYPE, true); - if (this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL) == null) { - throw new UnknownHostException(); - } - Uri uri = getUri(); - - int port = (uri.getPort() == -1) ? 80 : uri.getPort(); - this.client = new DefaultHttpClient(); - this.client.getCredentialsProvider().setCredentials( - new AuthScope(uri.getHost(), port), - new UsernamePasswordCredentials(username, password) - ); - this.client.setKeepAliveStrategy(this.getKeepAliveStrategy()); - this.host = new HttpHost(uri.getHost(), port, (uri.getScheme() == "https") ? "https" : "http"); - } - - return this.client; - } - - private void parseResponse(HttpResponse resp, Uri uri, DefaultHttpClient client, HttpHost targetHost, LinkedList insertList) throws IOException, OperationCanceledException, AuthenticatorException { - boolean skipFirst = true; - for (TreeNode n :WebdavUtils.parseResponseToNodes(resp.getEntity().getContent())) { - String path = n.stripPathFromFilename(uri.getPath()); - if (skipFirst) { - skipFirst = false; - continue; - } - insertList.add(n); - - if (!TextUtils.isEmpty(n.getProperty(NodeProperty.NAME)) && - n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) { - - HttpPropFind method = new HttpPropFind(uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/"); - HttpResponse response = fireRawRequest(method); - parseResponse(response, uri, client, targetHost, n.getChildList()); - } - } - } - +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.syncadapter; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.Date; +import java.util.LinkedList; + +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.Context; +import android.net.Uri; +import android.text.TextUtils; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.webdav.HttpPropFind; +import eu.alefzero.webdav.TreeNode; +import eu.alefzero.webdav.TreeNode.NodeProperty; +import eu.alefzero.webdav.WebdavUtils; + +/** + * Base SyncAdapter for OwnCloud + * Designed to be subclassed for the concreete SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc.. + * + * @author sassman + * + */ +public abstract class AbstractOwnCloudSyncAdapter extends AbstractThreadedSyncAdapter { + + private AccountManager accountManager; + private Account account; + private ContentProviderClient contentProvider; + private Date lastUpdated; + + private DefaultHttpClient client = null; + private HttpHost host; + + public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + this.setAccountManager(AccountManager.get(context)); + } + + public AccountManager getAccountManager() { + return accountManager; + } + + public void setAccountManager(AccountManager accountManager) { + this.accountManager = accountManager; + } + + public Account getAccount() { + return account; + } + + public void setAccount(Account account) { + this.account = account; + } + + public ContentProviderClient getContentProvider() { + return contentProvider; + } + + public void setContentProvider(ContentProviderClient contentProvider) { + this.contentProvider = contentProvider; + } + + public Date getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + protected ConnectionKeepAliveStrategy getKeepAliveStrategy() { + return new ConnectionKeepAliveStrategy() { + public long getKeepAliveDuration(HttpResponse response, HttpContext context) { + // TODO: change keep alive straategy basing on response: ie forbidden/not found/etc + // should have keep alive 0 + // default return: 5s + return 5 * 1000; + } + }; + } + + protected HttpPropFind getPropFindQuery() throws OperationCanceledException, AuthenticatorException, IOException { + HttpPropFind query = new HttpPropFind(getUri().toString()); + query.setHeader("Content-type", "text/xml"); + query.setHeader("User-Agent", "Android-ownCloud"); + return query; + } + + protected HttpResponse fireRawRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException { + BasicHttpContext httpContext = new BasicHttpContext(); + BasicScheme basicAuth = new BasicScheme(); + httpContext.setAttribute("preemptive-auth", basicAuth); + + HttpResponse response = getClient().execute(this.host, query, httpContext); + return response; + } + + protected TreeNode fireRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException { + HttpResponse response = fireRawRequest(query); + + TreeNode root = new TreeNode(); + root.setProperty(TreeNode.NodeProperty.NAME, "/"); + this.parseResponse(response, getUri(), getClient(), this.host, root.getChildList()); + return root; + } + + protected Uri getUri() { + return Uri.parse(this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL)); + } + + private DefaultHttpClient getClient() throws OperationCanceledException, AuthenticatorException, IOException { + if(this.client == null) { + String username = getAccount().name.split("@")[0]; + String password = this.getAccountManager().blockingGetAuthToken(getAccount(), AccountAuthenticator.AUTH_TOKEN_TYPE, true); + if (this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL) == null) { + throw new UnknownHostException(); + } + Uri uri = getUri(); + + int port = (uri.getPort() == -1) ? 80 : uri.getPort(); + this.client = new DefaultHttpClient(); + this.client.getCredentialsProvider().setCredentials( + new AuthScope(uri.getHost(), port), + new UsernamePasswordCredentials(username, password) + ); + this.client.setKeepAliveStrategy(this.getKeepAliveStrategy()); + this.host = new HttpHost(uri.getHost(), port, (uri.getScheme() == "https") ? "https" : "http"); + } + + return this.client; + } + + private void parseResponse(HttpResponse resp, Uri uri, DefaultHttpClient client, HttpHost targetHost, LinkedList insertList) throws IOException, OperationCanceledException, AuthenticatorException { + boolean skipFirst = true; + for (TreeNode n :WebdavUtils.parseResponseToNodes(resp.getEntity().getContent())) { + String path = n.stripPathFromFilename(uri.getPath()); + if (skipFirst) { + skipFirst = false; + continue; + } + insertList.add(n); + + if (!TextUtils.isEmpty(n.getProperty(NodeProperty.NAME)) && + n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) { + + HttpPropFind method = new HttpPropFind(uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/"); + HttpResponse response = fireRawRequest(method); + parseResponse(response, uri, client, targetHost, n.getChildList()); + } + } + } + } \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java index bf00240e..ef9da411 100644 --- a/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java +++ b/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java @@ -1,140 +1,142 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.syncadapter; - -import java.io.IOException; - -import org.apache.http.entity.StringEntity; - -import android.accounts.Account; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.ContentProviderClient; -import android.content.ContentValues; -import android.content.Context; -import android.content.SyncResult; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.RemoteException; -import android.util.Log; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.webdav.HttpPropFind; -import eu.alefzero.webdav.TreeNode; -import eu.alefzero.webdav.TreeNode.NodeProperty; -import eu.alefzero.webdav.WebdavUtils; - -/** - * SyncAdapter implementation for syncing sample SyncAdapter contacts to the - * platform ContactOperations provider. - */ -public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { - private static final String TAG = "FileSyncAdapter"; - - public FileSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - - @Override - public synchronized void onPerformSync( - Account account, - Bundle extras, - String authority, - ContentProviderClient provider, - SyncResult syncResult) { - - try { - this.setAccount(account); - this.setContentProvider(provider); - - HttpPropFind query = this.getPropFindQuery(); - query.setEntity(new StringEntity(WebdavUtils.prepareXmlForPropFind())); - TreeNode root = this.fireRequest(query); - - commitToDatabase(root, null); - } catch (OperationCanceledException e) { - e.printStackTrace(); - } catch (AuthenticatorException e) { - syncResult.stats.numAuthExceptions++; - e.printStackTrace(); - } catch (IOException e) { - syncResult.stats.numIoExceptions++; - e.printStackTrace(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - private void commitToDatabase(TreeNode root, String parentId) throws RemoteException { - for (TreeNode n : root.getChildList()) { - Log.d(TAG, n.toString()); - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, n.getProperty(NodeProperty.CONTENT_LENGTH)); - cv.put(ProviderTableMeta.FILE_MODIFIED, n.getProperty(NodeProperty.LAST_MODIFIED_DATE)); - cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, n.getProperty(NodeProperty.RESOURCE_TYPE)); - cv.put(ProviderTableMeta.FILE_PARENT, parentId); - - String name = n.getProperty(NodeProperty.NAME), - path = n.getProperty(NodeProperty.PATH); - Cursor c = this.getContentProvider().query(ProviderTableMeta.CONTENT_URI_FILE, - null, - ProviderTableMeta.FILE_NAME+"=? AND " + ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[]{name, path, this.getAccount().name}, - null); - if (c.moveToFirst()) { - this.getContentProvider().update(ProviderTableMeta.CONTENT_URI, - cv, - ProviderTableMeta._ID+"=?", - new String[]{c.getString(c.getColumnIndex(ProviderTableMeta._ID))}); - Log.d(TAG, "ID of: "+name+":"+c.getString(c.getColumnIndex(ProviderTableMeta._ID))); - } else { - cv.put(ProviderTableMeta.FILE_NAME, n.getProperty(NodeProperty.NAME)); - cv.put(ProviderTableMeta.FILE_PATH, n.getProperty(NodeProperty.PATH)); - cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, this.getAccount().name); - Uri entry = this.getContentProvider().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); - Log.d(TAG, "Inserting new entry " + path + name); - c = this.getContentProvider().query(entry, null, null, null, null); - c.moveToFirst(); - } - if (n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) { - commitToDatabase(n, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); - } - } - // clean removed files - String[] selection = new String[root.getChildList().size()+2]; - selection[0] = this.getAccount().name; - selection[1] = parentId; - String qm = ""; - for (int i = 2; i < selection.length-1; ++i) { - qm += "?,"; - selection[i] = root.getChildList().get(i-2).getProperty(NodeProperty.NAME); - } - if (selection.length >= 3) { - selection[selection.length-1] = root.getChildrenNames()[selection.length-3]; - qm += "?"; - } - for (int i = 0; i < selection.length; ++i) { - Log.d(TAG,selection[i]+""); - } - Log.d(TAG,"Removing files "+ parentId); - this.getContentProvider().delete(ProviderTableMeta.CONTENT_URI, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=? AND " + ProviderTableMeta.FILE_PARENT + (parentId==null?" IS ":"=")+"? AND " + ProviderTableMeta.FILE_NAME + " NOT IN ("+qm+")", - selection); - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package eu.alefzero.owncloud.syncadapter; + +import java.io.IOException; + +import org.apache.http.entity.StringEntity; + +import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.ContentProviderClient; +import android.content.ContentValues; +import android.content.Context; +import android.content.SyncResult; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; +import eu.alefzero.webdav.HttpPropFind; +import eu.alefzero.webdav.TreeNode; +import eu.alefzero.webdav.TreeNode.NodeProperty; +import eu.alefzero.webdav.WebdavUtils; + +/** + * SyncAdapter implementation for syncing sample SyncAdapter contacts to the + * platform ContactOperations provider. + * + * @author Bartek Przybylski + */ +public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { + private static final String TAG = "FileSyncAdapter"; + + public FileSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + } + + @Override + public synchronized void onPerformSync( + Account account, + Bundle extras, + String authority, + ContentProviderClient provider, + SyncResult syncResult) { + + try { + this.setAccount(account); + this.setContentProvider(provider); + + HttpPropFind query = this.getPropFindQuery(); + query.setEntity(new StringEntity(WebdavUtils.prepareXmlForPropFind())); + TreeNode root = this.fireRequest(query); + + commitToDatabase(root, null); + } catch (OperationCanceledException e) { + e.printStackTrace(); + } catch (AuthenticatorException e) { + syncResult.stats.numAuthExceptions++; + e.printStackTrace(); + } catch (IOException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + private void commitToDatabase(TreeNode root, String parentId) throws RemoteException { + for (TreeNode n : root.getChildList()) { + Log.d(TAG, n.toString()); + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, n.getProperty(NodeProperty.CONTENT_LENGTH)); + cv.put(ProviderTableMeta.FILE_MODIFIED, n.getProperty(NodeProperty.LAST_MODIFIED_DATE)); + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, n.getProperty(NodeProperty.RESOURCE_TYPE)); + cv.put(ProviderTableMeta.FILE_PARENT, parentId); + + String name = n.getProperty(NodeProperty.NAME), + path = n.getProperty(NodeProperty.PATH); + Cursor c = this.getContentProvider().query(ProviderTableMeta.CONTENT_URI_FILE, + null, + ProviderTableMeta.FILE_NAME+"=? AND " + ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[]{name, path, this.getAccount().name}, + null); + if (c.moveToFirst()) { + this.getContentProvider().update(ProviderTableMeta.CONTENT_URI, + cv, + ProviderTableMeta._ID+"=?", + new String[]{c.getString(c.getColumnIndex(ProviderTableMeta._ID))}); + Log.d(TAG, "ID of: "+name+":"+c.getString(c.getColumnIndex(ProviderTableMeta._ID))); + } else { + cv.put(ProviderTableMeta.FILE_NAME, n.getProperty(NodeProperty.NAME)); + cv.put(ProviderTableMeta.FILE_PATH, n.getProperty(NodeProperty.PATH)); + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, this.getAccount().name); + Uri entry = this.getContentProvider().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); + Log.d(TAG, "Inserting new entry " + path + name); + c = this.getContentProvider().query(entry, null, null, null, null); + c.moveToFirst(); + } + if (n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) { + commitToDatabase(n, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); + } + } + // clean removed files + String[] selection = new String[root.getChildList().size()+2]; + selection[0] = this.getAccount().name; + selection[1] = parentId; + String qm = ""; + for (int i = 2; i < selection.length-1; ++i) { + qm += "?,"; + selection[i] = root.getChildList().get(i-2).getProperty(NodeProperty.NAME); + } + if (selection.length >= 3) { + selection[selection.length-1] = root.getChildrenNames()[selection.length-3]; + qm += "?"; + } + for (int i = 0; i < selection.length; ++i) { + Log.d(TAG,selection[i]+""); + } + Log.d(TAG,"Removing files "+ parentId); + this.getContentProvider().delete(ProviderTableMeta.CONTENT_URI, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=? AND " + ProviderTableMeta.FILE_PARENT + (parentId==null?" IS ":"=")+"? AND " + ProviderTableMeta.FILE_NAME + " NOT IN ("+qm+")", + selection); + } +} diff --git a/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java b/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java index fa8a3542..ed8480ef 100644 --- a/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java +++ b/src/eu/alefzero/owncloud/syncadapter/FileSyncService.java @@ -1,31 +1,53 @@ - -package eu.alefzero.owncloud.syncadapter; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class FileSyncService extends Service { - private static final Object syncAdapterLock = new Object(); - private static AbstractOwnCloudSyncAdapter concretSyncAdapter = null; - - /* - * {@inheritDoc} - */ - @Override - public void onCreate() { - synchronized (syncAdapterLock) { - if (concretSyncAdapter == null) { - concretSyncAdapter = new FileSyncAdapter(getApplicationContext(), true); - } - } - } - - /* - * {@inheritDoc} - */ - @Override - public IBinder onBind(Intent intent) { - return concretSyncAdapter.getSyncAdapterBinder(); - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.syncadapter; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * Background service for syncing files to our + * local Database + * @author Bartek Przybylski + * + */ +public class FileSyncService extends Service { + private static final Object syncAdapterLock = new Object(); + private static AbstractOwnCloudSyncAdapter concretSyncAdapter = null; + + /* + * {@inheritDoc} + */ + @Override + public void onCreate() { + synchronized (syncAdapterLock) { + if (concretSyncAdapter == null) { + concretSyncAdapter = new FileSyncAdapter(getApplicationContext(), true); + } + } + } + + /* + * {@inheritDoc} + */ + @Override + public IBinder onBind(Intent intent) { + return concretSyncAdapter.getSyncAdapterBinder(); + } +} diff --git a/src/eu/alefzero/owncloud/ui/ActionItem.java b/src/eu/alefzero/owncloud/ui/ActionItem.java new file mode 100644 index 00000000..9d53fe0a --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/ActionItem.java @@ -0,0 +1,59 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui; + +import android.graphics.drawable.Drawable; +import android.view.View.OnClickListener; + +/** +* Represents an Item on the ActionBar. +* @author Bartek Przybylski +* +*/ +public class ActionItem { + private Drawable mIcon; + private String mTitle; + private OnClickListener mClickListener; + + public ActionItem() { } + + public void setTitle(String title) { + mTitle = title; + } + + public String getTitle() { + return mTitle; + } + + public void setIcon(Drawable icon) { + mIcon = icon; + } + + public Drawable getIcon() { + return mIcon; + } + + public void setOnClickListener(OnClickListener listener) { + mClickListener = listener; + } + + public OnClickListener getOnClickListerner() { + return mClickListener; + } + +} diff --git a/src/eu/alefzero/owncloud/ui/AuthenticatorActivity.java b/src/eu/alefzero/owncloud/ui/AuthenticatorActivity.java deleted file mode 100644 index a9121609..00000000 --- a/src/eu/alefzero/owncloud/ui/AuthenticatorActivity.java +++ /dev/null @@ -1,186 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.ui; - -import java.net.MalformedURLException; -import java.net.URL; - -import android.accounts.Account; -import android.accounts.AccountAuthenticatorActivity; -import android.accounts.AccountManager; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.ContentResolver; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Color; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.View; -import android.view.Window; -import android.widget.TextView; -import android.widget.Toast; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.authenticator.AuthUtils; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; - -public class AuthenticatorActivity extends AccountAuthenticatorActivity { - private Thread mAuthThread; - private final Handler mHandler = new Handler(); - - public static final String PARAM_USERNAME = "param_Username"; - public static final String PARAM_HOSTNAME = "param_Hostname"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.account_setup); - if (getIntent().hasExtra(PARAM_USERNAME)) { - String username = getIntent().getStringExtra(PARAM_HOSTNAME); - TextView host_text, user_text; - host_text = (TextView) findViewById(R.id.host_URL); - user_text = (TextView) findViewById(R.id.account_username); - host_text.setText(host_text.getText() + username.substring(username.lastIndexOf('@'))); - user_text.setText(user_text.getText() + username.substring(0, username.lastIndexOf('@') - 1)); - } - } - - @Override - protected Dialog onCreateDialog(int id) { - final ProgressDialog dialog = new ProgressDialog(this); - dialog.setMessage("Trying to login"); - dialog.setIndeterminate(true); - dialog.setCancelable(true); - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - Log.i(getClass().getName(), "Login canceled"); - if (mAuthThread != null) { - mAuthThread.interrupt(); - finish(); - } - } - }); - return dialog; - } - - public void onAuthenticationResult(boolean result, String message) { - if (result) { - TextView username_text = (TextView) findViewById(R.id.account_username), - password_text = (TextView) findViewById(R.id.account_password); - - URL url; - try { - url = new URL(message); - } catch (MalformedURLException e) { - // should never happend - Log.e(getClass().getName(), "Malformed URL: " + message); - return; - } - - String username = username_text.getText().toString().trim(); - Account account = new Account(username + "@" + url.getHost(), AccountAuthenticator.ACCOUNT_TYPE); - AccountManager accManager = AccountManager.get(this); - accManager.addAccountExplicitly(account, password_text.getText().toString(), null); - - final Intent intent = new Intent(); - intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE); - intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); - intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE); - accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, url.toString()); - - // TODO prepare this URL during a central service - intent.putExtra(AccountManager.KEY_USERDATA, username); - accManager.setUserData(account, AccountAuthenticator.KEY_CONTACT_URL, - url.toString().replace(AuthUtils.WEBDAV_PATH_2_0, AuthUtils.CARDDAV_PATH_2_0) - ); - - setAccountAuthenticatorResult(intent.getExtras()); - setResult(RESULT_OK, intent); - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, bundle); - - dismissDialog(0); - finish(); - } else { - Toast.makeText(this, message, Toast.LENGTH_LONG).show(); - dismissDialog(0); - } - } - - public void onCancelClick(View view) { - Log.i(getClass().getName(), "Account creating canceled"); - this.finish(); - } - - public void onOkClick(View view) { - TextView url_text = (TextView) findViewById(R.id.host_URL); - TextView username_text = (TextView) findViewById(R.id.account_username); - TextView password_text = (TextView) findViewById(R.id.account_password); - Log.i(getClass().getName(), "OK clicked"); - boolean hasErrors = false; - - URL uri = null; - if (url_text.getText().toString().trim().length() == 0) { - url_text.setTextColor(Color.RED); - hasErrors = true; - } else { - url_text.setTextColor(Color.BLACK); - } - try { - String url_str = url_text.getText().toString(); - if (!url_str.startsWith("http://") && - !url_str.startsWith("https://")) { - url_str = "http://" + url_str; - } - uri = new URL(url_str); - } catch (MalformedURLException e) { - url_text.setTextColor(Color.RED); - e.printStackTrace(); - hasErrors = true; - } - - if (username_text.getText().toString().contains(" ") || - username_text.getText().toString().trim().length() == 0) { - username_text.setTextColor(Color.RED); - hasErrors = true; - } else { - username_text.setTextColor(Color.BLACK); - } - - if (password_text.getText().toString().trim().length() == 0) { - password_text.setTextColor(Color.RED); - hasErrors = true; - } else { - password_text.setTextColor(Color.BLACK); - } - if (hasErrors) { - return; - } - showDialog(0); - mAuthThread = AuthUtils.attemptAuth(uri, - username_text.getText().toString(), - password_text.getText().toString(), - mHandler, - AuthenticatorActivity.this); - } -} diff --git a/src/eu/alefzero/owncloud/ui/CustomPopup.java b/src/eu/alefzero/owncloud/ui/CustomPopup.java new file mode 100644 index 00000000..7709f927 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/CustomPopup.java @@ -0,0 +1,148 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.View.OnTouchListener; +import android.view.ViewGroup.LayoutParams; +import android.widget.PopupWindow; + +/** + * Represents a custom PopupWindows + * @author Lorensius. W. T + * + */ +public class CustomPopup { + protected final View mAnchor; + protected final PopupWindow mWindow; + private View root; + private Drawable background = null; + protected final WindowManager mWManager; + + public CustomPopup(View anchor) { + mAnchor = anchor; + mWindow = new PopupWindow(anchor.getContext()); + + mWindow.setTouchInterceptor(new OnTouchListener() { + + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { + CustomPopup.this.dismiss(); + return true; + } + return false; + } + }); + + mWManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE); + onCreate(); + } + + + public void onCreate() {} + public void onShow() {} + + public void preShow() { + if (root == null) { + throw new IllegalStateException("setContentView called with a view to display"); + } + + onShow(); + + if (background == null) { + mWindow.setBackgroundDrawable(new BitmapDrawable()); + } else { + mWindow.setBackgroundDrawable(background); + } + + mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); + mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); + mWindow.setTouchable(true); + mWindow.setFocusable(true); + mWindow.setOutsideTouchable(true); + + mWindow.setContentView(root); + } + + public void setBackgroundDrawable(Drawable background) { + this.background = background; + } + + public void setContentView(View root) { + this.root = root; + mWindow.setContentView(root); + } + + public void setContentView(int layoutResId) { + LayoutInflater inflater = + (LayoutInflater) mAnchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + setContentView(inflater.inflate(layoutResId, null)); + } + + public void showDropDown() { + showDropDown(0, 0); + } + + public void showDropDown(int x, int y) { + preShow(); + mWindow.setAnimationStyle(android.R.style.Animation_Dialog); + mWindow.showAsDropDown(mAnchor, x, y); + } + + public void showLikeQuickAction() { + showLikeQuickAction(0, 0); + } + + public void showLikeQuickAction(int x, int y) { + preShow(); + + mWindow.setAnimationStyle(android.R.style.Animation_Dialog); + int[] location = new int[2]; + mAnchor.getLocationOnScreen(location); + + Rect anchorRect = + new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); + + root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + + int rootW = root.getWidth(), rootH = root.getHeight(); + int screenW = mWManager.getDefaultDisplay().getWidth(); + + int xpos = ((screenW-rootW)/2) + x; + int ypos = anchorRect.top - rootH + y; + + if (rootH > anchorRect.top) { + ypos = anchorRect.bottom + y; + } + mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos); + } + + public void dismiss() { + mWindow.dismiss(); + } + +} diff --git a/src/eu/alefzero/owncloud/ui/FileDetailActivity.java b/src/eu/alefzero/owncloud/ui/FileDetailActivity.java deleted file mode 100644 index 989a601b..00000000 --- a/src/eu/alefzero/owncloud/ui/FileDetailActivity.java +++ /dev/null @@ -1,38 +0,0 @@ -package eu.alefzero.owncloud.ui; - - -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.R.id; -import eu.alefzero.owncloud.R.layout; -import eu.alefzero.owncloud.ui.fragment.ActionBar; -import eu.alefzero.owncloud.ui.fragment.FileDetail; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentTransaction; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.Window; - -public class FileDetailActivity extends FragmentActivity { - private FileDetail mFileDetail; - -@Override -protected void onCreate(Bundle savedInstanceState) { - // TODO Auto-generated method stub - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.file_activity_details); - - mFileDetail = new FileDetail(); - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - ft.add(R.id.fileDetail, mFileDetail); - ft.commit(); - -} - -} diff --git a/src/eu/alefzero/owncloud/ui/FileDisplayActivity.java b/src/eu/alefzero/owncloud/ui/FileDisplayActivity.java deleted file mode 100644 index eb882a0e..00000000 --- a/src/eu/alefzero/owncloud/ui/FileDisplayActivity.java +++ /dev/null @@ -1,355 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package eu.alefzero.owncloud.ui; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.LinkedList; -import java.util.Stack; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ListActivity; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.DialogInterface.OnCancelListener; -import android.content.res.Configuration; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentTransaction; -import android.text.TextUtils; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; -import eu.alefzero.owncloud.DbHandler; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.R.id; -import eu.alefzero.owncloud.R.layout; -import eu.alefzero.owncloud.R.menu; -import eu.alefzero.owncloud.R.string; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.owncloud.ui.fragment.FileDetail; -import eu.alefzero.owncloud.ui.fragment.FileList; -import eu.alefzero.owncloud.ui.fragment.ActionBar; -public class FileDisplayActivity extends FragmentActivity { - private DbHandler mDBHandler; - private Stack mParents; - private LinkedList mPath; - private Account mAccount; - private Cursor mCursor; - private boolean mIsDisplayingFile; - - private static final int DIALOG_CHOOSE_ACCOUNT = 0; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.files); - - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - //ft.add(R.id.actionBar, new ActionBar()); - ft.add(R.id.fileList, new FileList()); - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - ft.add(R.id.fileDetail, new FileDetail()); - } - ft.commit(); - - /*getSupportFragmentManager().beginTransaction().add(arg0, arg1); - FileList fl = new FileList(); - ft.add(R.id.fileList, fl); - ft.commit(); - /* - - - if (savedInstanceState != null) { - mParents = (Stack)savedInstanceState.getSerializable("parentsStack"); - mIsDisplayingFile = savedInstanceState.getBoolean("isDisplayingFile"); - mPath = (LinkedList)savedInstanceState.getSerializable("path"); - } else { - mParents = new Stack(); - mPath = new LinkedList(); - mIsDisplayingFile = false; - } - - mDBHandler = new DbHandler(getBaseContext()); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.main); - - AccountManager accMan = AccountManager.get(this); - Account[] accounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - - if (accounts.length == 0) { - // using string value since in API7 this constatn is not defined - // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS - // and Settings.EXTRA_AUTHORITIES - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE}); - startActivity(intent); - } else if (accounts.length > 1) { - showDialog(DIALOG_CHOOSE_ACCOUNT); - } else { - mAccount = accounts[0]; - populateFileList(); - }*/ - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.settingsItem : - Intent i = new Intent(this, Preferences.class); - startActivity(i); - break; - } - return true; - } - - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case DIALOG_CHOOSE_ACCOUNT: - return createChooseAccountDialog(); - default: - throw new IllegalArgumentException("Unknown dialog id: " + id); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu, menu); - return true; - } - - private Dialog createChooseAccountDialog() { - final AccountManager accMan = AccountManager.get(this); - CharSequence[] items = new CharSequence[accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; - int i = 0; - for (Account a : accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)) { - items[i++] = a.name; - } - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.common_choose_account); - builder.setCancelable(true); - builder.setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - mAccount = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[item]; - dialog.dismiss(); - populateFileList(); - } - }); - builder.setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - FileDisplayActivity.this.finish(); - } - }); - AlertDialog alert = builder.create(); - return alert; - } - - //@Override - //public void onBackPressed() { - /*PathLayout pl = (PathLayout) findViewById(R.id.pathLayout1); - if (mIsDisplayingFile) { - mIsDisplayingFile = false; - setContentView(R.layout.main); - pl = (PathLayout) findViewById(R.id.pathLayout1); - Uri uri; - if (mParents.empty()) { - uri = ProviderTableMeta.CONTENT_URI; - } else { - uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()); - } - mCursor = managedQuery(uri, - null, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}, null); - - if (mCursor.moveToFirst()) { - String s = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)); - for (String str : s.split("/")) { - if (!TextUtils.isEmpty(str)) - pl.push(DisplayUtils.HtmlDecode(str)); - } - } - getListView().setAdapter(new FileListListAdapter(mCursor, this)); - getListView().invalidate(); - return; - } - if (mParents.size()==0) { - super.onBackPressed(); - return; - } else if (mParents.size() == 1) { - mParents.pop(); - mPath.removeLast(); - pl.pop(); - mCursor = managedQuery(ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}, - null); - } else { - mParents.pop(); - mPath.removeLast(); - pl.pop(); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), - null, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}, - null); - } - - setListAdapter(new FileListListAdapter(mCursor, this)); - getListView().invalidate();*/ - //} - - //@Override -/* protected void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - /*PathLayout pl = (PathLayout) findViewById(R.id.pathLayout1); - if (!mCursor.moveToPosition(position)) { - throw new IndexOutOfBoundsException("Incorrect item selected"); - } - if (!mIsDisplayingFile) { - if (mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) { - String id_ = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); - String dirname = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)); - pl.push(DisplayUtils.HtmlDecode(dirname)); - mPath.addLast(DisplayUtils.HtmlDecode(dirname)); - mParents.push(id_); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, id_), - null, - ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[]{mAccount.name}, null); - setListAdapter(new FileListListAdapter(mCursor, this)); - } else { - mIsDisplayingFile = true; - setContentView(R.layout.file_display); - String id_ = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, id_), - null, - null, - null, - null); - mCursor.moveToFirst(); - // filename - TextView tv = (TextView) findViewById(R.id.textView1); - tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME))); - // filetype - tv = (TextView) findViewById(R.id.textView2); - tv.setText(DisplayUtils.convertMIMEtoPrettyPrint(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)))); - // size - tv = (TextView) findViewById(R.id.textView3); - tv.setText(DisplayUtils.bitsToHumanReadable(mCursor.getLong(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)))); - // modified - tv = (TextView) findViewById(R.id.textView4); - tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_MODIFIED))); - if (!TextUtils.isEmpty(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))) && - mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).matches("image/*")) { - ImageView iv = (ImageView) findViewById(R.id.imageView1); - Bitmap bmp = BitmapFactory.decodeFile(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))); - Matrix m = new Matrix(); - float scale; - if (bmp.getWidth() > bmp.getHeight()) { - scale = (float) (200./bmp.getWidth()); - } else { - scale = (float) (200./bmp.getHeight()); - } - m.postScale(scale, scale); - Bitmap newBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); - iv.setImageBitmap(newBmp); - } - setListAdapter(new FileListActionListAdapter(mCursor, this, mAccount)); - } - getListView().invalidate(); - } else { - Intent i = (Intent) getListAdapter().getItem(position); - if (i.hasExtra("toDownload")) { - - Intent intent = new Intent(this, FileDownloader.class); - intent.putExtra(FileDownloader.EXTRA_FILE_PATH, "/"+((TextView)findViewById(R.id.textView1)).getText().toString()); - intent.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); - startService(intent); - /* - if (i.getBooleanExtra("toDownload", false)) { - startActivityForResult(i, 200); - } else { - startActivity(i); - }*/ - // } - - //} -// } - - private void populateFileList() { - if (mParents.empty()) { - mCursor = getContentResolver().query(ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}, - null); - } else { - mCursor = getContentResolver().query(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), - null, - ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[]{mAccount.name}, null); - if (!mIsDisplayingFile) { - //PathLayout pl = (PathLayout) findViewById(R.id.pathLayout1); - //for (String s : mPath) { - // pl.push(s); - // } - } - } -// setListAdapter(new FileListListAdapter(mCursor, this)); -// getListView().invalidate(); - } - - //@Override - /*protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable("parentsStack", mParents); - outState.putSerializable("path", mPath); - outState.putBoolean("isDisplayingFile", mIsDisplayingFile); - }*/ - -} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/ui/LandingActivity.java b/src/eu/alefzero/owncloud/ui/LandingActivity.java deleted file mode 100644 index afc7a3fe..00000000 --- a/src/eu/alefzero/owncloud/ui/LandingActivity.java +++ /dev/null @@ -1,104 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012 Lennart Rosam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package eu.alefzero.owncloud.ui; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.DialogInterface.OnClickListener; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; - -/** - * This activity is used as a landing page when the user first opens this app. - * - * @author Lennart Rosam - */ -public class LandingActivity extends FragmentActivity implements OnClickListener { - - public static final int DIALOG_SETUP_ACCOUNT = 1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - // Check, if there are ownCloud accounts - if(!accountsAreSetup()){ - showDialog(DIALOG_SETUP_ACCOUNT); - } - - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog; - switch(id){ - case DIALOG_SETUP_ACCOUNT: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.main_tit_accsetup); - builder.setMessage(R.string.main_wrn_accsetup); - builder.setCancelable(false); - builder.setPositiveButton(R.string.common_ok, this); - builder.setNegativeButton(R.string.common_cancel, this); - dialog = builder.create(); - break; - default: - dialog = null; - } - - return dialog; - } - - @Override - public void onClick(DialogInterface dialog, int which) { - // In any case - we won't need it anymore - dialog.dismiss(); - switch(which){ - case DialogInterface.BUTTON_POSITIVE: - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", - new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); - break; - case DialogInterface.BUTTON_NEGATIVE: - finish(); - } - - } - - /** - * Checks, whether or not there are any ownCloud accounts - * setup. - * - * @return true, if there is at least one account. - */ - private boolean accountsAreSetup() { - AccountManager accMan = AccountManager.get(this); - Account[] accounts = accMan - .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - return accounts.length > 0; - } - - -} diff --git a/src/eu/alefzero/owncloud/ui/Preferences.java b/src/eu/alefzero/owncloud/ui/Preferences.java deleted file mode 100644 index 5dc260d5..00000000 --- a/src/eu/alefzero/owncloud/ui/Preferences.java +++ /dev/null @@ -1,146 +0,0 @@ -package eu.alefzero.owncloud.ui; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Vector; - -import eu.alefzero.owncloud.DbHandler; -import eu.alefzero.owncloud.OwnCloudSession; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.R.id; -import eu.alefzero.owncloud.R.menu; -import eu.alefzero.owncloud.R.xml; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceScreen; -import android.util.Log; -import android.view.ContextMenu; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ContextMenu.ContextMenuInfo; -import android.widget.AdapterView.AdapterContextMenuInfo; - -public class Preferences extends PreferenceActivity { - private String TAG = "OwnCloudPreferences"; - private final int mNewSession = 47; - private final int mEditSession = 48; - private DbHandler mDbHandler; - private Vector mSessions; - private int mSelectedMenuItem; - - @Override - public void onCreate(Bundle savedInstanceState){ - super.onCreate(savedInstanceState); - mDbHandler = new DbHandler(getBaseContext()); - mSessions = new Vector(); - addPreferencesFromResource(R.xml.preferences); - registerForContextMenu(getListView()); - //populateSessionList(); - } - - private void populateSessionList() { - mSessions.clear(); - mSessions = mDbHandler.getSessionList(); - PreferenceScreen ps = getPreferenceScreen(); - ps.removeAll(); - addPreferencesFromResource(R.xml.preferences); - for (int i = 0; i < mSessions.size(); i++) { - Preference preference = new Preference(getBaseContext()); - preference.setTitle(mSessions.get(i).getName()); - URI uri; - try { - uri = new URI(mSessions.get(i).getUrl()); - } catch (URISyntaxException e) { - e.printStackTrace(); // should never happend - continue; - } - preference.setSummary(uri.getScheme() + "://" + uri.getHost()+uri.getPath()); - ps.addPreference(preference); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.prefs_menu, menu); - return true; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - super.onMenuItemSelected(featureId, item); - Intent intent; - - switch (item.getItemId()) { - case R.id.addSessionItem: - intent = new Intent(this, PreferencesNewSession.class); - startActivityForResult(intent, mNewSession); - break; - case R.id.SessionContextEdit: - intent = new Intent(this, PreferencesNewSession.class); - intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem).getEntryId()); - intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem).getName()); - intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem).getUrl()); - startActivityForResult(intent, mEditSession); - break; - case R.id.SessionContextRemove: - OwnCloudSession ocs = mSessions.get(mSelectedMenuItem); - mDbHandler.removeSessionWithId(ocs.getEntryId()); - mSessions.remove(ocs); - getPreferenceScreen().removePreference(getPreferenceScreen().getPreference(mSelectedMenuItem+1)); - break; - default: - Log.w(TAG, "Unknown menu item triggered"); - return false; - } - return true; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - switch (requestCode) { - case mNewSession: - mDbHandler.addSession(data.getStringExtra("sessionName"), - data.getStringExtra("sessionURL")); - getPreferenceScreen().removeAll(); - addPreferencesFromResource(R.xml.preferences); - populateSessionList(); - break; - case mEditSession: - mDbHandler.changeSessionFields(data.getIntExtra("sessionId", -1), - data.getStringExtra("sessionName"), - data.getStringExtra("sessionURL")); - populateSessionList(); - break; - } - } - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; - mSelectedMenuItem = info.position-1; - menu.setHeaderTitle(mSessions.get(mSelectedMenuItem).getName()); - - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.session_context_menu, menu); - - } - - @Override - protected void onDestroy() { - mDbHandler.close(); - super.onDestroy(); - } - -} diff --git a/src/eu/alefzero/owncloud/ui/PreferencesNewSession.java b/src/eu/alefzero/owncloud/ui/PreferencesNewSession.java deleted file mode 100644 index 9900abf9..00000000 --- a/src/eu/alefzero/owncloud/ui/PreferencesNewSession.java +++ /dev/null @@ -1,143 +0,0 @@ -package eu.alefzero.owncloud.ui; - -import java.net.URI; -import java.net.URISyntaxException; - -import eu.alefzero.owncloud.authenticator.AccountAuthenticatorService; - -import android.accounts.Account; -import android.accounts.AccountAuthenticatorActivity; -import android.accounts.AccountManager; -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Toast; - -public class PreferencesNewSession extends AccountAuthenticatorActivity implements OnClickListener { - private Intent mReturnData; - private final String TAG = "OwnCloudPreferencesNewSession"; - @Override - public void onCreate(Bundle savedInstanceState){ - super.onCreate(savedInstanceState); - //setContentView(R.layout.add_new_session); - /* - EditText et;// = (EditText) findViewById(R.id.newSession_sessionName); - - et = (EditText) findViewById(R.id.newSession_URL); - if (getIntent().hasExtra("sessionURL")) { - try { - URI uri = new URI(getIntent().getStringExtra("sessionURL")); - String url = uri.getHost(); - if (uri.getPort() != -1) { - url += ":" + String.valueOf(uri.getPort()); - } - if (uri.getPath() != null) { - url += uri.getPath(); - } else { - url += "/"; - } - et.setText(url); - et = (EditText) findViewById(R.id.newSession_username); - if (uri.getAuthority() != null) { - if (uri.getUserInfo().indexOf(':') != -1) { - et.setText(uri.getUserInfo().substring(0, uri.getUserInfo().indexOf(':'))); - et = (EditText) findViewById(R.id.newSession_password); - et.setText(uri.getUserInfo().substring(uri.getUserInfo().indexOf(':')+1)); - } else { - et.setText(uri.getUserInfo()); - } - } - - } catch (URISyntaxException e) { - Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage()); - } - } - - mReturnData = new Intent(); - setResult(Activity.RESULT_OK, mReturnData); - ((Button) findViewById(R.id.button1)).setOnClickListener(this); - ((Button) findViewById(R.id.button2)).setOnClickListener(this);*/ - } - - @Override - protected void onResume() { - super.onResume(); - } - - public void onClick(View v) { - /* switch (v.getId()) { - case R.id.button1: - Intent intent = new Intent(); - if (getIntent().hasExtra("sessionId")) { - intent.putExtra("sessionId", getIntent().getIntExtra("sessionId", -1)); - } - //String sessionName = ((EditText) findViewById(R.id.newSession_sessionName)).getText().toString(); - // if (sessionName.trim().equals("") || !isNameValid(sessionName)) { - // Toast.makeText(this, R.string.new_session_session_name_error, Toast.LENGTH_LONG).show(); - // break; - // } - URI uri = prepareURI(); - if (uri != null) { - //intent.putExtra("sessionName", sessionName); - intent.putExtra("sessionURL", uri.toString()); - setResult(Activity.RESULT_OK, intent); - AccountManager accMgr = AccountManager.get(this); - Account a = new Account("OwnCloud", AccountAuthenticatorService.ACCOUNT_TYPE); - accMgr.addAccountExplicitly(a, "asd", null); - finish(); - } - break; - case R.id.button2: - setResult(Activity.RESULT_CANCELED); - finish(); - break; - }*/ - } - - private URI prepareURI() { - URI uri = null; - /* String url = ""; - try { - String username = ((EditText) findViewById(R.id.newSession_username)).getText().toString().trim(); - String password = ((EditText) findViewById(R.id.newSession_password)).getText().toString().trim(); - String hostname = ((EditText) findViewById(R.id.newSession_URL)).getText().toString().trim(); - String scheme; - if (hostname.matches("[A-Za-z]://")) { - scheme = hostname.substring(0, hostname.indexOf("://")+3); - hostname = hostname.substring(hostname.indexOf("://")+3); - } else { - scheme = "http://"; - } - if (!username.equals("")) { - if (!password.equals("")) { - username += ":" + password + "@"; - } else { - username += "@"; - } - } - url = scheme + username + hostname; - Log.i(TAG, url); - uri = new URI(url); - } catch (URISyntaxException e) { - Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage()); - Toast.makeText(this, R.string.new_session_uri_error, Toast.LENGTH_LONG).show(); - } - */return uri; - } - - private boolean isNameValid(String string) { - return string.matches("[A-Za-z0-9 _-]*"); - } - - @Override - public void onBackPressed() { - setResult(Activity.RESULT_CANCELED); - super.onBackPressed(); - } - -} diff --git a/src/eu/alefzero/owncloud/ui/QuickAction.java b/src/eu/alefzero/owncloud/ui/QuickAction.java new file mode 100644 index 00000000..6f61253b --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/QuickAction.java @@ -0,0 +1,289 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui; + +import android.content.Context; + +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.LinearLayout; +import android.widget.ScrollView; + +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup.LayoutParams; +import android.view.ViewGroup; + +import java.util.ArrayList; + +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.R.id; +import eu.alefzero.owncloud.R.layout; +import eu.alefzero.owncloud.R.style; + +/** + * Popup window, shows action list as icon and text like the one in Gallery3D app. + * + * @author Lorensius. W. T + */ +public class QuickAction extends CustomPopup { + private final View root; + private final ImageView mArrowUp; + private final ImageView mArrowDown; + private final LayoutInflater inflater; + private final Context context; + + protected static final int ANIM_GROW_FROM_LEFT = 1; + protected static final int ANIM_GROW_FROM_RIGHT = 2; + protected static final int ANIM_GROW_FROM_CENTER = 3; + protected static final int ANIM_REFLECT = 4; + protected static final int ANIM_AUTO = 5; + + private int animStyle; + private ViewGroup mTrack; + private ScrollView scroller; + private ArrayList actionList; + + /** + * Constructor + * + * @param anchor {@link View} on where the popup window should be displayed + */ + public QuickAction(View anchor) { + super(anchor); + + actionList = new ArrayList(); + context = anchor.getContext(); + inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + root = (ViewGroup) inflater.inflate(R.layout.popup, null); + + mArrowDown = (ImageView) root.findViewById(R.id.arrow_down); + mArrowUp = (ImageView) root.findViewById(R.id.arrow_up); + + setContentView(root); + + mTrack = (ViewGroup) root.findViewById(R.id.tracks); + scroller = (ScrollView) root.findViewById(R.id.scroller); + animStyle = ANIM_AUTO; + } + + /** + * Set animation style + * + * @param animStyle animation style, default is set to ANIM_AUTO + */ + public void setAnimStyle(int animStyle) { + this.animStyle = animStyle; + } + + /** + * Add action item + * + * @param action {@link ActionItem} object + */ + public void addActionItem(ActionItem action) { + actionList.add(action); + } + + /** + * Show popup window. Popup is automatically positioned, on top or bottom of anchor view. + * + */ + public void show () { + preShow(); + + int xPos, yPos; + + int[] location = new int[2]; + + mAnchor.getLocationOnScreen(location); + + Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + + mAnchor.getHeight()); + + createActionList(); + + root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + + int rootHeight = root.getMeasuredHeight(); + int rootWidth = root.getMeasuredWidth(); + + int screenWidth = mWManager.getDefaultDisplay().getWidth(); + int screenHeight = mWManager.getDefaultDisplay().getHeight(); + + //automatically get X coord of popup (top left) + if ((anchorRect.left + rootWidth) > screenWidth) { + xPos = anchorRect.left - (rootWidth-mAnchor.getWidth()); + } else { + if (mAnchor.getWidth() > rootWidth) { + xPos = anchorRect.centerX() - (rootWidth/2); + } else { + xPos = anchorRect.left; + } + } + + int dyTop = anchorRect.top; + int dyBottom = screenHeight - anchorRect.bottom; + + boolean onTop = (dyTop > dyBottom) ? true : false; + + if (onTop) { + if (rootHeight > dyTop) { + yPos = 15; + LayoutParams l = scroller.getLayoutParams(); + l.height = dyTop - mAnchor.getHeight(); + } else { + yPos = anchorRect.top - rootHeight; + } + } else { + yPos = anchorRect.bottom; + + if (rootHeight > dyBottom) { + LayoutParams l = scroller.getLayoutParams(); + l.height = dyBottom; + } + } + + showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), anchorRect.centerX()-xPos); + + setAnimationStyle(screenWidth, anchorRect.centerX(), onTop); + + mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos); + } + + /** + * Set animation style + * + * @param screenWidth screen width + * @param requestedX distance from left edge + * @param onTop flag to indicate where the popup should be displayed. Set TRUE if displayed on top of anchor view + * and vice versa + */ + private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) { + int arrowPos = requestedX - mArrowUp.getMeasuredWidth()/2; + + switch (animStyle) { + case ANIM_GROW_FROM_LEFT: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left); + break; + + case ANIM_GROW_FROM_RIGHT: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right); + break; + + case ANIM_GROW_FROM_CENTER: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center); + break; + + case ANIM_REFLECT: + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect); + break; + + case ANIM_AUTO: + if (arrowPos <= screenWidth/4) { + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left); + } else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) { + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center); + } else { + mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right); + } + + break; + } + } + + /** + * Create action list + */ + private void createActionList() { + View view; + String title; + Drawable icon; + OnClickListener listener; + + for (int i = 0; i < actionList.size(); i++) { + title = actionList.get(i).getTitle(); + icon = actionList.get(i).getIcon(); + listener = actionList.get(i).getOnClickListerner(); + + view = getActionItem(title, icon, listener); + + view.setFocusable(true); + view.setClickable(true); + + mTrack.addView(view); + } + } + + /** + * Get action item {@link View} + * + * @param title action item title + * @param icon {@link Drawable} action item icon + * @param listener {@link View.OnClickListener} action item listener + * @return action item {@link View} + */ + private View getActionItem(String title, Drawable icon, OnClickListener listener) { + LinearLayout container = (LinearLayout) inflater.inflate(R.layout.action_item, null); + + ImageView img = (ImageView) container.findViewById(R.id.icon); + TextView text = (TextView) container.findViewById(R.id.title); + + if (icon != null) { + img.setImageDrawable(icon); + } + + if (title != null) { + text.setText(title); + } + + if (listener != null) { + container.setOnClickListener(listener); + } + + return container; + } + + /** + * Show arrow + * + * @param whichArrow arrow type resource id + * @param requestedX distance from left screen + */ + private void showArrow(int whichArrow, int requestedX) { + final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown; + final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp; + + final int arrowWidth = mArrowUp.getMeasuredWidth(); + + showArrow.setVisibility(View.VISIBLE); + + ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams(); + + param.leftMargin = requestedX - arrowWidth / 2; + + hideArrow.setVisibility(View.INVISIBLE); + } +} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java b/src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java new file mode 100644 index 00000000..79781f3e --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java @@ -0,0 +1,191 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package eu.alefzero.owncloud.ui.activity; + +import java.net.MalformedURLException; +import java.net.URL; + +import android.accounts.Account; +import android.accounts.AccountAuthenticatorActivity; +import android.accounts.AccountManager; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.ContentResolver; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.widget.TextView; +import android.widget.Toast; +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.owncloud.authenticator.AuthUtils; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; + +/** + * This Activity is used to add an ownCloud account to the App + * @author Bartek Przybylski + * + */ +public class AuthenticatorActivity extends AccountAuthenticatorActivity { + private Thread mAuthThread; + private final Handler mHandler = new Handler(); + + public static final String PARAM_USERNAME = "param_Username"; + public static final String PARAM_HOSTNAME = "param_Hostname"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.account_setup); + if (getIntent().hasExtra(PARAM_USERNAME)) { + String username = getIntent().getStringExtra(PARAM_HOSTNAME); + TextView host_text, user_text; + host_text = (TextView) findViewById(R.id.host_URL); + user_text = (TextView) findViewById(R.id.account_username); + host_text.setText(host_text.getText() + username.substring(username.lastIndexOf('@'))); + user_text.setText(user_text.getText() + username.substring(0, username.lastIndexOf('@') - 1)); + } + } + + @Override + protected Dialog onCreateDialog(int id) { + final ProgressDialog dialog = new ProgressDialog(this); + dialog.setMessage("Trying to login"); + dialog.setIndeterminate(true); + dialog.setCancelable(true); + dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + Log.i(getClass().getName(), "Login canceled"); + if (mAuthThread != null) { + mAuthThread.interrupt(); + finish(); + } + } + }); + return dialog; + } + + public void onAuthenticationResult(boolean result, String message) { + if (result) { + TextView username_text = (TextView) findViewById(R.id.account_username), + password_text = (TextView) findViewById(R.id.account_password); + + URL url; + try { + url = new URL(message); + } catch (MalformedURLException e) { + // should never happend + Log.e(getClass().getName(), "Malformed URL: " + message); + return; + } + + String username = username_text.getText().toString().trim(); + Account account = new Account(username + "@" + url.getHost(), AccountAuthenticator.ACCOUNT_TYPE); + AccountManager accManager = AccountManager.get(this); + accManager.addAccountExplicitly(account, password_text.getText().toString(), null); + + final Intent intent = new Intent(); + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); + intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE); + accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, url.toString()); + + // TODO prepare this URL during a central service + intent.putExtra(AccountManager.KEY_USERDATA, username); + accManager.setUserData(account, AccountAuthenticator.KEY_CONTACT_URL, + url.toString().replace(AuthUtils.WEBDAV_PATH_2_0, AuthUtils.CARDDAV_PATH_2_0) + ); + + setAccountAuthenticatorResult(intent.getExtras()); + setResult(RESULT_OK, intent); + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, bundle); + + dismissDialog(0); + finish(); + } else { + Toast.makeText(this, message, Toast.LENGTH_LONG).show(); + dismissDialog(0); + } + } + + public void onCancelClick(View view) { + Log.i(getClass().getName(), "Account creating canceled"); + this.finish(); + } + + public void onOkClick(View view) { + TextView url_text = (TextView) findViewById(R.id.host_URL); + TextView username_text = (TextView) findViewById(R.id.account_username); + TextView password_text = (TextView) findViewById(R.id.account_password); + Log.i(getClass().getName(), "OK clicked"); + boolean hasErrors = false; + + URL uri = null; + if (url_text.getText().toString().trim().length() == 0) { + url_text.setTextColor(Color.RED); + hasErrors = true; + } else { + url_text.setTextColor(Color.BLACK); + } + try { + String url_str = url_text.getText().toString(); + if (!url_str.startsWith("http://") && + !url_str.startsWith("https://")) { + url_str = "http://" + url_str; + } + uri = new URL(url_str); + } catch (MalformedURLException e) { + url_text.setTextColor(Color.RED); + e.printStackTrace(); + hasErrors = true; + } + + if (username_text.getText().toString().contains(" ") || + username_text.getText().toString().trim().length() == 0) { + username_text.setTextColor(Color.RED); + hasErrors = true; + } else { + username_text.setTextColor(Color.BLACK); + } + + if (password_text.getText().toString().trim().length() == 0) { + password_text.setTextColor(Color.RED); + hasErrors = true; + } else { + password_text.setTextColor(Color.BLACK); + } + if (hasErrors) { + return; + } + showDialog(0); + mAuthThread = AuthUtils.attemptAuth(uri, + username_text.getText().toString(), + password_text.getText().toString(), + mHandler, + AuthenticatorActivity.this); + } +} diff --git a/src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java b/src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java new file mode 100644 index 00000000..7aeb9c25 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java @@ -0,0 +1,61 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.activity; + + +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.R.id; +import eu.alefzero.owncloud.R.layout; +import eu.alefzero.owncloud.ui.fragment.ActionBar; +import eu.alefzero.owncloud.ui.fragment.FileDetail; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.Window; + +/** + * This activity displays the details of a file like + * its name, its size and so on. + * @author Bartek Przybylski + * + */ +public class FileDetailActivity extends FragmentActivity { + private FileDetail mFileDetail; + +@Override +protected void onCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.file_activity_details); + + mFileDetail = new FileDetail(); + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.add(R.id.fileDetail, mFileDetail); + ft.commit(); + +} + +} diff --git a/src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java b/src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java new file mode 100644 index 00000000..d27061f1 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java @@ -0,0 +1,361 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package eu.alefzero.owncloud.ui.activity; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.LinkedList; +import java.util.Stack; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ListActivity; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.DialogInterface.OnCancelListener; +import android.content.res.Configuration; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.text.TextUtils; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.R.id; +import eu.alefzero.owncloud.R.layout; +import eu.alefzero.owncloud.R.menu; +import eu.alefzero.owncloud.R.string; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.owncloud.db.DbHandler; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; +import eu.alefzero.owncloud.ui.fragment.FileDetail; +import eu.alefzero.owncloud.ui.fragment.FileList; +import eu.alefzero.owncloud.ui.fragment.ActionBar; + +/** + * Displays, what files the user has available in his ownCloud. + * @author Bartek Przybylski + * + */ +public class FileDisplayActivity extends FragmentActivity { + private DbHandler mDBHandler; + private Stack mParents; + private LinkedList mPath; + private Account mAccount; + private Cursor mCursor; + private boolean mIsDisplayingFile; + + private static final int DIALOG_CHOOSE_ACCOUNT = 0; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.files); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + //ft.add(R.id.actionBar, new ActionBar()); + ft.add(R.id.fileList, new FileList()); + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + ft.add(R.id.fileDetail, new FileDetail()); + } + ft.commit(); + + /*getSupportFragmentManager().beginTransaction().add(arg0, arg1); + FileList fl = new FileList(); + ft.add(R.id.fileList, fl); + ft.commit(); + /* + + + if (savedInstanceState != null) { + mParents = (Stack)savedInstanceState.getSerializable("parentsStack"); + mIsDisplayingFile = savedInstanceState.getBoolean("isDisplayingFile"); + mPath = (LinkedList)savedInstanceState.getSerializable("path"); + } else { + mParents = new Stack(); + mPath = new LinkedList(); + mIsDisplayingFile = false; + } + + mDBHandler = new DbHandler(getBaseContext()); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.main); + + AccountManager accMan = AccountManager.get(this); + Account[] accounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + + if (accounts.length == 0) { + // using string value since in API7 this constatn is not defined + // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS + // and Settings.EXTRA_AUTHORITIES + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE}); + startActivity(intent); + } else if (accounts.length > 1) { + showDialog(DIALOG_CHOOSE_ACCOUNT); + } else { + mAccount = accounts[0]; + populateFileList(); + }*/ + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.settingsItem : + Intent i = new Intent(this, Preferences.class); + startActivity(i); + break; + } + return true; + } + + @Override + protected Dialog onCreateDialog(int id) { + switch (id) { + case DIALOG_CHOOSE_ACCOUNT: + return createChooseAccountDialog(); + default: + throw new IllegalArgumentException("Unknown dialog id: " + id); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu, menu); + return true; + } + + private Dialog createChooseAccountDialog() { + final AccountManager accMan = AccountManager.get(this); + CharSequence[] items = new CharSequence[accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; + int i = 0; + for (Account a : accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)) { + items[i++] = a.name; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.common_choose_account); + builder.setCancelable(true); + builder.setItems(items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + mAccount = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[item]; + dialog.dismiss(); + populateFileList(); + } + }); + builder.setOnCancelListener(new OnCancelListener() { + public void onCancel(DialogInterface dialog) { + FileDisplayActivity.this.finish(); + } + }); + AlertDialog alert = builder.create(); + return alert; + } + + //@Override + //public void onBackPressed() { + /*PathLayout pl = (PathLayout) findViewById(R.id.pathLayout1); + if (mIsDisplayingFile) { + mIsDisplayingFile = false; + setContentView(R.layout.main); + pl = (PathLayout) findViewById(R.id.pathLayout1); + Uri uri; + if (mParents.empty()) { + uri = ProviderTableMeta.CONTENT_URI; + } else { + uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()); + } + mCursor = managedQuery(uri, + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", + new String[]{mAccount.name}, null); + + if (mCursor.moveToFirst()) { + String s = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)); + for (String str : s.split("/")) { + if (!TextUtils.isEmpty(str)) + pl.push(DisplayUtils.HtmlDecode(str)); + } + } + getListView().setAdapter(new FileListListAdapter(mCursor, this)); + getListView().invalidate(); + return; + } + if (mParents.size()==0) { + super.onBackPressed(); + return; + } else if (mParents.size() == 1) { + mParents.pop(); + mPath.removeLast(); + pl.pop(); + mCursor = managedQuery(ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", + new String[]{mAccount.name}, + null); + } else { + mParents.pop(); + mPath.removeLast(); + pl.pop(); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", + new String[]{mAccount.name}, + null); + } + + setListAdapter(new FileListListAdapter(mCursor, this)); + getListView().invalidate();*/ + //} + + //@Override +/* protected void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + /*PathLayout pl = (PathLayout) findViewById(R.id.pathLayout1); + if (!mCursor.moveToPosition(position)) { + throw new IndexOutOfBoundsException("Incorrect item selected"); + } + if (!mIsDisplayingFile) { + if (mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) { + String id_ = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); + String dirname = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)); + pl.push(DisplayUtils.HtmlDecode(dirname)); + mPath.addLast(DisplayUtils.HtmlDecode(dirname)); + mParents.push(id_); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, id_), + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[]{mAccount.name}, null); + setListAdapter(new FileListListAdapter(mCursor, this)); + } else { + mIsDisplayingFile = true; + setContentView(R.layout.file_display); + String id_ = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, id_), + null, + null, + null, + null); + mCursor.moveToFirst(); + // filename + TextView tv = (TextView) findViewById(R.id.textView1); + tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME))); + // filetype + tv = (TextView) findViewById(R.id.textView2); + tv.setText(DisplayUtils.convertMIMEtoPrettyPrint(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)))); + // size + tv = (TextView) findViewById(R.id.textView3); + tv.setText(DisplayUtils.bitsToHumanReadable(mCursor.getLong(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)))); + // modified + tv = (TextView) findViewById(R.id.textView4); + tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_MODIFIED))); + if (!TextUtils.isEmpty(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))) && + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).matches("image/*")) { + ImageView iv = (ImageView) findViewById(R.id.imageView1); + Bitmap bmp = BitmapFactory.decodeFile(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))); + Matrix m = new Matrix(); + float scale; + if (bmp.getWidth() > bmp.getHeight()) { + scale = (float) (200./bmp.getWidth()); + } else { + scale = (float) (200./bmp.getHeight()); + } + m.postScale(scale, scale); + Bitmap newBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); + iv.setImageBitmap(newBmp); + } + setListAdapter(new FileListActionListAdapter(mCursor, this, mAccount)); + } + getListView().invalidate(); + } else { + Intent i = (Intent) getListAdapter().getItem(position); + if (i.hasExtra("toDownload")) { + + Intent intent = new Intent(this, FileDownloader.class); + intent.putExtra(FileDownloader.EXTRA_FILE_PATH, "/"+((TextView)findViewById(R.id.textView1)).getText().toString()); + intent.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); + startService(intent); + /* + if (i.getBooleanExtra("toDownload", false)) { + startActivityForResult(i, 200); + } else { + startActivity(i); + }*/ + // } + + //} +// } + + private void populateFileList() { + if (mParents.empty()) { + mCursor = getContentResolver().query(ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", + new String[]{mAccount.name}, + null); + } else { + mCursor = getContentResolver().query(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[]{mAccount.name}, null); + if (!mIsDisplayingFile) { + //PathLayout pl = (PathLayout) findViewById(R.id.pathLayout1); + //for (String s : mPath) { + // pl.push(s); + // } + } + } +// setListAdapter(new FileListListAdapter(mCursor, this)); +// getListView().invalidate(); + } + + //@Override + /*protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable("parentsStack", mParents); + outState.putSerializable("path", mPath); + outState.putBoolean("isDisplayingFile", mIsDisplayingFile); + }*/ + +} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/ui/activity/LandingActivity.java b/src/eu/alefzero/owncloud/ui/activity/LandingActivity.java new file mode 100644 index 00000000..b8f18781 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/activity/LandingActivity.java @@ -0,0 +1,104 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.activity; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; + +/** + * This activity is used as a landing page when the user first opens this app. + * @author Lennart Rosam + * + */ +public class LandingActivity extends FragmentActivity implements OnClickListener { + + public static final int DIALOG_SETUP_ACCOUNT = 1; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // Check, if there are ownCloud accounts + if(!accountsAreSetup()){ + showDialog(DIALOG_SETUP_ACCOUNT); + } + + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog; + switch(id){ + case DIALOG_SETUP_ACCOUNT: + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.main_tit_accsetup); + builder.setMessage(R.string.main_wrn_accsetup); + builder.setCancelable(false); + builder.setPositiveButton(R.string.common_ok, this); + builder.setNegativeButton(R.string.common_cancel, this); + dialog = builder.create(); + break; + default: + dialog = null; + } + + return dialog; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + // In any case - we won't need it anymore + dialog.dismiss(); + switch(which){ + case DialogInterface.BUTTON_POSITIVE: + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", + new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); + break; + case DialogInterface.BUTTON_NEGATIVE: + finish(); + } + + } + + /** + * Checks, whether or not there are any ownCloud accounts + * setup. + * + * @return true, if there is at least one account. + */ + private boolean accountsAreSetup() { + AccountManager accMan = AccountManager.get(this); + Account[] accounts = accMan + .getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + return accounts.length > 0; + } + + +} diff --git a/src/eu/alefzero/owncloud/ui/activity/Preferences.java b/src/eu/alefzero/owncloud/ui/activity/Preferences.java new file mode 100644 index 00000000..dadffaf6 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/activity/Preferences.java @@ -0,0 +1,168 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.activity; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Vector; + +import eu.alefzero.owncloud.OwnCloudSession; +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.R.id; +import eu.alefzero.owncloud.R.menu; +import eu.alefzero.owncloud.R.xml; +import eu.alefzero.owncloud.db.DbHandler; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceScreen; +import android.util.Log; +import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ContextMenu.ContextMenuInfo; +import android.widget.AdapterView.AdapterContextMenuInfo; + +/** + * An Activity that allows the user to change the application's settings. + * @author Bartek Przybylski + * + */ +public class Preferences extends PreferenceActivity { + private String TAG = "OwnCloudPreferences"; + private final int mNewSession = 47; + private final int mEditSession = 48; + private DbHandler mDbHandler; + private Vector mSessions; + private int mSelectedMenuItem; + + @Override + public void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + mDbHandler = new DbHandler(getBaseContext()); + mSessions = new Vector(); + addPreferencesFromResource(R.xml.preferences); + registerForContextMenu(getListView()); + //populateSessionList(); + } + + private void populateSessionList() { + mSessions.clear(); + mSessions = mDbHandler.getSessionList(); + PreferenceScreen ps = getPreferenceScreen(); + ps.removeAll(); + addPreferencesFromResource(R.xml.preferences); + for (int i = 0; i < mSessions.size(); i++) { + Preference preference = new Preference(getBaseContext()); + preference.setTitle(mSessions.get(i).getName()); + URI uri; + try { + uri = new URI(mSessions.get(i).getUrl()); + } catch (URISyntaxException e) { + e.printStackTrace(); // should never happend + continue; + } + preference.setSummary(uri.getScheme() + "://" + uri.getHost()+uri.getPath()); + ps.addPreference(preference); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.prefs_menu, menu); + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + super.onMenuItemSelected(featureId, item); + Intent intent; + + switch (item.getItemId()) { + case R.id.addSessionItem: + intent = new Intent(this, PreferencesNewSession.class); + startActivityForResult(intent, mNewSession); + break; + case R.id.SessionContextEdit: + intent = new Intent(this, PreferencesNewSession.class); + intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem).getEntryId()); + intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem).getName()); + intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem).getUrl()); + startActivityForResult(intent, mEditSession); + break; + case R.id.SessionContextRemove: + OwnCloudSession ocs = mSessions.get(mSelectedMenuItem); + mDbHandler.removeSessionWithId(ocs.getEntryId()); + mSessions.remove(ocs); + getPreferenceScreen().removePreference(getPreferenceScreen().getPreference(mSelectedMenuItem+1)); + break; + default: + Log.w(TAG, "Unknown menu item triggered"); + return false; + } + return true; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == Activity.RESULT_OK) { + switch (requestCode) { + case mNewSession: + mDbHandler.addSession(data.getStringExtra("sessionName"), + data.getStringExtra("sessionURL")); + getPreferenceScreen().removeAll(); + addPreferencesFromResource(R.xml.preferences); + populateSessionList(); + break; + case mEditSession: + mDbHandler.changeSessionFields(data.getIntExtra("sessionId", -1), + data.getStringExtra("sessionName"), + data.getStringExtra("sessionURL")); + populateSessionList(); + break; + } + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + mSelectedMenuItem = info.position-1; + menu.setHeaderTitle(mSessions.get(mSelectedMenuItem).getName()); + + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.session_context_menu, menu); + + } + + @Override + protected void onDestroy() { + mDbHandler.close(); + super.onDestroy(); + } + +} diff --git a/src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java b/src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java new file mode 100644 index 00000000..95114154 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java @@ -0,0 +1,143 @@ +package eu.alefzero.owncloud.ui.activity; + +import java.net.URI; +import java.net.URISyntaxException; + +import eu.alefzero.owncloud.authenticator.AccountAuthenticatorService; + +import android.accounts.Account; +import android.accounts.AccountAuthenticatorActivity; +import android.accounts.AccountManager; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +public class PreferencesNewSession extends AccountAuthenticatorActivity implements OnClickListener { + private Intent mReturnData; + private final String TAG = "OwnCloudPreferencesNewSession"; + @Override + public void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + //setContentView(R.layout.add_new_session); + /* + EditText et;// = (EditText) findViewById(R.id.newSession_sessionName); + + et = (EditText) findViewById(R.id.newSession_URL); + if (getIntent().hasExtra("sessionURL")) { + try { + URI uri = new URI(getIntent().getStringExtra("sessionURL")); + String url = uri.getHost(); + if (uri.getPort() != -1) { + url += ":" + String.valueOf(uri.getPort()); + } + if (uri.getPath() != null) { + url += uri.getPath(); + } else { + url += "/"; + } + et.setText(url); + et = (EditText) findViewById(R.id.newSession_username); + if (uri.getAuthority() != null) { + if (uri.getUserInfo().indexOf(':') != -1) { + et.setText(uri.getUserInfo().substring(0, uri.getUserInfo().indexOf(':'))); + et = (EditText) findViewById(R.id.newSession_password); + et.setText(uri.getUserInfo().substring(uri.getUserInfo().indexOf(':')+1)); + } else { + et.setText(uri.getUserInfo()); + } + } + + } catch (URISyntaxException e) { + Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage()); + } + } + + mReturnData = new Intent(); + setResult(Activity.RESULT_OK, mReturnData); + ((Button) findViewById(R.id.button1)).setOnClickListener(this); + ((Button) findViewById(R.id.button2)).setOnClickListener(this);*/ + } + + @Override + protected void onResume() { + super.onResume(); + } + + public void onClick(View v) { + /* switch (v.getId()) { + case R.id.button1: + Intent intent = new Intent(); + if (getIntent().hasExtra("sessionId")) { + intent.putExtra("sessionId", getIntent().getIntExtra("sessionId", -1)); + } + //String sessionName = ((EditText) findViewById(R.id.newSession_sessionName)).getText().toString(); + // if (sessionName.trim().equals("") || !isNameValid(sessionName)) { + // Toast.makeText(this, R.string.new_session_session_name_error, Toast.LENGTH_LONG).show(); + // break; + // } + URI uri = prepareURI(); + if (uri != null) { + //intent.putExtra("sessionName", sessionName); + intent.putExtra("sessionURL", uri.toString()); + setResult(Activity.RESULT_OK, intent); + AccountManager accMgr = AccountManager.get(this); + Account a = new Account("OwnCloud", AccountAuthenticatorService.ACCOUNT_TYPE); + accMgr.addAccountExplicitly(a, "asd", null); + finish(); + } + break; + case R.id.button2: + setResult(Activity.RESULT_CANCELED); + finish(); + break; + }*/ + } + + private URI prepareURI() { + URI uri = null; + /* String url = ""; + try { + String username = ((EditText) findViewById(R.id.newSession_username)).getText().toString().trim(); + String password = ((EditText) findViewById(R.id.newSession_password)).getText().toString().trim(); + String hostname = ((EditText) findViewById(R.id.newSession_URL)).getText().toString().trim(); + String scheme; + if (hostname.matches("[A-Za-z]://")) { + scheme = hostname.substring(0, hostname.indexOf("://")+3); + hostname = hostname.substring(hostname.indexOf("://")+3); + } else { + scheme = "http://"; + } + if (!username.equals("")) { + if (!password.equals("")) { + username += ":" + password + "@"; + } else { + username += "@"; + } + } + url = scheme + username + hostname; + Log.i(TAG, url); + uri = new URI(url); + } catch (URISyntaxException e) { + Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage()); + Toast.makeText(this, R.string.new_session_uri_error, Toast.LENGTH_LONG).show(); + } + */return uri; + } + + private boolean isNameValid(String string) { + return string.matches("[A-Za-z0-9 _-]*"); + } + + @Override + public void onBackPressed() { + setResult(Activity.RESULT_CANCELED); + super.onBackPressed(); + } + +} diff --git a/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java b/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java index 02f1db2c..ab69f075 100644 --- a/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java +++ b/src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java @@ -1,108 +1,131 @@ -package eu.alefzero.owncloud.ui.adapter; - -import java.security.Provider; - -import eu.alefzero.owncloud.DisplayUtils; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.R.drawable; -import eu.alefzero.owncloud.R.id; -import eu.alefzero.owncloud.R.layout; -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; - -import android.content.Context; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.View.OnLongClickListener; -import android.widget.AdapterView; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.TextView; -import android.widget.AdapterView.OnItemClickListener; - -public class FileListListAdapter implements ListAdapter { - - private Cursor mCursor; - private Context mContext; - - public FileListListAdapter(Cursor c, Context context) { - mCursor = c; - mContext = context; - } - - public boolean areAllItemsEnabled() { - return true; - } - - public boolean isEnabled(int position) { - // TODO Auto-generated method stub - return true; - } - - public int getCount() { - // TODO Auto-generated method stub - return mCursor.getCount(); - } - - public Object getItem(int position) { - // TODO Auto-generated method stub - 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.list_layout, null); - } - if (mCursor.moveToPosition(position)) { - TextView tv = (TextView) v.findViewById(R.id.Filename); - tv.setText(DisplayUtils.HtmlDecode(mCursor.getString(mCursor.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_NAME)))); - if (!mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) { - ImageView iv = (ImageView) v.findViewById(R.id.imageView1); - iv.setImageResource(R.drawable.file); - } - } - - return v; - } - - public int getViewTypeCount() { - // TODO Auto-generated method stub - return 4; - } - - public boolean hasStableIds() { - // TODO Auto-generated method stub - return true; - } - - 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 - - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.adapter; + +import java.security.Provider; + +import eu.alefzero.owncloud.DisplayUtils; +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.R.drawable; +import eu.alefzero.owncloud.R.id; +import eu.alefzero.owncloud.R.layout; +import eu.alefzero.owncloud.db.ProviderMeta; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; + +import android.content.Context; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.View.OnLongClickListener; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.TextView; +import android.widget.AdapterView.OnItemClickListener; + +/** + * This Adapter populates a ListView with all files and + * folders in an ownCloud instance. + * @author Bartek Przybylski + * + */ +public class FileListListAdapter implements ListAdapter { + + private Cursor mCursor; + private Context mContext; + + public FileListListAdapter(Cursor c, Context context) { + mCursor = c; + mContext = context; + } + + public boolean areAllItemsEnabled() { + return true; + } + + public boolean isEnabled(int position) { + // TODO Auto-generated method stub + return true; + } + + public int getCount() { + // TODO Auto-generated method stub + return mCursor.getCount(); + } + + public Object getItem(int position) { + // TODO Auto-generated method stub + 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.list_layout, null); + } + if (mCursor.moveToPosition(position)) { + TextView tv = (TextView) v.findViewById(R.id.Filename); + tv.setText(DisplayUtils.HtmlDecode(mCursor.getString(mCursor.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_NAME)))); + if (!mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) { + ImageView iv = (ImageView) v.findViewById(R.id.imageView1); + iv.setImageResource(R.drawable.file); + } + } + + return v; + } + + public int getViewTypeCount() { + // TODO Auto-generated method stub + return 4; + } + + public boolean hasStableIds() { + // TODO Auto-generated method stub + return true; + } + + 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 + + } +} diff --git a/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java b/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java index d14ac0fa..694225d5 100644 --- a/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java +++ b/src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java @@ -1,87 +1,104 @@ -package eu.alefzero.owncloud.ui.adapter; - -import android.content.Context; -import android.content.Intent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.TextView; -import eu.alefzero.owncloud.R; -import eu.alefzero.owncloud.ui.FileDisplayActivity; -import eu.alefzero.owncloud.ui.Preferences; - -/** - * Populates the landing screen icons. - * @author Benutzer - * - */ -public class LandingScreenAdapter extends BaseAdapter { - - private Context mContext; - - private final Integer[] mLandingScreenIcons = { R.drawable.home, - R.drawable.music, R.drawable.contacts, - R.drawable.calendar, - android.R.drawable.ic_menu_agenda, - R.drawable.settings }; - - private final Integer[] mLandingScreenTexts = { R.string.main_files, - R.string.main_music, R.string.main_contacts, - R.string.main_calendar, R.string.main_bookmarks, - R.string.main_settings }; - - public LandingScreenAdapter(Context context) { - mContext = context; - } - - @Override - public int getCount() { - return mLandingScreenIcons.length; - } - - @Override - /** - * Returns the Intent associated with this object - * or null if the functionality is not yet implemented - */ - public Object getItem(int position) { - Intent intent = new Intent(); - switch (position) { - case 0: - intent.setClass(mContext, FileDisplayActivity.class); - break; - case 5: - intent.setClass(mContext, Preferences.class); - break; - default: - intent = null; - } - return intent; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - LayoutInflater inflator = LayoutInflater.from(mContext); - convertView = inflator - .inflate(R.layout.landing_page_item, null); - - ImageView icon = (ImageView) convertView - .findViewById(R.id.gridImage); - TextView iconText = (TextView) convertView - .findViewById(R.id.gridText); - - icon.setImageResource(mLandingScreenIcons[position]); - iconText.setText(mLandingScreenTexts[position]); - } - return convertView; - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.adapter; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.ui.activity.FileDisplayActivity; +import eu.alefzero.owncloud.ui.activity.Preferences; + +/** + * Populates the landing screen icons. + * @author Lennart Rosam + * + */ +public class LandingScreenAdapter extends BaseAdapter { + + private Context mContext; + + private final Integer[] mLandingScreenIcons = { R.drawable.home, + R.drawable.music, R.drawable.contacts, + R.drawable.calendar, + android.R.drawable.ic_menu_agenda, + R.drawable.settings }; + + private final Integer[] mLandingScreenTexts = { R.string.main_files, + R.string.main_music, R.string.main_contacts, + R.string.main_calendar, R.string.main_bookmarks, + R.string.main_settings }; + + public LandingScreenAdapter(Context context) { + mContext = context; + } + + @Override + public int getCount() { + return mLandingScreenIcons.length; + } + + @Override + /** + * Returns the Intent associated with this object + * or null if the functionality is not yet implemented + */ + public Object getItem(int position) { + Intent intent = new Intent(); + switch (position) { + case 0: + intent.setClass(mContext, FileDisplayActivity.class); + break; + case 5: + intent.setClass(mContext, Preferences.class); + break; + default: + intent = null; + } + return intent; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + LayoutInflater inflator = LayoutInflater.from(mContext); + convertView = inflator + .inflate(R.layout.landing_page_item, null); + + ImageView icon = (ImageView) convertView + .findViewById(R.id.gridImage); + TextView iconText = (TextView) convertView + .findViewById(R.id.gridText); + + icon.setImageResource(mLandingScreenIcons[position]); + iconText.setText(mLandingScreenTexts[position]); + } + return convertView; + } + +} diff --git a/src/eu/alefzero/owncloud/ui/fragment/ActionBar.java b/src/eu/alefzero/owncloud/ui/fragment/ActionBar.java index 9a3291b6..8810be76 100644 --- a/src/eu/alefzero/owncloud/ui/fragment/ActionBar.java +++ b/src/eu/alefzero/owncloud/ui/fragment/ActionBar.java @@ -1,45 +1,66 @@ -package eu.alefzero.owncloud.ui.fragment; - -import eu.alefzero.owncloud.PathLayout; -import eu.alefzero.owncloud.R; -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -public class ActionBar extends Fragment { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.action_bar, container, false); - return v; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - } - - public void setPath(String path) { - if (getPathLayout() != null) - getPathLayout().addPath(path); - } - - public String getCurrentPath() { - if (getPathLayout() != null) - return getPathLayout().getFullPath(); - return ""; - } - - private PathLayout getPathLayout() { - return (PathLayout) getActivity().findViewById(R.id.pathLayout1); - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.fragment; + +import eu.alefzero.owncloud.R; +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * A custom ActionBar implementation used in the FileDisplayActivity + * @author Bartek Przybylski + * + */ +public class ActionBar extends Fragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + } + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.action_bar, container, false); + return v; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + public void setPath(String path) { + if (getPathLayout() != null) + getPathLayout().addPath(path); + } + + public String getCurrentPath() { + if (getPathLayout() != null) + return getPathLayout().getFullPath(); + return ""; + } + + private PathLayout getPathLayout() { + return (PathLayout) getActivity().findViewById(R.id.pathLayout1); + } +} diff --git a/src/eu/alefzero/owncloud/ui/fragment/FileDetail.java b/src/eu/alefzero/owncloud/ui/fragment/FileDetail.java index de11bc69..50f35a5f 100644 --- a/src/eu/alefzero/owncloud/ui/fragment/FileDetail.java +++ b/src/eu/alefzero/owncloud/ui/fragment/FileDetail.java @@ -1,3 +1,20 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ package eu.alefzero.owncloud.ui.fragment; import eu.alefzero.owncloud.R; @@ -13,6 +30,11 @@ import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; +/** + * This Fragment is used to display the details about a file. + * @author Bartek Przybylski + * + */ public class FileDetail extends Fragment { public Intent mIntent; diff --git a/src/eu/alefzero/owncloud/ui/fragment/FileList.java b/src/eu/alefzero/owncloud/ui/fragment/FileList.java index e3d1f261..1fb8abcc 100644 --- a/src/eu/alefzero/owncloud/ui/fragment/FileList.java +++ b/src/eu/alefzero/owncloud/ui/fragment/FileList.java @@ -1,10 +1,27 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ package eu.alefzero.owncloud.ui.fragment; import eu.alefzero.owncloud.R; import eu.alefzero.owncloud.R.id; import eu.alefzero.owncloud.authenticator.AccountAuthenticator; import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.owncloud.ui.FileDetailActivity; +import eu.alefzero.owncloud.ui.activity.FileDetailActivity; import eu.alefzero.owncloud.ui.adapter.FileListListAdapter; import eu.alefzero.owncloud.ui.fragment.ActionBar; import android.accounts.Account; @@ -25,6 +42,11 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; +/** + * A Fragment that lists all files and folders in a given path. + * @author Bartek Przybylski + * + */ public class FileList extends ListFragment { private Cursor mCursor; private Account mAccount; diff --git a/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java b/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java index 69651146..dd7ca316 100644 --- a/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java +++ b/src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java @@ -1,3 +1,20 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ package eu.alefzero.owncloud.ui.fragment; import android.content.Intent; @@ -13,6 +30,13 @@ import android.widget.Toast; import eu.alefzero.owncloud.R; import eu.alefzero.owncloud.ui.adapter.LandingScreenAdapter; +/** + * Used on the Landing page to display what Components of + * the ownCloud there are. Like Files, Music, Contacts, etc. + * + * @author Lennart Rosam + * + */ public class LandingPageFragment extends Fragment implements OnItemClickListener { @Override diff --git a/src/eu/alefzero/owncloud/ui/fragment/PathLayout.java b/src/eu/alefzero/owncloud/ui/fragment/PathLayout.java new file mode 100644 index 00000000..e9714c71 --- /dev/null +++ b/src/eu/alefzero/owncloud/ui/fragment/PathLayout.java @@ -0,0 +1,117 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.owncloud.ui.fragment; + +import java.util.LinkedList; +import java.util.Stack; + +import eu.alefzero.owncloud.R; +import eu.alefzero.owncloud.R.drawable; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.HorizontalScrollView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +/** + * Part of the ActionBar Layout + * @author Bartek Przybylski + * + */ +public class PathLayout extends LinearLayout { + + private LinkedList paths; + ScrollView internalScroll; + LinearLayout view; + + public PathLayout(Context context) { + super(context); + initialize(); + } + + public PathLayout(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(); + } + + public String pop() { + if (paths.size() == 0) { + return null; + } + int start = paths.size()*2-2; + int count = 2; + if (paths.size() == 1) { + start++; + count--; + } + view.removeViews(start, count); + return paths.removeLast(); + } + + public void addPath(String path) { + for (String s : path.split("/")) if (s.length() != 0) push(s); + } + + public void push(String path) { + // its weird that we cannot declare static imgView as path separator + if (paths.size() != 0) { + ImageView iv = new ImageView(getContext()); + iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb)); + iv.setPadding(2, 0, 2, 0); + view.addView(iv); + } + TextView tv = new TextView(getContext()); + tv.setLayoutParams(getLayoutParams()); + tv.setText(path); + view.addView(tv); + HorizontalScrollView hsv = (HorizontalScrollView) internalScroll.getChildAt(0); + hsv.smoothScrollTo(hsv.getMaxScrollAmount()*2, 0); + paths.addLast(path); + } + + public String peek() { + return paths.peek(); + } + + public String getFullPath() { + String ret = new String(); + for (int i = 0; i < paths.size(); i++) { + ret += "/" + paths.get(i); + } + return ret; + } + + private void initialize() { + paths = new LinkedList(); + internalScroll = new ScrollView(getContext()); + internalScroll.setFillViewport(true); + HorizontalScrollView hsv = new HorizontalScrollView(getContext()); + hsv.setSmoothScrollingEnabled(true); + internalScroll.addView(hsv); + view = new LinearLayout(getContext()); + addView(internalScroll); + hsv.addView(view); + ImageView iv = new ImageView(getContext()); + iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb)); + view.addView(iv); + } + +} diff --git a/src/eu/alefzero/webdav/HttpMkCol.java b/src/eu/alefzero/webdav/HttpMkCol.java index c7acab9c..8fcac160 100644 --- a/src/eu/alefzero/webdav/HttpMkCol.java +++ b/src/eu/alefzero/webdav/HttpMkCol.java @@ -1,19 +1,36 @@ -package eu.alefzero.webdav; - -import java.net.URI; - -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; - -public class HttpMkCol extends HttpEntityEnclosingRequestBase { - - public final static String METHOD_NAME = "MKCOL"; - - public HttpMkCol(final String uri) { - setURI(URI.create(uri)); - } - - @Override - public String getMethod() { - return METHOD_NAME; - } -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +public class HttpMkCol extends HttpEntityEnclosingRequestBase { + + public final static String METHOD_NAME = "MKCOL"; + + public HttpMkCol(final String uri) { + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} diff --git a/src/eu/alefzero/webdav/HttpPropFind.java b/src/eu/alefzero/webdav/HttpPropFind.java index f7b930c3..a3d00634 100644 --- a/src/eu/alefzero/webdav/HttpPropFind.java +++ b/src/eu/alefzero/webdav/HttpPropFind.java @@ -1,32 +1,49 @@ -package eu.alefzero.webdav; - -import java.net.URI; - -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.protocol.HTTP; - -public class HttpPropFind extends HttpEntityEnclosingRequestBase { - - public final static String METHOD_NAME = "PROPFIND"; - - public HttpPropFind(final URI uri) { - super(); - setURI(uri); - } - - public HttpPropFind(final String uri) { - this.setDepth("1"); - setURI(URI.create(uri)); - this.setHeader(HTTP.CONTENT_TYPE, "text/xml" + HTTP.CHARSET_PARAM + HTTP.UTF_8.toLowerCase()); - } - - @Override - public String getMethod() { - return METHOD_NAME; - } - - public void setDepth(String depth) { - this.setHeader("Depth", depth); - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.protocol.HTTP; + +public class HttpPropFind extends HttpEntityEnclosingRequestBase { + + public final static String METHOD_NAME = "PROPFIND"; + + public HttpPropFind(final URI uri) { + super(); + setURI(uri); + } + + public HttpPropFind(final String uri) { + this.setDepth("1"); + setURI(URI.create(uri)); + this.setHeader(HTTP.CONTENT_TYPE, "text/xml" + HTTP.CHARSET_PARAM + HTTP.UTF_8.toLowerCase()); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } + + public void setDepth(String depth) { + this.setHeader("Depth", depth); + } + +} diff --git a/src/eu/alefzero/webdav/HttpPropPatch.java b/src/eu/alefzero/webdav/HttpPropPatch.java index bdd352ef..82898d3c 100644 --- a/src/eu/alefzero/webdav/HttpPropPatch.java +++ b/src/eu/alefzero/webdav/HttpPropPatch.java @@ -1,26 +1,43 @@ -package eu.alefzero.webdav; - -import java.net.URI; - -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; - -public class HttpPropPatch extends HttpEntityEnclosingRequestBase { - - public static final String METHOD_NAME = "PROPPATCH"; - - public HttpPropPatch(URI uri) { - super(); - setURI(uri); - } - - public HttpPropPatch(final String uri) { - super(); - setURI(URI.create(uri)); - } - - @Override - public String getMethod() { - return METHOD_NAME; - } - -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +public class HttpPropPatch extends HttpEntityEnclosingRequestBase { + + public static final String METHOD_NAME = "PROPPATCH"; + + public HttpPropPatch(URI uri) { + super(); + setURI(uri); + } + + public HttpPropPatch(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } + +} diff --git a/src/eu/alefzero/webdav/TreeNodeContainer.java b/src/eu/alefzero/webdav/TreeNodeContainer.java index ef092545..5656fde0 100644 --- a/src/eu/alefzero/webdav/TreeNodeContainer.java +++ b/src/eu/alefzero/webdav/TreeNodeContainer.java @@ -1,21 +1,38 @@ -package eu.alefzero.webdav; - -import java.util.List; -import java.util.ListIterator; - -import org.w3c.dom.Document; - -import android.util.Xml; - -public class TreeNodeContainer extends TreeNode { - - @Override - void refreshData(Document document) { - ListIterator iterator = children_.listIterator(); - while (iterator.hasNext()) { - iterator.next().refreshData(document); - } - } - - private List children_; -} +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.webdav; + +import java.util.List; +import java.util.ListIterator; + +import org.w3c.dom.Document; + +import android.util.Xml; + +public class TreeNodeContainer extends TreeNode { + + @Override + void refreshData(Document document) { + ListIterator iterator = children_.listIterator(); + while (iterator.hasNext()) { + iterator.next().refreshData(document); + } + } + + private List children_; +} diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java new file mode 100644 index 00000000..4d97ceb3 --- /dev/null +++ b/src/eu/alefzero/webdav/WebdavClient.java @@ -0,0 +1,196 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package eu.alefzero.webdav; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.params.ConnManagerPNames; +import org.apache.http.conn.params.ConnPerRouteBean; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.FileEntity; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.BasicHttpContext; + +import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory; + +import android.net.Uri; +import android.util.Log; + +/** + * A basic WebDAV-Client + * @author Bartek Przybylski + * + */ +public class WebdavClient { + private DefaultHttpClient mHttpClient; + private BasicHttpContext mHttpContext; + private HttpHost mTargetHost; + private SchemeRegistry mSchemeRegistry; + private Uri mUri; + final private static String TAG = "WebdavClient"; + + public WebdavClient(Uri uri) { + mUri = uri; + mSchemeRegistry = new SchemeRegistry(); + setupHttpClient(); + } + + public void setCredentials(String username, String password) { + // determine default port for http or https + int targetPort = mTargetHost.getPort() == -1 ? + ( mUri.getScheme().equals("https") ? 443 : 80) + : mUri.getPort(); + + mHttpClient.getCredentialsProvider().setCredentials( + new AuthScope(mUri.getHost(), targetPort), + new UsernamePasswordCredentials(username, password)); + BasicScheme basicAuth = new BasicScheme(); + mHttpContext.setAttribute("preemptive-auth", basicAuth); + } + + public void allowUnsignedCertificates() { + // https + mSchemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); + } + + public boolean downloadFile(String filepath, File targetPath) { + HttpGet get = new HttpGet(mUri.toString() + filepath.replace(" ", "%20")); + get.setHeader("Host", mUri.getHost()); + get.setHeader("User-Agent", "Android-ownCloud"); + + try { + HttpResponse response = mHttpClient.execute(mTargetHost, get, mHttpContext); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + return false; + } + BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent()); + FileOutputStream fos = new FileOutputStream(targetPath); + + byte[] bytes = new byte[512]; + int readResult; + while ((readResult = bis.read(bytes)) != -1) fos.write(bytes, 0, readResult); + + } catch (IOException e) { + e.printStackTrace(); + return false; + } + return true; + } + + void getFileList(String dirPath) { + + } + + public boolean putFile(String localFile, + String remoteTarget, + String contentType) { + boolean result = true; + HttpPut method = new HttpPut(mUri.toString() + remoteTarget.replace(" ", "%20")); + method.setHeader("Content-type", contentType); + method.setHeader("Host", mUri.getHost()); + method.setHeader("User-Agent", "Android-ownCloud"); + + try { + FileBody fb = new FileBody(new File(localFile, contentType)); + final FileEntity fileEntity = new FileEntity(new File(localFile), contentType); + + method.setEntity(fileEntity); + Log.i(TAG, "executing:" + method.getRequestLine().toString()); + + mHttpClient.execute(mTargetHost, method, mHttpContext); + /*mHandler.post(new Runnable() { + public void run() { + Uploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)), + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), + mUploadPath + (mUploadPath.equals("/")?"":"/"), + fileEntity.getContentType().getValue(), + fileEntity.getContentLength()+""); + } + }); + Log.i(TAG, "Uploading, done"); +*/ + Log.i(TAG, "Uploading, done"); + } catch (final Exception e) { + Log.i(TAG, ""+e.getMessage()); + result = false; + } + + return result; + } + + public boolean createDirectory(String path) { + HttpMkCol method = new HttpMkCol(mUri.toString() + path + "/"); + method.setHeader("User-Agent", "Android-ownCloud"); + + try { + mHttpClient.execute(mTargetHost, method, mHttpContext); + Log.i(TAG, "Creating dir completed"); + } catch (final Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + private void setupHttpClient() { + // http scheme + mSchemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + mSchemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); + + HttpParams params = new BasicHttpParams(); + params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); + params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); + params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + + mHttpContext = new BasicHttpContext(); + ClientConnectionManager cm = new ThreadSafeClientConnManager(params, mSchemeRegistry); + + int port = mUri.getPort() == -1 ? + mUri.getScheme().equals("https") ? 443 : 80 + : mUri.getPort(); + + mTargetHost = new HttpHost(mUri.getHost(), port, mUri.getScheme()); + + mHttpClient = new DefaultHttpClient(cm, params); + } +}