/** * */ package com.gmail.charleszq.picorner.offline; import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.app.IntentService; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.v4.app.NotificationCompat; import android.util.Log; import com.gmail.charleszq.picorner.BuildConfig; import com.gmail.charleszq.picorner.R; import com.gmail.charleszq.picorner.SPUtil; /** * @author charles(charleszq@gmail.com) * */ public class OfflineHandleService extends IntentService { /** * The log tag */ private static final String TAG = OfflineHandleService.class .getSimpleName(); private static final int DOWNLOAD_NOTIF_ID = 100001; private static final int REMOVE_OFFLINE_PHOTOS_MSG_ID = 100003; private static final int EXPORT_OFFLINE_PHOTOS_MSG_ID = 100004; public static final int ADD_OFFLINE_PARAM = 1; public static final int REMOVE_OFFLINE_PARAM = 2; public static final int REFRESH_OFFLINE_PARAM = 3; public static final int DOWNLOAD_OFFLINE_PARAM = 4; public static final int DELETE_OFFLINE_PHOTO_PARAM = 5; public static final int EXPORT_OFFLINE_PHOTO_PARAM = 6; /** * @param name */ public OfflineHandleService() { super("PiCorner offline view photo service"); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see android.app.IntentService#onHandleIntent(android.content.Intent) */ @Override protected void onHandleIntent(Intent intent) { // check if offline is enabled or not boolean offlineEnabled = SPUtil.isOfflineEnabled(this); boolean isDownloadWhenCharging = SPUtil .isDownloadingWhenChargingEnabled(this); if (!offlineEnabled) return; // get the caller information to see if the call comes from battery // charging String caller = intent .getStringExtra(IOfflineViewParameter.OFFLINE_INVOKER_INTENT_KEY); if (BatteryStatusReceiver.class.getName().equals(caller) && !isDownloadWhenCharging) { if (BuildConfig.DEBUG) Log.d(TAG, "user disabled the setting: download when charging."); //$NON-NLS-1$ return; } // process IOfflineViewParameter param = (IOfflineViewParameter) intent .getSerializableExtra(IOfflineViewParameter.OFFLINE_PARAM_INTENT_KEY); int actionType = intent .getIntExtra( IOfflineViewParameter.OFFLINE_PARAM_INTENT_ADD_REMOVE_REFRESH_KEY, ADD_OFFLINE_PARAM); if (param == null) { downlaodPhotos(param, false); } else { switch (actionType) { case ADD_OFFLINE_PARAM: manageRepository(param, true); break; case REMOVE_OFFLINE_PARAM: manageRepository(param, false); break; case REFRESH_OFFLINE_PARAM: downlaodPhotos(param, false); break; case DOWNLOAD_OFFLINE_PARAM: downlaodPhotos(param, true); break; case DELETE_OFFLINE_PHOTO_PARAM: removeCachedPhotos(param); break; case EXPORT_OFFLINE_PHOTO_PARAM: String foldername = intent .getStringExtra(IOfflineViewParameter.OFFLINE_EXPORT_FOLDER_NAME_KEY); if (foldername == null) { Log.e(TAG, "missing folder name."); //$NON-NLS-1$ foldername = param.getTitle(); } boolean overwrite = intent.getBooleanExtra( IOfflineViewParameter.OFFLINE_EXPORT_OVERWRITE_KEY, false); exportPhotos(param, foldername, overwrite); break; } } } /** * Exports the photos to a folder inside 'picorner' * * @param param * @param foldername */ private void exportPhotos(IOfflineViewParameter param, String foldername, boolean overwrite) { IOfflinePhotoCollectionProcessor p = param .getPhotoCollectionProcessor(); String msg = getString(R.string.msg_offline_exporting); NotificationCompat.Builder builder = sendNotification( EXPORT_OFFLINE_PHOTOS_MSG_ID, msg); msg = getString(R.string.msg_offline_export_photos_error); try { IProgressReporter reporter = new ProgressReporter(builder, EXPORT_OFFLINE_PHOTOS_MSG_ID ); int count = p.exportCachedPhotos(this, param, foldername, overwrite, reporter); msg = getString(R.string.msg_offline_export_photos); msg = String.format(msg, foldername); msg = count + " " + msg; //$NON-NLS-1$ } catch (IOException e) { } sendNotification(EXPORT_OFFLINE_PHOTOS_MSG_ID, msg); } /** * Removes all the cached photos for the given <code>param</code> * * @param param */ private void removeCachedPhotos(IOfflineViewParameter param) { IOfflinePhotoCollectionProcessor p = param .getPhotoCollectionProcessor(); int count = p.removeCachedPhotos(this, param); if (count == -1) { sendNotification(REMOVE_OFFLINE_PHOTOS_MSG_ID, getString(R.string.msg_offline_delete_photos_minus_one)); } else { String msg = getString(R.string.msg_offline_delete_photos); msg = String.format(msg, count); sendNotification(REMOVE_OFFLINE_PHOTOS_MSG_ID, msg); } } /** * * @param offline * @param redownload * <code>true</code> to download photos even there is no update * on server; <code>false</code> otherwise. */ private void downlaodPhotos(IOfflineViewParameter offline, boolean redownload) { // check network connection type ConnectivityManager cm = (ConnectivityManager) this .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); if (activeNetwork == null) { if (BuildConfig.DEBUG) { Log.d(TAG, "not network available."); //$NON-NLS-1$ } return; } boolean isWifiOnly = SPUtil.isOfflineWifiOnly(this); boolean isConnected = activeNetwork.isConnectedOrConnecting(); boolean isWifi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI; if (!isConnected) { if (BuildConfig.DEBUG) Log.d(TAG, "network is not connected, don't start the offline download process."); //$NON-NLS-1$ return; } else { if (isWifiOnly && !isWifi) { if (BuildConfig.DEBUG) Log.d(TAG, "wifi only offline download, but the network is not wifi."); //$NON-NLS-1$ return; } } // nofify user in status bar. NotificationCompat.Builder builder = sendNotification(DOWNLOAD_NOTIF_ID, getString(R.string.msg_offline_downloading)); IProgressReporter reporter = new ProgressReporter(builder,DOWNLOAD_NOTIF_ID); List<IOfflineViewParameter> params = OfflineControlFileUtil .getExistingOfflineParameters(this); if (params == null) { Log.w(TAG, "repository file not found."); //$NON-NLS-1$ return; } if (offline != null) { if (params.contains(offline)) { int pos = params.indexOf(offline); offline = params.get(pos); ((AbstractOfflineParameter) offline).setLastUpdateTime(System .currentTimeMillis()); processOfflineParameter(offline, true, redownload, reporter); } else { // not enabled, just return return; } } else { for (IOfflineViewParameter param : params) { this.processOfflineParameter(param, false, redownload, reporter); } } try { OfflineControlFileUtil.saveRepositoryControlFile(this, params); } catch (Exception e) { if (BuildConfig.DEBUG) Log.w(TAG, "error to save offline control file: " + e.getMessage()); //$NON-NLS-1$ } } private NotificationCompat.Builder sendNotification(int id, String msg) { NotificationCompat.Builder builder = new NotificationCompat.Builder( this).setSmallIcon(R.drawable.ic_launcher) .setContentTitle(getString(R.string.app_name)) .setContentText(msg); NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.notify(id, builder.build()); return builder; } /** * Manages the repository. * * @param param * @param add */ private void manageRepository(IOfflineViewParameter param, boolean add) { Log.d(TAG, param.toString()); List<IOfflineViewParameter> params = OfflineControlFileUtil .getExistingOfflineParameters(this); if (params == null) { params = new ArrayList<IOfflineViewParameter>(); } if (add) { if (!params.contains(param)) params.add(0, param); } else { params.remove(param); } try { OfflineControlFileUtil.saveRepositoryControlFile(this, params); } catch (Exception e) { Log.w(TAG, e.getMessage()); } } /** * Starts the process to get the photo collection information, and download * large image * * @param param */ private void processOfflineParameter(IOfflineViewParameter param, boolean doitnow, boolean redownload, IProgressReporter reporter) { if (doitnow || longerThanFiveHours(param)) { // do it. IOfflinePhotoCollectionProcessor p = param .getPhotoCollectionProcessor(); ((AbstractOfflineParameter) param).setLastUpdateTime(System .currentTimeMillis()); p.process(this, param, redownload, reporter); } } private boolean longerThanFiveHours(IOfflineViewParameter param) { long lastUpdateTime = param.getLastUpdateTime(); if (lastUpdateTime == 0) { if (BuildConfig.DEBUG) Log.d(TAG, "the offline parameter has no last update time saved."); //$NON-NLS-1$ return true; } long delta = System.currentTimeMillis() - lastUpdateTime; boolean ret = delta > 5 * 60 * 60 * 1000; if (BuildConfig.DEBUG) Log.d(TAG, "longer than 5 hours? " + Boolean.toString(ret)); //$NON-NLS-1$ return ret; } @Override public void onDestroy() { NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.cancel(DOWNLOAD_NOTIF_ID); super.onDestroy(); } /** * Represents the interface to set progress on notification bar. * @author charles(charleszq@gmail.com) * */ public interface IProgressReporter { void reportProgress(int total, int progress); } /** * Represents the status bar progress report. * @author charles(charleszq@gmail.com) * */ private class ProgressReporter implements IProgressReporter { private NotificationCompat.Builder mBuilder; private int mNotificationId; ProgressReporter(NotificationCompat.Builder builder, int id) { this.mBuilder = builder; this.mNotificationId = id; } @Override public void reportProgress(int total, int progress) { mBuilder.setProgress(total, progress, false); mBuilder.setContentInfo( progress + "/" + total ); //$NON-NLS-1$ NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); nm.notify(mNotificationId, mBuilder.build()); } } }