diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index fad2ec9..f37101e 100755
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,10 +1,12 @@
CHANGELOG ENIGMANDROID
v0.1.5-not.yet.released<
-*added missing licenses to class files
-*Added proper documentation
-*Extended input interpretation (number spelling in different languages, any unknown special
-character now becomes 'X'
+*Added french number spelling
+*Added Enigma Models M3, M4
+*Added option to select different enigma models into options menu
+*Added developer class for simple rotor creation (not a feature in the app)
+*Fixed broken ring settings
+*Fixed false reset of ring settings when switching from/to landscape mode
v0.1.4-15.08.2015<
@@ -12,6 +14,10 @@ v0.1.4-15.08.2015<
*Fixed some layout issues
*Fixed anomaly for step by step inputs
*Added send/receive text functionality
+*added missing licenses to class files
+*Added proper documentation
+*Extended input interpretation (number spelling in different languages, any unknown special
+character now becomes 'X'
v0.1.3-14.03.2015<
*Added About Dialog with ChangeLog-Button
diff --git a/app/app.iml b/app/app.iml
index c5beb38..e002617 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -71,7 +71,7 @@
-
+
@@ -87,9 +87,9 @@
-
+
-
-
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 467b24a..5032d0f 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,15 +1,15 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 22
+ compileSdkVersion 23
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "de.vanitasvitae.enigmandroid"
minSdkVersion 15
- targetSdkVersion 22
- versionCode 10
- versionName "0.1.4-15.08.2015-beta"
+ targetSdkVersion 23
+ versionCode 11
+ versionName "0.1.5-27.08.2015-beta"
}
buildTypes {
release {
@@ -19,5 +19,5 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:support-v4:22.2.1'
+ compile 'com.android.support:support-v4:23.0.0'
}
diff --git a/app/src/androidTest/java/de/vanitasvitae/enigmandroid/ApplicationTest.java b/app/src/androidTest/java/de/vanitasvitae/enigmandroid/ApplicationTest.java
deleted file mode 100644
index 5e12da5..0000000
--- a/app/src/androidTest/java/de/vanitasvitae/enigmandroid/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package de.vanitasvitae.enigmandroid;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 568284b..e24a93d 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
android:theme="@style/AppTheme" >
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/Enigma.java b/app/src/main/java/de/vanitasvitae/enigmandroid/Enigma.java
deleted file mode 100755
index a1dce31..0000000
--- a/app/src/main/java/de/vanitasvitae/enigmandroid/Enigma.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package de.vanitasvitae.enigmandroid;
-
-import de.vanitasvitae.enigmandroid.rotors.Reflector;
-import de.vanitasvitae.enigmandroid.rotors.Rotor;
-
-/**
- * Main component of the Enigma machine
- * 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 Enigma
-{
- private Plugboard plugboard;
-
- //Slots for the rotors
- private Rotor r1;
- private Rotor r2;
- private Rotor r3;
-
- //Slot for the reflector
- private Reflector reflector;
-
- private boolean doAnomaly = false; //Has the time come to handle an anomaly?
-
- private boolean prefAnomaly; //Do you WANT to simulate the anomaly?
- private InputPreparator inputPreparator;
-
- /**
- * Create new Enigma with standard configuration.
- * Empty Plugboard, reflector B, rotors I,II,III, Positions 0,0,0
- */
- public Enigma()
- {
- initialize();
- }
-
- private void initialize()
- {
- this.r1 = Rotor.createRotorI(0, 0);
- this.r2 = Rotor.createRotorII(0, 0);
- this.r3 = Rotor.createRotorIII(0, 0);
- this.reflector = Reflector.createReflectorB();
- plugboard = new Plugboard();
- prefAnomaly = true; //TODO: Is this necessary?
- }
-
- /**
- * Encrypt / Decrypt a given String w.
- * w must be prepared using prepare(w) beforehand.
- * Doing so changes the state of the rotors but not the state of the plugboard and the
- * ringSettings
- *
- * @param w Text to decrypt/encrypt
- * @return encrypted/decrypted string
- */
- public String encrypt(String w)
- {
- //output string
- String output = "";
- //for each char x in k
- for (char x : w.toCharArray())
- {
- output = output + this.encryptChar(x);
- }
- //return en-/decrypted string
- return output;
- }
-
- /**
- * Substitute char k by sending the signal through the enigma.
- * This rotates the first rotor and eventually also the second/third beforehand.
- * Also this method handles the anomaly in case it should happen
- *
- * @param k input char
- * @return substituted output char
- */
- public char encryptChar(char k)
- {
- //Rotate rotors
- r1.rotate();
- //Eventually turn next rotor (usual turnOver or anomaly)
- if (r1.isAtTurnoverPosition() || (this.doAnomaly && prefAnomaly))
- {
- r2.rotate();
- //Set doAnomaly for next call of encryptChar
- this.doAnomaly = r2.doubleTurnAnomaly();
- //Eventually rotate next rotor
- if (r2.isAtTurnoverPosition())
- {
- r3.rotate();
- }
- }
- int x = ((int) k)-65; //Cast to int and remove Unicode Offset (A=65 in Unicode.)
-
- //Encryption
- //forward direction
- x = plugboard.encrypt(x);
- x = normalize(x + r1.getRotation());
- x = r1.encryptForward(x);
- x = normalize(x + r2.getRotation() - r1.getRotation());
- x = r2.encryptForward(x);
- x = normalize(x + r3.getRotation() - r2.getRotation());
- x = r3.encryptForward(x);
- x = normalize(x - r3.getRotation());
- //backward direction
- x = reflector.encrypt(x);
- x = normalize(x + r3.getRotation());
- x = r3.encryptBackward(x);
- x = normalize(x - r3.getRotation() + r2.getRotation());
- x = r2.encryptBackward(x);
- x = normalize(x - r2.getRotation() + r1.getRotation());
- x = r1.encryptBackward(x);
- x = normalize(x - r1.getRotation());
- x = plugboard.encrypt(x);
-
- return (char) (x + 65); //Add Offset again and cast back to char
- }
-
- /**
- * Normalize the input.
- * Normalizing means keeping the input via modulo in the range from 0 to n-1, where n is equal
- * to the size of the rotors (in this case fixed to 26, TODO?).
- * This is necessary since java allows negative modulo values,
- * which can break this implementation
- * @param input input signal
- * @return "normalized" input signal
- */
- public int normalize(int input)
- {
- return (26+input)%26;
- }
-
- /**
- * Set config of the enigma
- *
- * @param conf configuration
- */
- public void setConfiguration(int[] conf)
- {
- if (conf == null || conf.length != 10)
- {
- initialize();
- }
- else
- {
- int ro1 = conf[0];
- int ro2 = conf[1];
- int ro3 = conf[2];
- int ref = conf[3];
- int ro1rot = normalize(conf[4] - 1);
- int ro2rot = normalize(conf[5] - 1);
- int ro3rot = normalize(conf[6] - 1);
- int ro1Ring = conf[7];
- int ro2Ring = conf[8];
- int ro3Ring = conf[9];
-
- //Set rotors
- r1 = Rotor.createRotor(ro1, ro1Ring, ro1rot);
- r2 = Rotor.createRotor(ro2, ro2Ring, ro2rot);
- r3 = Rotor.createRotor(ro3, ro3Ring, ro3rot);
-
- //Set reflector
- reflector = Reflector.createReflector(ref);
-
- //catch double turn anomaly on step by step basis
- this.doAnomaly = r2.doubleTurnAnomaly();
- }
- }
-
- /**
- * Set the plugboard
- * @param p Plugboard
- */
- public void setPlugboard(Plugboard p)
- {
- this.plugboard = p;
- }
-
- /**
- * Return the configuration, the enigma machine is in right NOW
- *
- * @return array containing configuration
- */
- public int[] getConfiguration()
- {
- int[] configuration = new int[10];
- {
- configuration[0] = r1.getType();
- configuration[1] = r2.getType();
- configuration[2] = r3.getType();
- configuration[3] = reflector.getType();
- configuration[4] = r1.getRotation();
- configuration[5] = r2.getRotation();
- configuration[6] = r3.getRotation();
- configuration[7] = r1.getRingSetting();
- configuration[8] = r2.getRingSetting();
- configuration[9] = r3.getRingSetting();
- }
- return configuration;
- }
-
- /**
- * Set the inputPreparator
- * @param preparator concrete InputPreparator
- */
- public void setInputPreparator(InputPreparator preparator)
- {
- this.inputPreparator = preparator;
- }
-
- /**
- * Return the inputPreparator
- * @return inputPreparator
- */
- public InputPreparator getInputPreparator()
- {
- return this.inputPreparator;
- }
-
- /**
- * set prefAnomaly variable
- * @param b boolean
- */
- public void setPrefAnomaly(boolean b)
- {
- this.prefAnomaly = b;
- }
-}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/MainActivity.java b/app/src/main/java/de/vanitasvitae/enigmandroid/MainActivity.java
index 4f1525b..9f029a1 100755
--- a/app/src/main/java/de/vanitasvitae/enigmandroid/MainActivity.java
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/MainActivity.java
@@ -5,16 +5,19 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.ArrayAdapter;
+import android.view.View;
import android.widget.Toast;
+
+import de.vanitasvitae.enigmandroid.enigma.Plugboard;
+import de.vanitasvitae.enigmandroid.enigma.inputPreparer.InputPreparer;
+import de.vanitasvitae.enigmandroid.layout.LayoutContainer;
+
/**
* Main Android Activity of the app
* Copyright (C) 2015 Paul Schaub
@@ -36,41 +39,27 @@ import android.widget.Toast;
*/
public class MainActivity extends Activity
{
- private Spinner rotor1View;
- private Spinner rotor2View;
- private Spinner rotor3View;
- private Spinner reflectorView;
- private Spinner rotor1PositionView;
- private Spinner rotor2PositionView;
- private Spinner rotor3PositionView;
-
- private EditText plugboardView;
- private EditText inputView;
- private EditText outputView;
-
private static final int RESULT_SETTINGS = 1;
- private static final String URI_CHANGELOG = "https://github.com/vanitasvitae/EnigmAndroid/blob/master/CHANGELOG.txt";
+ private static final String URI_CHANGELOG =
+ "https://github.com/vanitasvitae/EnigmAndroid/blob/master/CHANGELOG.txt";
- private Enigma enigma;
- //memory for the ringSettings
- private int[] ringSettings = {0,0,0};
- private boolean prefAnomaly;
- private String prefNumericLanguage;
+ LayoutContainer layoutContainer;
+ protected String prefMachineType;
+ protected boolean prefAnomaly;
+ protected String prefNumericLanguage;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
- this.setContentView(R.layout.activity_main);
- this.initLayout();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- this.prefAnomaly = sharedPreferences.getBoolean("prefAnomaly", true);
- this.prefNumericLanguage = sharedPreferences.getString("prefNumericLanguage",getResources().
- getStringArray(R.array.pref_alias_numeric_spelling_language)[0]);
- this.resetLayout();
+ this.prefMachineType = sharedPreferences.getString("prefMachineType", getResources().
+ getStringArray(R.array.pref_list_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();
@@ -82,12 +71,102 @@ public class MainActivity extends Activity
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null)
{
- inputView.setText(sharedText);
+ layoutContainer.getInputView().setText(sharedText);
}
}
}
}
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ }
+
+ private void updateContentView()
+ {
+ switch (prefMachineType)
+ {
+ case "M4":
+ this.setContentView(R.layout.activity_main_m4);
+ break;
+ case "M3":
+ this.setContentView(R.layout.activity_main_i_m3);
+ break;
+ default:
+ this.setContentView(R.layout.activity_main_i_m3);
+ break;
+ }
+ }
+
+ private void updatePreferenceValues()
+ {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ this.setPrefMachineType(sharedPreferences.getString("prefMachineType", getResources().
+ getStringArray(R.array.pref_list_machine_type)[0]));
+ this.setPrefAnomaly(sharedPreferences.getBoolean("prefAnomaly", true));
+ this.setPrefNumericLanguage(sharedPreferences.getString("prefNumericLanguage", getResources().
+ getStringArray(R.array.pref_alias_numeric_spelling_language)[0]));
+ }
+
+ public void setPrefMachineType(String type)
+ {
+ if(prefMachineType == null || !prefMachineType.equals(type))
+ {
+ prefMachineType = type;
+ String savedInput = "";
+ if(layoutContainer != null)
+ {
+ savedInput = layoutContainer.getInputView().getText().toString();
+ }
+ updateContentView();
+ layoutContainer = LayoutContainer.createLayoutContainer(prefMachineType);
+ layoutContainer.getInputView().setText(savedInput);
+ }
+ }
+
+ public String getPrefMachineType()
+ {
+ if(prefMachineType != null) return prefMachineType;
+ else
+ {
+ updatePreferenceValues();
+ return prefMachineType;
+ }
+ }
+
+ public void setPrefAnomaly(boolean anomaly)
+ {
+ if(prefAnomaly !=anomaly)
+ {
+ prefAnomaly = anomaly;
+ layoutContainer.getEnigma().setPrefAnomaly(anomaly);
+ }
+ }
+
+ public boolean getPrefAnomaly()
+ {
+ return prefAnomaly;
+ }
+
+ public void setPrefNumericLanguage(String lang)
+ {
+ if(prefNumericLanguage == null || !prefNumericLanguage.equals(lang))
+ {
+ prefNumericLanguage = lang;
+ layoutContainer.getEnigma().setInputPreparer(InputPreparer.createInputPreparer(lang));
+ }
+ }
+
+ public String getPrefNumericLanguage()
+ {
+ if(prefNumericLanguage != null) return prefNumericLanguage;
+ else
+ {
+ updatePreferenceValues();
+ return prefNumericLanguage;
+ }
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
@@ -104,14 +183,14 @@ public class MainActivity extends Activity
int id = item.getItemId();
if (id == R.id.action_reset)
{
- this.resetLayout();
+ layoutContainer.reset();
Toast.makeText(getApplicationContext(), R.string.message_reset,
Toast.LENGTH_SHORT).show();
return true;
}
else if (id == R.id.action_choose_ringstellung)
{
- showRingSettingsDialog();
+ layoutContainer.showRingSettingsDialog();
return true;
}
else if (id == R.id.action_settings)
@@ -126,7 +205,7 @@ public class MainActivity extends Activity
}
else if (id == R.id.action_send)
{
- if(outputView.getText().length() == 0)
+ if(layoutContainer.getOutputView().getText().length() == 0)
{
Toast.makeText(this, R.string.error_no_text_to_send, Toast.LENGTH_SHORT).show();
}
@@ -134,7 +213,7 @@ public class MainActivity extends Activity
{
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_TEXT, outputView.getText().toString());
+ sendIntent.putExtra(Intent.EXTRA_TEXT, layoutContainer.getOutputView().getText().toString());
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));
}
@@ -142,36 +221,6 @@ public class MainActivity extends Activity
return super.onOptionsItemSelected(item);
}
- /**
- * Updates the enigma to the chosen rotors and plugboard
- *
- * @param v View
- */
- public void updateEnigma(View v)
- {
- int[] conf = new int[10];
- conf[0] = rotor1View.getSelectedItemPosition() + 1;
- conf[1] = rotor2View.getSelectedItemPosition() + 1;
- conf[2] = rotor3View.getSelectedItemPosition() + 1;
- conf[3] = reflectorView.getSelectedItemPosition() + 1;
- conf[4] = rotor1PositionView.getSelectedItemPosition() + 1;
- conf[5] = rotor2PositionView.getSelectedItemPosition() + 1;
- conf[6] = rotor3PositionView.getSelectedItemPosition() + 1;
- conf[7] = ringSettings[0];
- conf[8] = ringSettings[1];
- conf[9] = ringSettings[2];
-
- enigma = new Enigma();
-
- int[][] plugboardConfiguration;
- plugboardView.setText(plugboardView.getText().toString().toUpperCase());
- plugboardConfiguration = Plugboard.parseConfigurationString(plugboardView.getText().toString());
- enigma.setConfiguration(conf);
- enigma.setPlugboard(new Plugboard(plugboardConfiguration));
- enigma.setPrefAnomaly(prefAnomaly);
- enigma.setInputPreparator(InputPreparator.createInputPreparator(prefNumericLanguage));
- }
-
/**
* Set the chosen Configuration to the enigma, get the input string from the input textbox and
* prepare it, set the input to the prepared text, encrypt the prepared input and set the
@@ -180,174 +229,21 @@ public class MainActivity extends Activity
*/
public void doCrypto(View v)
{
- if(inputView.getText().length()!=0) {
- updateEnigma(null);
- String m = inputView.getText().toString();
- m = enigma.getInputPreparator().prepareString(m);
- inputView.setText(m);
- outputView.setText(enigma.encrypt(m));
- updateSpinner(enigma.getConfiguration());
+ if(layoutContainer.getInputView().getText().length()!=0) {
+ layoutContainer.getEnigma().setConfiguration(layoutContainer.createConfiguration());
+ layoutContainer.getEnigma().setPlugboard(new Plugboard(layoutContainer.createPlugboardConfiguration()));
+ String m = layoutContainer.getInputView().getText().toString();
+ m = layoutContainer.getEnigma().getInputPreparer().prepareString(m);
+ layoutContainer.getInputView().setText(m);
+ layoutContainer.getOutputView().setText(layoutContainer.getEnigma().encrypt(m));
+ layoutContainer.updateLayout();
}
}
-
/**
- * Reset all the spinners and textboxes and the ringsettings memory
+ * Show a Dialog containing information about the app, license, usage, author and a link
+ * to the changelog
*/
- private void resetLayout()
- {
- rotor1View.setSelection(0);
- rotor2View.setSelection(1);
- rotor3View.setSelection(2);
- reflectorView.setSelection(1);
- rotor1PositionView.setSelection(0);
- rotor2PositionView.setSelection(0);
- rotor3PositionView.setSelection(0);
- ringSettings = new int[]{0,0,0};
- plugboardView.setText("");
- inputView.setText("");
- outputView.setText("");
- }
-
- /**
- * Initialize the Layout
- */
- private void initLayout()
- {
- Character[] charArray = new Character[26];
- for(int i=0; i<26; i++) {charArray[i] = (char) (65+i);}
-
- rotor1View = (Spinner) findViewById(R.id.rotor1);
- ArrayAdapter rotor1Adapter = ArrayAdapter.createFromResource(this,
- R.array.enigma_rotors, android.R.layout.simple_spinner_item);
- rotor1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- rotor1View.setAdapter(rotor1Adapter);
-
-
- rotor2View = (Spinner) findViewById(R.id.rotor2);
- ArrayAdapter rotor2Adapter = ArrayAdapter.createFromResource(this,
- R.array.enigma_rotors, android.R.layout.simple_spinner_item);
- rotor2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- rotor2View.setAdapter(rotor2Adapter);
-
- rotor3View = (Spinner) findViewById(R.id.rotor3);
- ArrayAdapter rotor3Adapter = ArrayAdapter.createFromResource(this,
- R.array.enigma_rotors, android.R.layout.simple_spinner_item);
- rotor3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- rotor3View.setAdapter(rotor3Adapter);
-
- reflectorView = (Spinner) findViewById(R.id.reflector);
- ArrayAdapter relfectorAdapter = ArrayAdapter.createFromResource(this,
- R.array.enigma_reflectors, android.R.layout.simple_spinner_item);
- relfectorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- reflectorView.setAdapter(relfectorAdapter);
-
- rotor1PositionView = (Spinner) findViewById(R.id.rotor1position);
- ArrayAdapter rotor1PositionAdapter = new ArrayAdapter<>(this.getApplicationContext(),
- android.R.layout.simple_spinner_item,charArray);
- rotor1PositionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- rotor1PositionView.setAdapter(rotor1PositionAdapter);
-
- rotor2PositionView = (Spinner) findViewById(R.id.rotor2position);
- ArrayAdapter rotor2PositionAdapter = new ArrayAdapter<>(this.getApplicationContext(),
- android.R.layout.simple_spinner_item,charArray);
- rotor2PositionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- rotor2PositionView.setAdapter(rotor2PositionAdapter);
-
- rotor3PositionView = (Spinner) findViewById(R.id.rotor3position);
- ArrayAdapter rotor3PositionAdapter = new ArrayAdapter<>(this.getApplicationContext(),
- android.R.layout.simple_spinner_item,charArray);
- rotor3PositionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- rotor3PositionView.setAdapter(rotor3PositionAdapter);
-
- plugboardView = (EditText) findViewById(R.id.plugboard);
- plugboardView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (!hasFocus) {
- plugboardView.setText(plugboardView.getText().toString().toUpperCase());
- }
- }
- });
- inputView = (EditText) findViewById(R.id.input);
- outputView = (EditText) findViewById(R.id.output);
-
- inputView.requestFocus();
- }
-
- /**
- * Update the Spinners to their new Positions
- * @param c Configuration
- */
- public void updateSpinner(int[] c)
- {
- rotor1View.setSelection(c[0] - 1);
- rotor2View.setSelection(c[1] - 1);
- rotor3View.setSelection(c[2] - 1);
- rotor1PositionView.setSelection(c[4]);
- rotor2PositionView.setSelection(c[5]);
- rotor3PositionView.setSelection(c[6]);
- }
-
- /**
- * Show the dialog where the user can pick the ringsettings and set them if the user doesn't
- * abort.
- */
- public void showRingSettingsDialog()
- {
- View ringSettingsView = View.inflate(this, R.layout.dialog_ringsettings, null);
-
- Integer[] ringArray = new Integer[26];
- for(int i=1; i<=26; i++) {ringArray[i-1] = i;}
-
- final Spinner ring1 = (Spinner) ringSettingsView.findViewById(R.id.rotor1ring);
- ArrayAdapter ring1Adapter = new ArrayAdapter<>(this.getApplicationContext(),
- android.R.layout.simple_spinner_item,ringArray);
- ring1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- ring1.setAdapter(ring1Adapter);
- ring1.setSelection(ringSettings[0]);
-
- final Spinner ring2 = (Spinner) ringSettingsView.findViewById(R.id.rotor2ring);
- ArrayAdapter ring2Adapter = new ArrayAdapter<>(this.getApplicationContext(),
- android.R.layout.simple_spinner_item,ringArray);
- ring2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- ring2.setAdapter(ring2Adapter);
- ring2.setSelection(ringSettings[1]);
-
- final Spinner ring3 = (Spinner) ringSettingsView.findViewById(R.id.rotor3ring);
- ArrayAdapter ring3Adapter = new ArrayAdapter<>(this.getApplicationContext(),
- android.R.layout.simple_spinner_item,ringArray);
- ring3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- ring3.setAdapter(ring3Adapter);
- ring3.setSelection(ringSettings[2]);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.title_ringsetting);
- builder.setView(ringSettingsView)
- .setCancelable(true)
- .setPositiveButton(R.string.dialog_positiv, new DialogInterface.OnClickListener()
- {
- public void onClick(DialogInterface dialog, int id)
- {
- ringSettings = new int[]{ring1.getSelectedItemPosition(),
- ring2.getSelectedItemPosition(), ring3.getSelectedItemPosition()};
- String message = getResources().getString(R.string.dialog_ringsettings_success) + " " + (ringSettings[2]+1) + ", " +
- (ringSettings[1]+1) + ", " + (ringSettings[0]+1) + ".";
- Toast.makeText(getApplicationContext(), message,
- Toast.LENGTH_LONG).show();
- }
- })
- .setNegativeButton(R.string.dialog_negativ, new DialogInterface.OnClickListener()
- {
- public void onClick(DialogInterface dialog, int id)
- {
- dialog.cancel();
- Toast.makeText(getApplicationContext(), R.string.dialog_ringsettings_abort,
- Toast.LENGTH_SHORT).show();
- }
- }).show();
- }
-
public void showAboutDialog()
{
final View aboutView = View.inflate(this, R.layout.dialog_about, null);
@@ -373,6 +269,12 @@ public class MainActivity extends Activity
}).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);
@@ -380,45 +282,63 @@ public class MainActivity extends Activity
case RESULT_SETTINGS:
{
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- this.prefAnomaly = sharedPrefs.getBoolean("prefAnomaly", true);
- this.prefNumericLanguage = sharedPrefs.getString("prefNumericLanguage",getResources().
- getStringArray(R.array.pref_alias_numeric_spelling_language)[0]);
- ;
+ this.setPrefMachineType(sharedPrefs.getString("prefMachineType", getResources()
+ .getStringArray(R.array.pref_list_machine_type)[0]));
+ this.setPrefAnomaly(sharedPrefs.getBoolean("prefAnomaly", true));
+ this.setPrefNumericLanguage(this.prefNumericLanguage = sharedPrefs.getString("prefNumericLanguage", getResources().
+ getStringArray(R.array.pref_alias_numeric_spelling_language)[0]));
break;
}
}
}
+ /**
+ * Open the web page with the URL url
+ * @param url URL of the website
+ */
public void openWebPage(String url) {
- Uri webpage = Uri.parse(url);
- Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
+ Uri webPage = Uri.parse(url);
+ Intent intent = new Intent(Intent.ACTION_VIEW, webPage);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
- public static class ActivitySingleton
+/**
+ * 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()
{
- private static ActivitySingleton instance = null;
- private Activity activity;
-
- private ActivitySingleton(){}
- public static ActivitySingleton getInstance()
- {
- if(instance == null) instance = new ActivitySingleton();
- return instance;
- }
-
- public void setActivity(Activity activity)
- {
- this.activity = activity;
- }
-
- public Activity getActivity()
- {
- return activity;
- }
-
+ 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;
+ }
+
+}
}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma.java
new file mode 100755
index 0000000..d14652a
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma.java
@@ -0,0 +1,168 @@
+package de.vanitasvitae.enigmandroid.enigma;
+
+import de.vanitasvitae.enigmandroid.MainActivity;
+import de.vanitasvitae.enigmandroid.enigma.inputPreparer.InputPreparer;
+
+/**
+ * Main component of the Enigma machine
+ * This is the mostly abstract base of any enigma machine.
+ * 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 abstract class Enigma
+{
+ protected static String machineType;
+ protected boolean doAnomaly = false; //Has the time come to handle an anomaly?
+ protected boolean prefAnomaly; //Do you WANT to simulate the anomaly?
+ protected InputPreparer inputPreparer;
+
+ /**
+ * Set the enigma to an initial state
+ */
+ public abstract void initialize();
+
+ /**
+ * Set the reflector of the enigma machine to one of type type.
+ * @param type type indicator of the reflector
+ * @return success (not every reflector fits in every machine)
+ */
+ public abstract boolean setReflector(int type);
+
+ /**
+ * Set the rotor on position pos to a rotor of type type with ring-setting ringSetting and
+ * rotation rotation.
+ * @param pos position of the rotor
+ * @param type type indicator
+ * @param ringSetting ringSetting
+ * @param rotation rotation
+ * @return success
+ */
+ public abstract boolean setRotor(int pos, int type, int ringSetting, int rotation);
+
+ /**
+ * Encrypt / Decrypt a given String w.
+ * w must be prepared using prepare(w) beforehand.
+ * Doing so changes the state of the rotors but not the state of the plugboard and the
+ * ringSettings
+ *
+ * @param w Text to decrypt/encrypt
+ * @return encrypted/decrypted string
+ */
+ public String encrypt(String w)
+ {
+ //output string
+ String output = "";
+ //for each char x in k
+ for (char x : w.toCharArray())
+ {
+ output = output + this.encryptChar(x);
+ }
+ //return en-/decrypted string
+ return output;
+ }
+
+ /**
+ * Set the enigma into the next mechanical state.
+ * This rotates the first rotor and eventually also the second/third.
+ * Also this method handles the anomaly in case it should happen.
+ */
+ public abstract void nextState();
+
+ /**
+ * Substitute char k by sending the signal through the enigma.
+ * The signal passes the plugboard, the rotors and returns back after going through the
+ * reflector wheel.
+ *
+ * @param k input char
+ * @return substituted output char
+ */
+ public abstract char encryptChar(char k);
+
+ /**
+ * Normalize the input.
+ * Normalizing means keeping the input via modulo in the range from 0 to n-1, where n is equal
+ * to the size of the rotors.
+ * This is necessary since java allows negative modulo values,
+ * which can break this implementation
+ * @param input input signal
+ * @return "normalized" input signal
+ */
+ public abstract int normalize(int input);
+
+ /**
+ * Set config of the enigma
+ *
+ * @param conf configuration
+ */
+ public abstract void setConfiguration(int[] conf);
+
+ /**
+ * Set the plugboard
+ * @param p Plugboard
+ */
+ public abstract void setPlugboard(Plugboard p);
+
+ /**
+ * Return the configuration, the enigma machine is in right NOW
+ *
+ * @return array containing configuration
+ */
+ public abstract int[] getConfiguration();
+
+ /**
+ * Set the inputPreparer
+ * @param preparer concrete InputPreparer
+ */
+ public void setInputPreparer(InputPreparer preparer)
+ {
+ this.inputPreparer = preparer;
+ }
+
+
+
+ /**
+ * Return the inputPreparer
+ * @return inputPreparer
+ */
+ public InputPreparer getInputPreparer()
+ {
+ if(inputPreparer == null)
+ {
+ MainActivity main = (MainActivity) MainActivity.ActivitySingleton.getInstance().getActivity();
+ inputPreparer = InputPreparer.createInputPreparer(main.getPrefNumericLanguage());
+ }
+ return this.inputPreparer;
+ }
+
+ /**
+ * set prefAnomaly variable
+ * @param b boolean
+ */
+ public void setPrefAnomaly(boolean b)
+ {
+ this.prefAnomaly = b;
+ }
+
+ /**
+ * Return the type indicator of the enigma machine
+ * @return type
+ */
+ public String getMachineType()
+ {
+ return machineType;
+ }
+}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_I.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_I.java
new file mode 100644
index 0000000..969f950
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_I.java
@@ -0,0 +1,171 @@
+package de.vanitasvitae.enigmandroid.enigma;
+
+import android.util.Log;
+
+import de.vanitasvitae.enigmandroid.enigma.rotors.Reflector;
+import de.vanitasvitae.enigmandroid.enigma.rotors.Rotor;
+
+/**
+ * Concrete implementation of an enigma machine of type I
+ * 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 Enigma_I extends Enigma {
+ protected Rotor rotor1;
+ protected Rotor rotor2;
+ protected Rotor rotor3;
+
+ protected Reflector reflector;
+
+ protected Plugboard plugboard;
+
+ public Enigma_I() {
+ machineType = "I";
+ }
+
+ @Override
+ public void initialize()
+ {
+ this.setPlugboard(new Plugboard());
+ //I,II,III, A, 0,0,0, 0,0,0
+ this.setConfiguration(new int[]{1,2,3,1,0,0,0,0,0,0});
+ }
+
+ @Override
+ public void nextState()
+ {
+ rotor1.rotate();
+ if (rotor1.isAtTurnoverPosition() || (this.doAnomaly && prefAnomaly))
+ {
+ rotor2.rotate();
+ this.doAnomaly = rotor2.doubleTurnAnomaly();
+ if (rotor2.isAtTurnoverPosition())
+ {
+ rotor3.rotate();
+ }
+ }
+ }
+
+ @Override
+ public char encryptChar(char k)
+ {
+ nextState();
+ int x = ((int) k)-65; //Cast to int and remove Unicode Offset (A=65 in Unicode.)
+ //Encryption
+ //forward direction
+ x = plugboard.encrypt(x);
+ x = normalize(x + rotor1.getRotation() - rotor1.getRingSetting());
+ x = rotor1.encryptForward(x);
+ x = normalize(x - rotor1.getRotation() + rotor1.getRingSetting() + rotor2.getRotation() - rotor2.getRingSetting());
+ x = rotor2.encryptForward(x);
+ x = normalize(x - rotor2.getRotation() + rotor2.getRingSetting() + rotor3.getRotation() - rotor3.getRingSetting());
+ x = rotor3.encryptForward(x);
+ x = normalize(x - rotor3.getRotation() + rotor3.getRingSetting());
+ //TODO: CHECK
+ //backward direction
+ x = reflector.encrypt(x);
+ x = normalize(x + rotor3.getRotation() - rotor3.getRingSetting());
+ x = rotor3.encryptBackward(x);
+ x = normalize(x + rotor2.getRotation() - rotor2.getRingSetting() - rotor3.getRotation() + rotor3.getRingSetting());
+ x = rotor2.encryptBackward(x);
+ x = normalize(x + rotor1.getRotation() - rotor1.getRingSetting() - rotor2.getRotation() + rotor2.getRingSetting());
+ x = rotor1.encryptBackward(x);
+ x = normalize(x - rotor1.getRotation() + rotor1.getRingSetting());
+ x = plugboard.encrypt(x);
+ return (char) (x + 65); //Add Offset again, cast back to char and return
+ }
+
+ @Override
+ public int normalize(int input) {
+ return (input+26) % 26;
+ }
+
+ @Override
+ public void setPlugboard(Plugboard p)
+ {
+ this.plugboard = p;
+ }
+
+ @Override
+ public int[] getConfiguration()
+ {
+ int[] conf = new int[10];
+ conf[0] = rotor1.getType();
+ conf[1] = rotor2.getType();
+ conf[2] = rotor3.getType();
+ conf[3] = reflector.getType();
+ conf[4] = rotor1.getRotation();
+ conf[5] = rotor2.getRotation();
+ conf[6] = rotor3.getRotation();
+ conf[7] = rotor1.getRingSetting();
+ conf[8] = rotor2.getRingSetting();
+ conf[9] = rotor3.getRingSetting();
+ return conf;
+ }
+
+ @Override
+ /**
+ * conf:
+ * 0..2 -> rotor1..rotor3 type
+ * 3 -> reflector type
+ * 4..6 -> rotor1..rotor3 rotation
+ * 7..9 -> rotor1..rotor3 ringSetting
+ */
+ public void setConfiguration(int[] conf)
+ {
+ this.setRotor(1,conf[0],conf[7],conf[4]);
+ this.setRotor(2,conf[1],conf[8],conf[5]);
+ this.setRotor(3,conf[2],conf[9],conf[6]);
+ this.setReflector(conf[3]);
+ }
+
+ @Override
+ public boolean setRotor(int pos, int type, int ringSetting, int rotation)
+ {
+ if(pos >= 1 && pos <= 3) {
+ if (type >= 1 && type <= 5) {
+ Rotor rotor = Rotor.createRotor(type, ringSetting, rotation);
+ switch (pos) {
+ case 1:
+ rotor1 = rotor;
+ break;
+ case 2:
+ rotor2 = rotor;
+ break;
+ default:
+ rotor3 = rotor;
+ break;
+ }
+ return true;
+ }
+ }
+ Log.d("EnigmAndroid/M3/setRot", "Error: Type " + type + " at position " + pos);
+ return false;
+ }
+
+ @Override
+ public boolean setReflector(int type)
+ {
+ if(type >= 1 && type <= 3)
+ {
+ reflector = Reflector.createReflector(type);
+ return true;
+ }
+ Log.d("EnigmAndroid/I/setRef", "Error: Can't set type "+type);
+ return false;
+ }
+}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_M3.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_M3.java
new file mode 100644
index 0000000..d016838
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_M3.java
@@ -0,0 +1,75 @@
+package de.vanitasvitae.enigmandroid.enigma;
+
+import android.util.Log;
+
+import de.vanitasvitae.enigmandroid.enigma.rotors.Reflector;
+import de.vanitasvitae.enigmandroid.enigma.rotors.Rotor;
+
+/**
+ * Concrete implementation of an enigma machine model M3
+ * 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 Enigma_M3 extends Enigma_I
+{
+ public Enigma_M3()
+ {
+ machineType = "M3";
+ }
+ @Override
+ public void initialize()
+ {
+ this.setPlugboard(new Plugboard());
+ //I,II,III, B, 0,0,0, 0,0,0
+ this.setConfiguration(new int[]{1,2,3,2,0,0,0,0,0,0});
+ }
+ @Override
+ public boolean setRotor(int pos, int type, int ringSetting, int rotation)
+ {
+ if(pos >= 1 && pos <= 3) {
+ if (type >= 1 && type <= 8) {
+ Rotor rotor = Rotor.createRotor(type, ringSetting, rotation);
+ switch (pos) {
+ case 1:
+ rotor1 = rotor;
+ break;
+ case 2:
+ rotor2 = rotor;
+ break;
+ default:
+ rotor3 = rotor;
+ break;
+ }
+ return true;
+ }
+ }
+ Log.d("EnigmAndroid/M3/setRot", "Error: Type " + type + " at position " + pos);
+ return false;
+ }
+
+ @Override
+ public boolean setReflector(int type)
+ {
+ if(type >= 2 && type <= 3)
+ {
+ reflector = Reflector.createReflector(type);
+ return true;
+ }
+ Log.d("EnigmAndroid/M3/setRef", "Error: Can't set type "+type);
+ return false;
+ }
+}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_M4.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_M4.java
new file mode 100644
index 0000000..444faab
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Enigma_M4.java
@@ -0,0 +1,214 @@
+package de.vanitasvitae.enigmandroid.enigma;
+
+import android.util.Log;
+
+import de.vanitasvitae.enigmandroid.enigma.rotors.Reflector;
+import de.vanitasvitae.enigmandroid.enigma.rotors.Rotor;
+
+/**
+ * Concrete Implementation of the Enigma Machine type M4 of the german Kriegsmarine
+ * 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 Enigma_M4 extends Enigma
+{
+ private Rotor rotor1;
+ private Rotor rotor2;
+ private Rotor rotor3;
+
+ private Rotor rotor4;
+ private Reflector thinReflector;
+
+ private Plugboard plugboard;
+
+ public Enigma_M4()
+ {
+ machineType = "M4";
+ }
+
+ @Override
+ public boolean setRotor(int pos, int type, int ringSetting, int rotation)
+ {
+ if(pos >= 1 && pos <= 3)
+ {
+ if(type >= 1 && type <= 8)
+ {
+ Rotor rotor = Rotor.createRotor(type, ringSetting, rotation);
+ switch (pos)
+ {
+ case 1: rotor1 = rotor;
+ break;
+ case 2: rotor2 = rotor;
+ break;
+ default: rotor3 = rotor;
+ }
+ return true;
+ }
+ else
+ {
+ Log.d("EnigmAndroid/M4/setRot", "Error: Type " + type + " at position " + pos);
+ return false;
+ }
+ }
+ //Thin rotor
+ else if(pos == 4)
+ {
+ if(type >=9 && type <=10) {
+ rotor4 = Rotor.createRotor(type, ringSetting, rotation);
+ return true;
+ }
+ }
+ Log.d("EnigmAndroid/M3/setRot", "Error: Type " + type + " at position " + pos);
+ return false;
+ }
+
+ @Override
+ public boolean setReflector(int type)
+ {
+ if(type >= 4 && type <=5)
+ {
+ this.thinReflector = Reflector.createReflector(type);
+ return true;
+ }
+ Log.d("EnigmAndroid/M4/setRef","Error: Can't set type "+type);
+ return false;
+ }
+
+ @Override
+ public void initialize()
+ {
+ this.setPlugboard(new Plugboard());
+ this.setConfiguration(new int[]{1,2,3,9,4,0,0,0,0,0,0,0,0});
+ this.prefAnomaly = true;
+ }
+
+ @Override
+ /**
+ * Set the enigma into the next mechanical state.
+ * This rotates the first rotor and eventually also the second/third.
+ * Also this method handles the anomaly in case it should happen.
+ */
+ public void nextState()
+ {
+ //Rotate rotors
+ rotor1.rotate();
+ //Eventually turn next rotor (usual turnOver or anomaly)
+ if (rotor1.isAtTurnoverPosition() || (this.doAnomaly && prefAnomaly))
+ {
+ rotor2.rotate();
+ //Set doAnomaly for next call of encryptChar
+ this.doAnomaly = rotor2.doubleTurnAnomaly();
+ //Eventually rotate next rotor
+ if (rotor2.isAtTurnoverPosition())
+ {
+ rotor3.rotate();
+ }
+ }
+ }
+
+ @Override
+ /**
+ * Substitute char k by sending the signal through the enigma.
+ * The signal passes the plugboard, the rotors and returns back after going through the
+ * reflector wheel.
+ *
+ * @param k input char
+ * @return substituted output char
+ */
+ public char encryptChar(char k)
+ {
+ nextState(); //Rotate rotors
+ int x = ((int) k)-65; //Cast to int and remove Unicode Offset (A=65 in Unicode.)
+ //Encryption
+ //forward direction
+ x = plugboard.encrypt(x);
+ x = normalize(x + rotor1.getRotation() - rotor1.getRingSetting());
+ x = rotor1.encryptForward(x);
+ x = normalize(x - rotor1.getRotation() + rotor1.getRingSetting() + rotor2.getRotation() - rotor2.getRingSetting());
+ x = rotor2.encryptForward(x);
+ x = normalize(x - rotor2.getRotation() + rotor2.getRingSetting() + rotor3.getRotation() - rotor3.getRingSetting());
+ x = rotor3.encryptForward(x);
+ x = normalize(x - rotor3.getRotation() + rotor3.getRingSetting() + rotor4.getRotation() - rotor4.getRingSetting());
+ x = rotor4.encryptForward(x);
+ x = normalize(x - rotor4.getRotation() + rotor4.getRingSetting());
+ //backward direction
+ x = thinReflector.encrypt(x);
+ x = normalize(x + rotor4.getRotation() - rotor4.getRingSetting());
+ x = rotor4.encryptBackward(x);
+ x = normalize(x + rotor3.getRotation() - rotor3.getRingSetting() - rotor4.getRotation() + rotor4.getRingSetting());
+ x = rotor3.encryptBackward(x);
+ x = normalize(x + rotor2.getRotation() - rotor2.getRingSetting() - rotor3.getRotation() + rotor3.getRingSetting());
+ x = rotor2.encryptBackward(x);
+ x = normalize(x + rotor1.getRotation() - rotor1.getRingSetting() - rotor2.getRotation() + rotor2.getRingSetting());
+ x = rotor1.encryptBackward(x);
+ x = normalize(x - rotor1.getRotation() + rotor1.getRingSetting());
+ x = plugboard.encrypt(x);
+ return (char) (x + 65); //Add Offset again and cast back to char
+ }
+
+ @Override
+ public int normalize(int input) {
+ return (input + 26) % 26;
+ }
+
+ @Override
+ public void setPlugboard(Plugboard p)
+ {
+ this.plugboard = p;
+ }
+
+ @Override
+ public int[] getConfiguration() {
+ int[] configuration = new int[13];
+ configuration[0] = rotor1.getType();
+ configuration[1] = rotor2.getType();
+ configuration[2] = rotor3.getType();
+ configuration[3] = rotor4.getType();
+
+ configuration[4] = thinReflector.getType();
+
+ configuration[5] = rotor1.getRotation();
+ configuration[6] = rotor2.getRotation();
+ configuration[7] = rotor3.getRotation();
+ configuration[8] = rotor4.getRotation();
+
+ configuration[9] = rotor1.getRingSetting();
+ configuration[10] = rotor2.getRingSetting();
+ configuration[11] = rotor3.getRingSetting();
+
+ configuration[12] = rotor4.getRingSetting();
+ return configuration;
+ }
+
+ @Override
+ public void setConfiguration(int[] conf)
+ {
+ if(conf.length != 13)
+ {
+ Log.d("EnigmAndroid/M4/setCon", "Invalid conf array length. conf array length " +
+ "should be 13 (is "+conf.length+")");
+ }
+ else
+ {
+ setRotor(1, conf[0], conf[9], conf[5]);
+ setRotor(2, conf[1], conf[10], conf[6]);
+ setRotor(3, conf[2], conf[11], conf[7]);
+ setRotor(4, conf[3], conf[12], conf[8]);
+ setReflector(conf[4]);
+ }
+ }
+}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/Plugboard.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Plugboard.java
similarity index 97%
rename from app/src/main/java/de/vanitasvitae/enigmandroid/Plugboard.java
rename to app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Plugboard.java
index f182320..3d3350d 100644
--- a/app/src/main/java/de/vanitasvitae/enigmandroid/Plugboard.java
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/Plugboard.java
@@ -1,10 +1,13 @@
-package de.vanitasvitae.enigmandroid;
+package de.vanitasvitae.enigmandroid.enigma;
import android.app.Activity;
import android.widget.Toast;
import java.util.ArrayList;
+import de.vanitasvitae.enigmandroid.MainActivity;
+import de.vanitasvitae.enigmandroid.R;
+
/**
* Plugboard of the enigma
* Copyright (C) 2015 Paul Schaub
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/InputPreparator.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/inputPreparer/InputPreparer.java
similarity index 67%
rename from app/src/main/java/de/vanitasvitae/enigmandroid/InputPreparator.java
rename to app/src/main/java/de/vanitasvitae/enigmandroid/enigma/inputPreparer/InputPreparer.java
index 81eb0f8..64e6561 100644
--- a/app/src/main/java/de/vanitasvitae/enigmandroid/InputPreparator.java
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/inputPreparer/InputPreparer.java
@@ -1,9 +1,7 @@
-package de.vanitasvitae.enigmandroid;
-
-import java.text.Normalizer;
+package de.vanitasvitae.enigmandroid.enigma.inputPreparer;
/**
- * Preparator class that prepares input text to only consist of [A..Z]
+ * Preparer class that prepares input text to only consist of [A..Z]
* Copyright (C) 2015 Paul Schaub
This program is free software; you can redistribute it and/or modify
@@ -21,11 +19,11 @@ import java.text.Normalizer;
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* @author vanitasvitae
*/
-public abstract class InputPreparator
+public abstract class InputPreparer
{
/**
* Prepare the input String in a way that it only contains letters from [A..Z].
- * Replace special characters and spell numbers.
+ * Replace special characters, remove spaces and spell numbers.
* @param input String
* @return prepared String
*/
@@ -46,7 +44,7 @@ public abstract class InputPreparator
output = output + replaceNumber(x);
}
//x is special symbol
- else
+ else if (x != ' ')
{
output = output + 'X';
}
@@ -62,24 +60,25 @@ public abstract class InputPreparator
public abstract String replaceNumber(char input);
/**
- * Factory method that creates a specific InputPreparator
- * @param language language alias that specifies the language (de,en)
- * @return concrete InputPreparator
+ * Factory method that creates a specific InputPreparer
+ * @param language language alias that specifies the language (de,fr,en)
+ * @return concrete InputPreparer
*/
- public static InputPreparator createInputPreparator(String language)
+ public static InputPreparer createInputPreparer(String language)
{
switch (language)
{
- case "de": return new InputPreparatorGerman();
- default: return new InputPreparatorEnglish();
+ case "de": return new InputPreparerGerman();
+ case "fr": return new InputPreparerFrench();
+ default: return new InputPreparerEnglish();
}
}
}
/**
- * Concrete implementation of a german InputPreparator
+ * Concrete implementation of a german InputPreparer
*/
-class InputPreparatorGerman extends InputPreparator
+class InputPreparerGerman extends InputPreparer
{
@Override
public String replaceNumber(char input) {
@@ -100,9 +99,9 @@ class InputPreparatorGerman extends InputPreparator
}
/**
- * Concrete implementation of an english InputPreparator
+ * Concrete implementation of an english InputPreparer
*/
-class InputPreparatorEnglish extends InputPreparator
+class InputPreparerEnglish extends InputPreparer
{
@Override
public String replaceNumber(char input)
@@ -120,4 +119,28 @@ class InputPreparatorEnglish extends InputPreparator
default: return "NINE";
}
}
+}
+
+/**
+ * Concrete implementation of a french InputPreparer
+ */
+class InputPreparerFrench extends InputPreparer
+{
+
+ @Override
+ public String replaceNumber(char input)
+ {
+ switch (input) {
+ case '0': return "ZERO";
+ case '1': return "UN";
+ case '2': return "DEUX";
+ case '3': return "TROIS";
+ case '4': return "QUATRE";
+ case '5': return "CINQ";
+ case '6': return "SIX";
+ case '7': return "SEPT";
+ case '8': return "HUIT";
+ default: return "NEUF";
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/rotors/Reflector.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Reflector.java
similarity index 67%
rename from app/src/main/java/de/vanitasvitae/enigmandroid/rotors/Reflector.java
rename to app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Reflector.java
index 9917095..c7d782d 100644
--- a/app/src/main/java/de/vanitasvitae/enigmandroid/rotors/Reflector.java
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Reflector.java
@@ -1,4 +1,4 @@
-package de.vanitasvitae.enigmandroid.rotors;
+package de.vanitasvitae.enigmandroid.enigma.rotors;
/**
* Reflector of the enigma machine.
@@ -42,33 +42,6 @@ public class Reflector
this.connections = connections;
}
- /**
- * Creates a reflector of type A
- * @return ReflectorA
- */
- public static Reflector createReflectorA()
- {
- return new ReflectorA();
- }
-
- /**
- * Creates a reflector of type B
- * @return ReflectorB
- */
- public static Reflector createReflectorB()
- {
- return new ReflectorB();
- }
-
- /**
- * Creates a reflector of type C
- * @return ReflectorC
- */
- public static Reflector createReflectorC()
- {
- return new ReflectorC();
- }
-
/**
* Factory method to create reflectors.
* @param type type of the created reflector
@@ -81,9 +54,11 @@ public class Reflector
{
switch (type)
{
- case 1: return createReflectorA();
- case 2: return createReflectorB();
- default: return createReflectorC();
+ case 1: return new ReflectorA();
+ case 2: return new ReflectorB();
+ case 3: return new ReflectorC();
+ case 4: return new ReflectorThinB();
+ default: return new ReflectorThinC();
}
}
@@ -141,34 +116,70 @@ public class Reflector
/**
* Concrete implementation of ReflectorA
+ * Used in Enigma I
+ * AE BJ CM DZ FL GY HX IV KW NR OQ PU ST
*/
private static class ReflectorA extends Reflector
{
public ReflectorA()
{
- super("A", 1, new Integer[]{4, 9, 12, 25, 0, 11, 24, 23, 21, 1, 22, 5, 2, 17, 16, 20, 14, 13, 19, 18, 15, 8, 10, 7, 6, 3});
+ super("A", 1, new Integer[]{4,9,12,25,0,11,24,23,21,1,22,5,2,17,16,20,14,13,19,18,15,8,10,7,6,3});
}
}
/**
* Concrete implementation of ReflectorB
+ * Used in Enigma I, M3
+ * AY BR CU DH EQ FS GL IP JX KN MO TZ VW
*/
private static class ReflectorB extends Reflector
{
public ReflectorB()
{
- super("B", 2, new Integer[]{24, 17, 20, 7, 16, 18, 11, 3, 15, 23, 13, 6, 14, 10, 12, 8, 4, 1, 5, 25, 2, 22, 21, 9, 0, 19});
+ super("B", 2, new Integer[]{24,17,20,7,16,18,11,3,15,23,13,6,14,10,12,8,4,1,5,25,2,22,21,9,0,19});
}
}
/**
* Concrete implementation of ReflectorC
+ * Used in Enigma I, M3
+ * AF BV CP DJ EI GO HY KR LZ MX NW QT SU
*/
private static class ReflectorC extends Reflector
{
public ReflectorC()
{
- super("C", 3, new Integer[]{5, 21, 15, 9, 8, 0, 14, 24, 4, 3, 17, 25, 23, 22, 6, 2, 19, 10, 20, 16, 18, 1, 13, 12, 7, 11});
+ super("C", 3, new Integer[]{5,21,15,9,8,0,14,24,4,3,17,25,23,22,6,2,19,10,20,16,18,1,13,12,7,11});
+ }
+ }
+
+ /**
+ * Concrete implementation of thin reflector type b (not equal to normal type b!)
+ * When used with Rotor Beta on rotation 0, the pair was equivalent to normal reflector B
+ * S->Beta->ThinB->Beta'->X == X->UKWB->S
+ * Used in Enigma M4
+ * E N K Q A U Y W J I C O P B L M D X Z V F T H R G S
+ */
+ private static class ReflectorThinB extends Reflector
+ {
+ public ReflectorThinB()
+ {
+ super("B", 4, new Integer[]{4,13,10,16,0,20,24,22,9,8,2,14,15,1,11,12,3,23,25,21,5,19,7,17,6,18});
+ }
+ }
+
+ /**
+ * Concrete implementation of thin reflector type c (not equal to normal type c!)
+ * When used with Rotor Gamma on rotation 0, the pair was equivalent to normal reflector C
+ * S->Gamma->ThinC->Gamma'->X == X->UKWC->S
+ * Used in Enigma M4
+ * R D O B J N T K V E H M L F C W Z A X G Y I P S U Q
+ */
+ private static class ReflectorThinC extends Reflector
+ {
+ public ReflectorThinC()
+ {
+ super("B", 5, new Integer[]{17,3,14,1,9,13,19,10,21,4,7,12,11,5,2,22,25,0,23,6,24,8,15,18,20,16});
}
}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/rotors/Rotor.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Rotor.java
similarity index 56%
rename from app/src/main/java/de/vanitasvitae/enigmandroid/rotors/Rotor.java
rename to app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Rotor.java
index 105b766..b45fcb2 100644
--- a/app/src/main/java/de/vanitasvitae/enigmandroid/rotors/Rotor.java
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/rotors/Rotor.java
@@ -1,4 +1,4 @@
-package de.vanitasvitae.enigmandroid.rotors;
+package de.vanitasvitae.enigmandroid.enigma.rotors;
/**
* Rotor super class and inner concrete implementations
@@ -30,7 +30,7 @@ public class Rotor
protected int type;
protected Integer[] connections;
protected Integer[] reversedConnections;
- protected int turnOverNotch;
+ protected Integer[] turnOverNotches;
protected int ringSetting;
protected int rotation;
@@ -47,18 +47,18 @@ public class Rotor
* @param reversedConnections inverse wiring used to encrypt in the opposite direction
* (connections[reversedConnections[i]] = i
* for all i in 0..getRotorSize()-1.
- * @param turnOverNotch Position of the turnover notch
+ * @param turnOverNotches Position(s) of the turnover notch(es)
* @param ringSetting setting of the ring that holds the letters
* @param rotation rotation of the rotor
*/
protected Rotor(String name, int type, Integer[] connections, Integer[] reversedConnections,
- int turnOverNotch, int ringSetting, int rotation)
+ Integer[] turnOverNotches, int ringSetting, int rotation)
{
this.name = name;
this.type = type;
this.connections = connections;
this.reversedConnections = reversedConnections;
- this.turnOverNotch = turnOverNotch;
+ this.turnOverNotches = turnOverNotches;
this.ringSetting = ringSetting;
this.rotation = rotation;
}
@@ -66,7 +66,9 @@ public class Rotor
/**
* Factory method that creates a rotor accordingly to the type.
* Also initialize the rotor with ringSetting and rotation.
- * @param type type indicator (1..5)
+ * @param type type indicator (1..10)
+ * 1..8 -> I..VIII
+ * 9,10 -> Beta, Gamma
* @param ringSetting setting of the outer ring (0..25)
* @param rotation rotation of the rotor
* @return Concrete rotor
@@ -75,77 +77,28 @@ public class Rotor
{
switch (type)
{
- case 1: return createRotorI(ringSetting, rotation);
- case 2: return createRotorII(ringSetting, rotation);
- case 3: return createRotorIII(ringSetting, rotation);
- case 4: return createRotorIV(ringSetting, rotation);
- default: return createRotorV(ringSetting, rotation);
+ case 1: return new RotorI(ringSetting, rotation);
+ case 2: return new RotorII(ringSetting, rotation);
+ case 3: return new RotorIII(ringSetting, rotation);
+ case 4: return new RotorIV(ringSetting, rotation);
+ case 5: return new RotorV(ringSetting, rotation);
+ case 6: return new RotorVI(ringSetting, rotation);
+ case 7: return new RotorVII(ringSetting, rotation);
+ case 8: return new RotorVIII(ringSetting, rotation);
+ case 9: return new RotorBeta(ringSetting, rotation);
+ default: return new RotorGamma(ringSetting, rotation);
}
}
/**
- * Create concrete Rotor of type 1 (I) initialized with ringSetting and rotation
- * @param ringSetting setting of the outer ring
- * @param rotation rotation of the rotor
- * @return RotorI
- */
- public static Rotor createRotorI(int ringSetting, int rotation)
- {
- return new RotorI(ringSetting, rotation);
- }
-
- /**
- * Create concrete Rotor of type 2 (II) initialized with ringSetting and rotation
- * @param ringSetting setting of the outer ring
- * @param rotation rotation of the rotor
- * @return RotorI
- */
- public static Rotor createRotorII(int ringSetting, int rotation)
- {
- return new RotorII(ringSetting, rotation);
- }
-
- /**
- * Create concrete Rotor of type 3 (III) initialized with ringSetting and rotation
- * @param ringSetting setting of the outer ring
- * @param rotation rotation of the rotor
- * @return RotorI
- */
- public static Rotor createRotorIII(int ringSetting, int rotation)
- {
- return new RotorIII(ringSetting, rotation);
- }
-
- /**
- * Create concrete Rotor of type 4 (IV) initialized with ringSetting and rotation
- * @param ringSetting setting of the outer ring
- * @param rotation rotation of the rotor
- * @return RotorI
- */
- public static Rotor createRotorIV(int ringSetting, int rotation)
- {
- return new RotorIV(ringSetting, rotation);
- }
-
- /**
- * Create concrete Rotor of type 5 (V) initialized with ringSetting and rotation
- * @param ringSetting setting of the outer ring
- * @param rotation rotation of the rotor
- * @return RotorI
- */
- public static Rotor createRotorV(int ringSetting, int rotation)
- {
- return new RotorV(ringSetting, rotation);
- }
-
- /**
- * Encrypt an input signal via the internal wiring in "forward" direction (using connections)
+ * Encrypt an input signal via the internal wiring in "forward" direction towards the reflector
+ * (using connections)
* @param input signal
* @return encrypted signal
*/
public int encryptForward(int input)
{
- return this.connections[normalize(input)];
+ return this.connections[normalize(input)];// - this.ringSetting)];
}
/**
@@ -156,7 +109,7 @@ public class Rotor
*/
public int encryptBackward(int input)
{
- return this.reversedConnections[normalize(input)];
+ return this.reversedConnections[normalize(input)];// + this.ringSetting)];
}
/**
@@ -175,7 +128,7 @@ public class Rotor
*/
public int getRotation()
{
- return this.rotation - this.getRingSetting();
+ return this.rotation;
}
/**
@@ -192,7 +145,12 @@ public class Rotor
*/
public boolean isAtTurnoverPosition()
{
- return this.rotation == this.turnOverNotch;
+ for(int x : getTurnOverNotches())
+ {
+ //if(x == this.rotation + this.ringSetting) return true;
+ if(x == this.rotation) return true;
+ }
+ return false;
}
/**
@@ -206,16 +164,20 @@ public class Rotor
*/
public boolean doubleTurnAnomaly()
{
- return this.rotation == this.getTurnOver() - 1;
+ for(int x : getTurnOverNotches())
+ {
+ if(this.rotation == x-1) return true;
+ }
+ return false;
}
/**
- * Returns the position of the turnover notch
- * @return turnOverNotch
+ * Returns the positions of the turnover notches in a array
+ * @return turnOverNotches
*/
- public int getTurnOver()
+ public Integer[] getTurnOverNotches()
{
- return this.turnOverNotch;
+ return this.turnOverNotches;
}
/**
@@ -261,6 +223,8 @@ public class Rotor
/**
* Concrete implementation of Rotor of type 1 (I)
+ * Used in Enigma I, M3, M4
+ * E K M F L G D Q V Z N T O W Y H X U S P A I B R C J
*/
private static class RotorI extends Rotor
{
@@ -269,12 +233,14 @@ public class Rotor
super("I", 1,
new Integer[]{4, 10, 12, 5, 11, 6, 3, 16, 21, 25, 13, 19, 14, 22, 24, 7, 23, 20, 18, 15, 0, 8, 1, 17, 2, 9},
new Integer[]{20, 22, 24, 6, 0, 3, 5, 15, 21, 25, 1, 4, 2, 10, 12, 19, 7, 23, 18, 11, 17, 8, 13, 16, 14, 9},
- 17, ringSetting, rotation);
+ new Integer[]{17}, ringSetting, rotation);
}
}
/**
* Concrete implementation of Rotor of type 2 (II)
+ * Used in Enigma I, M3, M4
+ * A J D K S I R U X B L H W T M C Q G Z N P Y F V O E
*/
private static class RotorII extends Rotor
{
@@ -283,12 +249,14 @@ public class Rotor
super("II", 2,
new Integer[]{0, 9, 3, 10, 18, 8, 17, 20, 23, 1, 11, 7, 22, 19, 12, 2, 16, 6, 25, 13, 15, 24, 5, 21, 14, 4},
new Integer[]{0, 9, 15, 2, 25, 22, 17, 11, 5, 1, 3, 10, 14, 19, 24, 20, 16, 6, 4, 13, 7, 23, 12, 8, 21, 18},
- 5, ringSetting, rotation);
+ new Integer[]{5}, ringSetting, rotation);
}
}
/**
* Concrete implementation of Rotor of type 3 (III)
+ * Used in Enigma I, M3, M4
+ * B D F H J L C P R T X V Z N Y E I W G A K M U S Q O
*/
private static class RotorIII extends Rotor
{
@@ -297,12 +265,14 @@ public class Rotor
super("III", 3,
new Integer[]{1, 3, 5, 7, 9, 11, 2, 15, 17, 19, 23, 21, 25, 13, 24, 4, 8, 22, 6, 0, 10, 12, 20, 18, 16, 14},
new Integer[]{19, 0, 6, 1, 15, 2, 18, 3, 16, 4, 20, 5, 21, 13, 25, 7, 24, 8, 23, 9, 22, 11, 17, 10, 14, 12},
- 22, ringSetting, rotation);
+ new Integer[]{22}, ringSetting, rotation);
}
}
/**
* Concrete implementation of Rotor of type 4 (IV)
+ * Used in Enigma M3, M4
+ * E S O V P Z J A Y Q U I R H X L N F T G K D C M W B
*/
private static class RotorIV extends Rotor
{
@@ -311,12 +281,14 @@ public class Rotor
super("IV", 4,
new Integer[]{4, 18, 14, 21, 15, 25, 9, 0, 24, 16, 20, 8, 17, 7, 23, 11, 13, 5, 19, 6, 10, 3, 2, 12, 22, 1},
new Integer[]{7, 25, 22, 21, 0, 17, 19, 13, 11, 6, 20, 15, 23, 16, 2, 4, 9, 12, 1, 18, 10, 3, 24, 14, 8, 5},
- 10, ringSetting, rotation);
+ new Integer[]{10}, ringSetting, rotation);
}
}
/**
* Concrete implementation of Rotor of type 5 (V)
+ * Used in Enigma M3, M4
+ * V Z B R G I T Y U P S D N H L X A W M J Q O F E C K
*/
private static class RotorV extends Rotor
{
@@ -325,7 +297,117 @@ public class Rotor
super("V", 5,
new Integer[]{21, 25, 1, 17, 6, 8, 19, 24, 20, 15, 18, 3, 13, 7, 11, 23, 0, 22, 12, 9, 16, 14, 5, 4, 2, 10},
new Integer[]{16, 2, 24, 11, 23, 22, 4, 13, 5, 19, 25, 14, 18, 12, 21, 9, 20, 3, 10, 6, 8, 0, 17, 15, 7, 1},
- 0, ringSetting, rotation);
+ new Integer[]{0}, ringSetting, rotation);
+ }
+ }
+
+ /**
+ * Concrete implementation of Rotor of type 6 (VI)
+ * Used in Enigma M3, M4
+ * J P G V O U M F Y Q B E N H Z R D K A S X L I C T W
+ */
+ private static class RotorVI extends Rotor
+ {
+ public RotorVI(int ringSetting, int rotation)
+ {
+ super("VI", 6,
+ new Integer[]{9,15,6,21,14,20,12,5,24,16,1,4,13,7,25,17,3,10,0,18,23,11,8,2,19,22},
+ new Integer[]{18,10,23,16,11,7,2,13,22,0,17,21,6,12,4,1,9,15,19,24,5,3,25,20,8,14},
+ new Integer[]{0,13}, ringSetting, rotation);
+ }
+ }
+
+ /**
+ * Concrete implementation of Rotor of type 7 (VII)
+ * Used in Enigma M3, M4
+ * N Z J H G R C X M Y S W B O U F A I V L P E K Q D T
+ */
+ private static class RotorVII extends Rotor
+ {
+ public RotorVII(int ringSetting, int rotation)
+ {
+ super("VII", 7,
+ new Integer[]{13,25,9,7,6,17,2,23,12,24,18,22,1,14,20,5,0,8,21,11,15,4,10,16,3,19},
+ new Integer[]{16,12,6,24,21,15,4,3,17,2,22,19,8,0,13,20,23,5,10,25,14,18,11,7,9,1},
+ new Integer[]{0,13}, ringSetting, rotation);
+ }
+ }
+
+ /**
+ * Concrete implementation of Rotor of type 8 (VIII)
+ * Used in Enigma M3, M4
+ * F K Q H T L X O C B J S P D Z R A M E W N I U Y G V
+ */
+ private static class RotorVIII extends Rotor
+ {
+ public RotorVIII(int ringSetting, int rotation)
+ {
+ super("VIII", 8,
+ new Integer[]{5,10,16,7,19,11,23,14,2,1,9,18,15,3,25,17,0,12,4,22,13,8,20,24,6,21},
+ new Integer[]{16,9,8,13,18,0,24,3,21,10,1,5,17,20,7,12,2,15,11,4,22,25,19,6,23,14},
+ new Integer[]{0,13}, ringSetting, rotation);
+ }
+ }
+
+ /**
+ * Concrete implementation of Rotor of type beta (Griechenwalze Beta)
+ * Beta was used as a "thin" rotor in the M4. It was thinner than a "normal" rotor, so it
+ * could be used together with one of the two thin reflectors as one rotor.
+ * When used together with ReflectorThinB, Beta was equivalent to Reflector B (if rotation == 0)
+ * That way the M4 was backwards compatible to the M3
+ * Used in M4
+ */
+ private static class RotorBeta extends Rotor
+ {
+ public RotorBeta(int ringSetting, int rotation)
+ {
+ super("Beta",9,
+ new Integer[]{11,4,24,9,21,2,13,8,23,22,15,1,16,12,3,17,19,0,10,25,6,5,20,7,14,18},
+ new Integer[]{17,11,5,14,1,21,20,23,7,3,18,0,13,6,24,10,12,15,25,16,22,4,9,8,2,19},
+ new Integer[]{}, ringSetting, rotation);
+ }
+ @Override
+ public void rotate()
+ {
+ //Thin rotors are fixed in position, so they dont rotate
+ }
+
+ @Override
+ public boolean doubleTurnAnomaly()
+ {
+ //Nope, no anomaly
+ return false;
+ }
+ }
+
+ /**
+ * Concrete implementation of Rotor of type gamma (Griechenwalze Gamma)
+ * Gamma was used as a "thin" rotor in the M4. It was thinner than a "normal" rotor, so it
+ * could be used together with one of the two thin reflectors as one rotor.
+ * When used together with ReflectorThinC, Gamma is equivalent to Reflector C
+ * (if rotation == 0). That way the M4 was backwards compatible to the M3
+ * Used in M4
+ */
+ private static class RotorGamma extends Rotor
+ {
+ public RotorGamma(int ringSetting, int rotation)
+ {
+ super("Gamma",10,
+ new Integer[]{5,18,14,10,0,13,20,4,17,7,12,1,19,8,24,2,22,11,16,15,25,23,21,6,9,3},
+ new Integer[]{4,11,15,25,7,0,23,9,13,24,3,17,10,5,2,19,18,8,1,12,6,22,16,21,14,20},
+ new Integer[]{}, ringSetting, rotation);
+ }
+ @Override
+ public void rotate()
+ {
+ //Thin rotors are fixed in position, so they don't rotate
+ }
+
+ @Override
+ public boolean doubleTurnAnomaly()
+ {
+ //Thin rotors don't do such weird stuff, they're normal just like you and me.
+ return false;
}
}
}
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/util/RotorMaker.java b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/util/RotorMaker.java
new file mode 100644
index 0000000..858e578
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/enigma/util/RotorMaker.java
@@ -0,0 +1,107 @@
+package de.vanitasvitae.enigmandroid.enigma.util;
+
+/**
+ * Used to create wiring arrays from strings
+ * Use strings like "E K M F L G D Q V Z N T O W Y H X U S P A I B R C J" as input
+ * 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 RotorMaker
+{
+ public static final int l = 26;
+ public static void main(String[] args)
+ {
+ if(args.length == l) makeRotor(args);
+ else if(args.length == 1) makeRotor(prepare(args[0]));
+ else System.out.println("wrong input format!");
+ }
+
+ public static void makeRotor(String input)
+ {
+ makeRotor(prepare(input));
+ }
+
+ /**
+ * Prepare the string (add spaces)
+ * @param in input string
+ * @return prepared string
+ */
+ public static String[] prepare(String in)
+ {
+ String[] out = new String[l];
+ int pos = 0;
+ for(char x : in.toCharArray())
+ {
+ if(x != ' ')
+ {
+ try
+ {
+ out[pos] = ""+x;
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ System.out.println("String too long!");
+ return null;
+ }
+ pos++;
+ }
+ }
+ if(pos!=l)
+ {
+ System.out.println("String too short!");
+ return null;
+ }
+ return out;
+ }
+
+ /**
+ * Generate Array initializer for the given rotor configuration
+ * @param input String describing the rotor
+ */
+ public static void makeRotor(String[] input)
+ {
+ if(input.length != l) System.out.println("Wrong length! Input must have length "+l+"!");
+ else
+ {
+ Integer[] out1 = new Integer[l];
+ for(int i=0; i rotor1Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_5,
+ android.R.layout.simple_spinner_item);
+ rotor1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor1View.setAdapter(rotor1Adapter);
+ ArrayAdapter rotor2Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_5,
+ android.R.layout.simple_spinner_item);
+ rotor2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor2View.setAdapter(rotor2Adapter);
+ ArrayAdapter rotor3Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_5,
+ android.R.layout.simple_spinner_item);
+ rotor3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor3View.setAdapter(rotor3Adapter);
+
+ ArrayAdapter reflectorAdapter = ArrayAdapter.createFromResource(main, R.array.reflectors_a_c,
+ android.R.layout.simple_spinner_item);
+ reflectorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ reflectorView.setAdapter(reflectorAdapter);
+
+ ArrayAdapter rotor1PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor1PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor1PositionView.setAdapter(rotor1PositionAdapter);
+ ArrayAdapter rotor2PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor2PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor2PositionView.setAdapter(rotor2PositionAdapter);
+ ArrayAdapter rotor3PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor3PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor3PositionView.setAdapter(rotor3PositionAdapter);
+ }
+
+ @Override
+ public void reset()
+ {
+ rotor1View.setSelection(0); //I
+ rotor2View.setSelection(1); //II
+ rotor3View.setSelection(2); //III
+ reflectorView.setSelection(0); //A
+ rotor1PositionView.setSelection(0); //0
+ rotor2PositionView.setSelection(0); //0
+ rotor3PositionView.setSelection(0); //0
+ this.ringSettings = new int[]{0,0,0};
+ inputView.setText("");
+ outputView.setText("");
+ plugboardView.setText("");
+ enigma.setConfiguration(createConfiguration());
+ enigma.setPlugboard(new Plugboard());
+ }
+
+ @Override
+ public void updateLayout()
+ {
+ int[] conf = enigma.getConfiguration();
+ rotor1View.setSelection(conf[0]-1);
+ rotor2View.setSelection(conf[1]-1);
+ rotor3View.setSelection(conf[2]-1);
+ reflectorView.setSelection(conf[3]-1);
+ rotor1PositionView.setSelection(conf[4]);
+ rotor2PositionView.setSelection(conf[5]);
+ rotor3PositionView.setSelection(conf[6]);
+ ringSettings[0] = conf[7];
+ ringSettings[1] = conf[8];
+ ringSettings[2] = conf[9];
+ }
+
+ @Override
+ public int[] createConfiguration()
+ {
+ int[] conf = new int[10];
+ //Rotors 1..3
+ conf[0] = rotor1View.getSelectedItemPosition() + 1;
+ conf[1] = rotor2View.getSelectedItemPosition() + 1;
+ conf[2] = rotor3View.getSelectedItemPosition() + 1;
+ //Reflector
+ conf[3] = reflectorView.getSelectedItemPosition() + 1;
+
+ conf[4] = rotor1PositionView.getSelectedItemPosition();
+ conf[5] = rotor2PositionView.getSelectedItemPosition();
+ conf[6] = rotor3PositionView.getSelectedItemPosition();
+
+ conf[7] = ringSettings[0];
+ conf[8] = ringSettings[1];
+ conf[9] = ringSettings[2];
+
+ return conf;
+ }
+
+ @Override
+ public int[][] createPlugboardConfiguration() {
+ return Plugboard.parseConfigurationString(plugboardView.getText().toString());
+ }
+
+ @Override
+ public void showRingSettingsDialog()
+ {
+ Integer[] ringArray = new Integer[26];
+ for(int i=1; i<=26; i++) {ringArray[i-1] = i;}
+ View ringSettingsView = View.inflate(main, R.layout.dialog_ringsettings_i_m3, null);
+ final Spinner ring1 = (Spinner) ringSettingsView.findViewById(R.id.rotor1ring);
+ ArrayAdapter ring1Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item,ringArray);
+ ring1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring1.setAdapter(ring1Adapter);
+ ring1.setSelection(ringSettings[0]);
+
+ final Spinner ring2 = (Spinner) ringSettingsView.findViewById(R.id.rotor2ring);
+ ArrayAdapter ring2Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item,ringArray);
+ ring2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring2.setAdapter(ring2Adapter);
+ ring2.setSelection(ringSettings[1]);
+
+ final Spinner ring3 = (Spinner) ringSettingsView.findViewById(R.id.rotor3ring);
+ ArrayAdapter ring3Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item,ringArray);
+ ring3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring3.setAdapter(ring3Adapter);
+ ring3.setSelection(ringSettings[2]);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(main);
+ builder.setTitle(R.string.title_ringsetting);
+ builder.setView(ringSettingsView)
+ .setCancelable(true)
+ .setPositiveButton(R.string.dialog_positiv, new DialogInterface.OnClickListener()
+ {
+ public void onClick(DialogInterface dialog, int id)
+ {
+ ringSettings[0] = ring1.getSelectedItemPosition();
+ ringSettings[1] = ring2.getSelectedItemPosition();
+ ringSettings[2] = ring3.getSelectedItemPosition();
+ String message = main.getResources().getString(
+ R.string.dialog_ringsettings_success) + " " +
+ (ringSettings[2]+1) + ", " +
+ (ringSettings[1]+1) + ", " +
+ (ringSettings[0]+1) + ".";
+ Toast.makeText(main, message, Toast.LENGTH_LONG).show();
+ }
+ })
+ .setNegativeButton(R.string.dialog_negativ, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ Toast.makeText(main, R.string.dialog_ringsettings_abort,
+ Toast.LENGTH_SHORT).show();
+ }
+ }).show();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/layout/LayoutContainer_M3.java b/app/src/main/java/de/vanitasvitae/enigmandroid/layout/LayoutContainer_M3.java
new file mode 100644
index 0000000..d4b7cc1
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/layout/LayoutContainer_M3.java
@@ -0,0 +1,115 @@
+package de.vanitasvitae.enigmandroid.layout;
+
+import android.widget.ArrayAdapter;
+
+import de.vanitasvitae.enigmandroid.R;
+import de.vanitasvitae.enigmandroid.enigma.Enigma_M3;
+
+/**
+ * Concrete LayoutContainer for the M3 layout.
+ * This class contains the layout and controls the layout elements such as spinners and stuff
+ * 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 LayoutContainer_M3 extends LayoutContainer_I
+{
+ public LayoutContainer_M3()
+ {
+ super();
+ main.setTitle("M3 - EnigmAndroid");
+ this.enigma = new Enigma_M3();
+ }
+
+ @Override
+ void initialize()
+ {
+ Character[] rotorPositionArray = new Character[26];
+ for(int i=0; i<26; i++) {rotorPositionArray[i] = (char) (65+i); /**Fill with A..Z*/}
+
+ ArrayAdapter rotor1Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_8,
+ android.R.layout.simple_spinner_item);
+ rotor1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor1View.setAdapter(rotor1Adapter);
+ ArrayAdapter rotor2Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_8,
+ android.R.layout.simple_spinner_item);
+ rotor2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor2View.setAdapter(rotor2Adapter);
+ ArrayAdapter rotor3Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_8,
+ android.R.layout.simple_spinner_item);
+ rotor3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor3View.setAdapter(rotor3Adapter);
+
+ ArrayAdapter reflectorAdapter = ArrayAdapter.createFromResource(main, R.array.reflectors_b_c,
+ android.R.layout.simple_spinner_item);
+ reflectorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ reflectorView.setAdapter(reflectorAdapter);
+
+ ArrayAdapter rotor1PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor1PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor1PositionView.setAdapter(rotor1PositionAdapter);
+ ArrayAdapter rotor2PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor2PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor2PositionView.setAdapter(rotor2PositionAdapter);
+ ArrayAdapter rotor3PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor3PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor3PositionView.setAdapter(rotor3PositionAdapter);
+ }
+
+ @Override
+ public void updateLayout()
+ {
+ int[] conf = enigma.getConfiguration();
+ rotor1View.setSelection(conf[0]-1);
+ rotor2View.setSelection(conf[1]-1);
+ rotor3View.setSelection(conf[2]-1);
+ reflectorView.setSelection(conf[3]-2); //B=2 -> 0
+ rotor1PositionView.setSelection(conf[4]);
+ rotor2PositionView.setSelection(conf[5]);
+ rotor3PositionView.setSelection(conf[6]);
+ ringSettings[0] = conf[7];
+ ringSettings[1] = conf[8];
+ ringSettings[2] = conf[9];
+ }
+
+ @Override
+ public int[] createConfiguration()
+ {
+ int[] conf = new int[10];
+ //Rotors 1..3
+ conf[0] = rotor1View.getSelectedItemPosition() + 1;
+ conf[1] = rotor2View.getSelectedItemPosition() + 1;
+ conf[2] = rotor3View.getSelectedItemPosition() + 1;
+ //Reflector
+ conf[3] = reflectorView.getSelectedItemPosition() + 2; //M3 has no B
+
+ conf[4] = rotor1PositionView.getSelectedItemPosition();
+ conf[5] = rotor2PositionView.getSelectedItemPosition();
+ conf[6] = rotor3PositionView.getSelectedItemPosition();
+
+ conf[7] = ringSettings[0];
+ conf[8] = ringSettings[1];
+ conf[9] = ringSettings[2];
+
+ return conf;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/vanitasvitae/enigmandroid/layout/LayoutContainer_M4.java b/app/src/main/java/de/vanitasvitae/enigmandroid/layout/LayoutContainer_M4.java
new file mode 100644
index 0000000..cea28c4
--- /dev/null
+++ b/app/src/main/java/de/vanitasvitae/enigmandroid/layout/LayoutContainer_M4.java
@@ -0,0 +1,254 @@
+package de.vanitasvitae.enigmandroid.layout;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import de.vanitasvitae.enigmandroid.R;
+import de.vanitasvitae.enigmandroid.enigma.Enigma_M4;
+import de.vanitasvitae.enigmandroid.enigma.Plugboard;
+
+/**
+ * Concrete LayoutContainer for the M4 layout.
+ * This class contains the layout and controls the layout elements such as spinners and stuff
+ * 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 LayoutContainer_M4 extends LayoutContainer
+{
+ private Spinner rotor1View;
+ private Spinner rotor2View;
+ private Spinner rotor3View;
+ private Spinner rotor4View;
+ private Spinner reflectorView;
+ private Spinner rotor1PositionView;
+ private Spinner rotor2PositionView;
+ private Spinner rotor3PositionView;
+ private Spinner rotor4PositionView;
+
+ private EditText plugboardView;
+
+ public LayoutContainer_M4()
+ {
+ super();
+ main.setTitle("M4 - EnigmAndroid");
+ this.enigma = new Enigma_M4();
+ this.ringSettings = new int[]{0,0,0,0};
+ this.rotor1View = (Spinner) main.findViewById(R.id.rotor1);
+ this.rotor2View = (Spinner) main.findViewById(R.id.rotor2);
+ this.rotor3View = (Spinner) main.findViewById(R.id.rotor3);
+ this.rotor4View = (Spinner) main.findViewById(R.id.thin_rotor);
+ this.reflectorView = (Spinner) main.findViewById(R.id.reflector);
+ this.rotor1PositionView = (Spinner) main.findViewById(R.id.rotor1position);
+ this.rotor2PositionView = (Spinner) main.findViewById(R.id.rotor2position);
+ this.rotor3PositionView = (Spinner) main.findViewById(R.id.rotor3position);
+ this.rotor4PositionView = (Spinner) main.findViewById(R.id.thin_rotor_position);
+ this.plugboardView = (EditText) main.findViewById(R.id.plugboard);
+ this.inputView = (EditText) main.findViewById(R.id.input);
+ this.outputView = (EditText) main.findViewById(R.id.output);
+
+ initialize();
+ reset();
+ }
+
+ @Override
+ void initialize()
+ {
+ Character[] rotorPositionArray = new Character[26];
+ for(int i=0; i<26; i++) {rotorPositionArray[i] = (char) (65+i); /**Fill with A..Z*/}
+
+ ArrayAdapter rotor1Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_8,
+ android.R.layout.simple_spinner_item);
+ rotor1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor1View.setAdapter(rotor1Adapter);
+ ArrayAdapter rotor2Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_8,
+ android.R.layout.simple_spinner_item);
+ rotor2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor2View.setAdapter(rotor2Adapter);
+ ArrayAdapter rotor3Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_1_8,
+ android.R.layout.simple_spinner_item);
+ rotor3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor3View.setAdapter(rotor3Adapter);
+ ArrayAdapter rotor4Adapter = ArrayAdapter.createFromResource(main, R.array.rotors_beta_gamma,
+ android.R.layout.simple_spinner_item);
+ rotor4Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rotor4View.setAdapter(rotor4Adapter);
+
+ ArrayAdapter reflectorAdapter = ArrayAdapter.createFromResource(main, R.array.reflectors_b_c,
+ android.R.layout.simple_spinner_item);
+ reflectorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ reflectorView.setAdapter(reflectorAdapter);
+
+ ArrayAdapter rotor1PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor1PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor1PositionView.setAdapter(rotor1PositionAdapter);
+ ArrayAdapter rotor2PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor2PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor2PositionView.setAdapter(rotor2PositionAdapter);
+ ArrayAdapter rotor3PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor3PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor3PositionView.setAdapter(rotor3PositionAdapter);
+ ArrayAdapter rotor4PositionAdapter = new ArrayAdapter<>(main.getApplicationContext(),
+ android.R.layout.simple_spinner_item,rotorPositionArray);
+ rotor4PositionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ rotor4PositionView.setAdapter(rotor4PositionAdapter);
+ }
+
+ @Override
+ public void reset()
+ {
+ rotor1View.setSelection(0); //I
+ rotor2View.setSelection(1); //II
+ rotor3View.setSelection(2); //III
+ rotor4View.setSelection(0); //Beta
+ reflectorView.setSelection(0); //B
+ rotor1PositionView.setSelection(0); //0
+ rotor2PositionView.setSelection(0); //0
+ rotor3PositionView.setSelection(0); //0
+ rotor4PositionView.setSelection(0); //0
+ ringSettings = new int[]{0,0,0,0};
+ inputView.setText("");
+ outputView.setText("");
+ plugboardView.setText("");
+ enigma.setConfiguration(createConfiguration());
+ enigma.setPlugboard(new Plugboard());
+ }
+
+ @Override
+ public void updateLayout()
+ {
+ int[] conf = enigma.getConfiguration();
+ rotor1View.setSelection(conf[0]-1);
+ rotor2View.setSelection(conf[1]-1);
+ rotor3View.setSelection(conf[2]-1);
+ rotor4View.setSelection(conf[3]-9);
+ reflectorView.setSelection(conf[4]-4);
+ rotor1PositionView.setSelection(conf[5]);
+ rotor2PositionView.setSelection(conf[6]);
+ rotor3PositionView.setSelection(conf[7]);
+ rotor4PositionView.setSelection(conf[8]);
+ ringSettings[0] = conf[9];
+ ringSettings[1] = conf[10];
+ ringSettings[2] = conf[11];
+ ringSettings[3] = conf[12];
+ }
+
+ @Override
+ public int[] createConfiguration()
+ {
+ int[] conf = new int[13];
+ //Rotors 1..4
+ conf[0] = rotor1View.getSelectedItemPosition() + 1;
+ conf[1] = rotor2View.getSelectedItemPosition() + 1;
+ conf[2] = rotor3View.getSelectedItemPosition() + 1;
+ conf[3] = rotor4View.getSelectedItemPosition() + 9; //Beta is rotor #9
+ //Reflector
+ conf[4] = reflectorView.getSelectedItemPosition() + 4; //thinB is reflector #4
+
+ conf[5] = rotor1PositionView.getSelectedItemPosition();
+ conf[6] = rotor2PositionView.getSelectedItemPosition();
+ conf[7] = rotor3PositionView.getSelectedItemPosition();
+ conf[8] = rotor4PositionView.getSelectedItemPosition();
+
+ conf[9] = ringSettings[0];
+ conf[10] = ringSettings[1];
+ conf[11] = ringSettings[2];
+ conf[12] = ringSettings[3];
+
+ return conf;
+ }
+
+ @Override
+ public int[][] createPlugboardConfiguration() {
+ return Plugboard.parseConfigurationString(plugboardView.getText().toString());
+ }
+
+ @Override
+ public void showRingSettingsDialog()
+ {
+ Integer[] ringArray = new Integer[26];
+ for(int i=1; i<=26; i++) {ringArray[i-1] = i;}
+ View ringSettingsView = View.inflate(main, R.layout.dialog_ringsettings_m4, null);
+ final Spinner ring1 = (Spinner) ringSettingsView.findViewById(R.id.rotor1ring);
+ ArrayAdapter ring1Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item,ringArray);
+ ring1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring1.setAdapter(ring1Adapter);
+ ring1.setSelection(ringSettings[0]);
+
+ final Spinner ring2 = (Spinner) ringSettingsView.findViewById(R.id.rotor2ring);
+ ArrayAdapter ring2Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item,ringArray);
+ ring2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring2.setAdapter(ring2Adapter);
+ ring2.setSelection(ringSettings[1]);
+
+ final Spinner ring3 = (Spinner) ringSettingsView.findViewById(R.id.rotor3ring);
+ ArrayAdapter ring3Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item,ringArray);
+ ring3Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring3.setAdapter(ring3Adapter);
+ ring3.setSelection(ringSettings[2]);
+
+ final Spinner ring4 = (Spinner) ringSettingsView.findViewById(R.id.rotor4ring);
+ ArrayAdapter ring4Adapter = new ArrayAdapter<>(main,
+ android.R.layout.simple_spinner_item, ringArray);
+ ring4Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ ring4.setAdapter(ring4Adapter);
+ ring4.setSelection(ringSettings[3]);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(main);
+ builder.setTitle(R.string.title_ringsetting);
+ builder.setView(ringSettingsView)
+ .setCancelable(true)
+ .setPositiveButton(R.string.dialog_positiv, new DialogInterface.OnClickListener()
+ {
+ public void onClick(DialogInterface dialog, int id)
+ {
+ ringSettings[0] = ring1.getSelectedItemPosition();
+ ringSettings[1] = ring2.getSelectedItemPosition();
+ ringSettings[2] = ring3.getSelectedItemPosition();
+ ringSettings[3] = ring4.getSelectedItemPosition();
+ String message = main.getResources().getString(
+ R.string.dialog_ringsettings_success) + " " +
+ (ringSettings[3]+1) + ", " +
+ (ringSettings[2]+1) + ", " +
+ (ringSettings[1]+1) + ", " +
+ (ringSettings[0]+1) + ".";
+ Toast.makeText(main, message, Toast.LENGTH_LONG).show();
+ }
+ })
+ .setNegativeButton(R.string.dialog_negativ, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ Toast.makeText(main, R.string.dialog_ringsettings_abort,
+ Toast.LENGTH_SHORT).show();
+ }
+ }).show();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main_i_m3.xml
similarity index 100%
rename from app/src/main/res/layout-land/activity_main.xml
rename to app/src/main/res/layout-land/activity_main_i_m3.xml
diff --git a/app/src/main/res/layout-land/activity_main_m4.xml b/app/src/main/res/layout-land/activity_main_m4.xml
new file mode 100755
index 0000000..f40f043
--- /dev/null
+++ b/app/src/main/res/layout-land/activity_main_m4.xml
@@ -0,0 +1,202 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main_i_m3.xml
similarity index 99%
rename from app/src/main/res/layout/activity_main.xml
rename to app/src/main/res/layout/activity_main_i_m3.xml
index 17167ff..6acb3c7 100755
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main_i_m3.xml
@@ -159,7 +159,7 @@
android:layout_weight=".50"
android:layout_height="match_parent"
android:id="@+id/input"
- android:inputType="textNoSuggestions"
+ android:inputType="textNoSuggestions|textMultiLine"
android:hint="@string/hint_enigma_type_here" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_ringsettings.xml b/app/src/main/res/layout/dialog_ringsettings_i_m3.xml
similarity index 100%
rename from app/src/main/res/layout/dialog_ringsettings.xml
rename to app/src/main/res/layout/dialog_ringsettings_i_m3.xml
diff --git a/app/src/main/res/layout/dialog_ringsettings_m4.xml b/app/src/main/res/layout/dialog_ringsettings_m4.xml
new file mode 100755
index 0000000..8385818
--- /dev/null
+++ b/app/src/main/res/layout/dialog_ringsettings_m4.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 29cd319..f43d66d 100755
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -11,14 +11,16 @@
Wähle die Ringstellungen für die Walzen:Hier TippenEnigma-Code
- Steckerbrett (AZ,BE...)
+ Steckerbrett (AZ,BE…)Walze 1Walze 2Walze 3
+ Walze 4Umkehr-\nWalzePosition\nWalze 1Position\nWalze 2Position\nWalze 3
+ Position\nWalze 4Ver-/EntschlüsselnFehler: Fehlerhafte Steckerbrettkonfiguration.Kann Stecker nicht setzen:
@@ -31,18 +33,4 @@
Keine ÄnderungenEnigma zurückgesetzt
-
- I
- II
- III
- IV
- V
-
-
-
- A
- B
- C
-
-
diff --git a/app/src/main/res/values-de/strings_activity_settings.xml b/app/src/main/res/values-de/strings_activity_settings.xml
index 4023864..b6ee06b 100755
--- a/app/src/main/res/values-de/strings_activity_settings.xml
+++ b/app/src/main/res/values-de/strings_activity_settings.xml
@@ -4,13 +4,24 @@
Simulation
+ Enigma Modell
+ Welches Modell soll simuliert werden?
+
+ I
+ M3
+ M4
+
+
Doppelschritt Anomalie
- Die Doppelschritt Anomalie lässt die mittlere Walze zweimal rotieren, falls sie sich vor dem Übertragspunkt befindet.
+ Die Doppelschritt Anomalie lässt die mittlere Walze zweimal rotieren,
+ falls sie sich vor dem Übertragspunkt befindet.
+
ZahlenbuchstabierspracheSprache in der Zahlen buchstabiert werden sollen.Deutsch
+ FranzösischEnglisch
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f1e9824..d344547 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,7 +1,7 @@
- 0.1.4-15.08.2015
+ 0.1.5-27.08.2015EnigmAndroidVersionReset
@@ -16,10 +16,12 @@
Rotor 1Rotor 2Rotor 3
+ Rotor 4ReflectorPosition\nRotor 1Position\nRotor 2Position\nRotor 3
+ Position\nRotor 4En-/Decrypt!Error: Can\'t interpret plugboard input.Unable to plug
@@ -32,16 +34,35 @@
No changesEnigma reset
-
+ IIIIIIIVV
-
+
+ I
+ II
+ III
+ IV
+ V
+ VI
+ VII
+ VIII
+
+ ABC
+
+ B
+ C
+
+
+ \u03B2
+ \u03B3
+
+
diff --git a/app/src/main/res/values/strings_activity_settings.xml b/app/src/main/res/values/strings_activity_settings.xml
index d3d38bb..d3e2acf 100755
--- a/app/src/main/res/values/strings_activity_settings.xml
+++ b/app/src/main/res/values/strings_activity_settings.xml
@@ -4,18 +4,30 @@
Simulation
+ Enigma Model
+ Which model do you want to simulate?
+
+ I
+ M3
+ M4
+
+
Simulate AnomalyThe double step anomaly causes the middle rotor
to rotate twice, if it is one step before its turnover point.
+
Number spelling languageLanguage, in which numbers are spelled.German
+ FrenchEnglish
+
de
+ fren
diff --git a/app/src/main/res/xml/pref_page.xml b/app/src/main/res/xml/pref_page.xml
index 60ce2b0..b1f1754 100755
--- a/app/src/main/res/xml/pref_page.xml
+++ b/app/src/main/res/xml/pref_page.xml
@@ -2,18 +2,25 @@
-
-
+
+
+
\ No newline at end of file