com.ereinecke.eatsafe.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.ereinecke.eatsafe.MainActivity.java

Source

package com.ereinecke.eatsafe;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import com.commonsware.cwac.provider.StreamProvider;
import com.ereinecke.eatsafe.data.OpenFoodContract;
import com.ereinecke.eatsafe.services.OpenFoodService;
import com.ereinecke.eatsafe.ui.AboutFragment;
import com.ereinecke.eatsafe.ui.DeleteDialog;
import com.ereinecke.eatsafe.ui.LoginDialog;
import com.ereinecke.eatsafe.ui.ProductFragment;
import com.ereinecke.eatsafe.ui.SearchFragment;
import com.ereinecke.eatsafe.ui.SplashFragment;
import com.ereinecke.eatsafe.ui.TabPagerFragment;
import com.ereinecke.eatsafe.ui.UploadDialog;
import com.ereinecke.eatsafe.ui.UploadFragment;
import com.ereinecke.eatsafe.ui.UploadFragment.PhotoRequest;
import com.ereinecke.eatsafe.ui.WebFragment;
import com.ereinecke.eatsafe.util.App;
import com.ereinecke.eatsafe.util.Constants;
import com.ereinecke.eatsafe.util.Utility;
import com.ereinecke.eatsafe.util.Utility.Callback;
import com.github.johnpersano.supertoasts.library.SuperActivityToast;
import com.google.android.gms.ads.MobileAds;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import com.mikepenz.aboutlibraries.LibsBuilder;
import com.mikepenz.aboutlibraries.ui.LibsSupportFragment;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;

import static com.ereinecke.eatsafe.util.Utility.Logd;
import static com.ereinecke.eatsafe.util.Utility.infoStyle;

