com.putlocker.upload.DownloadService.java Source code

Java tutorial

Introduction

Here is the source code for com.putlocker.upload.DownloadService.java

Source

/**
 * Putlocker Android - Putlocker scraper for Android 
 *
 * Author: Julian Haldenby (j.haldenby@gmail.com)
 *
 *  This file is part of Putlocker Android.
 *
 * Putlocker Android 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.
 *
 * Putlocker Android 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 Putlocker Android.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.putlocker.upload;

import java.io.File;
import java.util.Hashtable;
import java.util.Random;

import android.support.v4.app.NotificationCompat;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
import android.util.SparseArray;
import android.widget.RemoteViews;
import android.widget.Toast;

import com.putlocker.upload.activity.ActivityBase;
import com.putlocker.upload.concurrency.PutlockerDownloadJob;
import com.putlocker.upload.concurrency.interfaces.PutlockerTransferResponder;
import com.putlocker.upload.concurrency.interfaces.StopableRequest;
import com.putlocker.upload.http.HttpFetch;
import com.putlocker.upload.http.HttpFetch.RequestStatus;
import com.putlocker.upload.http.PutlockerFileDownload;
import com.putlocker.upload.http.PutlockerUploadFile;
import com.putlocker.upload.http.RequestCallback;
import com.putlocker.upload.storage.Persistable;
import com.putlocker.upload.storage.PutlockerUpDownloadJob;
import com.putlocker.upload.storage.PutlockerUpDownloadJob.DownloadStatus;
import com.putlocker.upload.storage.PutlockerUploadJob;
import com.putlocker.upload.storage.TypedStorageInterface;
import com.putlocker.upload.util.FileFactory;
import com.putlocker.upload.util.MimeTypeMap;
import com.putlocker.upload.util.FileFactory.FileType;

/**
 * This will manage the download queue. This is nicely handled by the
 * Android's intent service.
 * 
 * 
 * @class DownloadService A service that will be started as a foreground service  
 *
 */
public class DownloadService extends IntentService implements PutlockerTransferResponder {
    public static final String JOB_EXTRA_DOWNLOAD = "extras.job.download";
    public static final String JOB_EXTRA_UPLOAD = "extras.job.upload";
    private File baseFile;
    private PutlockerTransferResponder _nextResponder;
    private Object _threadLock = new Object();
    private Handler _mainThread;
    private long _lastProgress = 0l;
    private SparseArray<Notification> downloadJobs = new SparseArray<Notification>();
    private SparseArray<Boolean> cancelledJobs = new SparseArray<Boolean>();
    private SparseArray<StopableRequest> runningJobs = new SparseArray<StopableRequest>();

    public DownloadService() {
        super("Download Service");
    }

    /** For showing and hiding our notification. */
    NotificationManager mNM;
    Hashtable<Long, PutlockerUpDownloadJob> _download = new Hashtable<Long, PutlockerUpDownloadJob>();

    @Override
    public void onCreate() {
        super.onCreate();
        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        _mainThread = new Handler(getMainLooper());

        PutlockerApplication app = (PutlockerApplication) getApplication();

        // register the service as started in the application
        app.setService(this);

        // This will retrieve the current base acitivity
        ActivityBase base = app.getCurrentActivityBase();

        // Do we have a current activity?
        if (base != null) {

            // Is the base activity a responder in our download queue?
            if (base.isResponder()) {
                _nextResponder = (PutlockerTransferResponder) base;
            }
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        PutlockerUpDownloadJob upDownJob = null;
        Notification notification = null;

        if (intent.hasExtra(JOB_EXTRA_DOWNLOAD)) {
            final PutlockerDownloadJob job = intent.getParcelableExtra(JOB_EXTRA_DOWNLOAD);
            notification = createDownloadNotification(job, this, 0);
            upDownJob = job;
        } else {
            final PutlockerUploadJob job = intent.getParcelableExtra(JOB_EXTRA_UPLOAD);
            notification = createDownloadNotification(job, this, 0);
            upDownJob = job;
        }

        if (downloadJobs.size() == 0) {
            startForeground((int) upDownJob.getGlobalId(), notification);
        } else {
            mNM.notify(upDownJob.getGlobalId(), notification);
        }

        downloadJobs.append(upDownJob.getGlobalId(), notification);

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);

        // close the notification that we have stopped
        PutlockerApplication app = (PutlockerApplication) getApplication();

        // Null out our service
        app.setService(null);
    }

