paulscode.android.mupen64plusae.GalleryActivity.java Source code

Java tutorial

Introduction

Here is the source code for paulscode.android.mupen64plusae.GalleryActivity.java

Source

/**
 * Mupen64PlusAE, an N64 emulator for the Android platform
 *
 * Copyright (C) 2013 Paul Lamb
 *
 * This file is part of Mupen64PlusAE.
 *
 * Mupen64PlusAE 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.
 *
 * Mupen64PlusAE 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 Mupen64PlusAE. If
 * not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: littleguy77
 */
package paulscode.android.mupen64plusae;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.mupen64plusae.v3.alpha.R;

import paulscode.android.mupen64plusae.GameSidebar.GameSidebarActionHandler;
import paulscode.android.mupen64plusae.dialog.ChangeLog;
import paulscode.android.mupen64plusae.dialog.ConfirmationDialog;
import paulscode.android.mupen64plusae.dialog.ConfirmationDialog.PromptConfirmListener;
import paulscode.android.mupen64plusae.dialog.Popups;
import paulscode.android.mupen64plusae.persistent.AppData;
import paulscode.android.mupen64plusae.persistent.ConfigFile;
import paulscode.android.mupen64plusae.persistent.ConfigFile.ConfigSection;
import paulscode.android.mupen64plusae.persistent.GamePrefs;
import paulscode.android.mupen64plusae.persistent.GlobalPrefs;
import paulscode.android.mupen64plusae.task.ComputeMd5Task;
import paulscode.android.mupen64plusae.task.ComputeMd5Task.ComputeMd5Listener;
import paulscode.android.mupen64plusae.util.FileUtil;
import paulscode.android.mupen64plusae.util.Notifier;
import paulscode.android.mupen64plusae.util.RomDatabase;
import paulscode.android.mupen64plusae.util.RomDatabase.RomDetail;
import paulscode.android.mupen64plusae.util.RomHeader;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.MenuItemCompat.OnActionExpandListener;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SearchView.OnQueryTextListener;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;

public class GalleryActivity extends AppCompatActivity implements GameSidebarActionHandler, PromptConfirmListener {
    // Saved instance states
    private static final String STATE_QUERY = "query";
    private static final String STATE_SIDEBAR = "sidebar";
    private static final String STATE_CACHE_ROM_INFO_FRAGMENT = "cache_rom_info_fragment";
    private static final String STATE_EXTRACT_TEXTURES_FRAGMENT = "STATE_EXTRACT_TEXTURES_FRAGMENT";
    private static final String STATE_GALLERY_REFRESH_NEEDED = "gallery_refresh_needed";
    private static final String STATE_RESTART_CONFIRM_DIALOG = "STATE_RESTART_CONFIRM_DIALOG";
    private static final String STATE_CLEAR_CONFIRM_DIALOG = "STATE_CLEAR_CONFIRM_DIALOG";
    private static final int RESTART_CONFIRM_DIALOG_ID = 0;
    private static final int CLEAR_CONFIRM_DIALOG_ID = 1;

    // App data and user preferences
    private AppData mAppData = null;
    private GlobalPrefs mGlobalPrefs = null;

    // Widgets
    private RecyclerView mGridView;
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private MenuListView mDrawerList;
    private GameSidebar mGameSidebar;

    // Searching
    private SearchView mSearchView;
    private String mSearchQuery = "";

    // Resizable gallery thumbnails
    public int galleryWidth;
    public int galleryMaxWidth;
    public int galleryHalfSpacing;
    public int galleryColumns = 2;
    public float galleryAspectRatio;

    // Misc.
    private List<GalleryItem> mGalleryItems = null;
    private GalleryItem mSelectedItem = null;
    private boolean mDragging = false;

    private ScanRomsFragment mCacheRomInfoFragment = null;
    private ExtractTexturesFragment mExtractTexturesFragment = null;

    //True if the restart promp is enabled
    boolean mRestartPromptEnabled = true;

    //If this is set to true, the gallery will be refreshed next time this activity is resumed
    boolean mRefreshNeeded = false;

