/*
This file is part of BeepMe.
BeepMe 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.
BeepMe 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 BeepMe. If not, see <http://www.gnu.org/licenses/>.
Copyright 2012-2014 Michael Glanznig
http://beepme.yourexp.at
*/
package com.glanznig.beepme.view;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.glanznig.beepme.BeeperApp;
import com.glanznig.beepme.R;
import com.glanznig.beepme.data.DataExporter;
import com.glanznig.beepme.helper.PhotoUtils;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Calendar;
public class ExportActivity extends Activity implements View.OnClickListener {
private static class ExportHandler extends Handler {
WeakReference<ExportActivity> activity;
Bundle data;
ExportHandler(ExportActivity activity) {
this.activity = new WeakReference<ExportActivity>(activity);
}
@Override
public void handleMessage(Message message) {
if (activity.get() != null) {
NotificationManager manager = (NotificationManager)activity.get().getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(TAG, EXPORT_RUNNING_NOTIFICATION);
BeeperApp app = (BeeperApp) activity.get().getApplication();
app.getPreferences().setExportRunningSince(0L);
ProgressBar progress = (ProgressBar)activity.get().findViewById(R.id.export_progress_bar);
progress.setVisibility(View.GONE);
DisplayMetrics metrics = activity.get().getResources().getDisplayMetrics();
TextView runningText = (TextView)activity.get().findViewById(R.id.export_running_text);
runningText.setTextSize(16);
runningText.setPadding(0, (int)(32 * metrics.density + 0.5f), 0, 0);
data = message.getData();
if (data.getString("fileName") != null) {
// check if archive exists
File archive = new File(data.getString("fileName"));
if (archive != null && archive.exists()) {
runningText.setText(R.string.export_successful);
activity.get().createExportFinishedNotification(true);
}
else {
runningText.setText(R.string.export_failed);
activity.get().createExportFinishedNotification(false);
}
String action = data.getString("action");
if (action != null) {
if (action.equals("mail")) {
Uri fUri = Uri.fromFile(archive);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, activity.get().getString(R.string.export_mail_subject));
sendIntent.putExtra(Intent.EXTRA_STREAM, fUri);
sendIntent.setType("text/rfc822");
try {
activity.get().startActivity(Intent.createChooser(sendIntent, activity.get().getString((R.string.export_mail_chooser_title))));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(activity.get(), R.string.export_no_mail_apps, Toast.LENGTH_SHORT).show();
}
}
}
}
}
}
}
private static class ExportRunnable implements Runnable {
WeakReference<ExportActivity> activity;
Bundle opts;
String action;
public ExportRunnable(ExportActivity activity, Bundle opts) {
this.activity = new WeakReference<ExportActivity>(activity);
this.opts = opts;
Spinner actions = (Spinner)this.activity.get().findViewById(R.id.export_post_actions);
int pos = actions.getSelectedItemPosition();
switch (pos) {
case 1:
action = "mail";
break;
}
}
@Override
public void run() {
if (activity.get() != null) {
DataExporter exporter = new DataExporter(activity.get().getApplicationContext());
String fileName;
int densityFactor = 1;
if (opts.getBoolean("photoExport", true)) {
if (activity.get().densityItem > -1) {
densityFactor = activity.get().densityFactors.get(activity.get().densityItem);
}
}
opts.putInt("densityFactor", densityFactor);
fileName = exporter.exportToZipFile(opts);
if (activity.get().exportHandler != null) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("fileName", fileName);
if (action != null) {
bundle.putString("action", action);
}
msg.setData(bundle);
activity.get().exportHandler.sendMessage(msg);
}
}
}
}
private static class PhotoDimRunnable implements Runnable {
WeakReference<ExportActivity> activity;
WeakReference<PhotoDimHandler> handler;
public PhotoDimRunnable(ExportActivity activity, PhotoDimHandler handler) {
this.activity = new WeakReference<ExportActivity>(activity);
this.handler = new WeakReference<PhotoDimHandler>(handler);
}
@Override
public void run() {
if (activity.get() != null) {
File[] photos = PhotoUtils.getPhotos(activity.get());
int count = 0;
int overallDensity = 0;
if (photos != null) {
for (count = 0; count < photos.length; count++) {
Bundle dim = PhotoUtils.getPhotoDimensions(photos[count].getAbsolutePath());
int width = dim.getInt("width");
int height = dim.getInt("height");
overallDensity += width * height;
}
}
float avgDensity;
if (count > 0 ) {
avgDensity = ((float)overallDensity / count) / 1000000; // megapixel
}
else {
avgDensity = 0;
}
if (handler.get() != null) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putFloat("photoAvgDensity", avgDensity);
msg.setData(bundle);
handler.get().sendMessage(msg);
}
}
}
}
private static class PhotoDimHandler extends Handler {
WeakReference<ExportActivity> activity;
PhotoDimHandler(ExportActivity activity) {
this.activity = new WeakReference<ExportActivity>(activity);
}
@Override
public void handleMessage(Message message) {
if (activity.get() != null) {
Bundle data = message.getData();
if (data.containsKey("photoAvgDensity")) {
activity.get().photoAvgDensity = data.getFloat("photoAvgDensity");
TextView density = (TextView)activity.get().findViewById(R.id.export_photos_avg_size);
density.setText(activity.get().getString(R.string.export_photos_avg_size,
String.format("%.1f", activity.get().photoAvgDensity)));
activity.get().downscaleAdapter.add(String.format(activity.get().getString(R.string.export_downscale_original_size),
DataExporter.getReadableFileSize(activity.get().photoAvgSize, 0)));
activity.get().densityFactors.add(Integer.valueOf(1));
int densityFactor = 2;
for (; (Math.round((activity.get().photoAvgDensity / densityFactor) * 2) / 2f) > 1; densityFactor *= 2) {
activity.get().downscaleAdapter.add(String.format(activity.get().getString(R.string.export_downscale),
String.format("%.1f", Math.round((activity.get().photoAvgDensity / densityFactor) * 2) / 2f),
DataExporter.getReadableFileSize(activity.get().photoAvgSize / densityFactor, 0)));
activity.get().densityFactors.add(Integer.valueOf(densityFactor));
}
activity.get().downscaleAdapter.add(String.format(activity.get().getString(R.string.export_downscale),
String.valueOf(1), DataExporter.getReadableFileSize(activity.get().photoAvgSize / densityFactor, 0)));
activity.get().densityFactors.add(Integer.valueOf(densityFactor));
if (activity.get().densityItem != -1) {
activity.get().downscalePhotos.setSelection(activity.get().densityItem);
}
}
}
}
}
private static final String TAG = "ExportActivity";
public static final int EXPORT_RUNNING_NOTIFICATION = 523;
private static final int EXPORT_FINISHED_NOTIFICATION = 524;
private boolean rawExport = false;
private boolean photoExport = true;
private int postActionItem = -1;
private int densityItem = -1;
private double photoAvgSize = 0;
private float photoAvgDensity = 0;
private ArrayList<Integer> densityFactors;
private DataExporter exporter;
private ArrayAdapter<CharSequence> downscaleAdapter;
private ExportHandler exportHandler;
private Spinner postActions;
private Spinner downscalePhotos;
private TextView estimatedSize;
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.export_data);
exporter = new DataExporter(ExportActivity.this);
densityFactors = new ArrayList<Integer>();
if (savedState != null) {
rawExport = savedState.getBoolean("rawExport");
photoExport = savedState.getBoolean("photoExport");
if (savedState.getInt("postActionItem") != 0) {
postActionItem = savedState.getInt("postActionItem") - 1;
}
if (savedState.getInt("densityItem") != 0) {
densityItem = savedState.getInt("densityItem") - 1;
}
photoAvgSize = savedState.getDouble("photoAvgSize");
photoAvgDensity = savedState.getFloat("photoAvgDensity");
}
}
@Override
public void onResume() {
super.onResume();
populateFields();
}
private void populateFields() {
BeeperApp app = (BeeperApp)getApplication();
if (app.getPreferences().exportRunningSince() == 0L ||
(Calendar.getInstance().getTimeInMillis() -
app.getPreferences().exportRunningSince()) >= 120000) { //2 min
enableDisableView(findViewById(R.id.export_settings), true);
CheckBox rawExp = (CheckBox)findViewById(R.id.export_raw);
rawExp.setChecked(rawExport);
rawExp.setOnClickListener(this);
CheckBox photoExp = (CheckBox)findViewById(R.id.export_photos);
View photoExpGroup = findViewById(R.id.export_photos_group);
if (PhotoUtils.isEnabled(ExportActivity.this)) {
photoExp.setVisibility(View.VISIBLE);
photoExpGroup.setVisibility(View.VISIBLE);
File[] photos = PhotoUtils.getPhotos(ExportActivity.this);
if (photos != null && photos.length > 0) {
photoExp.setEnabled(true);
photoExp.setChecked(photoExport);
photoExp.setOnClickListener(this);
enableDisableView(photoExpGroup, photoExport);
} else {
photoExp.setChecked(false);
photoExp.setEnabled(false);
enableDisableView(photoExpGroup, false);
}
downscalePhotos = (Spinner)findViewById(R.id.export_downscale_photos);
downscaleAdapter = new ArrayAdapter<CharSequence>(ExportActivity.this,
android.R.layout.simple_spinner_item, new ArrayList<CharSequence>());
downscaleAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
downscalePhotos.setAdapter(downscaleAdapter);
downscalePhotos.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
densityItem = position;
Bundle opts = new Bundle();
opts.putBoolean("photoExport", photoExport);
opts.putBoolean("rawExport", rawExport);
estimatedSize.setText(String.format(getString(R.string.export_archive_estimated_size),
exporter.getReadableArchiveSize(opts,
densityFactors.get(downscalePhotos.getSelectedItemPosition()).intValue())));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
if (photoAvgSize == 0) {
File[] photoFiles = PhotoUtils.getPhotos(ExportActivity.this);
int count = 0;
int overallSize = 0;
if (photoFiles != null) {
for (count = 0; count < photoFiles.length; count++) {
overallSize += photoFiles[count].length();
}
if (count > 0) {
photoAvgSize = overallSize / count;
}
}
}
if (photoAvgDensity == 0) {
new Thread(new PhotoDimRunnable(ExportActivity.this, new PhotoDimHandler(ExportActivity.this))).start();
}
else {
TextView density = (TextView)findViewById(R.id.export_photos_avg_size);
density.setText(getString(R.string.export_photos_avg_size,
String.format("%.1f", photoAvgDensity)));
downscaleAdapter.add(String.format(getString(R.string.export_downscale_original_size),
DataExporter.getReadableFileSize(photoAvgSize, 0)));
densityFactors.add(Integer.valueOf(1));
int densityFactor = 2;
for (; (Math.round((photoAvgDensity / densityFactor) * 2) / 2f) > 1; densityFactor *= 2) {
downscaleAdapter.add(String.format(getString(R.string.export_downscale),
String.format("%.1f", Math.round((photoAvgDensity / densityFactor) * 2) / 2f),
DataExporter.getReadableFileSize(photoAvgSize / densityFactor, 0)));
densityFactors.add(Integer.valueOf(densityFactor));
}
downscaleAdapter.add(String.format(getString(R.string.export_downscale),
String.valueOf(1), DataExporter.getReadableFileSize(photoAvgSize / densityFactor, 0)));
densityFactors.add(Integer.valueOf(densityFactor));
if (densityItem != -1) {
downscalePhotos.setSelection(densityItem);
}
}
} else {
photoExp.setVisibility(View.GONE);
photoExpGroup.setVisibility(View.GONE);
}
postActions = (Spinner)findViewById(R.id.export_post_actions);
ArrayAdapter<CharSequence> actionsAdapter = ArrayAdapter.createFromResource(this,
R.array.post_export_actions, android.R.layout.simple_spinner_item);
actionsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
postActions.setAdapter(actionsAdapter);
if (postActionItem != -1) {
postActions.setSelection(postActionItem);
}
estimatedSize = (TextView)findViewById(R.id.export_estimated_size);
int densityFactor = 1;
if (densityFactors.size() > 0 && downscalePhotos.getSelectedItemPosition() >= 0) {
densityFactor = densityFactors.get(downscalePhotos.getSelectedItemPosition()).intValue();
}
Bundle opts = new Bundle();
opts.putBoolean("photoExport", photoExport);
opts.putBoolean("rawExport", rawExport);
estimatedSize.setText(String.format(getString(R.string.export_archive_estimated_size),
exporter.getReadableArchiveSize(opts, densityFactor)));
Button start = (Button)findViewById(R.id.export_start_button);
ProgressBar progress = (ProgressBar)findViewById(R.id.export_progress_bar);
TextView runningText = (TextView)findViewById(R.id.export_running_text);
start.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
runningText.setVisibility(View.GONE);
}
else {
Button start = (Button)findViewById(R.id.export_start_button);
ProgressBar progress = (ProgressBar)findViewById(R.id.export_progress_bar);
TextView runningText = (TextView)findViewById(R.id.export_running_text);
start.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
runningText.setVisibility(View.VISIBLE);
enableDisableView(findViewById(R.id.export_settings), false);
}
}
private void enableDisableView(View view, boolean enabled) {
view.setEnabled(enabled);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup)view;
for (int i = 0 ; i < group.getChildCount(); i++) {
enableDisableView(group.getChildAt(i), enabled);
}
}
}
@Override
public void onSaveInstanceState(Bundle savedState) {
savedState.putBoolean("rawExport", rawExport);
savedState.putBoolean("photoExport", photoExport);
savedState.putInt("postActionItem", postActions.getSelectedItemPosition() + 1);
savedState.putInt("densityItem", downscalePhotos.getSelectedItemPosition() + 1);
savedState.putDouble("photoAvgSize", photoAvgSize);
savedState.putFloat("photoAvgDensity", photoAvgDensity);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.export_photos:
photoExport = ((CheckBox)view).isChecked();
enableDisableView(findViewById(R.id.export_photos_group), photoExport);
break;
case R.id.export_raw:
rawExport = ((CheckBox)view).isChecked();
break;
}
Bundle opts = new Bundle();
opts.putBoolean("photoExport", photoExport);
opts.putBoolean("rawExport", rawExport);
estimatedSize.setText(String.format(getString(R.string.export_archive_estimated_size),
exporter.getReadableArchiveSize(opts,
densityFactors.get(downscalePhotos.getSelectedItemPosition()).intValue())
));
}
public void startExport(View v) {
Button start = (Button)findViewById(R.id.export_start_button);
ProgressBar progress = (ProgressBar)findViewById(R.id.export_progress_bar);
TextView runningText = (TextView)findViewById(R.id.export_running_text);
BeeperApp app = (BeeperApp)getApplication();
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
enableDisableView(findViewById(R.id.export_settings), false);
start.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
runningText.setVisibility(View.VISIBLE);
if (app.getPreferences().exportRunningSince() == 0L ||
(Calendar.getInstance().getTimeInMillis() -
app.getPreferences().exportRunningSince()) >= 120000) { //2 min
app.getPreferences().setExportRunningSince(Calendar.getInstance().getTimeInMillis());
createExportRunningNotification();
exportHandler = new ExportHandler(ExportActivity.this);
Bundle opts = new Bundle();
opts.putBoolean("photoExport", photoExport);
opts.putBoolean("rawExport", rawExport);
new Thread(new ExportRunnable(ExportActivity.this, opts)).start();
}
}
else {
Toast.makeText(ExportActivity.this, R.string.export_storage_error, Toast.LENGTH_SHORT).show();
}
}
private void createExportRunningNotification() {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this.getApplicationContext());
notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify);
notificationBuilder.setContentTitle(getResources().getString(R.string.app_name));
notificationBuilder.setContentText(this.getString(R.string.export_running_data));
//set as ongoing, so it cannot be cleared
notificationBuilder.setOngoing(true);
//add progress bar (indeterminate)
notificationBuilder.setProgress(0, 0, true);
Intent resultIntent = new Intent(this.getApplicationContext(), ExportActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
stackBuilder.addParentStack(ExportActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(resultPendingIntent);
NotificationManager manager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(TAG, EXPORT_RUNNING_NOTIFICATION, notificationBuilder.build());
}
private void createExportFinishedNotification(boolean successful) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this.getApplicationContext());
notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify);
notificationBuilder.setContentTitle(getResources().getString(R.string.app_name));
String notify;
if (successful) {
notify = this.getString(R.string.export_successful);
}
else {
notify = this.getString(R.string.export_failed);
}
notificationBuilder.setContentText(notify);
Intent resultIntent = new Intent(this.getApplicationContext(), MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(resultPendingIntent);
NotificationManager manager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(TAG, EXPORT_FINISHED_NOTIFICATION, notificationBuilder.build());
}
}