    /**
     * @param job The job to notify about
     * @param context The context to use
     * Show a notification while this service is running.
     */
    public Notification createDownloadNotification(PutlockerUpDownloadJob job, Context context, int progress) {
        CharSequence text;
        if (job.getJobType() == PutlockerUpDownloadJob.DOWNLOAD_JOB) {
            text = context.getText(R.string.remote_service_started);
        } else {
            text = context.getText(R.string.service_upload_started);
        }

        PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
                new Intent(context, PutlockerTransferList.class), 0);
        // Set the icon, scrolling text and timestamp
        Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
        notification.contentView = new RemoteViews(context.getApplicationContext().getPackageName(),
                R.layout.download_progress);

        notification.contentView.setImageViewResource(R.id.status_icon, R.drawable.ic_launcher);

        if (job.getJobType() == PutlockerUpDownloadJob.DOWNLOAD_JOB) {

            if (FileFactory.typeFromFileName(job.getName()) == FileType.FILE_TYPE_VIDEO) {
                notification.contentIntent = PendingIntent.getActivity(this, 0,
                        getIntentForJob((PutlockerDownloadJob) job), Intent.FLAG_ACTIVITY_NEW_TASK);
            } else {
                notification.contentIntent = contentIntent;
            }

            notification.contentView.setTextViewText(R.id.status_text,
                    context.getString(R.string.download_started, job.getName()));
        } else {
            notification.contentView.setTextViewText(R.id.status_text,
                    context.getString(R.string.upload_started, job.getName()));
            notification.contentIntent = contentIntent;
        }