    @Override
    protected void onNewIntent(Intent intent) {
        // If the activity is already running and is launched again (e.g. from a file manager app),
        // the existing instance will be reused rather than a new one created. This behavior is
        // specified in the manifest (launchMode = singleTask). In that situation, any activities
        // above this on the stack (e.g. GameActivity, GamePrefsActivity) will be destroyed
        // gracefully and onNewIntent() will be called on this instance. onCreate() will NOT be
        // called again on this instance. Currently, the only info that may be passed via the intent
        // is the selected game path, so we only need to refresh that aspect of the UI. This will
        // happen anyhow in onResume(), so we don't really need to do much here.
        super.onNewIntent(intent);

        // Only remember the last intent used
        setIntent(intent);
    }

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get app data and user preferences
        mAppData = new AppData(this);
        mGlobalPrefs = new GlobalPrefs(this, mAppData);
        mGlobalPrefs.enforceLocale(this);

        final int lastVer = mAppData.getLastAppVersionCode();
        final int currVer = mAppData.appVersionCode;
        if (lastVer != currVer) {
            // First run after install/update, greet user with changelog, then help dialog
            Popups.showFaq(this);
            final ChangeLog log = new ChangeLog(getAssets());
            if (log.show(this, lastVer + 1, currVer)) {
                mAppData.putLastAppVersionCode(currVer);
            }
        }

        // Get the ROM path if it was passed from another activity/app
        final Bundle extras = getIntent().getExtras();
        if (extras != null) {
            final String givenRomPath = extras.getString(ActivityHelper.Keys.ROM_PATH);
            if (!TextUtils.isEmpty(givenRomPath)) {
                // Asynchronously compute MD5 and launch game when finished
                Notifier.showToast(this, getString(R.string.toast_loadingGameInfo));
                final ComputeMd5Task task = new ComputeMd5Task(new File(givenRomPath), new ComputeMd5Listener() {
                    @Override
                    public void onComputeMd5Finished(File file, String md5) {
                        final RomHeader header = new RomHeader(file);

                        final RomDatabase database = RomDatabase.getInstance();

                        if (!database.hasDatabaseFile()) {
                            database.setDatabaseFile(mAppData.mupen64plus_ini);
                        }

                        final RomDetail detail = database.lookupByMd5WithFallback(md5, file, header.crc);
                        launchGameActivity(file.getAbsolutePath(), null, true, md5, header.crc, header.name,
                                header.countryCode, null, detail.goodName, false);
                    }
                });
                task.execute();
            }
        }

        // Lay out the content
        setContentView(R.layout.gallery_activity);
        mGridView = (RecyclerView) findViewById(R.id.gridview);
        refreshGrid();

        // Update the grid layout
        galleryMaxWidth = (int) getResources().getDimension(R.dimen.galleryImageWidth);
        galleryHalfSpacing = (int) getResources().getDimension(R.dimen.galleryHalfSpacing);
        galleryAspectRatio = galleryMaxWidth * 1.0f / getResources().getDimension(R.dimen.galleryImageHeight);