public class MainActivity extends AppCompatActivity implements Callback, PhotoRequest,
        UploadDialog.UploadDialogListener, DeleteDialog.NoticeDialogListener, LoginDialog.LoginDialogListener {

    private final static String LOG_TAG = MainActivity.class.getSimpleName();
    public static boolean isTablet = false;
    private long barcode = Constants.BARCODE_NONE; // most recent scanned or entered barcode
    private final int currentFragment = 0;
    private static int whichPhoto = 0;
    private static boolean loggedIn;
    private static String barcodeRequested;
    private Uri photoReceived;
    private MenuItem loginItem;
    private WebFragment webFragment;
    private BroadcastReceiver messageReceiver;
    private final IntentFilter messageFilter = new IntentFilter(Constants.MESSAGE_EVENT);

    /* === Lifecycle methods =============================================== */

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        boolean scanner = false;

        setContentView(R.layout.activity_main);
        View rootView = findViewById(android.R.id.content);

        Toolbar toolbar = findViewById(R.id.app_bar);
        setSupportActionBar(toolbar);
        //noinspection ConstantConditions
        getSupportActionBar().setDisplayShowTitleEnabled(false);

        MobileAds.initialize(getApplicationContext(), getString(R.string.app_id));

        // See if activity was started by widget
        Intent intent = getIntent(); // may not be needed here
        if (intent != null) {
            Logd(LOG_TAG, "in onCreate(), intent: " + intent.toString());
            String message = intent.getStringExtra(Constants.MESSAGE_KEY);
            if (message != null && message.equals(Constants.ACTION_SCAN_BARCODE)) {
                scanner = true;
            }
        }

        // messageReceiver catches barcode from service or fragment display requests.
        messageReceiver = new MessageReceiver();

        isTablet = (findViewById(R.id.dual_pane) != null);

        if (findViewById(R.id.tab_container) != null) {

            Bundle bundle = new Bundle();
            bundle.putInt(Constants.CURRENT_FRAGMENT, currentFragment);
            TabPagerFragment tabPagerFragment = new TabPagerFragment();
            tabPagerFragment.setArguments(bundle);
            getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, new TabPagerFragment())
                    .commit();

            // Handle right-hand pane on dual-pane layouts
            if (isTablet && (savedInstanceState == null)) {
                getSupportFragmentManager().beginTransaction()
                        .replace(R.id.right_pane_container, new SplashFragment()).commit();
            }

            if (scanner) {
                launchScannerIntent();
            }
        }

        // Silent login at initial startup
        if (savedInstanceState == null) {
            if (silentLogin()) {
                Logd(LOG_TAG, "Login successful.");
            } else {
                Logd(LOG_TAG, "Login failed");
            }
        }
        // ATTENTION: This was auto-generated to handle app links.
        Intent appLinkIntent = getIntent();
        String appLinkAction = appLinkIntent.getAction();
        Uri appLinkData = appLinkIntent.getData();
    }

    @Override
    public void onResume() {

        LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
        super.onResume();
    }

    @Override
    public void onDestroy() {

        // Unregister since the activity is about to be closed.
        LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        loginItem = menu.findItem(R.id.action_login);

        if (loggedIn) {
            loginItem.setTitle(R.string.action_logout);
        } else {
            loginItem.setTitle(R.string.action_login);
        }

        return true;
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {

        if (photoReceived != null) {
            savedInstanceState.putString(Constants.CURRENT_PHOTO, photoReceived.toString());
        } else {
            savedInstanceState.putString(Constants.CURRENT_PHOTO, null);
        }
        savedInstanceState.putInt(Constants.CURRENT_FRAGMENT, currentFragment);
        savedInstanceState.putBoolean(Constants.LOGIN_STATE, loggedIn);

        super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {

        // Always call the superclass so it can restore the view hierarchy
        super.onRestoreInstanceState(savedInstanceState);

        savedInstanceState.getString(Constants.CURRENT_PHOTO);
        savedInstanceState.getInt(Constants.CURRENT_FRAGMENT);
        savedInstanceState.getBoolean(Constants.LOGIN_STATE);

    }

    /* === User interactions =============================================== */

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.

        switch (item.getItemId()) {
        // respond to the action bar's Up/Home button.  Should only be visible when
        // the TabPagerFragment isn't showing.

        case android.R.id.home:
            FragmentManager fm = getSupportFragmentManager();
            fm.popBackStackImmediate();
            showBackArrow(false);
            return true;

        case R.id.action_scan:
            launchScannerIntent();
            return true;

        // noinspection SimplifiableIfStatement
        case R.id.action_login:
            if (isLoggedIn()) {
                logOut();
            } else {
                DialogFragment loginDialog = new LoginDialog();
                loginDialog.show(getSupportFragmentManager(), "login");
                // getSupportFragmentManager().executePendingTransactions();
            }
            return true;

        case R.id.action_sensitivities:
            SuperActivityToast.create(this, Utility.errorStyle()).setText(getString(R.string.no_sensitivities_yet))
                    .show();
            return true;

        case R.id.action_about_off:
            // Call OFF webview
            launchWebFragment(getString(R.string.about_off), getString(R.string.off_domain));
            return true;

        case R.id.action_about:
            launchAboutFragment();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /* Hide or show back arrow, which only happens in single-pane mode
     * Setting HomeAsUp seems to turn on Title, so turn it off
     */
    private void showBackArrow(boolean showArrow) {

        if (isTablet) {
            return;
        }
        try {
            getSupportActionBar().setDisplayHomeAsUpEnabled(showArrow);
        } catch (Exception e) {
            Logd(LOG_TAG, "Exception in showBackArrow: " + e.getMessage());
            e.printStackTrace();
        }
        getSupportActionBar().setDisplayShowTitleEnabled(false);

    }

    @Override
    public void onBackPressed() {

        /* Capture back events when WebFragment is active and pass them to WebView */
        if (webFragment != null) {
            if (webFragment.canGoBack()) {
                // Logd(LOG_TAG, "webFragment canGoBack, will take backPress");
                webFragment.goBack();
                return;
            }
        }

        /* Only go back if we're in single-pane mode */
        if (!isTablet) {
            /* Assume we only have one level of navigation, clear back arrow and title */
            showBackArrow(false);

            /* if we are showing a child view (ProductFragment, WebFragment that can't go back) */
            FragmentManager fm = getSupportFragmentManager();
            int count = fm.getBackStackEntryCount();
            // (LOG_TAG, "BackStackEntryCount: " + count);
            if (count == 0) { // no fragments on backstack
                super.onBackPressed();
            } else { // pop that fragment
                getFragmentManager().popBackStackImmediate();
            }
        }
    }

    // The dialog fragment receives a reference to this Activity through the
    // Fragment.onAttach() callback, which it uses to call the following methods
    // defined by the LoginDialog.NoticeDialogListener interface or
    // UploadDialog.NoticeDialogListener
    @Override
    public void onDialogPositiveClick(DialogFragment dialog) {
        // User touched the dialog's positive button
        Bundle args = dialog.getArguments();
        if (args == null) {
            // Logd(LOG_TAG,"No args found in dialog intent");
            return;
        }
        String dialogType = args.getString(Constants.DIALOG_TYPE);
        Logd(LOG_TAG, "Positive click on [" + dialogType + "]");
        assert dialogType != null;
        switch (dialogType) {
        case Constants.DIALOG_DELETE:
            String barcode = args.getString(Constants.BARCODE_KEY);
            Logd(LOG_TAG, "to delete item#: " + barcode);
            deleteItem(barcode);
            break;

        case Constants.DIALOG_UPLOAD:
            launchUploadFragment(barcodeRequested);
            break;

        default:
            break;
        }
    }

    @Override
    public void onDialogNegativeClick(DialogFragment dialog) {
        // User touched the dialog's negative button, do nothing
    }

    @Override
    public void onItemSelected(String barcode) {

        try {
            long productId = Long.parseLong(barcode);
            launchProductFragment(productId);
        } catch (NumberFormatException e) {
            Log.e(LOG_TAG, "Selected item contains unparseable barcode: " + barcode);
            Log.e(LOG_TAG, e.toString());
        }
    }

    /* After successful login, refresh menu to show Log Out */
    @Override
    public void onLogin() {
        if (loggedIn) {
            loginItem.setTitle(R.string.action_logout);
        } else {
            loginItem.setTitle(R.string.action_login);
        }
        invalidateOptionsMenu();
    }

    /* === Receivers ======================================================= */

    /* MessageReceiver is listening for any of the following:
     *   - an intent from OpenFoodService, containing a product barcode and a result string.
     *   - intents from various fragments, requesting that other fragments be displayed.
     */

    private class MessageReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Logd(LOG_TAG, "in onReceive(), intent: " + intent.getAction());

            // Assume any other message key will be the barcode
            // Barcode returned from OpenFoodService
            if (intent.getAction().equals(Constants.MESSAGE_EVENT)) {

                String messageKey = intent.getStringExtra(Constants.MESSAGE_KEY);
                Logd(LOG_TAG, "messageKey: " + messageKey);

                switch (messageKey) {

                case Constants.BARCODE_KEY:
                    barcode = intent.getLongExtra(Constants.MESSAGE_RESULT, Constants.BARCODE_NOT_FOUND);

                    if (barcode == Constants.BARCODE_NOT_FOUND) {
                        if (isTablet) {
                            launchSplashFragment();
                        }
                        UploadDialog uploadDialog = UploadDialog.newInstance(Constants.DIALOG_UPLOAD);
                        uploadDialog.show(getSupportFragmentManager(), getString(R.string.upload));
                    } else {
                        Logd(LOG_TAG, "MessageReceiver result: " + messageKey);
                        SuperActivityToast.create(MainActivity.this, infoStyle())
                                .setText(getString(R.string.barcode_found)).show();

                        launchProductFragment(barcode);
                    }
                    break;
                case Constants.ACTION_BACK_PRESS:
                    onBackPressed();
                    break;

                case Constants.ACTION_UPLOAD_FRAGMENT:
                    launchUploadFragment(barcodeRequested);
                    break;

                case Constants.ACTION_RESULTS_FRAGMENT:
                    launchResultsFragment();
                    break;

                case Constants.ACTION_PRODUCT_FRAGMENT:
                    launchProductFragment(barcode);
                    break;

                case Constants.ACTION_SEARCH_FRAGMENT:
                    // launchSearchFragment();
                    break;

                case Constants.ACTION_SPLASH_FRAGMENT:
                    launchSplashFragment();
                    break;

                case Constants.ACTION_VIEW_WEB:
                    /* if no url passed, goes to OFF website.  If no domain, all links open
                     * in a browser  */
                    String url = intent.getStringExtra(Constants.MESSAGE_RESULT);
                    String domain = intent.getStringExtra(Constants.PARAM_DOMAIN);
                    if (url.length() == 0) {
                        url = Constants.OFF_URL;
                    }
                    launchWebFragment(url, domain);
                    break;
                }
            }
        }
    }

    /* Receives intent results from activities such as Camera, Gallery or Scanner  */

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {

        if (intent == null) {
            Logd(LOG_TAG, "in onActivityResult, null intent received");
            Logd(LOG_TAG, "   requestCode: " + requestCode);
            Logd(LOG_TAG, "   resultCode: " + resultCode);
            return;
        }
        Logd(LOG_TAG,
                "requestCode: " + requestCode + "; resultCode: " + resultCode + "; intent: " + intent.toString());

        switch (requestCode) {

        case IntentIntegrator.REQUEST_CODE: {
            /* Catching result from barcode scan */
            if (resultCode == RESULT_OK) {
                IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
                Logd(LOG_TAG, "IntentResult: " + result.toString());

                String barcode = result.getContents();
                if (result.getContents() == null) {
                    SuperActivityToast.create(this, Utility.errorStyle()).setText(getString(R.string.result_failed))
                            .show();
                } else {
                    Logd(LOG_TAG, "Scan result: " + result.toString());
                    // Have a (potentially) valid barcode, update text view and fetch product info
                    SearchFragment.handleScanResult(barcode);
                    // TODO: Need a progress spinner here
                    Intent productIntent = new Intent(this, OpenFoodService.class);
                    productIntent.putExtra(Constants.BARCODE_KEY, barcode);
                    productIntent.setAction(Constants.ACTION_FETCH_PRODUCT);
                    startService(productIntent);
                }
            } else {
                Logd(LOG_TAG, "Error scanning barcode: " + resultCode);
            }
            break;
        }

        case Constants.CAMERA_IMAGE_REQUEST: {
            /* Catching result from camera */
            if (resultCode == RESULT_OK) {
                scanMedia(photoReceived.toString());
                UploadFragment.updateImage(photoReceived);
            } else { // capture image request came back with error
                Logd(LOG_TAG, "Error taking photo: " + resultCode);
            }
            break;
        }

        case Constants.GALLERY_IMAGE_REQUEST: {
            /* Catching result from gallery */

            InputStream imageStream;
            if (resultCode == RESULT_OK) {
                final Uri imageUri = intent.getData();
                try {
                    // TODO: figure out what imageStream might be needed for?
                    imageStream = getContentResolver().openInputStream(imageUri);
                    Logd(LOG_TAG, "Gallery image request returned Uri: " + imageUri);
                    UploadFragment.updateImageFromGallery(imageUri);
                } catch (FileNotFoundException e) {
                    Logd(LOG_TAG, e.getMessage());
                }

            } else {
                Logd(LOG_TAG, "Error picking photo from gallery: " + resultCode);
            }
            break;
        }

        default: {
            Logd(LOG_TAG, "Unexpected requestCode received: " + requestCode);
            // super.onActivityResult(requestCode, resultCode, intent);
        }
        }
    }

    /* Gets a photo from camera or gallery and returns the uri */
    @Override
    public Uri PhotoRequest(int source, int photo) {

        // TODO: check to make sure we have camera & storage permissions here.
        Logd(LOG_TAG, "PhotoRequest(" + photo + ") received.");
        photoReceived = null;
        if (source == Constants.CAMERA_IMAGE_REQUEST) {
            launchPhotoIntent(photo);
        } else if (source == Constants.GALLERY_IMAGE_REQUEST) {
            launchGalleryIntent(photo);
        }
        return photoReceived;
    }

    /* === Fragment management ============================================= */

    /* Moves upload fragment to front   */
    public void launchUploadFragment(String barcodeRequested) {
        Logd(LOG_TAG, "Launching UploadFragment");
        if (findViewById(R.id.tab_container) != null) {

            Bundle bundle = new Bundle();
            bundle.putInt(Constants.CURRENT_FRAGMENT, Constants.FRAG_UPLOAD);
            TabPagerFragment tabPagerFragment = new TabPagerFragment();
            tabPagerFragment.setArguments(bundle);
            getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, tabPagerFragment).commit();
        }

    }

    /* Moves results fragment to front   */
    private void launchResultsFragment() {
        // Logd(LOG_TAG, "in launchResultsFragment()");
        if (findViewById(R.id.tab_container) != null) {

            Bundle bundle = new Bundle();
            bundle.putInt(Constants.CURRENT_FRAGMENT, Constants.FRAG_RESULTS);
            TabPagerFragment tabPagerFragment = new TabPagerFragment();
            tabPagerFragment.setArguments(bundle);
            getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, tabPagerFragment).commit();
        }
    }

    private void launchProductFragment(long barcode) {

        // Pass barcode to ProductFragment
        if (barcode != Constants.BARCODE_NOT_FOUND) {
            Bundle args = new Bundle();
            args.putLong(Constants.BARCODE_KEY, barcode);

            /* Set up back arrow */
            Toolbar toolbar = findViewById(R.id.app_bar);
            setSupportActionBar(toolbar);

            ProductFragment ProductFragment = new ProductFragment();
            ProductFragment.setArguments(args);

            if (!isTablet) { // productFragment replaces TabPagerFragment
                try {
                    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                    getSupportActionBar().setDisplayShowTitleEnabled(false);
                } catch (Exception e) {
                    Logd(LOG_TAG, "Exception in launchProductFragment: " + e.getMessage());
                }
                getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, ProductFragment)
                        .addToBackStack(null).commit();

            } else { // productFragment replaces splashFragment
                try {
                    getSupportActionBar().setDisplayShowTitleEnabled(false);
                } catch (Exception e) {
                    Logd(LOG_TAG, "Exception in launchProductFragment: " + e.getMessage());
                }
                getSupportFragmentManager().beginTransaction().replace(R.id.right_pane_container, ProductFragment)
                        .addToBackStack(null).commit();
            }
        } else {
            Logd(LOG_TAG, "Barcode not found, not launching product fragment.");
        }
    }

    /* Displays a web view fragment to allow access to openfoodfacts.org, to register, change
     * password, etc.
     */
    private void launchWebFragment(String url, String domain) {
        webFragment = WebFragment.newInstance(url, domain);

        // Handle right-hand pane on dual-pane layouts
        if (isTablet) {
            getSupportFragmentManager().beginTransaction().replace(R.id.right_pane_container, webFragment)
                    .addToBackStack(null).commit();
        } else {
            showBackArrow(true);
            getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, webFragment)
                    .addToBackStack(null).commit();
        }
    }

    /* Puts up SplashFragment.  Should only do in dual-pane mode, otherwise only menu items are
     * available.
     */
    private void launchSplashFragment() {
        // Handle right-hand pane on dual-pane layouts
        if (isTablet) {
            getSupportFragmentManager().beginTransaction().replace(R.id.right_pane_container, new SplashFragment())
                    .commit();
        } else {
            showBackArrow(true);
            getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, new SplashFragment())
                    .commit();
        }
    }

    /* Puts up AboutFragment.
     */
    private void launchAboutFragment() {

        // Handle right-hand pane on dual-pane layouts
        if (isTablet) {
            getSupportFragmentManager().beginTransaction().replace(R.id.right_pane_container, new AboutFragment())
                    .commit();
        } else {
            showBackArrow(true);
            getSupportFragmentManager().beginTransaction().replace(R.id.tab_container, new AboutFragment())
                    .commit();
        }

        LibsSupportFragment libsFragment = new LibsBuilder().withLicenseShown(false).withAboutVersionShown(true)
                .withAboutAppName(getString(R.string.app_name))
                .withAboutDescription(getString(R.string.app_description)).supportFragment();

        getSupportFragmentManager().beginTransaction().replace(R.id.about_libs_fragment, libsFragment).commit();

    }

    /* === Intent launchers ================================================ */

    private void launchPhotoIntent(int whichPhoto) {

        Logd(LOG_TAG, "Launching intent for photo #" + whichPhoto);
        // create Intent to take a picture and return control to the calling application
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {

            // Create the File where the photo should go
            File photoFile = openOutputMediaFile();
            Logd(LOG_TAG, "photoReceived: " + photoReceived);

            if (photoFile != null) {

                Uri photoUri = StreamProvider.getUriForFile("com.ereinecke.eatsafe.fileprovider", photoFile);
                try {
                    Logd(LOG_TAG, "photoUri: " + photoUri.toString());
                } catch (Exception e) {
                    Logd(LOG_TAG, "photoUri is null: " + e.getMessage());
                }
                // set the image file name
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                takePictureIntent.putExtra(Constants.WHICH_PHOTO, whichPhoto);
                takePictureIntent
                        .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                // start the image capture Intent
                startActivityForResult(takePictureIntent, Constants.CAMERA_IMAGE_REQUEST);
            }
        }
    }

    private void launchGalleryIntent(int whichPhoto) {

        Logd(LOG_TAG, "Launching intent for photo #" + whichPhoto);
        // create Intent to take a picture and return control to the calling application
        Intent pickPictureIntent = new Intent(Intent.ACTION_PICK);
        pickPictureIntent.setType("image/*");

        startActivityForResult(pickPictureIntent, Constants.GALLERY_IMAGE_REQUEST);
    }

    /* Launches the barcode scanner by replacing the SearchFragment with a new SearchFragment
     * with an action as an extra.
     */
    private void launchScannerIntent() {

        Bundle bundle = new Bundle();
        bundle.putString(Constants.MESSAGE_KEY, Constants.ACTION_SCAN_BARCODE);
        SearchFragment searchFragment = new SearchFragment();
        searchFragment.setArguments(bundle);

        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_search, searchFragment).commit();

    }

    /* === Getters & setters  ============================================== */

    public long getBarcode() {
        return barcode;
    }

    public static void setLoggedIn(boolean setLoggedIn) {
        loggedIn = setLoggedIn;
    }

    public static void setBarcodeRequested(String bcRequested) {
        barcodeRequested = bcRequested;
    }

    public static String getBarcodeRequested() {
        return barcodeRequested;
    }

    /* === Utilities ======================================================= */
    /*  TODO: candidates to move elsewhere?  */

    /* Silent login */
    private boolean silentLogin() {
        SharedPreferences preferences = getSharedPreferences(Constants.LOGIN_PREFERENCES, Context.MODE_PRIVATE);

        String password = preferences.getString(Constants.PASSWORD, "");
        String userName = preferences.getString(Constants.USER_NAME, "");

        loggedIn = LoginDialog.attemptLogin(this, userName, password, true);

        return loggedIn;
    }

    /* Returns true if there's a password set in SharedPreferences  */
    private boolean isLoggedIn() {
        return loggedIn;
    }

    private void logOut() {
        SharedPreferences.Editor prefs = getSharedPreferences(Constants.LOGIN_PREFERENCES, Context.MODE_PRIVATE)
                .edit();
        prefs.putString(Constants.PASSWORD, "");

        SharedPreferences prefsRead = getSharedPreferences(Constants.LOGIN_PREFERENCES, Context.MODE_PRIVATE);
        String userName = prefsRead.getString(Constants.USER_NAME, "");
        // TODO: clear cookies?
        prefs.apply();
        loggedIn = false;
        Logd(LOG_TAG, "Logged out.");
        SuperActivityToast st = new SuperActivityToast(this, infoStyle());
        st.setText(getString(R.string.result_logout, userName));
        st.show();
        // change Log Out to Log In
        invalidateOptionsMenu();
    }

    /* removes the current item from the database
     *  TODO: use URI approach */
    private void deleteItem(String barcode) {

        getContentResolver().delete(OpenFoodContract.ProductEntry.CONTENT_URI,
                OpenFoodContract.ProductEntry._ID + "=" + barcode, null);
        launchSplashFragment();
        launchResultsFragment();
        Logd(LOG_TAG, "Deleted item# " + barcode);
    }

    /** Returns a unique, opened file for image; sets photoReceived with filespec */
    private File openOutputMediaFile() {

        String appName = App.getContext().getString(R.string.app_name);
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return null;
        }

        File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), appName);
        Logd(LOG_TAG, "mediaStorageDir: " + mediaStorageDir.toString());

        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                Logd(LOG_TAG, "failed to create directory " + mediaStorageDir);
                return null;
            }
        }

        // Create a media file name
        @SuppressLint("SimpleDateFormat")
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String fileName = Constants.IMG_PREFIX + timeStamp;
        File imageFile = null;

        // Open a temp file to pass to Camera
        try {
            imageFile = File.createTempFile(fileName, ".jpg", mediaStorageDir);
            Logd(LOG_TAG, "imageFile: " + imageFile);
        } catch (IOException e) {
            e.printStackTrace();
            Logd(LOG_TAG, e.getMessage());
        }

        // Generate a file: path for use with intent
        if (imageFile != null) {
            URI uri = imageFile.toURI();
            photoReceived = Uri.parse(uri.toString());
        }
        return imageFile;
    }

    /**
     * Sends a broadcast to have the media scanner scan a file
     *
     * @param path
     *            the file to scan
     */
    private void scanMedia(String path) {

        File file = new File(path);
        Uri uri = Uri.fromFile(file);
        Intent scanFileIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
        sendBroadcast(scanFileIntent);
    }
}