1 package eu
.alefzero
.owncloud
.files
.services
; 
   4 import java
.io
.IOException
; 
   5 import java
.util
.Collections
; 
   6 import java
.util
.HashMap
; 
   9 import android
.accounts
.Account
; 
  10 import android
.accounts
.AccountManager
; 
  11 import android
.app
.Notification
; 
  12 import android
.app
.NotificationManager
; 
  13 import android
.app
.PendingIntent
; 
  14 import android
.app
.Service
; 
  15 import android
.content
.ContentValues
; 
  16 import android
.content
.Intent
; 
  17 import android
.os
.Environment
; 
  18 import android
.os
.Handler
; 
  19 import android
.os
.HandlerThread
; 
  20 import android
.os
.IBinder
; 
  21 import android
.os
.Looper
; 
  22 import android
.os
.Message
; 
  23 import android
.os
.Process
; 
  24 import android
.util
.Log
; 
  25 import android
.widget
.RemoteViews
; 
  26 import android
.widget
.Toast
; 
  27 import eu
.alefzero
.owncloud
.R
; 
  28 import eu
.alefzero
.owncloud
.authenticator
.AccountAuthenticator
; 
  29 import eu
.alefzero
.owncloud
.db
.ProviderMeta
.ProviderTableMeta
; 
  30 import eu
.alefzero
.owncloud
.files
.interfaces
.OnDatatransferProgressListener
; 
  31 import eu
.alefzero
.owncloud
.syncadapter
.FileSyncService
; 
  32 import eu
.alefzero
.webdav
.WebdavClient
; 
  34 public class FileDownloader 