        final DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);

        final int width = metrics.widthPixels - galleryHalfSpacing * 2;
        galleryColumns = (int) Math.ceil(width * 1.0 / (galleryMaxWidth + galleryHalfSpacing * 2));
        galleryWidth = width / galleryColumns - galleryHalfSpacing * 2;

        final GridLayoutManager layoutManager = (GridLayoutManager) mGridView.getLayoutManager();
        layoutManager.setSpanCount(galleryColumns);
        mGridView.getAdapter().notifyDataSetChanged();
        mGridView.setFocusable(false);
        mGridView.setFocusableInTouchMode(false);

        // Add the toolbar to the activity (which supports the fancy menu/arrow animation)
        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle(R.string.app_name);
        final View firstGridChild = mGridView.getChildAt(0);

        if (firstGridChild != null) {
            toolbar.setNextFocusDownId(firstGridChild.getId());
        }

        setSupportActionBar(toolbar);

        // Configure the navigation drawer
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, 0, 0) {
            @Override
            public void onDrawerStateChanged(int newState) {
                // Intercepting the drawer open animation and re-closing it causes onDrawerClosed to
                // not fire,
                // So detect when this happens and wait until the drawer closes to handle it
                // manually
                if (newState == DrawerLayout.STATE_DRAGGING) {
                    // INTERCEPTED!
                    mDragging = true;
                    hideSoftKeyboard();
                } else if (newState == DrawerLayout.STATE_IDLE) {
                    if (mDragging && !mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
                        // onDrawerClosed from dragging it
                        mDragging = false;
                        mDrawerList.setVisibility(View.VISIBLE);
                        mGameSidebar.setVisibility(View.GONE);
                        mSelectedItem = null;
                    }
                }
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                // Hide the game information sidebar
                mDrawerList.setVisibility(View.VISIBLE);
                mGameSidebar.setVisibility(View.GONE);
                mSelectedItem = null;

                super.onDrawerClosed(drawerView);
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                hideSoftKeyboard();
                super.onDrawerOpened(drawerView);
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        // Configure the list in the navigation drawer
        mDrawerList = (MenuListView) findViewById(R.id.drawerNavigation);
        mDrawerList.setMenuResource(R.menu.gallery_drawer);

        //Remove touch screen profile configuration if in TV mode
        if (mGlobalPrefs.isBigScreenMode) {
            final MenuItem profileGroupItem = mDrawerList.getMenu().findItem(R.id.menuItem_profiles);
            profileGroupItem.getSubMenu().removeItem(R.id.menuItem_touchscreenProfiles);

            final MenuItem settingsGroupItem = mDrawerList.getMenu().findItem(R.id.menuItem_settings);
            settingsGroupItem.getSubMenu().removeItem(R.id.menuItem_categoryTouchscreen);
        }

        // Select the Library section
        mDrawerList.getMenu().getItem(0).setChecked(true);

        // Handle menu item selections
        mDrawerList.setOnClickListener(new MenuListView.OnClickListener() {
            @Override
            public void onClick(MenuItem menuItem) {
                GalleryActivity.this.onOptionsItemSelected(menuItem);
            }
        });

        // Configure the game information drawer
        mGameSidebar = (GameSidebar) findViewById(R.id.gameSidebar);

        // Handle events from the side bar
        mGameSidebar.setActionHandler(this, R.menu.gallery_game_drawer);

        if (savedInstanceState != null) {
            mSelectedItem = null;
            final String md5 = savedInstanceState.getString(STATE_SIDEBAR);
            if (md5 != null) {
                // Repopulate the game sidebar
                for (final GalleryItem item : mGalleryItems) {
                    if (md5.equals(item.md5)) {
                        onGalleryItemClick(item);
                        break;
                    }
                }
            }

            final String query = savedInstanceState.getString(STATE_QUERY);
            if (query != null)
                mSearchQuery = query;

            mRefreshNeeded = savedInstanceState.getBoolean(STATE_GALLERY_REFRESH_NEEDED);
        }

        // find the retained fragment on activity restarts
        final FragmentManager fm = getSupportFragmentManager();
        mCacheRomInfoFragment = (ScanRomsFragment) fm.findFragmentByTag(STATE_CACHE_ROM_INFO_FRAGMENT);
        mExtractTexturesFragment = (ExtractTexturesFragment) fm.findFragmentByTag(STATE_EXTRACT_TEXTURES_FRAGMENT);

        if (mCacheRomInfoFragment == null) {
            mCacheRomInfoFragment = new ScanRomsFragment();
            fm.beginTransaction().add(mCacheRomInfoFragment, STATE_CACHE_ROM_INFO_FRAGMENT).commit();
        }

        if (mExtractTexturesFragment == null) {
            mExtractTexturesFragment = new ExtractTexturesFragment();
            fm.beginTransaction().add(mExtractTexturesFragment, STATE_EXTRACT_TEXTURES_FRAGMENT).commit();
        }

        // Set the sidebar opacity on the two sidebars
        mDrawerList.setBackgroundDrawable(new DrawerDrawable(mGlobalPrefs.displayActionBarTransparency));
        mGameSidebar.setBackgroundDrawable(new DrawerDrawable(mGlobalPrefs.displayActionBarTransparency));
    }

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

        //mRefreshNeeded will be set to true whenever a game is launched
        if (mRefreshNeeded) {
            mRefreshNeeded = false;
            refreshGrid();

            mGameSidebar.setVisibility(View.GONE);
            mDrawerList.setVisibility(View.VISIBLE);

            //Close the drawer without an animation
            final View view = mDrawerLayout.getChildAt(mDrawerLayout.getChildCount() - 1);
            final ViewTreeObserver vto = view.getViewTreeObserver();

            vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    final DrawerLayout.LayoutParams lp = new DrawerLayout.LayoutParams(view.getWidth(),
                            view.getHeight());
                    lp.gravity = GravityCompat.START;
                    view.setLayoutParams(lp);
                    view.setLeft(-view.getMeasuredWidth());
                    view.getViewTreeObserver().removeOnPreDrawListener(this);

                    return true;
                }
            });
        }
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        if (mSearchView != null)
            savedInstanceState.putString(STATE_QUERY, mSearchView.getQuery().toString());
        if (mSelectedItem != null)
            savedInstanceState.putString(STATE_SIDEBAR, mSelectedItem.md5);
        savedInstanceState.putBoolean(STATE_GALLERY_REFRESH_NEEDED, mRefreshNeeded);

        super.onSaveInstanceState(savedInstanceState);
    }

    public void hideSoftKeyboard() {
        // Hide the soft keyboard if needed
        if (mSearchView == null)
            return;

        final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mSearchView.getWindowToken(), 0);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.gallery_activity, menu);

        final MenuItem searchItem = menu.findItem(R.id.menuItem_search);
        MenuItemCompat.setOnActionExpandListener(searchItem, new OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                mSearchQuery = "";
                refreshGrid();
                return true;
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item) {
                return true;
            }
        });

        mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {

                return false;
            }

            @Override
            public boolean onQueryTextChange(String query) {
                mSearchQuery = query;
                refreshGrid();
                return false;
            }
        });

        if (!"".equals(mSearchQuery)) {
            final String query = mSearchQuery;
            MenuItemCompat.expandActionView(searchItem);
            mSearchView.setQuery(query, true);
        }

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menuItem_refreshRoms:
            ActivityHelper.startRomScanActivity(this);
            return true;
        case R.id.menuItem_library:
            mDrawerLayout.closeDrawer(GravityCompat.START);
            return true;
        case R.id.menuItem_categoryLibrary:
            ActivityHelper.startLibraryPrefsActivity(this);
            return true;
        case R.id.menuItem_categoryDisplay:
            ActivityHelper.startDisplayPrefsActivity(this);
            return true;
        case R.id.menuItem_categoryAudio:
            ActivityHelper.startAudioPrefsActivity(this);
            return true;
        case R.id.menuItem_categoryTouchscreen:
            ActivityHelper.startTouchscreenPrefsActivity(this);
            return true;
        case R.id.menuItem_categoryInput:
            ActivityHelper.startInputPrefsActivity(this);
            return true;
        case R.id.menuItem_categoryData:
            ActivityHelper.startDataPrefsActivity(this);
            return true;
        case R.id.menuItem_emulationProfiles:
            ActivityHelper.startManageEmulationProfilesActivity(this);
            return true;
        case R.id.menuItem_touchscreenProfiles:
            ActivityHelper.startManageTouchscreenProfilesActivity(this);
            return true;
        case R.id.menuItem_controllerProfiles:
            ActivityHelper.startManageControllerProfilesActivity(this);
            return true;
        case R.id.menuItem_faq:
            Popups.showFaq(this);
            return true;
        case R.id.menuItem_helpForum:
            ActivityHelper.launchUri(this, R.string.uri_forum);
            return true;
        case R.id.menuItem_controllerDiagnostics:
            ActivityHelper.startDiagnosticActivity(this);
            return true;
        case R.id.menuItem_reportBug:
            ActivityHelper.launchUri(this, R.string.uri_bugReport);
            return true;
        case R.id.menuItem_appVersion:
            Popups.showAppVersion(this);
            return true;
        case R.id.menuItem_changelog:
            new ChangeLog(getAssets()).show(this, 0, mAppData.appVersionCode);
            return true;
        case R.id.menuItem_logcat:
            Popups.showLogcat(this);
            return true;
        case R.id.menuItem_hardwareInfo:
            Popups.showHardwareInfo(this);
            return true;
        case R.id.menuItem_credits:
            ActivityHelper.launchUri(GalleryActivity.this, R.string.uri_credits);
            return true;
        case R.id.menuItem_localeOverride:
            mGlobalPrefs.changeLocale(this);
            return true;
        case R.id.menuItem_extract:
            ActivityHelper.starExtractTextureActivity(this);
            return true;
        case R.id.menuItem_clear: {
            String title = getString(R.string.confirm_title);
            String message = getString(R.string.confirmClearData_message);

            ConfirmationDialog confirmationDialog = ConfirmationDialog.newInstance(CLEAR_CONFIRM_DIALOG_ID, title,
                    message);

            FragmentManager fm = getSupportFragmentManager();
            confirmationDialog.show(fm, STATE_CLEAR_CONFIRM_DIALOG);
        }
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onGameSidebarAction(MenuItem menuItem) {
        final GalleryItem item = mSelectedItem;
        if (item == null)
            return;

        switch (menuItem.getItemId()) {
        case R.id.menuItem_resume:
            launchGameActivity(item.romFile.getAbsolutePath(),
                    item.zipFile == null ? null : item.zipFile.getAbsolutePath(), item.isExtracted, item.md5,
                    item.crc, item.headerName, item.countryCode, item.artPath, item.goodName, false);
            break;
        case R.id.menuItem_restart:
            //Don't show the prompt if this is the first time we start a game
            if (mRestartPromptEnabled) {
                final CharSequence title = getText(R.string.confirm_title);
                final CharSequence message = getText(R.string.confirmResetGame_message);

                final ConfirmationDialog confirmationDialog = ConfirmationDialog
                        .newInstance(RESTART_CONFIRM_DIALOG_ID, title.toString(), message.toString());

                final FragmentManager fm = getSupportFragmentManager();
                confirmationDialog.show(fm, STATE_RESTART_CONFIRM_DIALOG);
            } else {
                launchGameActivity(item.romFile.getAbsolutePath(),
                        item.zipFile == null ? null : item.zipFile.getAbsolutePath(), item.isExtracted, item.md5,
                        item.crc, item.headerName, item.countryCode, item.artPath, item.goodName, true);
            }

            break;
        case R.id.menuItem_settings: {
            String romLegacySaveFileName = null;

            if (item.zipFile != null) {
                romLegacySaveFileName = item.zipFile.getName();
            } else {
                romLegacySaveFileName = item.romFile.getName();
            }
            ActivityHelper.startGamePrefsActivity(GalleryActivity.this, item.romFile.getAbsolutePath(), item.md5,
                    item.crc, item.headerName, item.goodName, item.countryCode, romLegacySaveFileName);
            break;

        }
        default:
        }
    }

    @Override
    public void onPromptDialogClosed(int id, int which) {
        if (which == DialogInterface.BUTTON_POSITIVE) {
            if (id == RESTART_CONFIRM_DIALOG_ID && mSelectedItem != null) {
                launchGameActivity(mSelectedItem.romFile.getAbsolutePath(),
                        mSelectedItem.zipFile == null ? null : mSelectedItem.zipFile.getAbsolutePath(),
                        mSelectedItem.isExtracted, mSelectedItem.md5, mSelectedItem.crc, mSelectedItem.headerName,
                        mSelectedItem.countryCode, mSelectedItem.artPath, mSelectedItem.goodName, true);
            }
            if (id == CLEAR_CONFIRM_DIALOG_ID) {
                FileUtil.deleteFolder(new File(mGlobalPrefs.coreUserDataDir));
                FileUtil.deleteFolder(new File(mGlobalPrefs.coreUserCacheDir));
            }
        }
    }

    public void onGalleryItemClick(GalleryItem item) {
        mSelectedItem = item;

        // Show the game info sidebar
        mDrawerList.setVisibility(View.GONE);
        mGameSidebar.setVisibility(View.VISIBLE);
        mGameSidebar.scrollTo(0, 0);

        // Set the cover art in the sidebar
        item.loadBitmap();
        mGameSidebar.setImage(item.artBitmap);

        // Set the game title
        mGameSidebar.setTitle(item.goodName);

        // If there are no saves for this game, disable the resume
        // option
        final String gameDataPath = GamePrefs.getGameDataPath(mSelectedItem.md5, mSelectedItem.headerName,
                RomHeader.countryCodeToSymbol(mSelectedItem.countryCode), mGlobalPrefs);
        final String autoSavePath = gameDataPath + "/" + GamePrefs.AUTO_SAVES_DIR + "/";

        final File autoSavePathFile = new File(autoSavePath);
        final File[] allFilesInSavePath = autoSavePathFile.listFiles();

        //No saves, go ahead and remove it
        final boolean visible = allFilesInSavePath != null && allFilesInSavePath.length != 0;

        if (visible) {
            // Restore the menu
            mGameSidebar.setActionHandler(GalleryActivity.this, R.menu.gallery_game_drawer);
            mRestartPromptEnabled = true;
        } else {
            // Disable the action handler
            mGameSidebar.getMenu().removeItem(R.id.menuItem_resume);
            mGameSidebar.reload();
            mRestartPromptEnabled = false;
        }

        // Open the navigation drawer
        mDrawerLayout.openDrawer(GravityCompat.START);
    }

    public boolean onGalleryItemLongClick(GalleryItem item) {
        launchGameActivity(item.romFile.getAbsolutePath(),
                item.zipFile == null ? null : item.zipFile.getAbsolutePath(), item.isExtracted, item.md5, item.crc,
                item.headerName, item.countryCode, item.artPath, item.goodName, false);
        return true;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            // Show the navigation drawer when the user presses the Menu button
            // http://stackoverflow.com/q/22220275
            if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
                mDrawerLayout.closeDrawer(GravityCompat.START);
            } else {
                mDrawerLayout.openDrawer(GravityCompat.START);
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public void onBackPressed() {
        if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
            mDrawerLayout.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // Check which request we're responding to
        if (requestCode == ActivityHelper.SCAN_ROM_REQUEST_CODE) {
            // Make sure the request was successful
            if (resultCode == RESULT_OK && data != null) {
                final Bundle extras = data.getExtras();
                final String searchPath = extras.getString(ActivityHelper.Keys.SEARCH_PATH);
                final boolean searchZips = extras.getBoolean(ActivityHelper.Keys.SEARCH_ZIPS);
                final boolean downloadArt = extras.getBoolean(ActivityHelper.Keys.DOWNLOAD_ART);
                final boolean clearGallery = extras.getBoolean(ActivityHelper.Keys.CLEAR_GALLERY);

                if (searchPath != null) {
                    refreshRoms(new File(searchPath), searchZips, downloadArt, clearGallery);
                }
            }
        } else if (requestCode == ActivityHelper.EXTRACT_TEXTURES_CODE) {
            // Make sure the request was successful
            if (resultCode == RESULT_OK && data != null) {
                final Bundle extras = data.getExtras();
                final String searchPath = extras.getString(ActivityHelper.Keys.SEARCH_PATH);

                if (searchPath != null) {
                    mExtractTexturesFragment.extractTextures(new File(searchPath));
                }
            }
        }
    }

    private void refreshRoms(final File startDir, boolean searchZips, boolean downloadArt, boolean clearGallery) {
        mCacheRomInfoFragment.refreshRoms(startDir, searchZips, downloadArt, clearGallery, mAppData, mGlobalPrefs);
    }

    void refreshGrid() {

        final ConfigFile config = new ConfigFile(mGlobalPrefs.romInfoCache_cfg);

        final String query = mSearchQuery.toLowerCase(Locale.US);
        String[] searches = null;
        if (query.length() > 0)
            searches = query.split(" ");

        List<GalleryItem> items = new ArrayList<>();
        List<GalleryItem> recentItems = null;
        int currentTime = 0;
        if (mGlobalPrefs.isRecentShown) {
            recentItems = new ArrayList<>();
            currentTime = (int) (new Date().getTime() / 1000);
        }

        for (final String md5 : config.keySet()) {
            if (!ConfigFile.SECTIONLESS_NAME.equals(md5)) {
                final ConfigSection section = config.get(md5);
                String goodName;
                if (mGlobalPrefs.isFullNameShown || !section.keySet().contains("baseName"))
                    goodName = section.get("goodName");
                else
                    goodName = section.get("baseName");

                boolean matchesSearch = true;
                if (searches != null && searches.length > 0) {
                    // Make sure the ROM name contains every token in the query
                    final String lowerName = goodName.toLowerCase(Locale.US);
                    for (final String search : searches) {
                        if (search.length() > 0 && !lowerName.contains(search)) {
                            matchesSearch = false;
                            break;
                        }
                    }
                }

                if (matchesSearch) {
                    final String romPath = config.get(md5, "romPath");
                    String zipPath = config.get(md5, "zipPath");
                    final String artFullPath = config.get(md5, "artPath");
                    String artPath = new File(artFullPath).getName();
                    artPath = mGlobalPrefs.coverArtDir + "/" + artPath;

                    String crc = config.get(md5, "crc");
                    String headerName = config.get(md5, "headerName");
                    final String countryCodeString = config.get(md5, "countryCode");
                    byte countryCode = 0;

                    //We can't really do much if the rompath is null
                    if (romPath != null) {

                        if (countryCodeString != null) {
                            countryCode = Byte.parseByte(countryCodeString);
                        }
                        final String lastPlayedStr = config.get(md5, "lastPlayed");
                        String extracted = config.get(md5, "extracted");

                        if (zipPath == null || crc == null || headerName == null || countryCodeString == null
                                || extracted == null) {
                            final File file = new File(romPath);
                            final RomHeader header = new RomHeader(file);

                            zipPath = "";
                            crc = header.crc;
                            headerName = header.name;
                            countryCode = header.countryCode;
                            extracted = "false";

                            config.put(md5, "zipPath", zipPath);
                            config.put(md5, "crc", crc);
                            config.put(md5, "headerName", headerName);
                            config.put(md5, "countryCode", Byte.toString(countryCode));
                            config.put(md5, "extracted", extracted);
                        }

                        int lastPlayed = 0;
                        if (lastPlayedStr != null)
                            lastPlayed = Integer.parseInt(lastPlayedStr);

                        final GalleryItem item = new GalleryItem(this, md5, crc, headerName, countryCode, goodName,
                                romPath, zipPath, extracted.equals("true"), artPath, lastPlayed);
                        items.add(item);
                        if (mGlobalPrefs.isRecentShown && currentTime - item.lastPlayed <= 60 * 60 * 24 * 7) // 7
                                                                                                             // days
                        {
                            recentItems.add(item);
                        }
                        // Delete any old files that already exist inside a zip
                        // file
                        else if (!zipPath.equals("") && extracted.equals("true")) {
                            final File deleteFile = new File(romPath);
                            deleteFile.delete();

                            config.put(md5, "extracted", "false");
                        }
                    }
                }
            }
        }

        config.save();

        Collections.sort(items, new GalleryItem.NameComparator());
        if (recentItems != null)
            Collections.sort(recentItems, new GalleryItem.RecentlyPlayedComparator());

        List<GalleryItem> combinedItems = items;
        if (mGlobalPrefs.isRecentShown && recentItems.size() > 0) {
            combinedItems = new ArrayList<>();

            combinedItems.add(new GalleryItem(this, getString(R.string.galleryRecentlyPlayed)));
            combinedItems.addAll(recentItems);

            combinedItems.add(new GalleryItem(this, getString(R.string.galleryLibrary)));
            combinedItems.addAll(items);

            items = combinedItems;
        }

        mGalleryItems = items;
        mGridView.setAdapter(new GalleryItem.Adapter(this, items));

        // Allow the headings to take up the entire width of the layout
        final List<GalleryItem> finalItems = items;
        final GridLayoutManager layoutManager = new GridLayoutManagerBetterScrolling(this, galleryColumns);
        layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                // Headings will take up every span (column) in the grid
                if (finalItems.get(position).isHeading)
                    return galleryColumns;

                // Games will fit in a single column
                return 1;
            }
        });

        mGridView.setLayoutManager(layoutManager);
    }

    public void launchGameActivity(String romPath, String zipPath, boolean extracted, String romMd5, String romCrc,
            String romHeaderName, byte romCountryCode, String romArtPath, String romGoodName,
            boolean isRestarting) {
        // Make sure that the storage is accessible
        if (!mAppData.isSdCardAccessible()) {
            Log.e("GalleryActivity", "SD Card not accessible");
            Notifier.showToast(this, R.string.toast_sdInaccessible);
            return;
        }

        // Notify user that the game activity is starting
        Notifier.showToast(this, R.string.toast_launchingEmulator);

        // Update the ConfigSection with the new value for lastPlayed
        final String lastPlayed = Integer.toString((int) (new Date().getTime() / 1000));
        final ConfigFile config = new ConfigFile(mGlobalPrefs.romInfoCache_cfg);
        if (config.get(romMd5) != null) {
            config.put(romMd5, "lastPlayed", lastPlayed);

            if (zipPath != null) {
                ExtractFileIfNeeded(romMd5, config, romPath, zipPath, extracted);
            }

            config.save();
        }

        mRefreshNeeded = true;
        mSelectedItem = null;

        String romLegacySaveFileName;

        if (zipPath != null) {
            File zipFile = new File(zipPath);
            romLegacySaveFileName = zipFile.getName();
        } else {
            File romFile = new File(romPath);
            romLegacySaveFileName = romFile.getName();
        }

        // Launch the game activity
        ActivityHelper.startGameActivity(this, romPath, romMd5, romCrc, romHeaderName, romCountryCode, romArtPath,
                romGoodName, romLegacySaveFileName, isRestarting);
    }

    private void ExtractFileIfNeeded(String md5, ConfigFile config, String romPath, String zipPath,
            boolean isExtracted) {
        final File romFile = new File(romPath);
        final RomHeader romHeader = new RomHeader(zipPath);

        final boolean isZip = romHeader.isZip;

        if (isZip && (!romFile.exists() || !isExtracted)) {
            boolean lbFound = false;

            try {
                final ZipFile zipFile = new ZipFile(zipPath);
                final Enumeration<? extends ZipEntry> entries = zipFile.entries();
                while (entries.hasMoreElements() && !lbFound) {
                    final ZipEntry zipEntry = entries.nextElement();

                    try {
                        final InputStream zipStream = zipFile.getInputStream(zipEntry);

                        final File destDir = new File(mGlobalPrefs.unzippedRomsDir);
                        final String entryName = new File(zipEntry.getName()).getName();
                        File tempRomPath = new File(destDir, entryName);
                        final boolean fileExisted = tempRomPath.exists();

                        if (!fileExisted) {
                            tempRomPath = FileUtil.extractRomFile(destDir, zipEntry, zipStream);
                        }

                        final String computedMd5 = ComputeMd5Task.computeMd5(tempRomPath);
                        lbFound = computedMd5.equals(md5);

                        //only deleye the file if we extracted our selves
                        if (!lbFound && !fileExisted) {
                            tempRomPath.delete();
                        }

                        zipStream.close();
                    } catch (final IOException e) {
                        Log.w("CacheRomInfoTask", e);
                    }
                }
                zipFile.close();
            } catch (final IOException | ArrayIndexOutOfBoundsException e) {
                Log.w("GalleryActivity", e);
            }

            if (lbFound || romFile.exists()) {
                config.put(md5, "extracted", "true");
            }
        }
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        //Nothing to do
        return false;
    }
}