EnigmAndroid/app/src/main/java/de/vanitasvitae/enigmandroid/MainActivity.java

469 lines
17 KiB
Java
Executable File

package de.vanitasvitae.enigmandroid;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import java.math.BigInteger;
import java.security.SecureRandom;
import de.vanitasvitae.enigmandroid.enigma.Enigma;
import de.vanitasvitae.enigmandroid.enigma.EnigmaStateBundle;
import de.vanitasvitae.enigmandroid.enigma.inputPreparer.InputPreparer;
import de.vanitasvitae.enigmandroid.layout.LayoutContainer;
import de.vanitasvitae.enigmandroid.layout.PassphraseDialogBuilder;
/**
* Main Android Activity of the app
* Copyright (C) 2015 Paul Schaub
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* @author vanitasvitae
*/
public class MainActivity extends Activity
{
private static final int RESULT_SETTINGS = 1;
private static final String URI_CHANGELOG =
"https://github.com/vanitasvitae/EnigmAndroid/blob/master/CHANGELOG.txt";
public static final String APP_ID = "EnigmAndroid";
private LayoutContainer layoutContainer;
private String prefMachineType;
private String prefNumericLanguage;
private String prefMessageFormatting;
private SecureRandom secureRandom;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
secureRandom = new SecureRandom();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
this.prefMachineType = sharedPreferences.getString(SettingsActivity.PREF_MACHINE_TYPE, getResources().
getStringArray(R.array.pref_alias_machine_type)[0]);
ActivitySingleton singleton = ActivitySingleton.getInstance();
singleton.setActivity(this);
updateContentView();
layoutContainer = LayoutContainer.createLayoutContainer(prefMachineType);
updatePreferenceValues();
//Handle shared text
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type))
{
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null)
{
layoutContainer.getInput().setRawText(sharedText);
}
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
this.updateContentView();
}
private void updateContentView()
{
switch (prefMachineType)
{
case "I":
this.setContentView(R.layout.activity_main_i_m3);
break;
case "M3":
this.setContentView(R.layout.activity_main_i_m3);
break;
case "M4":
this.setContentView(R.layout.activity_main_m4);
break;
case "D":
this.setContentView(R.layout.activity_main_d);
break;
case "K":
case "KS":
case "KSA":
case "T":
case "R":
case "G31":
case "G312":
case "G260":
this.setContentView(R.layout.activity_main_g_k_r_t);
break;
default:
this.setContentView(R.layout.activity_main_i_m3);
break;
}
}
private void updatePreferenceValues()
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
this.setPrefMachineType(sharedPreferences.getString(SettingsActivity.PREF_MACHINE_TYPE, getResources().
getStringArray(R.array.pref_alias_machine_type)[0]));
this.setPrefNumericLanguage(sharedPreferences.getString(SettingsActivity.PREF_NUMERIC_LANGUAGE, getResources().
getStringArray(R.array.pref_alias_numeric_spelling_language)[0]));
this.setPrefMessageFormatting(sharedPreferences.getString(SettingsActivity.PREF_MESSAGE_FORMATTING, getResources().
getStringArray(R.array.pref_alias_message_formatting)[0]));
}
private void setPrefMachineType(String type)
{
if(prefMachineType == null || !prefMachineType.equals(type))
{
prefMachineType = type;
String savedInput = "";
if(layoutContainer != null)
{
savedInput = layoutContainer.getInput().getText();
}
updateContentView();
layoutContainer = LayoutContainer.createLayoutContainer(prefMachineType);
layoutContainer.setInputPreparer(InputPreparer.createInputPreparer());
layoutContainer.getInput().setText(savedInput);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
sharedPreferences.edit().putString(SettingsActivity.PREF_MACHINE_TYPE, type).apply();
}
}
public String getPrefMachineType()
{
if(prefMachineType != null) return prefMachineType;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
this.prefMachineType = sharedPreferences.getString(SettingsActivity.PREF_MACHINE_TYPE, getResources().
getStringArray(R.array.pref_alias_machine_type)[0]);
return prefMachineType;
}
public void setPrefNumericLanguage(String lang)
{
if(prefNumericLanguage == null || !prefNumericLanguage.equals(lang))
{
prefNumericLanguage = lang;
layoutContainer.setInputPreparer(InputPreparer.createInputPreparer());
}
}
public String getPrefNumericLanguage()
{
if(prefNumericLanguage != null) return prefNumericLanguage;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
this.prefNumericLanguage = sharedPreferences.getString(SettingsActivity.PREF_NUMERIC_LANGUAGE, getResources().
getStringArray(R.array.pref_alias_numeric_spelling_language)[0]);
return prefNumericLanguage;
}
public void setPrefMessageFormatting(String messageFormatting)
{
if(prefMessageFormatting == null || !prefMessageFormatting.equals(messageFormatting))
{
prefMessageFormatting = messageFormatting;
layoutContainer.setEditTextAdapter(messageFormatting);
}
}
public String getPrefMessageFormatting()
{
if(prefMessageFormatting != null) return prefMessageFormatting;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
this.prefMessageFormatting = sharedPreferences.getString(SettingsActivity.PREF_MESSAGE_FORMATTING, getResources().
getStringArray(R.array.pref_alias_message_formatting)[0]);
return prefMessageFormatting;
}
public SecureRandom getSecureRandom()
{
return this.secureRandom;
}
public void onDialogFinished(EnigmaStateBundle state)
{
layoutContainer.getEnigma().setState(state);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
this.getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
/**
* Handle Options menu clicks
*/
public boolean onOptionsItemSelected(MenuItem item)
{
int id = item.getItemId();
if (id == R.id.action_reset)
{
layoutContainer.resetLayout();
Toast.makeText(getApplicationContext(), R.string.message_reset,
Toast.LENGTH_SHORT).show();
return true;
}
else if (id == R.id.action_random_configuration)
{
layoutContainer.getEnigma().randomState();
layoutContainer.syncStateFromEnigmaToLayout();
Toast.makeText(getApplicationContext(), R.string.message_random,
Toast.LENGTH_SHORT).show();
return true;
}
else if (id == R.id.action_choose_ringsetting)
{
layoutContainer.showRingSettingsDialog();
return true;
}
else if (id == R.id.action_settings)
{
Intent i = new Intent(this, SettingsActivity.class);
startActivityForResult(i, RESULT_SETTINGS);
}
else if (id == R.id.action_about)
{
showAboutDialog();
return true;
}
else if (id == R.id.action_send)
{
if(layoutContainer.getOutput().getText().length() == 0)
{
Toast.makeText(this, R.string.error_no_text_to_send, Toast.LENGTH_SHORT).show();
}
else
{
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, layoutContainer.getOutput().getModifiedText());
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));
}
}
else if (id == R.id.action_receive_scan)
{
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.initiateScan();
return true;
}
else if(id == R.id.action_share_scan)
{
IntentIntegrator QRIntegrator = new IntentIntegrator(this);
layoutContainer.syncStateFromLayoutToEnigma();
Log.d(APP_ID, "Sharing configuration to QR: " + layoutContainer.getEnigma().stateToString());
QRIntegrator.shareText(APP_ID+"/"+layoutContainer.getEnigma().stateToString());
return true;
}
else if(id == R.id.action_enter_seed)
{
new PassphraseDialogBuilder().showDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Set the chosen Configuration to the enigma, get the input string from the input text box and
* prepare it, set the input to the prepared text, encrypt the prepared input and set the
* encrypted string to the output text box and update the spinners to their new positions.
* @param v View
*/
public void doCrypto(View v)
{
layoutContainer.doCrypto();
}
/**
* Show a Dialog containing information about the app, license, usage, author and a link
* to the changelog
*/
private void showAboutDialog()
{
final View aboutView = View.inflate(this, R.layout.dialog_about, null);
//Get and set Version code
PackageInfo pInfo = null;
try{ pInfo = getPackageManager().getPackageInfo(this.getPackageName(), 0);}
catch (PackageManager.NameNotFoundException e){ e.printStackTrace();}
String version = pInfo.versionName+ " ("+pInfo.versionCode+")";
TextView versionText = (TextView) aboutView.findViewById(R.id.about_version_section);
versionText.setText(version);
//Build and show dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.title_about_dialog);
builder.setView(aboutView)
.setCancelable(true)
.setPositiveButton(R.string.dialog_positiv, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
dialog.dismiss();
}
})
.setNegativeButton(R.string.button_show_changelog, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
dialog.cancel();
openWebPage(URI_CHANGELOG);
}
}).show();
}
/**
* Handle preference changes
* @param requestCode requestCode
* @param resultCode resultCode (RESULT_SETTINGS is defined at the top)
* @param data data (not important here)
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RESULT_SETTINGS:
{
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
this.setPrefMachineType(sharedPrefs.getString(SettingsActivity.PREF_MACHINE_TYPE, getResources()
.getStringArray(R.array.pref_alias_machine_type)[0]));
this.setPrefNumericLanguage(sharedPrefs.getString(SettingsActivity.PREF_NUMERIC_LANGUAGE, getResources().
getStringArray(R.array.pref_alias_numeric_spelling_language)[0]));
this.setPrefMessageFormatting(sharedPrefs.getString(SettingsActivity.PREF_MESSAGE_FORMATTING,
getResources().getStringArray(R.array.pref_alias_message_formatting)[0]));
break;
}
case IntentIntegrator.REQUEST_CODE:
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (scanResult != null) {
String content = scanResult.getContents();
if(content == null) Log.e(APP_ID, "Error! Received nothing from QR-Code!");
else {
Log.d(APP_ID, "Received " + content + " from QR-Code!");
restoreStateFromCode(content);
}
}
}
}
/**
* Set EnigmAndroid into a certain state as described in the QR-Code
* @param mem content of the QR-Code
*/
private void restoreStateFromCode(String mem)
{
if(!mem.startsWith(APP_ID+"/"))
{
Toast.makeText(this, R.string.error_no_valid_qr, Toast.LENGTH_LONG).show();
}
else
{
mem = mem.substring((APP_ID+"/").length());
BigInteger s = new BigInteger(mem, 16);
Log.d(APP_ID, s.toString());
setPrefMachineType(Enigma.chooseEnigmaFromSave(s));
updateContentView();
layoutContainer = LayoutContainer.createLayoutContainer(getPrefMachineType());
layoutContainer.getEnigma().restoreState(Enigma.removeDigit(s,20));
layoutContainer.setInputPreparer(InputPreparer.createInputPreparer());
layoutContainer.syncStateFromEnigmaToLayout();
}
}
/**
* Set EnigmAndroid into a state calculated from the seed.
* @param seed seed
*/
public void createStateFromSeed(String seed)
{
setPrefMachineType(Enigma.chooseEnigmaFromSeed(seed));
updateContentView();
layoutContainer = LayoutContainer.createLayoutContainer(getPrefMachineType());
layoutContainer.getEnigma().setStateFromSeed(seed);
layoutContainer.setInputPreparer(InputPreparer.createInputPreparer());
layoutContainer.syncStateFromEnigmaToLayout();
}
/**
* Open the web page with the URL url
* @param url URL of the website
*/
private void openWebPage(String url) {
Uri webPage = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, webPage);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
/**
* Singleton that grants access to an Activity from anywhere within the app
*/
public static class ActivitySingleton
{
private static ActivitySingleton instance = null;
private Activity activity;
//private constructor
private ActivitySingleton(){}
//Singleton method
public static ActivitySingleton getInstance()
{
if(instance == null) instance = new ActivitySingleton();
return instance;
}
/**
* Set an Activity that the Singleton returns
* @param activity activity that's stored
*/
public void setActivity(Activity activity)
{
this.activity = activity;
}
/**
* Returns the stored Activity
* @return stored Activity
*/
public Activity getActivity()
{
return activity;
}
}
}