        notification.contentView.setProgressBar(R.id.status_progress, 100, progress, false);
        return notification;
    }

    /**
     * Create an intent for the job that we are requesting
     * @param job the job to create the intent for
     * @return the intent for the mime type
     */
    Intent getIntentForJob(PutlockerDownloadJob job) {
        File f = new File(job.getFileLocation());
        Intent openIntent = new Intent();
        openIntent.setAction(android.content.Intent.ACTION_VIEW);
        openIntent.setDataAndType(Uri.fromFile(f), getMimeTypeForFilename(job._fileName));
        return Intent.createChooser(openIntent, "Open " + job._fileName + " with:");
    }

    /**
     * This attempt to return the mime type from the filename.
     * @param name the filename string
     * @return the string mime type
     */
    String getMimeTypeForFilename(String name) {
        if (name != null && name.length() >= 3) {
            int index = name.lastIndexOf('.');
            if (index != -1) {
                String extension = name.substring(index + 1);
                String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
                return mimeType;
            }
        }
        return "video/*";
    }

    void doCompleteNotification(PutlockerUpDownloadJob job, DownloadStatus status) {
        CharSequence text;
        CharSequence contentText;
        PendingIntent intent;
        if (job.getJobType() == PutlockerUpDownloadJob.DOWNLOAD_JOB) {
            if (status == DownloadStatus.JobSucess) {
                text = getText(R.string.download_completed_success);
                contentText = getText(R.string.click_to_open);
                intent = PendingIntent.getActivity(this, 0, getIntentForJob((PutlockerDownloadJob) job),
                        Intent.FLAG_ACTIVITY_NEW_TASK);
            } else {
                text = getText(R.string.download_completed_error);
                contentText = getText(R.string.click_to_see_transfers);
                intent = PendingIntent.getActivity(this, 0, new Intent(this, PutlockerTransferList.class),
                        Intent.FLAG_ACTIVITY_NEW_TASK);
            }
        } else {
            if (status == DownloadStatus.JobSucess) {
                text = getText(R.string.upload_completed_success);
                contentText = getText(R.string.click_to_see_files);
                intent = PendingIntent.getActivity(this, 0, new Intent(this, PutlockerHome.class),
                        Intent.FLAG_ACTIVITY_NEW_TASK);
            } else {
                text = getText(R.string.upload_completed_error);
                contentText = getText(R.string.click_to_see_transfers);
                intent = PendingIntent.getActivity(this, 0, new Intent(this, PutlockerTransferList.class),
                        Intent.FLAG_ACTIVITY_NEW_TASK);
            }
        }
        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);
        notif.setContentTitle(text);
        notif.setContentText(contentText);
        notif.setOngoing(false);
        notif.setSmallIcon(R.drawable.ic_launcher);
        notif.setContentIntent(intent);
        notif.setAutoCancel(true);
        mNM.notify(new Random().nextInt(), notif.build());
    }

    protected void updateContentView(PutlockerUpDownloadJob job, int progress) {
        Notification notification = downloadJobs.get(job.getGlobalId());
        if (notification != null) {
            if (_lastProgress != progress) {
                _lastProgress = progress;
                notification.contentView.setProgressBar(R.id.status_progress, 100, progress, false);
                mNM.notify(job.getGlobalId(), notification);
            }
        }
    }

    @Override
    public void setPutlockerJobStatus(PutlockerUpDownloadJob job, PutlockerDownloadJob.DownloadStatus status) {
        PutlockerTransferResponder responder = null;

        synchronized (_threadLock) {
            if (_nextResponder != null) {
                responder = _nextResponder;
            }
        }

        if (responder != null) {
            responder.setPutlockerJobStatus(job, status);
        }
        job.setStatus(status);
        getPutlockerApplication().getStorage().UpdateTyped(job);
    }

    @Override
    public void setDownloadJobProgress(final PutlockerUpDownloadJob job, final Long bytes, final Long bytesTotal) {
        final PutlockerTransferResponder responder;

        synchronized (_threadLock) {
            if (_nextResponder != null) {
                responder = _nextResponder;
            } else {
                responder = null;
            }
        }

        _mainThread.post(new Runnable() {
            @Override
            public void run() {

                getPutlockerApplication().getStorage().UpdateTyped(job);

                updateContentView(job, job.getProgressForDownload(bytes));
                /**
                 * Now take the responder and get the progress
                 */
                if (responder != null) {
                    responder.setDownloadJobProgress(job, bytes, bytesTotal);
                }
            }
        });

    }

    public void setNextResponder(PutlockerTransferResponder responder) {
        synchronized (_threadLock) {
            _nextResponder = responder;
        }
    }

    public boolean isDownloading(PutlockerUpDownloadJob job) {
        return _download.containsKey(job.getGlobalId());
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Download Wakelock");
        wl.acquire();

        ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        WifiLock wifiLock = null;
        // We only want to aquire the wifi wake lock
        if (mWifi.isConnected()) {
            wifiLock = ((WifiManager) this.getSystemService(Context.WIFI_SERVICE))
                    .createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "WlanSilencerScanLock");
            wifiLock.acquire();
        }

        if (intent.hasExtra(JOB_EXTRA_DOWNLOAD)) {
            handleDownloadIntent(intent);
        } else {
            handleUploadIntent(intent);
        }

        if (wifiLock != null && wifiLock.isHeld()) {
            wifiLock.release();
        }

        wl.release();
    }

    private void handleDownloadIntent(Intent intent) {
        baseFile = new File("/mnt/sdcard/", "putlocker");
        final PutlockerDownloadJob job = intent.getParcelableExtra(JOB_EXTRA_DOWNLOAD);
        if (cancelledJobs.get(job.getGlobalId()) != null) {
            cancelledJobs.remove(job.getGlobalId());
        } else {
            _download.put((long) job.getGlobalId(), job);
            if (!baseFile.exists()) {
                if (!baseFile.mkdir()) {
                    Toast.makeText(getApplicationContext(), "Could not download, must have an SDCard",
                            Toast.LENGTH_LONG);
                    setPutlockerJobStatus(job, DownloadStatus.JobError);
                    return;
                }
            }
            /*
             * Update our current file location
             */
            File newFile = new File(baseFile, String.valueOf(job._fileName));

            job.setFileLocation(newFile.getAbsolutePath());

            getPutlockerApplication().getStorage().UpdateTyped(job);
            Log.e("Julian", "Job id " + String.valueOf(job.getId()));
            RequestCallback callback = new RequestCallback() {
                @Override
                public void requestSuccess(HttpFetch fetch) {
                    job.setStatus(DownloadStatus.JobSucess);
                    setPutlockerJobStatus(job, DownloadStatus.JobSucess);
                    _download.remove(job.getGlobalId());
                }

                @Override
                public void requestRetry(HttpFetch fetch) {
                }

                @Override
                public void requestFailure(HttpFetch fetch) {
                    job.setStatus(DownloadStatus.JobError);
                    _download.remove(job.getGlobalId());
                    setPutlockerJobStatus(job, DownloadStatus.JobError);
                    _mainThread.post(new Runnable() {

                        @Override
                        public void run() {

                            Toast.makeText(getApplicationContext(), R.string.download_failed, Toast.LENGTH_LONG);
                        }
                    });

                }
            };
            PutlockerFileDownload download = new PutlockerFileDownload(job, this, callback, newFile);
            runningJobs.append(job.getGlobalId(), download);
            download.run();

            runningJobs.remove(job.getGlobalId());
            if (download.getStatus().equals(RequestStatus.RequestStatusCanceled)) {
                job.setStatus(DownloadStatus.JobError);
                setPutlockerJobStatus(job, DownloadStatus.JobError);
            }
        }
        downloadJobs.remove(job.getGlobalId());
        mNM.cancel(job.getGlobalId());
        // At the end we are going to update the status of the job
        getPutlockerApplication().getStorage().UpdateTyped(job);
        // We are going to stop the foreground services

        if (downloadJobs.size() == 0) {
            stopForeground(true);
        }
        doCompleteNotification(job, job.getStatus());
    }

    private void handleUploadIntent(Intent intent) {
        final PutlockerUploadJob job = intent.getParcelableExtra(JOB_EXTRA_UPLOAD);
        if (cancelledJobs.get(job.getGlobalId()) != null) {
            cancelledJobs.remove(job.getGlobalId());
        } else {
            _download.put((long) job.getGlobalId(), job);
            RequestCallback callback = new RequestCallback() {

                @Override
                public void requestSuccess(HttpFetch fetch) {
                    job.setStatus(DownloadStatus.JobSucess);
                    setPutlockerJobStatus(job, DownloadStatus.JobSucess);
                    _download.remove(job.getGlobalId());
                }

                @Override
                public void requestRetry(HttpFetch fetch) {
                }

                @Override
                public void requestFailure(HttpFetch fetch) {
                    job.setStatus(DownloadStatus.JobError);
                    setPutlockerJobStatus(job, DownloadStatus.JobError);
                    _download.remove(job.getGlobalId());
                    _mainThread.post(new Runnable() {

                        @Override
                        public void run() {
                            Toast.makeText(getApplicationContext(), R.string.download_failed, Toast.LENGTH_LONG);
                        }
                    });

                }
            };
            PutlockerUploadFile file = new PutlockerUploadFile(job, callback, this);

            runningJobs.append(job.getGlobalId(), file);
            file.run();
            runningJobs.remove(job.getGlobalId());

            if (file.getStatus().equals(RequestStatus.RequestStatusCanceled)) {
                job.setStatus(DownloadStatus.JobError);
                setPutlockerJobStatus(job, DownloadStatus.JobError);
            }
        }
        downloadJobs.remove(job.getGlobalId());
        mNM.cancel(job.getGlobalId());

        // We are going to stop the foreground services
        if (downloadJobs.size() == 0) {
            stopForeground(true);
        }
        doCompleteNotification(job, job.getStatus());
    }

    protected final PutlockerApplication getPutlockerApplication() {
        return (PutlockerApplication) getApplication();
    }

    public void cancelJob(PutlockerUpDownloadJob job) {
        StopableRequest request = runningJobs.get(job.getGlobalId());
        if (request != null) {
            request.stopRequest();
        } else {
            cancelledJobs.put(job.getGlobalId(), new Boolean(true));
        }
    }
}