1 package eu
.alefzero
.owncloud
.files
.services
;
5 import org
.apache
.commons
.httpclient
.methods
.GetMethod
;
6 import org
.apache
.commons
.httpclient
.methods
.HeadMethod
;
8 import android
.accounts
.Account
;
9 import android
.accounts
.AccountManager
;
10 import android
.app
.Notification
;
11 import android
.app
.NotificationManager
;
12 import android
.app
.PendingIntent
;
13 import android
.app
.Service
;
14 import android
.content
.Intent
;
15 import android
.os
.Handler
;
16 import android
.os
.HandlerThread
;
17 import android
.os
.IBinder
;
18 import android
.os
.Looper
;
19 import android
.os
.Message
;
20 import android
.os
.Process
;
21 import android
.util
.Log
;
22 import android
.webkit
.MimeTypeMap
;
23 import android
.widget
.RemoteViews
;
24 import android
.widget
.Toast
;
25 import eu
.alefzero
.owncloud
.R
;
26 import eu
.alefzero
.owncloud
.datamodel
.FileDataStorageManager
;
27 import eu
.alefzero
.owncloud
.datamodel
.OCFile
;
28 import eu
.alefzero
.owncloud
.files
.interfaces
.OnDatatransferProgressListener
;
29 import eu
.alefzero
.webdav
.WebdavClient
;
31 public class FileUploader
extends Service
implements OnDatatransferProgressListener
{
33 public static final String UPLOAD_FINISH_MESSAGE
= "UPLOAD_FINISH";
34 public static final String EXTRA_PARENT_DIR_ID
= "PARENT_DIR_ID";
36 public static final String KEY_LOCAL_FILE
= "LOCAL_FILE";
37 public static final String KEY_REMOTE_FILE
= "REMOTE_FILE";
38 public static final String KEY_ACCOUNT
= "ACCOUNT";
39 public static final String KEY_UPLOAD_TYPE
= "UPLOAD_TYPE";
40 public static final String ACCOUNT_NAME
= "ACCOUNT_NAME";
42 public static final int UPLOAD_SINGLE_FILE
= 0;
43 public static final int UPLOAD_MULTIPLE_FILES
= 1;
45 private static final String TAG
= "FileUploader";
46 private NotificationManager mNotificationManager
;
47 private Looper mServiceLooper
;
48 private ServiceHandler mServiceHandler
;
49 private Account mAccount
;
50 private String
[] mLocalPaths
, mRemotePaths
;
51 private int mUploadType
;
52 private Notification mNotification
;
53 private int mTotalDataToSend
, mSendData
;
54 private int mCurrentIndexUpload
, mPreviousPercent
;
55 private int mSuccessCounter
;
58 public IBinder
onBind(Intent arg0
) {
62 private final class ServiceHandler
extends Handler
{
63 public ServiceHandler(Looper looper
) {
68 public void handleMessage(Message msg
) {
75 public void onCreate() {
77 mNotificationManager
= (NotificationManager
) getSystemService(NOTIFICATION_SERVICE
);
78 HandlerThread thread
= new HandlerThread("FileUploaderThread",
79 Process
.THREAD_PRIORITY_BACKGROUND
);
81 mServiceLooper
= thread
.getLooper();
82 mServiceHandler
= new ServiceHandler(mServiceLooper
);
86 public int onStartCommand(Intent intent
, int flags
, int startId
) {
87 if (!intent
.hasExtra(KEY_ACCOUNT
) && !intent
.hasExtra(KEY_UPLOAD_TYPE
)) {
88 Log
.e(TAG
, "Not enought data in intent provided");
89 return Service
.START_NOT_STICKY
;
91 mAccount
= intent
.getParcelableExtra(KEY_ACCOUNT
);
92 mUploadType
= intent
.getIntExtra(KEY_UPLOAD_TYPE
, -1);
93 if (mUploadType
== -1) {
94 Log
.e(TAG
, "Incorrect upload type provided");
95 return Service
.START_NOT_STICKY
;
97 if (mUploadType
== UPLOAD_SINGLE_FILE
) {
98 mLocalPaths
= new String
[] { intent
.getStringExtra(KEY_LOCAL_FILE
) };
99 mRemotePaths
= new String
[] { intent
100 .getStringExtra(KEY_REMOTE_FILE
) };
101 } else { // mUploadType == UPLOAD_MULTIPLE_FILES
102 mLocalPaths
= intent
.getStringArrayExtra(KEY_LOCAL_FILE
);
103 mRemotePaths
= intent
.getStringArrayExtra(KEY_REMOTE_FILE
);
106 if (mLocalPaths
.length
!= mRemotePaths
.length
) {
107 Log
.e(TAG
, "Remote paths and local paths are not equal!");
108 return Service
.START_NOT_STICKY
;
111 Message msg
= mServiceHandler
.obtainMessage();
113 mServiceHandler
.sendMessage(msg
);
115 return Service
.START_NOT_STICKY
;
120 if (mSuccessCounter
== mLocalPaths
.length
) {
121 message
= getString(R
.string
.uploader_upload_succeed
);
123 message
= getString(R
.string
.uploader_upload_failed
);
124 if (mLocalPaths
.length
> 1)
125 message
+= " (" + mSuccessCounter
+ " / " + mLocalPaths
.length
+ getString(R
.string
.uploader_files_uploaded_suffix
) + ")";
127 Toast
.makeText(this, message
, Toast
.LENGTH_SHORT
).show();
130 public void uploadFile() {
131 FileDataStorageManager storageManager
= new FileDataStorageManager(mAccount
, getContentResolver());
133 mTotalDataToSend
= mSendData
= mPreviousPercent
= 0;
135 mNotification
= new Notification(
136 eu
.alefzero
.owncloud
.R
.drawable
.icon
, "Uploading...",
137 System
.currentTimeMillis());
138 mNotification
.flags
|= Notification
.FLAG_ONGOING_EVENT
;
139 mNotification
.contentView
= new RemoteViews(getApplicationContext().getPackageName(), R
.layout
.progressbar_layout
);
140 mNotification
.contentView
.setProgressBar(R
.id
.status_progress
, 100, 0, false
);
141 mNotification
.contentView
.setImageViewResource(R
.id
.status_icon
, R
.drawable
.icon
);
142 // dvelasco ; contentIntent MUST be assigned to avoid app crashes in versions previous to Android 4.x ;
143 // BUT an empty Intent is not a very elegant solution; something smart should happen when a user 'clicks' on an upload in the notification bar
144 mNotification
.contentIntent
= PendingIntent
.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent
.FLAG_UPDATE_CURRENT
);
146 mNotificationManager
.notify(42, mNotification
);
148 WebdavClient wc
= new WebdavClient(mAccount
, getApplicationContext());
149 wc
.setDataTransferProgressListener(this);
151 for (int i
= 0; i
< mLocalPaths
.length
; ++i
) {
152 File f
= new File(mLocalPaths
[i
]);
153 mTotalDataToSend
+= f
.length();
156 Log
.d(TAG
, "Will upload " + mTotalDataToSend
+ " bytes, with " + mLocalPaths
.length
+ " files");
160 for (int i
= 0; i
< mLocalPaths
.length
; ++i
) {
162 String mimeType
= null
;
164 mimeType
= MimeTypeMap
.getSingleton()
165 .getMimeTypeFromExtension(
166 mLocalPaths
[i
].substring(mLocalPaths
[i
]
167 .lastIndexOf('.') + 1));
168 } catch (IndexOutOfBoundsException e
) {
169 Log
.e(TAG
, "Trying to find out MIME type of a file without extension: " + mLocalPaths
[i
]);
171 if (mimeType
== null
)
172 mimeType
= "application/octet-stream";
174 mCurrentIndexUpload
= i
;
175 mRemotePaths
[i
] = getAvailableRemotePath(wc
, mRemotePaths
[i
]);
176 if (mRemotePaths
[i
] != null
&& wc
.putFile(mLocalPaths
[i
], mRemotePaths
[i
], mimeType
)) {
178 OCFile new_file
= new OCFile(mRemotePaths
[i
]);
179 new_file
.setMimetype(mimeType
);
180 new_file
.setFileLength(new File(mLocalPaths
[i
]).length());
181 new_file
.setModificationTimestamp(System
.currentTimeMillis());
182 new_file
.setLastSyncDate(0);
183 new_file
.setStoragePath(mLocalPaths
[i
]);
184 File f
= new File(mRemotePaths
[i
]);
185 long parentDirId
= storageManager
.getFileByPath(f
.getParent().endsWith("/")?f
.getParent():f
.getParent()+"/").getFileId();
186 new_file
.setParentId(parentDirId
);
187 storageManager
.saveFile(new_file
);
189 Intent end
= new Intent(UPLOAD_FINISH_MESSAGE
);
190 end
.putExtra(EXTRA_PARENT_DIR_ID
, parentDirId
);
191 end
.putExtra(ACCOUNT_NAME
, mAccount
.name
);
196 mNotificationManager
.cancel(42);
201 * Checks if remotePath does not exist in the server and returns it, or adds a suffix to it in order to avoid the server
202 * file is overwritten.
207 private String
getAvailableRemotePath(WebdavClient wc
, String remotePath
) {
208 Boolean check
= wc
.existsFile(remotePath
);
209 if (check
== null
) { // null means fail
215 int pos
= remotePath
.lastIndexOf(".");
217 String extension
= "";
219 extension
= remotePath
.substring(pos
+1);
220 remotePath
= remotePath
.substring(0, pos
);
223 while (check
!= null
&& check
) {
224 suffix
= " (" + count
+ ")";
226 check
= wc
.existsFile(remotePath
+ suffix
+ "." + extension
);
228 check
= wc
.existsFile(remotePath
+ suffix
);
233 } else if (pos
>=0) {
234 return remotePath
+ suffix
+ "." + extension
;
236 return remotePath
+ suffix
;
241 public void transferProgress(long progressRate
) {
242 mSendData
+= progressRate
;
243 int percent
= (int)(100*((double)mSendData
)/((double)mTotalDataToSend
));
244 if (percent
!= mPreviousPercent
) {
245 String text
= String
.format("%d%% Uploading %s file", percent
, new File(mLocalPaths
[mCurrentIndexUpload
]).getName());
246 mNotification
.contentView
.setProgressBar(R
.id
.status_progress
, 100, percent
, false
);
247 mNotification
.contentView
.setTextViewText(R
.id
.status_text
, text
);
248 mNotificationManager
.notify(42, mNotification
);
250 mPreviousPercent
= percent
;