package com.ianhanniballake.contractiontimer.ui;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.ShareCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.FileProvider;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.ianhanniballake.contractiontimer.BuildConfig;
import com.ianhanniballake.contractiontimer.R;
import com.ianhanniballake.contractiontimer.data.CSVTransformer;
import com.ianhanniballake.contractiontimer.notification.NotificationUpdateService;
import com.ianhanniballake.contractiontimer.provider.ContractionContract;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Main Activity for managing contractions
*/
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
/**
* Intent extra used to signify that this activity was launched from a widget
*/
public final static String LAUNCHED_FROM_WIDGET_EXTRA = "com.ianhanniballake.contractiontimer.LaunchedFromWidget";
/**
* Intent extra used to signify that this activity was launched from the notification
*/
public final static String LAUNCHED_FROM_NOTIFICATION_EXTRA =
"com.ianhanniballake.contractiontimer.LaunchedFromNotification";
/**
* Intent extra used to signify that this activity was launched from the notification's Add/Edit Note action
*/
public final static String LAUNCHED_FROM_NOTIFICATION_ACTION_NOTE_EXTRA =
"com.ianhanniballake.contractiontimer.LaunchedFromNotificationActionNote";
private final static String TAG = MainActivity.class.getSimpleName();
/**
* Adapter to store and manage the current cursor
*/
private CursorAdapter adapter;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
// If there is no data associated with the Intent, sets the data to the
// default URI, which accesses all contractions.
if (intent.getData() == null)
intent.setData(ContractionContract.Contractions.CONTENT_URI);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setElevation(getResources().getDimension(R.dimen.action_bar_elevation));
if (savedInstanceState == null)
showFragments();
adapter = new CursorAdapter(this, null, 0) {
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
// Nothing to do
}
@Override
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
return null;
}
};
getSupportLoaderManager().initLoader(0, null, this);
}
@Override
protected void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
final String[] projection = {BaseColumns._ID, ContractionContract.Contractions.COLUMN_NAME_START_TIME,
ContractionContract.Contractions.COLUMN_NAME_END_TIME,
ContractionContract.Contractions.COLUMN_NAME_NOTE};
final String selection = ContractionContract.Contractions.COLUMN_NAME_START_TIME + ">?";
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final long averagesTimeFrame = Long.parseLong(preferences.getString(
Preferences.AVERAGE_TIME_FRAME_PREFERENCE_KEY,
getString(R.string.pref_average_time_frame_default)));
final long timeCutoff = System.currentTimeMillis() - averagesTimeFrame;
final String[] selectionArgs = {Long.toString(timeCutoff)};
return new CursorLoader(this, getIntent().getData(), projection, selection, selectionArgs, null);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public void onLoaderReset(final Loader<Cursor> loader) {
adapter.swapCursor(null);
supportInvalidateOptionsMenu();
}
@Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
adapter.swapCursor(data);
supportInvalidateOptionsMenu();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(this);
switch (item.getItemId()) {
case R.id.menu_share:
if (BuildConfig.DEBUG)
Log.d(TAG, "Menu selected Share");
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, "contraction");
bundle.putString(FirebaseAnalytics.Param.ITEM_ID, Integer.toString(adapter.getCursor().getCount()));
analytics.logEvent(FirebaseAnalytics.Event.SHARE, bundle);
shareContractions();
return true;
case R.id.menu_add:
if (BuildConfig.DEBUG)
Log.d(TAG, "Menu selected Add");
analytics.logEvent("add_open", null);
final Intent addIntent = new Intent(Intent.ACTION_INSERT, getIntent().getData())
.setPackage(getPackageName());
startActivity(addIntent);
return true;
case R.id.menu_settings:
startActivity(new Intent(this, Preferences.class));
return true;
case R.id.menu_donate:
if (BuildConfig.DEBUG)
Log.d(TAG, "Menu selected Donate");
analytics.logEvent("donate_open", null);
startActivity(new Intent(this, DonateActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
super.onPrepareOptionsMenu(menu);
final int contractionCount = adapter == null ? 0 : adapter.getCount();
final boolean hasContractions = contractionCount > 0;
final MenuItem share = menu.findItem(R.id.menu_share);
share.setVisible(hasContractions);
return true;
}
@Override
protected void onResume() {
super.onResume();
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final boolean isKeepScreenOn = preferences.getBoolean(Preferences.KEEP_SCREEN_ON_PREFERENCE_KEY, getResources()
.getBoolean(R.bool.pref_keep_screen_on_default));
if (BuildConfig.DEBUG)
Log.d(TAG, "Keep Screen On: " + isKeepScreenOn);
if (isKeepScreenOn)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
else
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
final boolean isLockPortrait = preferences.getBoolean(Preferences.LOCK_PORTRAIT_PREFERENCE_KEY, getResources()
.getBoolean(R.bool.pref_lock_portrait_default));
if (BuildConfig.DEBUG)
Log.d(TAG, "Lock Portrait: " + isLockPortrait);
if (isLockPortrait)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
else
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
final boolean averageTimeFrameChanged = preferences.getBoolean(
Preferences.AVERAGE_TIME_FRAME_CHANGED_MAIN_PREFERENCE_KEY, false);
if (averageTimeFrameChanged) {
final Editor editor = preferences.edit();
editor.remove(Preferences.AVERAGE_TIME_FRAME_CHANGED_MAIN_PREFERENCE_KEY);
editor.commit();
getSupportLoaderManager().restartLoader(0, null, this);
}
}
@Override
protected void onStart() {
super.onStart();
FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(this);
Intent intent = getIntent();
if (intent.hasExtra(MainActivity.LAUNCHED_FROM_WIDGET_EXTRA)) {
final String widgetIdentifier = intent.getStringExtra(MainActivity.LAUNCHED_FROM_WIDGET_EXTRA);
if (BuildConfig.DEBUG)
Log.d(TAG, "Launched from " + widgetIdentifier);
analytics.logEvent(widgetIdentifier + "_launch", null);
intent.removeExtra(MainActivity.LAUNCHED_FROM_WIDGET_EXTRA);
}
if (intent.hasExtra(MainActivity.LAUNCHED_FROM_NOTIFICATION_EXTRA)) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Launched from Notification");
analytics.logEvent("notification_launch", null);
intent.removeExtra(MainActivity.LAUNCHED_FROM_NOTIFICATION_EXTRA);
}
if (intent.hasExtra(MainActivity.LAUNCHED_FROM_NOTIFICATION_ACTION_NOTE_EXTRA)) {
long id = intent.getLongExtra(BaseColumns._ID, -1L);
String existingNote = intent.getStringExtra(ContractionContract.Contractions.COLUMN_NAME_NOTE);
String type = TextUtils.isEmpty(existingNote) ? "Add Note" : "Edit Note";
if (BuildConfig.DEBUG)
Log.d(TAG, "Launched from Notification " + type + " action");
final NoteDialogFragment noteDialogFragment = new NoteDialogFragment();
final Bundle args = new Bundle();
args.putLong(NoteDialogFragment.CONTRACTION_ID_ARGUMENT, id);
args.putString(NoteDialogFragment.EXISTING_NOTE_ARGUMENT, existingNote);
noteDialogFragment.setArguments(args);
analytics.logEvent(TextUtils.isEmpty(existingNote) ? "note_add_launch" : "note_edit_launch", null);
noteDialogFragment.show(getSupportFragmentManager(), "note");
intent.removeExtra(MainActivity.LAUNCHED_FROM_NOTIFICATION_ACTION_NOTE_EXTRA);
}
NotificationUpdateService.updateNotification(this);
}
/**
* Builds the averages data to share and opens the Intent chooser
*/
private void shareContractions() {
final Cursor data = adapter.getCursor();
if (data.getCount() == 0)
return;
final TextView averageDurationView = (TextView) findViewById(R.id.average_duration);
final TextView averageFrequencyView = (TextView) findViewById(R.id.average_frequency);
data.moveToLast();
final int startTimeColumnIndex = data.getColumnIndex(ContractionContract.Contractions.COLUMN_NAME_START_TIME);
final long lastStartTime = data.getLong(startTimeColumnIndex);
final int count = adapter.getCount();
final CharSequence relativeTimeSpan = DateUtils.getRelativeTimeSpanString(lastStartTime);
final String formattedData = getResources().getQuantityString(
R.plurals.share_average,
count,
relativeTimeSpan,
count,
averageDurationView.getText(),
averageFrequencyView.getText());
new AsyncTask<Void, Void, Uri>() {
@Override
protected void onPreExecute() {
// TODO Show progress bar
}
@Override
protected Uri doInBackground(final Void... params) {
File exportPath = new File(getCacheDir(), "export");
if (!exportPath.mkdirs() && !exportPath.isDirectory()) {
Log.e(TAG, "Error creating export directory");
return null;
}
File file = new File(exportPath, getString(R.string.drive_default_filename) + ".csv");
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
CSVTransformer.writeContractions(MainActivity.this, fileOutputStream);
return FileProvider.getUriForFile(MainActivity.this, BuildConfig.FILES_AUTHORITY, file);
} catch (IOException e) {
Log.e(TAG, "Error writing contractions to file", e);
return null;
}
}
@Override
protected void onPostExecute(final Uri uri) {
// TODO Hide progress bar
ShareCompat.IntentBuilder intentBuilder = ShareCompat.IntentBuilder.from(MainActivity.this)
.setSubject(getString(R.string.share_subject)).setType("text/plain").setText(formattedData);
if (uri != null) {
intentBuilder.addStream(uri);
}
intentBuilder.setChooserTitle(R.string.share_pick_application).startChooser();
}
}.execute();
}
/**
* Creates and shows the fragments for the MainActivity
*/
private void showFragments() {
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(new ResetMenuControllerFragment(), "reset_menu");
ft.commit();
}
}