com.miz.service.TvShowsLibraryUpdate.java Source code

Java tutorial

Introduction

Here is the source code for com.miz.service.TvShowsLibraryUpdate.java

Source

/*
 * Copyright (C) 2014 Michell Bak
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.miz.service;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.miz.abstractclasses.TvShowFileSource;
import com.miz.apis.trakt.Trakt;
import com.miz.db.DbAdapterSources;
import com.miz.db.DbAdapterTvShowEpisodes;
import com.miz.db.DbAdapterTvShows;
import com.miz.filesources.FileTvShow;
import com.miz.filesources.SmbTvShow;
import com.miz.filesources.UpnpTvShow;
import com.miz.functions.FileSource;
import com.miz.functions.MizLib;
import com.miz.functions.TvShowLibraryUpdateCallback;
import com.miz.identification.ShowStructure;
import com.miz.identification.TvShowIdentification;
import com.miz.mizuu.CancelLibraryUpdate;
import com.miz.mizuu.Main;
import com.miz.mizuu.MizuuApplication;
import com.miz.mizuu.R;
import com.miz.utils.FileUtils;
import com.miz.utils.LocalBroadcastUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import static com.miz.functions.PreferenceKeys.CLEAR_LIBRARY_TVSHOWS;
import static com.miz.functions.PreferenceKeys.REMOVE_UNAVAILABLE_FILES_TVSHOWS;
import static com.miz.functions.PreferenceKeys.SYNC_WITH_TRAKT;

public class TvShowsLibraryUpdate extends IntentService implements TvShowLibraryUpdateCallback {

    public static final String STOP_TVSHOW_LIBRARY_UPDATE = "mizuu-stop-tvshow-library-update";
    private boolean mDebugging = true;
    private ArrayList<FileSource> mFileSources;
    private ArrayList<TvShowFileSource<?>> mTvShowFileSources;
    private ArrayList<ShowStructure> mFiles;
    private HashSet<String> mUniqueShowIds = new HashSet<String>();
    private boolean mClearLibrary, mClearUnavailable, mSyncLibraries, mStopUpdate;
    private int mTotalFiles, mShowCount, mEpisodeCount;
    private SharedPreferences mSettings;
    private Editor mEditor;
    private final int NOTIFICATION_ID = 300, POST_UPDATE_NOTIFICATION = 313;
    private NotificationManager mNotificationManager;
    private NotificationCompat.Builder mBuilder;
    private TvShowIdentification mIdentification;

    public TvShowsLibraryUpdate() {
        super("TvShowsLibraryUpdate");
    }

    public TvShowsLibraryUpdate(String name) {
        super(name);
    }

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

        log("onDestroy()");

        if (mNotificationManager == null)
            mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotificationManager.cancel(NOTIFICATION_ID);

        LocalBroadcastUtils.updateTvShowLibrary(this);

        showPostUpdateNotification();

        LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);

        MizLib.scheduleShowsUpdate(this);

        if (Trakt.hasTraktAccount(this) && mSyncLibraries && (mEpisodeCount > 0)) {
            startService(new Intent(getApplicationContext(), TraktTvShowsSyncService.class));
        }
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        log("clear()");

        // Clear and set up all variables
        clear();

        log("setup()");

        // Set up Notification, variables, etc.
        setup();

        log("loadFileSources()");

        // Load all file sources from the database
        loadFileSources();

        log("setupTvShowsFileSources()");

        // Add the different file sources to the TvShowFileSource ArrayList
        setupTvShowsFileSources(mClearLibrary);

        if (mStopUpdate)
            return;

        log("removeUnidentifiedFiles()");

        // Remove unavailable TV show files, so we can try to identify them again
        if (!mClearLibrary)
            removeUnidentifiedFiles();

        if (mStopUpdate)
            return;

        // Check if the library should be cleared
        if (mClearLibrary) {

            // Reset the preference, so it isn't checked the next
            // time the user wants to update the library
            mEditor = mSettings.edit();
            mEditor.putBoolean(CLEAR_LIBRARY_TVSHOWS, false);
            mEditor.apply();

            log("removeTvShowsFromDatabase()");

            // Remove all entries from the database
            removeTvShowsFromDatabase();
        }

        if (mStopUpdate)
            return;

        // Check if we should remove all unavailable files.
        // Note that this only makes sense if we haven't already cleared the library.
        if (!mClearLibrary && mClearUnavailable) {

            log("removeUnavailableFiles()");

            // Remove all unavailable files from the database
            removeUnavailableFiles();
        }

        log("searchFolders()");

        if (mStopUpdate)
            return;

        // Search all folders
        searchFolders();

        if (mStopUpdate)
            return;
        log("mTotalFiles > 0 check");

        // Check if we've found any files to identify
        if (mTotalFiles > 0) {
            log("updateTvShows()");

            // Start the actual TV shows update / identification task
            updateTvShows();
        }
    }

    private void loadFileSources() {
        mFileSources = new ArrayList<FileSource>();
        DbAdapterSources dbHelperSources = MizuuApplication.getSourcesAdapter();
        Cursor c = dbHelperSources.fetchAllShowSources();
        try {
            while (c.moveToNext()) {
                mFileSources.add(new FileSource(c.getLong(c.getColumnIndex(DbAdapterSources.KEY_ROWID)),
                        c.getString(c.getColumnIndex(DbAdapterSources.KEY_FILEPATH)),
                        c.getInt(c.getColumnIndex(DbAdapterSources.KEY_FILESOURCE_TYPE)),
                        c.getString(c.getColumnIndex(DbAdapterSources.KEY_USER)),
                        c.getString(c.getColumnIndex(DbAdapterSources.KEY_PASSWORD)),
                        c.getString(c.getColumnIndex(DbAdapterSources.KEY_DOMAIN)),
                        c.getString(c.getColumnIndex(DbAdapterSources.KEY_TYPE))));
            }
        } catch (Exception e) {
        } finally {
            c.close();
        }
    }

    private void setupTvShowsFileSources(boolean mClearLibrary) {
        for (FileSource fileSource : mFileSources) {
            if (mStopUpdate)
                return;
            switch (fileSource.getFileSourceType()) {
            case FileSource.FILE:
                mTvShowFileSources.add(new FileTvShow(getApplicationContext(), fileSource, mClearLibrary));
                break;
            case FileSource.SMB:
                mTvShowFileSources.add(new SmbTvShow(getApplicationContext(), fileSource, mClearLibrary));
                break;
            case FileSource.UPNP:
                mTvShowFileSources.add(new UpnpTvShow(getApplicationContext(), fileSource, mClearLibrary));
                break;
            }
        }
    }

    private void removeUnidentifiedFiles() {
        for (TvShowFileSource<?> tvShowFileSource : mTvShowFileSources) {
            tvShowFileSource.removeUnidentifiedFiles();
        }
    }

    private void removeTvShowsFromDatabase() {
        // Delete all shows from the database
        DbAdapterTvShows db = MizuuApplication.getTvDbAdapter();
        db.deleteAllShowsInDatabase();

        DbAdapterTvShowEpisodes dbEpisodes = MizuuApplication.getTvEpisodeDbAdapter();
        dbEpisodes.deleteAllEpisodes();

        MizuuApplication.getTvShowEpisodeMappingsDbAdapter().deleteAllFilepaths();

        // Delete all downloaded images files from the device
        FileUtils.deleteRecursive(MizuuApplication.getTvShowThumbFolder(this), false);
        FileUtils.deleteRecursive(MizuuApplication.getTvShowEpisodeFolder(this), false);
        FileUtils.deleteRecursive(MizuuApplication.getTvShowBackdropFolder(this), false);
        FileUtils.deleteRecursive(MizuuApplication.getTvShowSeasonFolder(this), false);
    }

    private void removeUnavailableFiles() {
        for (TvShowFileSource<?> tvShowFileSource : mTvShowFileSources) {
            tvShowFileSource.removeUnavailableFiles();
        }
    }

    private void searchFolders() {
        // Temporary collection
        List<String> tempList = null;

        for (int j = 0; j < mTvShowFileSources.size(); j++) {
            updateTvShowScanningNotification(mTvShowFileSources.get(j).toString());
            tempList = mTvShowFileSources.get(j).searchFolder();
            for (int i = 0; i < tempList.size(); i++) {
                mFiles.add(new ShowStructure(tempList.get(i)));
            }
        }

        // Clean up...
        if (tempList != null)
            tempList.clear();

        int episodeCount = 0;
        for (ShowStructure ss : mFiles)
            episodeCount += ss.getEpisodes().size();

        mTotalFiles = episodeCount;
    }

    private void setup() {
        if (!MizLib.isOnline(this)) {
            mStopUpdate = true;
            return;
        }

        LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageReceiver,
                new IntentFilter(STOP_TVSHOW_LIBRARY_UPDATE));

        // Set up cancel dialog intent
        Intent notificationIntent = new Intent(this, CancelLibraryUpdate.class);
        notificationIntent.putExtra("isMovie", false);
        notificationIntent.setAction(Intent.ACTION_MAIN);
        notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent contentIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, notificationIntent, 0);

        // Setup up notification
        mBuilder = new NotificationCompat.Builder(getApplicationContext());
        mBuilder.setColor(getResources().getColor(R.color.color_primary));
        mBuilder.setSmallIcon(R.drawable.ic_sync_white_24dp);
        mBuilder.setTicker(getString(R.string.updatingTvShows));
        mBuilder.setContentTitle(getString(R.string.updatingTvShows));
        mBuilder.setContentText(getString(R.string.gettingReady));
        mBuilder.setContentIntent(contentIntent);
        mBuilder.setOngoing(true);
        mBuilder.setOnlyAlertOnce(true);
        mBuilder.addAction(R.drawable.ic_close_white_24dp, getString(android.R.string.cancel), contentIntent);

        // Build notification
        Notification updateNotification = mBuilder.build();

        // Show the notification
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(NOTIFICATION_ID, updateNotification);

        // Tell the system that this is an ongoing notification, so it shouldn't be killed
        startForeground(NOTIFICATION_ID, updateNotification);

        mSettings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        mClearLibrary = mSettings.getBoolean(CLEAR_LIBRARY_TVSHOWS, false);
        mClearUnavailable = mSettings.getBoolean(REMOVE_UNAVAILABLE_FILES_TVSHOWS, false);
        mSyncLibraries = mSettings.getBoolean(SYNC_WITH_TRAKT, true);
    }

    private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mStopUpdate = true;

            if (mIdentification != null)
                mIdentification.cancel();
        }
    };

    private void updateTvShows() {

        // Show the "Analyzing files..." notification
        showTvShowAnalyzingNotification();

        mIdentification = new TvShowIdentification(getApplicationContext(), this, mFiles);
        mIdentification.start();
    }

    private void clear() {
        // Lists
        mFileSources = new ArrayList<FileSource>();
        mTvShowFileSources = new ArrayList<TvShowFileSource<?>>();
        mFiles = new ArrayList<ShowStructure>();
        mUniqueShowIds = new HashSet<String>();

        // Booleans
        mClearLibrary = false;
        mClearUnavailable = false;
        mSyncLibraries = true;
        mStopUpdate = false;

        // Other variables
        mEditor = null;
        mSettings = null;
        mTotalFiles = 0;
        mShowCount = 0;
        mNotificationManager = null;
        mBuilder = null;
    }

    private void log(String msg) {
        if (mDebugging)
            Log.d("TvShowsLibraryUpdate", msg);
    }

    @Override
    public void onTvShowAdded(String showId, String title, Bitmap cover, Bitmap backdrop, int count) {
        if (!showId.equals(DbAdapterTvShows.UNIDENTIFIED_ID)) {
            mUniqueShowIds.add(showId);
        }
        updateTvShowAddedNotification(showId, title, cover, backdrop, count);
    }

    @Override
    public void onEpisodeAdded(String showId, String title, Bitmap cover, Bitmap photo) {
        if (!showId.equals(DbAdapterTvShows.UNIDENTIFIED_ID))
            mEpisodeCount++;
        updateEpisodeAddedNotification(showId, title, cover, photo);
    }

    private void updateEpisodeAddedNotification(String showId, String title, Bitmap cover, Bitmap backdrop) {
        String contentText;
        if (showId.isEmpty() || showId.equalsIgnoreCase(DbAdapterTvShows.UNIDENTIFIED_ID))
            contentText = getString(R.string.unidentified) + ": " + title;
        else
            contentText = getString(R.string.stringJustAdded) + ": " + title;

        mBuilder.setLargeIcon(cover);
        mBuilder.setContentTitle(getString(R.string.updatingTvShows) + " ("
                + (int) ((100.0 / (double) mTotalFiles) * (double) mEpisodeCount) + "%)");
        mBuilder.setContentText(contentText);
        mBuilder.setStyle(
                new NotificationCompat.BigPictureStyle().setSummaryText(contentText).bigPicture(backdrop));

        // Show the updated notification
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

    private void updateTvShowAddedNotification(String showId, String title, Bitmap cover, Bitmap backdrop,
            int count) {
        String contentText;
        if (showId.isEmpty() || showId.equalsIgnoreCase(DbAdapterTvShows.UNIDENTIFIED_ID))
            contentText = getString(R.string.unidentified) + ": " + title + " (" + count + " "
                    + getResources().getQuantityString(R.plurals.episodes, count, count) + ")";
        else
            contentText = getString(R.string.stringJustAdded) + ": " + title + " (" + count + " "
                    + getResources().getQuantityString(R.plurals.episodes, count, count) + ")";

        mBuilder.setLargeIcon(cover);
        mBuilder.setContentTitle(getString(R.string.updatingTvShows) + " ("
                + (int) ((100.0 / (double) mTotalFiles) * (double) mEpisodeCount) + "%)");
        mBuilder.setContentText(contentText);
        mBuilder.setStyle(
                new NotificationCompat.BigPictureStyle().setSummaryText(contentText).bigPicture(backdrop));

        // Show the updated notification
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

    private void updateTvShowScanningNotification(String filesource) {
        mBuilder.setSmallIcon(R.drawable.ic_sync_white_24dp);
        mBuilder.setContentTitle(getString(R.string.updatingTvShows));
        mBuilder.setContentText(getString(R.string.scanning) + ": " + filesource);

        // Show the updated notification
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

    private void showTvShowAnalyzingNotification() {
        mBuilder.setSmallIcon(R.drawable.ic_sync_white_24dp);
        mBuilder.setContentTitle(getString(R.string.updatingTvShows));
        mBuilder.setContentText(getString(R.string.analyzing_files));

        // Show the updated notification
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

    private void showPostUpdateNotification() {
        mShowCount = mUniqueShowIds.size();

        // Set up cancel dialog intent
        Intent notificationIntent = new Intent(this, Main.class);
        notificationIntent.putExtra("fromUpdate", true);
        notificationIntent.putExtra("startup", "2");
        notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        // Setup up notification
        mBuilder = new NotificationCompat.Builder(getApplicationContext());
        mBuilder.setColor(getResources().getColor(R.color.color_primary));
        if (!mStopUpdate) {
            mBuilder.setSmallIcon(R.drawable.ic_done_white_24dp);
            mBuilder.setTicker(getString(R.string.finishedTvShowsLibraryUpdate));
            mBuilder.setContentTitle(getString(R.string.finishedTvShowsLibraryUpdate));
            mBuilder.setContentText(getString(R.string.stringJustAdded) + " " + mShowCount + " "
                    + getResources().getQuantityString(R.plurals.showsInLibrary, mShowCount, mShowCount) + " ("
                    + mEpisodeCount + " "
                    + getResources().getQuantityString(R.plurals.episodes, mEpisodeCount, mEpisodeCount) + ")");
        } else {
            mBuilder.setSmallIcon(R.drawable.ic_cancel_white_24dp);
            mBuilder.setTicker(getString(R.string.stringUpdateCancelled));
            mBuilder.setContentTitle(getString(R.string.stringUpdateCancelled));
            mBuilder.setContentText(getString(R.string.stringJustAdded) + " " + mShowCount + " "
                    + getResources().getQuantityString(R.plurals.showsInLibrary, mShowCount, mShowCount) + " ("
                    + mEpisodeCount + " "
                    + getResources().getQuantityString(R.plurals.episodes, mEpisodeCount, mEpisodeCount) + ")");
        }
        mBuilder.setContentIntent(contentIntent);
        mBuilder.setAutoCancel(true);

        // Build notification
        Notification updateNotification = mBuilder.build();

        // Show the notification
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        if (mEpisodeCount > 0)
            mNotificationManager.notify(POST_UPDATE_NOTIFICATION, updateNotification);
    }
}