org.puder.trs80.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.puder.trs80.MainActivity.java

Source

/*
 * Copyright 2012-2013, Arno Puder
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.puder.trs80;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.MediaRouteButton;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import com.google.common.base.Optional;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.puder.trs80.cast.CastMessageSender;
import org.puder.trs80.configuration.Configuration;
import org.puder.trs80.configuration.ConfigurationManager;
import org.puder.trs80.drag.ConfigurationItemTouchHelperCallback;
import org.puder.trs80.io.FileManager;
import org.puder.trs80.localstore.RomManager;
import org.retrostore.android.AppInstallListener;
import org.retrostore.android.RetrostoreActivity;
import org.retrostore.android.RetrostoreApi;
import org.retrostore.android.view.ImageLoader;
import org.retrostore.client.common.proto.App;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class MainActivity extends BaseActivity implements InitialSetupDialogFragment.DownloadCompletionListener,
        ConfigurationItemListener, NavigationView.OnNavigationItemSelectedListener {
    private static final String TAG = "MainActivity";

    private static final String EXTRA_KEY_NEW_CONFIG_ID = "CONFIG_ID";
    private static final String EXTRA_KEY_IS_NEW = "IS_NEW";

    private static final int COLUMN_WIDTH_DP = 300;

    private static final int REQUEST_CODE_EDIT_CONFIG = 1;
    private static final int REQUEST_CODE_EDIT_SETTINGS = 2;

    // Action Menu
    private static final int MENU_OPTION_DOWNLOAD = 0;
    private static final int MENU_OPTION_ADD_CONFIGURATION = 1;
    private static final int MENU_OPTION_HELP = 2;

    private RecyclerView configurationListView;
    private ConfigurationListViewAdapter configurationListViewAdapter;
    private SharedPreferences sharedPrefs;
    private MenuItem downloadMenuItem = null;

    private ActionBarDrawerToggle toggle;
    private Configuration backupConfiguration;

    private ConfigurationManager configManager;
    private RomManager romManager;
    // Note: This is in the RetroStore package.
    private AppInstaller appInstaller;
    private Executor mInstallExecutor;
    private CastMessageSender castMessageSender;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // StrictMode.enableDefaults();
        super.onCreate(savedInstanceState);

        mInstallExecutor = Executors.newSingleThreadExecutor();
        RetrostoreApi.get().registerAppInstallListener(new AppInstallListener() {
            @Override
            public void onInstallApp(App app) {
                asyncDownloadAndInstallApp(app);
            }
        });
        PreferenceManager.setDefaultValues(this, R.xml.configuration, false);
        sharedPrefs = this.getSharedPreferences(SettingsActivity.SHARED_PREF_NAME, Context.MODE_PRIVATE);
        setContentView(R.layout.main_activity);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open,
                R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
        FileManager.Creator fileManagerCreator = FileManager.Creator.get(getResources());
        try {
            configManager = ConfigurationManager.get(getApplicationContext());
            romManager = RomManager.init(fileManagerCreator);
        } catch (IOException e) {
            Log.e(TAG, "Cannot initialize RomManager / ConfigurationManager.", e);
            finish();
            // Cannot really launch the app if initialization fails.
            // TODO: Show an error message before exiting.
            return;
        }
        appInstaller = new AppInstaller(configManager, ImageLoader.get(getApplicationContext()),
                RetrostoreApi.get());
        castMessageSender = CastMessageSender.get();

        int screenWidthDp = this.getResources().getConfiguration().screenWidthDp;
        int numColumns = (screenWidthDp == android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED) ? 1
                : screenWidthDp / COLUMN_WIDTH_DP;
        RecyclerView.LayoutManager lm = null;
        if (numColumns <= 1) {
            lm = new LinearLayoutManager(this);
        } else {
            lm = new GridLayoutManager(this, numColumns);
        }
        configurationListViewAdapter = new ConfigurationListViewAdapter(configManager, this, numColumns);
        configurationListView = (RecyclerView) this.findViewById(R.id.list_configurations);
        configurationListView.setLayoutManager(lm);
        configurationListView.setAdapter(configurationListViewAdapter);

        ItemTouchHelper.Callback callback = new ConfigurationItemTouchHelperCallback(configurationListViewAdapter);
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
        itemTouchHelper.attachToRecyclerView(configurationListView);
    }

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

    @Override
    public void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    public void onResume() {
        super.onResume();
        updateView(-1, -1, -1);
        castMessageSender.start();
        // TODO: Enable once fully supported.
        // AudioHttpServer.get().start();

        boolean firstTime = sharedPrefs.getBoolean(SettingsActivity.CONF_FIRST_TIME, true);
        boolean ranNewAssistant = sharedPrefs.getBoolean(SettingsActivity.CONF_RAN_NEW_ASSISTANT, false);

        Editor editor = sharedPrefs.edit();
        editor.putBoolean(SettingsActivity.CONF_FIRST_TIME, false);
        editor.putBoolean(SettingsActivity.CONF_RAN_NEW_ASSISTANT, true);
        editor.apply();

        if (!ranNewAssistant || (!romManager.hasAllRoms() && firstTime)) {
            downloadROMs();
        }
    }

    @Override
    protected void onPause() {
        if (isFinishing()) {
            castMessageSender.stop();
            // TODO: Enable once fully supported.
            // AudioHttpServer.get().stop();
        }
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(ScreenshotTakenEvent event) {
        int position = configManager.getPositionOfConfigWithId(event.configurationId);
        updateView(position, -1, -1);
    }

    private void updateView(int positionChanged, int positionInserted, int positionDeleted) {
        View withoutConfigurationsView = this.findViewById(R.id.without_configurations);
        View withConfigurationsView = this.findViewById(R.id.with_configurations);
        if (configManager.getConfigCount() == 0) {
            withoutConfigurationsView.setVisibility(View.VISIBLE);
            withConfigurationsView.setVisibility(View.GONE);
            return;
        }

        withoutConfigurationsView.setVisibility(View.GONE);
        withConfigurationsView.setVisibility(View.VISIBLE);

        if (positionChanged != -1) {
            configurationListViewAdapter.notifyItemChanged(positionChanged);
        } else if (positionInserted != -1) {
            configurationListViewAdapter.notifyItemInserted(positionInserted);
            configurationListView.getLayoutManager().scrollToPosition(positionInserted);
        } else if (positionDeleted != -1) {
            configurationListViewAdapter.notifyItemRemoved(positionDeleted);
        } else {
            configurationListViewAdapter.notifyDataSetChanged();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        MenuItem mediaRouteItem = menu.findItem(R.id.action_cast_trs80);
        MediaRouteButton mediaRouteButton = (MediaRouteButton) MenuItemCompat.getActionView(mediaRouteItem);
        mediaRouteButton.setRouteSelector(castMessageSender.getRouteSelector());

        if (!romManager.hasAllRoms()) {
            downloadMenuItem = menu.add(Menu.NONE, MENU_OPTION_DOWNLOAD, Menu.NONE,
                    this.getString(R.string.menu_download));
            downloadMenuItem.setIcon(R.drawable.download_icon);
            MenuItemCompat.setShowAsAction(downloadMenuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
        }
        MenuItemCompat.setShowAsAction(
                menu.add(Menu.NONE, MENU_OPTION_ADD_CONFIGURATION, Menu.NONE,
                        this.getString(R.string.menu_add_configuration)).setIcon(R.drawable.add_icon),
                MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
        MenuItemCompat.setShowAsAction(
                menu.add(Menu.NONE, MENU_OPTION_HELP, Menu.NONE, this.getString(R.string.menu_help))
                        .setIcon(R.drawable.help_icon),
                MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (toggle.onOptionsItemSelected(item)) {
            return true;
        }
        switch (item.getItemId()) {
        case MENU_OPTION_DOWNLOAD:
            downloadROMs();
            return true;
        case MENU_OPTION_ADD_CONFIGURATION:
            addConfiguration();
            return true;
        case MENU_OPTION_HELP:
            showHelp();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.nav_settings) {
            showSettings();
        } else if (id == R.id.nav_rate) {
            showRating();
        } else if (id == R.id.nav_help) {
            showHelp();
        } else if (id == R.id.nav_community) {
            showCommunity();
        } else if (id == R.id.nav_share) {
            showShare();
        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    public void onRetrostoreBtnClicked(View view) {

        Intent intent = new Intent(this, RetrostoreActivity.class);
        MainActivity.this.startActivity(intent);
    }

    @Override
    public void onConfigurationEdit(Configuration configuration, int position) {
        editConfiguration(configuration, false);
    }

    @Override
    public void onConfigurationDelete(Configuration configuration, int position) {
        deleteConfiguration(configuration, position);
    }

    @Override
    public void onConfigurationStop(Configuration configuration, int position) {
        stopEmulator(configuration, position);
    }

    @Override
    public void onConfigurationRun(Configuration configuration, int position) {
        runEmulator(configuration, position);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE_EDIT_CONFIG) {
            if (data == null) {
                return;
            }
            boolean isNew = data.getBooleanExtra(EXTRA_KEY_IS_NEW, false);
            if (resultCode == Activity.RESULT_OK) {
                int id = data.getIntExtra(EXTRA_KEY_NEW_CONFIG_ID, -1);
                int position = configManager.getPositionOfConfigWithId(id);
                // Delete emulator state
                try {
                    configManager.getEmulatorState(id).deleteSavedState();
                } catch (IOException e) {
                    Log.e(TAG, "Could not delete emulator state.", e);
                }
                Optional<Configuration> conf = configManager.getConfigById(id);
                if (conf.isPresent()) {
                    conf.get().setCassettePosition(0f);
                }
                // Update UI
                if (isNew) {
                    updateView(-1, position, -1);
                } else {
                    updateView(position, -1, -1);
                }
                return;
            }
            if (backupConfiguration == null) {
                return;
            }
            if (isNew) {
                configManager.deleteConfigWithId(backupConfiguration.getId());
            } else {
                configManager.persistConfig(backupConfiguration);
            }
            backupConfiguration = null;
        }
    }

    private void addConfiguration() {
        Configuration currentConfiguration = configManager.newConfiguration();
        editConfiguration(currentConfiguration, true);
    }

    private void editConfiguration(Configuration conf, boolean isNew) {
        backupConfiguration = conf.createBackup();
        Intent i = new Intent(this, EditConfigurationActivity.class);
        i.putExtra(EXTRA_KEY_NEW_CONFIG_ID, conf.getId());
        i.putExtra(EXTRA_KEY_IS_NEW, isNew);
        startActivityForResult(i, REQUEST_CODE_EDIT_CONFIG);
    }

    private void deleteConfiguration(final Configuration conf, final int position) {
        String msg = this.getString(R.string.alert_dialog_confirm_delete, conf.getName().orNull());
        AlertDialog.Builder builder = AlertDialogUtil.createAlertDialog(this, R.string.app_name,
                R.drawable.warning_icon, msg);
        builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface d, int which) {
                AlertDialogUtil.dismissDialog(MainActivity.this);
                configManager.deleteConfigWithId(conf.getId());
                updateView(-1, -1, position);
            }

        });
        builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface d, int which) {
                AlertDialogUtil.dismissDialog(MainActivity.this);
            }

        });

        AlertDialogUtil.showDialog(this, builder);
    }

    private void stopEmulator(final Configuration conf, final int position) {
        String msg = this.getString(R.string.alert_dialog_confirm_stop_emu, conf.getName().orNull());
        AlertDialog.Builder builder = AlertDialogUtil.createAlertDialog(this, R.string.app_name,
                R.drawable.warning_icon, msg);
        builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface d, int which) {
                AlertDialogUtil.dismissDialog(MainActivity.this);
                try {
                    configManager.getEmulatorState(conf.getId()).deleteSavedState();
                } catch (IOException e) {
                    Log.e(TAG, "Could not delete emulator state.", e);
                }
                conf.setCassettePosition(0);
                updateView(position, -1, -1);
            }

        });
        builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface d, int which) {
                AlertDialogUtil.dismissDialog(MainActivity.this);
            }

        });

        AlertDialogUtil.showDialog(this, builder);
    }

    private void runEmulator(Configuration conf, int position) {
        Log.i(TAG, "RUN EMULATOR");
        View root = findViewById(R.id.main);

        int model = conf.getModel();
        if (model != Hardware.MODEL1 && model != Hardware.MODEL3) {
            Snackbar.make(root, R.string.error_model_not_supported, Snackbar.LENGTH_LONG).show();
            return;
        }

        if (!romManager.hasAllRoms()) {
            Snackbar.make(root, R.string.error_no_rom, Snackbar.LENGTH_LONG).show();
            return;
        }
        for (int i = 0; i < 4; i++) {
            if (!checkIfFileExists(conf.getDiskPath(i).orNull(), true, R.string.error_no_disk)) {
                return;
            }
        }

        Intent intent = new Intent(this, EmulatorActivity.class);
        intent.putExtra(EmulatorActivity.EXTRA_CONFIGURATION_ID, conf.getId());
        startActivity(intent);
    }

    private boolean checkIfFileExists(String path, boolean allowNull, int errMsg) {
        if (path == null && allowNull) {
            return true;
        }
        if (path == null || !new File(path).exists()) {
            View root = findViewById(R.id.main);
            Snackbar.make(root, errMsg, Snackbar.LENGTH_LONG).show();
            return false;
        }
        return true;
    }

    private void showSettings() {
        startActivityForResult(new Intent(this, SettingsActivity.class), REQUEST_CODE_EDIT_SETTINGS);
    }

    private void showHelp() {
        showDialog(R.string.help_title_configurations, -1, R.string.help_configurations);
    }

    private void showRating() {
        Uri uri = Uri.parse("market://details?id=" + getPackageName());
        Intent playMarketIntent = new Intent(Intent.ACTION_VIEW, uri);
        playMarketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
                | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        try {
            startActivity(playMarketIntent);
        } catch (ActivityNotFoundException e) {
            startActivity(new Intent(Intent.ACTION_VIEW,
                    Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())));
        }
    }

    private void showCommunity() {
        Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.google_plus_url)));
        startActivity(browserIntent);
    }

    private void downloadROMs() {
        AlertDialog.Builder builder = AlertDialogUtil.createAlertDialog(this, R.string.title_initial_setup,
                R.drawable.ic_info_black, R.string.initial_setup);
        builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface d, int whichButton) {
                AlertDialogUtil.dismissDialog(MainActivity.this);
                InitialSetupDialogFragment prog = new InitialSetupDialogFragment();
                prog.show(getSupportFragmentManager(), "dialog");
            }
        }).setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface d, int whichButton) {
                AlertDialogUtil.dismissDialog(MainActivity.this);
            }
        });

        AlertDialogUtil.showDialog(this, builder);
    }

    private void showShare() {
        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_subject));
        sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_message));
        sendIntent.setType("text/plain");
        startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.share_title)));
    }

    @Override
    public void onDownloadCompleted() {
        if (downloadMenuItem != null) {
            downloadMenuItem.setVisible(false);
        }
        updateView(-1, -1, -1);
    }

    public boolean showHint() {
        return showHint(R.string.hint_configuration_usage);
    }

    public boolean showHint(int id) {
        return AlertDialogUtil.showHint(this, id);
    }

    private void asyncDownloadAndInstallApp(final App app) {
        mInstallExecutor.execute(new Runnable() {
            @Override
            public void run() {
                if (appInstaller.downloadAndInstallApp(app)) {
                    String msg = getString(R.string.successfully_installed);
                    showToast(StrUtil.form(msg, app.getName()));
                }
            }
        });
    }

    private void showToast(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
            }
        });
    }
}