extends Service 
implements OnDatatransferProgressListener 
{ 
  35     public static final String DOWNLOAD_FINISH_MESSAGE 
= "DOWNLOAD_FINISH"; 
  36     public static final String EXTRA_DOWNLOAD_RESULT 
= "RESULT";     
  37     public static final String EXTRA_ACCOUNT 
= "ACCOUNT"; 
  38     public static final String EXTRA_FILE_PATH 
= "FILE_PATH"; 
  39     public static final String EXTRA_REMOTE_PATH 
= "REMOTE_PATH"; 
  40     public static final String EXTRA_FILE_SIZE 
= "FILE_SIZE"; 
  41     public static final String ACCOUNT_NAME 
= "ACCOUNT_NAME";     
  42     private static final String TAG 
= "FileDownloader"; 
  44     private NotificationManager mNotificationMngr
; 
  45     private Looper mServiceLooper
; 
  46     private ServiceHandler mServiceHandler
; 
  47     private Account mAccount
; 
  48     private String mFilePath
; 
  49     private String mRemotePath
; 
  50     private int mLastPercent
; 
  51     private long mTotalDownloadSize
; 
  52     private long mCurrentDownlodSize
; 
  53     private Notification mNotification
; 
  56      * Static map with the files being download and the path to the temporal file were are download 
  58     private static Map
<String
, String
> mDownloadsInProgress 
= Collections
.synchronizedMap(new HashMap
<String
, String
>()); 
  61      * Returns True when the file referred by 'remotePath' in the ownCloud account 'account' is downloading 
  63     public static boolean isDownloading(Account account
, String remotePath
) { 
  64         return (mDownloadsInProgress
.get(buildRemoteName(account
.name
, remotePath
)) != null
); 
  68      * Builds a key for mDownloadsInProgress from the accountName and remotePath 
  70     private static String 
buildRemoteName(String accountName
, String remotePath
) { 
  71         return accountName 
+ remotePath
; 
  75     private final class ServiceHandler 
extends Handler 
{ 
  76         public ServiceHandler(Looper looper
) { 
  81         public void handleMessage(Message msg
) { 
  87     public static final String 
getSavePath() { 
  88         File sdCard 
= Environment
.getExternalStorageDirectory(); 
  89         return sdCard
.getAbsolutePath() + "/owncloud/"; 
  92     public static final String 
getTemporalPath() { 
  93         File sdCard 
= Environment
.getExternalStorageDirectory(); 
  94         return sdCard
.getAbsolutePath() + "/owncloud.tmp/"; 
  98     public void onCreate() { 
 100         mNotificationMngr 
= (NotificationManager
) getSystemService(NOTIFICATION_SERVICE
); 
 101         HandlerThread thread 
= new HandlerThread("FileDownladerThread", 
 102                 Process
.THREAD_PRIORITY_BACKGROUND
); 
 104         mServiceLooper 
= thread
.getLooper(); 
 105         mServiceHandler 
= new ServiceHandler(mServiceLooper
); 
 109     public IBinder 
onBind(Intent arg0
) { 
 114     public int onStartCommand(Intent intent
, int flags
, int startId
) { 
 115         if (!intent
.hasExtra(EXTRA_ACCOUNT
) 
 116                 && !intent
.hasExtra(EXTRA_FILE_PATH
)) { 
 117             Log
.e(TAG
, "Not enough information provided in intent"); 
 120         mAccount 
= intent
.getParcelableExtra(EXTRA_ACCOUNT
); 
 121         mFilePath 
= intent
.getStringExtra(EXTRA_FILE_PATH
); 
 122         mRemotePath 
= intent
.getStringExtra(EXTRA_REMOTE_PATH
); 
 123         Message msg 
= mServiceHandler
.obtainMessage(); 
 125         mServiceHandler
.sendMessage(msg
); 
 126         mCurrentDownlodSize 
= mLastPercent 
= 0; 
 127         mTotalDownloadSize 
= intent
.getLongExtra(EXTRA_FILE_SIZE
, -1); 
 129         return START_NOT_STICKY
; 
 132     void downloadFile() { 
 133         AccountManager am 
= (AccountManager
) getSystemService(ACCOUNT_SERVICE
); 
 136         WebdavClient wdc 
= new WebdavClient(mAccount
, getApplicationContext()); 
 138         String username 
= mAccount
.name
.split("@")[0]; 
 139         String password 
= ""; 
 141             password 
= am
.blockingGetAuthToken(mAccount
, 
 142                     AccountAuthenticator
.AUTH_TOKEN_TYPE
, true
); 
 143         } catch (Exception e
) { 
 148         wdc
.setCredentials(username
, password
); 
 149         wdc
.allowSelfsignedCertificates(); 
 150         wdc
.setDataTransferProgressListener(this); 
 152         mNotification 
= new Notification(R
.drawable
.icon
, "Downloading file", System
.currentTimeMillis()); 
 154         mNotification
.flags 
|= Notification
.FLAG_ONGOING_EVENT
; 
 155         mNotification
.contentView 
= new RemoteViews(getApplicationContext().getPackageName(), R
.layout
.progressbar_layout
); 
 156         mNotification
.contentView
.setProgressBar(R
.id
.status_progress
, 100, 0, mTotalDownloadSize 
== -1); 
 157         mNotification
.contentView
.setImageViewResource(R
.id
.status_icon
, R
.drawable
.icon
); 
 158         // dvelasco ; contentIntent MUST be assigned to avoid app crashes in versions previous to Android 4.x ; 
 159         //              BUT an empty Intent is not a very elegant solution; something smart should happen when a user 'clicks' on a download in the notification bar 
 160         mNotification
.contentIntent 
= PendingIntent
.getActivity(getApplicationContext(), 0, new Intent(), PendingIntent
.FLAG_UPDATE_CURRENT
); 
 162         mNotificationMngr
.notify(1, mNotification
); 
 164         // download in a temporal file 
 165         File tmpFile 
= new File(getTemporalPath() + mAccount
.name 
+ mFilePath
); 
 166         tmpFile
.getParentFile().mkdirs(); 
 167         mDownloadsInProgress
.put(buildRemoteName(mAccount
.name
, mRemotePath
), tmpFile
.getAbsolutePath()); 
 169         boolean download_result 
= false
; 
 171         if (wdc
.downloadFile(mRemotePath
, tmpFile
)) { 
 172             newFile 
= new File(getSavePath() + mAccount
.name 
+ mFilePath
); 
 173             newFile
.getParentFile().mkdirs(); 
 174             boolean moved 
= tmpFile
.renameTo(newFile
); 
 177                 ContentValues cv 
= new ContentValues(); 
 178                 cv
.put(ProviderTableMeta
.FILE_STORAGE_PATH
, newFile
.getAbsolutePath()); 
 179                 getContentResolver().update( 
 180                     ProviderTableMeta
.CONTENT_URI
, 
 182                     ProviderTableMeta
.FILE_NAME 
+ "=? AND " 
 183                             + ProviderTableMeta
.FILE_ACCOUNT_OWNER 
+ "=?", 
 185                             mFilePath
.substring(mFilePath
.lastIndexOf('/') + 1), 
 187                 download_result 
= true
; 
 191         mDownloadsInProgress
.remove(buildRemoteName(mAccount
.name
, mRemotePath
)); 
 193         mNotificationMngr
.cancel(1); 
 194         Intent end 
= new Intent(DOWNLOAD_FINISH_MESSAGE
); 
 195         end
.putExtra(EXTRA_DOWNLOAD_RESULT
, download_result
); 
 196         end
.putExtra(ACCOUNT_NAME
, mAccount
.name
); 
 197         end
.putExtra(EXTRA_REMOTE_PATH
, mRemotePath
); 
 198         if (download_result
) { 
 199             end
.putExtra(EXTRA_FILE_PATH
, newFile
.getAbsolutePath()); 
 203         if (download_result
) { 
 204             Toast
.makeText(this, R
.string
.downloader_download_succeed 
, Toast
.LENGTH_SHORT
).show(); 
 206             Toast
.makeText(this, R
.string
.downloader_download_failed 
, Toast
.LENGTH_SHORT
).show(); 
 212     public void transferProgress(long progressRate
) { 
 213         mCurrentDownlodSize 
+= progressRate
; 
 214         int percent 
= (int)(100.0*((double)mCurrentDownlodSize
)/((double)mTotalDownloadSize
)); 
 215         if (percent 
!= mLastPercent
) { 
 216           mNotification
.contentView
.setProgressBar(R
.id
.status_progress
, 100, (int)(100*mCurrentDownlodSize
/mTotalDownloadSize
), mTotalDownloadSize 
== -1); 
 217           mNotification
.contentView
.setTextViewText(R
.id
.status_text
, percent
+"%"); 
 218           mNotificationMngr
.notify(1, mNotification
); 
 221         mLastPercent 
= percent
;