diff --git a/ReadMe.txt b/ReadMe.txt index 571971e..fd07516 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -74,6 +74,8 @@ Version 1.8beta3 (2020-04-XX) - Fix: Overlapping window source position when Background/Offset is not (0,0). - Wrap the table of content in the former help documentation. - Save the settings at the end of the state file. +- Transform all child activities with dialog fragments (to prevent unwanted state save). +- Fix an issue with the numpad keys which send the arrow keys and the numbers at the same time. Version 1.7 (2019-12-12) @@ -192,6 +194,8 @@ The Eric's Real scripts ("real*.kml" and "real*.bmp/png") are embedded in this a TODO +- Add a settings to switch between dark and light theme. +- Increase the loading speed (for Charlemagne faceplates) if possible. - Add the name of the file in the toast "State saved". - The clock seems unsynchronized sometimes. - Retain a key by right clicking if it is from a mouse. diff --git a/app/build.gradle b/app/build.gradle index c271469..d422cc4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,11 +28,11 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { applicationId "org.emulator.forty.eight" minSdkVersion 19 - targetSdkVersion 28 + targetSdkVersion 29 versionCode 13 versionName "1.8beta2" setProperty("archivesBaseName", "Emu48-v$versionName") @@ -80,13 +80,12 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3' - implementation 'androidx.preference:preference:1.1.0' - implementation 'com.google.android.material:material:1.2.0-alpha02' - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.viewpager:viewpager:1.0.0' + implementation 'androidx.appcompat:appcompat:1.2.0-beta01' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.preference:preference:1.1.1' + implementation 'com.google.android.material:material:1.1.0' + implementation 'androidx.documentfile:documentfile:1.0.1' testImplementation 'junit:junit:4.13-beta-3' - androidTestImplementation 'androidx.test:runner:1.3.0-alpha02' + androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 15b8cb1..f63b144 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,8 @@ android:label="@string/app_name" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:launchMode="singleTop" - android:theme="@style/AppTheme.NoActionBar"> + android:theme="@style/AppTheme.NoActionBar" + > @@ -44,31 +45,6 @@ android:host="*"/> - - - - - - - - - { + dismiss(); + }); // Programmatically load text from an asset and place it into the // text view. Note that the text we are loading is ASCII, so we // need to convert it to UTF-16. try { - InputStream is = getAssets().open(filepath); + InputStream is = requireContext().getAssets().open(getString(Utils.resId(this, "string", "info_readme"))); // We guarantee that the available method returns the total // size of the asset... of course, this does mean that a single @@ -58,23 +89,11 @@ public class InfoActivity extends AppCompatActivity { String text = new String(buffer); // Finally stick the string into the text view. - TextView textViewInfo = findViewById(Utils.resId(this, "id", "textViewInfo")); + TextView textViewInfo = view.findViewById(Utils.resId(this, "id", "textViewInfo")); textViewInfo.setMovementMethod(new ScrollingMovementMethod()); textViewInfo.setText(text); Linkify.addLinks(textViewInfo, Linkify.ALL); - } catch (IOException e) { - // Should never happen! - //throw new RuntimeException(e); - } + } catch (IOException ignored) { } + return view; } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == homeId) { - finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - } diff --git a/app/src/main/java/org/emulator/calculator/InfoWebActivity.java b/app/src/main/java/org/emulator/calculator/InfoWebActivity.java deleted file mode 100644 index 0035b20..0000000 --- a/app/src/main/java/org/emulator/calculator/InfoWebActivity.java +++ /dev/null @@ -1,61 +0,0 @@ -// 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. - -package org.emulator.calculator; - -import android.annotation.SuppressLint; -import android.os.Bundle; -import android.view.MenuItem; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import androidx.appcompat.app.AppCompatActivity; - -public class InfoWebActivity extends AppCompatActivity { - - private int homeId; - - @SuppressLint("SetJavaScriptEnabled") - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(Utils.resId(this, "layout", "activity_web_info")); - homeId = Utils.resId(this, "id", "home"); - - WebView webView = findViewById(Utils.resId(this, "id", "webViewInfo")); - webView.getSettings().setJavaScriptEnabled(true); - webView.setWebViewClient(new WebViewClient() { - @Override - public void onPageFinished(WebView view, String url) { - super.onPageFinished(view, url); - - if(url != null) - // Inject a CSS style to wrap the table of content if needed - view.evaluateJavascript("javascript:(function(){var css=document.createElement(\"style\");css.type=\"text/css\";css.innerHTML=\".nav1{overflow-wrap:break-word;}\";document.head.appendChild(css);})();", null); - } - }); - webView.loadUrl(getString(Utils.resId(this, "string", "help_url"))); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == homeId) { - finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - -} diff --git a/app/src/main/java/org/emulator/calculator/InfoWebFragment.java b/app/src/main/java/org/emulator/calculator/InfoWebFragment.java new file mode 100644 index 0000000..f629ab9 --- /dev/null +++ b/app/src/main/java/org/emulator/calculator/InfoWebFragment.java @@ -0,0 +1,85 @@ +// 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. + +package org.emulator.calculator; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatDialogFragment; +import androidx.appcompat.widget.Toolbar; + +public class InfoWebFragment extends AppCompatDialogFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(AppCompatDialogFragment.STYLE_NO_FRAME, Utils.resId(this, "style", "AppTheme")); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + return dialog; + } + + @SuppressLint("SetJavaScriptEnabled") + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + String title = getString(Utils.resId(this, "string", "title_web_fragment_info")); + Dialog dialog = getDialog(); + if(dialog != null) + dialog.setTitle(title); + + View view = inflater.inflate(Utils.resId(this, "layout", "fragment_web_info"), container, false); + + // Toolbar + + Toolbar toolbar = view.findViewById(Utils.resId(this, "id", "my_toolbar")); + toolbar.setTitle(title); + Utils.colorizeDrawableWithColor(requireContext(), toolbar.getNavigationIcon(), android.R.attr.colorForeground); + toolbar.setNavigationOnClickListener(v -> { + dismiss(); + }); + + WebView webView = view.findViewById(Utils.resId(this, "id", "webViewInfo")); + webView.getSettings().setJavaScriptEnabled(true); + webView.setWebViewClient(new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + if(url != null) + // Inject a CSS style to wrap the table of content if needed + view.evaluateJavascript("javascript:(function(){var css=document.createElement(\"style\");css.type=\"text/css\";css.innerHTML=\".nav1{overflow-wrap:break-word;}\";document.head.appendChild(css);})();", null); + } + }); + webView.loadUrl(getString(Utils.resId(this, "string", "help_url"))); + + return view; + } +} diff --git a/app/src/main/java/org/emulator/calculator/MainScreenView.java b/app/src/main/java/org/emulator/calculator/MainScreenView.java index 8d6302e..be64b77 100644 --- a/app/src/main/java/org/emulator/calculator/MainScreenView.java +++ b/app/src/main/java/org/emulator/calculator/MainScreenView.java @@ -30,14 +30,16 @@ import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; public class MainScreenView extends PanAndScaleView { protected static final String TAG = "MainScreenView"; - protected final boolean debug = false; + protected final boolean debug = true; private Paint paintFullCalc = new Paint(); private Paint paintLCD = new Paint(); @@ -45,6 +47,7 @@ public class MainScreenView extends PanAndScaleView { private Rect srcBitmapCopy = new Rect(); private SparseIntArray vkmap; private HashMap charmap; + private List numpadKey; private int kmlBackgroundColor = Color.BLACK; private boolean useKmlBackgroundColor = false; private int fallbackBackgroundColorType = 0; @@ -102,7 +105,11 @@ public class MainScreenView extends PanAndScaleView { // vkmap.put(KeyEvent.KEYCODE_CTRL_RIGHT, 0x11); // VK_CONTROL vkmap.put(KeyEvent.KEYCODE_ESCAPE, 0x1B); // VK_ESCAPE vkmap.put(KeyEvent.KEYCODE_SPACE, 0x20); // VK_SPACE - vkmap.put(KeyEvent.KEYCODE_DPAD_LEFT, 0x25); // VK_LEFT + vkmap.put(KeyEvent.KEYCODE_PAGE_UP, 0x21); // VK_PRIOR + vkmap.put(KeyEvent.KEYCODE_PAGE_DOWN, 0x22); // VK_NEXT + vkmap.put(KeyEvent.KEYCODE_MOVE_END, 0x23); // VK_END + vkmap.put(KeyEvent.KEYCODE_MOVE_HOME, 0x24); // VK_HOME + vkmap.put(KeyEvent.KEYCODE_DPAD_LEFT, 0x25); // VK_LEFT vkmap.put(KeyEvent.KEYCODE_DPAD_UP, 0x26); // VK_UP vkmap.put(KeyEvent.KEYCODE_DPAD_RIGHT, 0x27); // VK_RIGHT vkmap.put(KeyEvent.KEYCODE_DPAD_DOWN, 0x28); // VK_DOWN @@ -166,6 +173,21 @@ public class MainScreenView extends PanAndScaleView { vkmap.put(KeyEvent.KEYCODE_APOSTROPHE, 0xDE); // VK_OEM_7 (‘ ») vkmap.put(KeyEvent.KEYCODE_BACKSLASH, 0xDC); // VK_OEM_5 (\|) + numpadKey = Arrays.asList( + KeyEvent.KEYCODE_NUMPAD_0, + KeyEvent.KEYCODE_NUMPAD_1, + KeyEvent.KEYCODE_NUMPAD_2, + KeyEvent.KEYCODE_NUMPAD_3, + KeyEvent.KEYCODE_NUMPAD_4, + KeyEvent.KEYCODE_NUMPAD_5, + KeyEvent.KEYCODE_NUMPAD_6, + KeyEvent.KEYCODE_NUMPAD_7, + KeyEvent.KEYCODE_NUMPAD_8, + KeyEvent.KEYCODE_NUMPAD_9, + KeyEvent.KEYCODE_NUMPAD_DOT, + KeyEvent.KEYCODE_NUMPAD_COMMA + ); + this.setFocusable(true); this.setFocusableInTouchMode(true); } @@ -213,6 +235,8 @@ public class MainScreenView extends PanAndScaleView { public boolean onKeyDown(int keyCode, KeyEvent event) { if((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == 0 && (event.getSource() & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) { + if(!event.isNumLockOn() && numpadKey.indexOf(keyCode) != -1) + return false; char pressedKey = (char) event.getUnicodeChar(); Integer windowsKeycode = charmap.get(pressedKey); if(windowsKeycode == null) @@ -232,6 +256,8 @@ public class MainScreenView extends PanAndScaleView { public boolean onKeyUp(int keyCode, KeyEvent event) { if((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == 0 && (event.getSource() & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) { + if(!event.isNumLockOn() && numpadKey.indexOf(keyCode) != -1) + return false; char pressedKey = (char) event.getUnicodeChar(); Integer windowsKeycode = charmap.get(pressedKey); if(windowsKeycode == null) diff --git a/app/src/main/java/org/emulator/calculator/PrinterSimulator.java b/app/src/main/java/org/emulator/calculator/PrinterSimulator.java index 2d953a4..551a74a 100644 --- a/app/src/main/java/org/emulator/calculator/PrinterSimulator.java +++ b/app/src/main/java/org/emulator/calculator/PrinterSimulator.java @@ -70,14 +70,6 @@ public class PrinterSimulator { m_bPrinter82240A = enable; } - /** - * true to prevent the line wrapping for the textual printer when the character '\4' is sent by the calc. - * @param preventLineWrap true to prevent the line wrapping; false otherwise. - */ - public void setPreventLineWrap(boolean preventLineWrap) { - this.preventLineWrap = preventLineWrap; - } - /** * Change the paper, so we cleanup everything. @@ -252,8 +244,6 @@ public class PrinterSimulator { // Text Printer - private boolean preventLineWrap = false; - /** * ROMAN8 Unicode table */ @@ -303,7 +293,7 @@ public class PrinterSimulator { private void addTextData(int byData) { do { // special LF and LF characters - if (/*!preventLineWrap &&*/ byData == 0x04 || byData == 0x0A) { + if (byData == 0x04 || byData == 0x0A) { textUpdate.append('\r'); textUpdate.append('\n'); if(debug) Log.d(TAG, "addTextData(" + byData + ")"); diff --git a/app/src/main/java/org/emulator/calculator/PrinterSimulatorFragment.java b/app/src/main/java/org/emulator/calculator/PrinterSimulatorFragment.java index e1a3b2a..1bcc573 100644 --- a/app/src/main/java/org/emulator/calculator/PrinterSimulatorFragment.java +++ b/app/src/main/java/org/emulator/calculator/PrinterSimulatorFragment.java @@ -22,7 +22,9 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; @@ -70,9 +72,7 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); - Window window = dialog.getWindow(); - if(window != null) - window.requestFeature(Window.FEATURE_NO_TITLE); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); return dialog; } @@ -94,7 +94,7 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment { Toolbar toolbar = view.findViewById(Utils.resId(this, "id", "my_toolbar")); toolbar.setTitle(title); - toolbar.setNavigationIcon(Utils.resId(this, "drawable", "ic_keyboard_backspace_white_24dp")); + Utils.colorizeDrawableWithColor(requireContext(), toolbar.getNavigationIcon(), android.R.attr.colorForeground); toolbar.setNavigationOnClickListener( v -> dismiss() ); diff --git a/app/src/main/java/org/emulator/calculator/Settings.java b/app/src/main/java/org/emulator/calculator/Settings.java index a814605..05515be 100644 --- a/app/src/main/java/org/emulator/calculator/Settings.java +++ b/app/src/main/java/org/emulator/calculator/Settings.java @@ -14,6 +14,7 @@ package org.emulator.calculator; +import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; @@ -33,226 +34,82 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; public class Settings extends PreferenceDataStore { private static final String TAG = "Settings"; - protected final boolean debug = true; + protected final boolean debug = false; - private final SharedPreferences defaultSettings; + private final SharedPreferences androidSettings; + private List applicationSettingKeys = Arrays.asList("settings_kml_default", "settings_kml_folder", "lastDocument", "MRU"); + private final HashMap applicationSettings = new HashMap<>(); + private final HashMap commonSettings = new HashMap<>(); private final HashMap embeddedStateSettings = new HashMap<>(); - private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener; + private boolean isCommonSettings = true; + + public interface OnOneKeyChangedListener { + void onOneKeyChanged(String keyChanged); + } + private OnOneKeyChangedListener oneKeyChangedListener; private static String magic = "MYHP"; - private boolean isDefaultSettings = true; - public Settings(@NonNull SharedPreferences sharedPreferences) { if(debug) Log.d(TAG, "Settings()"); - this.defaultSettings = sharedPreferences; + androidSettings = sharedPreferences; + + loadApplicationSettings(); } - public void registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { - if(debug) Log.d(TAG, "registerOnSharedPreferenceChangeListener()"); - sharedPreferenceChangeListener = listener; + public void registerOnOneKeyChangeListener(OnOneKeyChangedListener listener) { + if(debug) Log.d(TAG, "registerOnOneKeyChangeListener()"); + oneKeyChangedListener = listener; } - public void unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { - if(debug) Log.d(TAG, "unregisterOnSharedPreferenceChangeListener()"); - sharedPreferenceChangeListener = null; + public void unregisterOnOneKeyChangeListener() { + if(debug) Log.d(TAG, "unregisterOnOneKeyChangeListener()"); + oneKeyChangedListener = null; } - @Override - public void putString(String key, @Nullable String value) { - putString(key, value, false); - } - public void putString(String key, @Nullable String value, boolean forceDefault) { - if(debug) Log.d(TAG, (isDefaultSettings ? "DEFAULT" : "LOCAL") + " putString(key: '" + key + "' value: '" + value + "')"); - if(isDefaultSettings || forceDefault) { - defaultSettings.edit().putString(key, value).apply(); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(defaultSettings, key); - } else { + private void putValue(String key, @Nullable Object value) { + if(applicationSettingKeys.indexOf(key) != -1) + applicationSettings.put(key, value); + else if(isCommonSettings) + commonSettings.put(key, value); + else embeddedStateSettings.put(key, value); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(null, key); + if(oneKeyChangedListener != null) + oneKeyChangedListener.onOneKeyChanged(key); + } + + private Object getValue(String key) { + Object value = null; + if(!isCommonSettings) + value = embeddedStateSettings.get(key); + if(value == null) { + if(applicationSettingKeys.indexOf(key) != -1) + value = applicationSettings.get(key); + else + value = commonSettings.get(key); } + return value; } - @Override - public void putStringSet(String key, @Nullable Set value) { - putStringSet(key, value, false); - } - public void putStringSet(String key, @Nullable Set value, boolean forceDefault) { - if(debug) Log.d(TAG, (isDefaultSettings ? "DEFAULT" : "LOCAL") + " putStringSet(key: '" + key + "' value: '" + "" + "')"); - if(isDefaultSettings || forceDefault) { - defaultSettings.edit().putStringSet(key, value).apply(); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(defaultSettings, key); - } else { - embeddedStateSettings.put(key, value); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(null, key); - } + public boolean getIsDefaultSettings() { + return isCommonSettings; } - @Override - public void putInt(String key, int value) { - putInt(key, value, false); - } - public void putInt(String key, int value, boolean forceDefault) { - if(debug) Log.d(TAG, (isDefaultSettings ? "DEFAULT" : "LOCAL") + " putInt(key: '" + key + "' value: '" + value + "')"); - if(isDefaultSettings || forceDefault) { - defaultSettings.edit().putInt(key, value).apply(); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(defaultSettings, key); - } else { - embeddedStateSettings.put(key, value); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(null, key); - } - } - - @Override - public void putLong(String key, long value){ - putLong(key,value,false); - } - public void putLong(String key, long value, boolean forceDefault) { - if(debug) Log.d(TAG, (isDefaultSettings ? "DEFAULT" : "LOCAL") + " putLong(key: '" + key + "' value: '" + value + "')"); - if(isDefaultSettings || forceDefault) { - defaultSettings.edit().putLong(key, value).apply(); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(defaultSettings, key); - } else { - embeddedStateSettings.put(key, value); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(null, key); - } - } - - @Override - public void putFloat(String key, float value){ - putFloat(key,value,false); - } - public void putFloat(String key, float value, boolean forceDefault) { - if(debug) Log.d(TAG, (isDefaultSettings ? "DEFAULT" : "LOCAL") + " putFloat(key: '" + key + "' value: '" + value + "')"); - if(isDefaultSettings || forceDefault) { - defaultSettings.edit().putFloat(key, value).apply(); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(defaultSettings, key); - } else { - embeddedStateSettings.put(key, value); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(null, key); - } - } - - @Override - public void putBoolean(String key, boolean value){ - putBoolean(key,value,false); - } - public void putBoolean(String key, boolean value, boolean forceDefault) { - if(debug) Log.d(TAG, (isDefaultSettings ? "DEFAULT" : "LOCAL") + " putBoolean(key: '" + key + "' value: '" + value + "')"); - if(isDefaultSettings || forceDefault) { - defaultSettings.edit().putBoolean(key, value).apply(); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(defaultSettings, key); - } else { - embeddedStateSettings.put(key, value); - if(sharedPreferenceChangeListener != null) - sharedPreferenceChangeListener.onSharedPreferenceChanged(null, key); - } - } - - @Nullable - @Override - public String getString(String key, @Nullable String defValue) { - if(debug) Log.d(TAG, "getString(key: '" + key + "')"); - if(!isDefaultSettings) { - Object result = embeddedStateSettings.get(key); - if(result instanceof String) - return (String) result; - } - return defaultSettings.getString(key, defValue); - } - - @SuppressWarnings("unchecked") - @Nullable - @Override - public Set getStringSet(String key, @Nullable Set defValues) { - if(debug) Log.d(TAG, "getStringSet(key: '" + key + "')"); - if(!isDefaultSettings) { - Object result = embeddedStateSettings.get(key); - if(result instanceof Set) - try { - return (Set) result; - } catch (Exception ignored) {} - } - return defaultSettings.getStringSet(key, defValues); - } - - @Override - public int getInt(String key, int defValue) { - if(debug) Log.d(TAG, "getInt(key: '" + key + "')"); - if(!isDefaultSettings) { - Object result = embeddedStateSettings.get(key); - if(result != null) - try { - return (Integer) result; - } catch (Exception ignored) {} - } - return defaultSettings.getInt(key, defValue); - } - - @Override - public long getLong(String key, long defValue) { - if(debug) Log.d(TAG, "getLong(key: '" + key + "')"); - if(!isDefaultSettings) { - Object result = embeddedStateSettings.get(key); - if(result != null) - try { - return (Long) result; - } catch (Exception ignored) {} - } - return defaultSettings.getLong(key, defValue); - } - - @Override - public float getFloat(String key, float defValue) { - if(debug) Log.d(TAG, "getFloat(key: '" + key + "')"); - if(!isDefaultSettings) { - Object result = embeddedStateSettings.get(key); - if(result != null) - try { - return (Float) result; - } catch (Exception ignored) {} - } - return defaultSettings.getFloat(key, defValue); - } - - @Override - public boolean getBoolean(String key, boolean defValue) { - if(debug) Log.d(TAG, "getBoolean(key: '" + key + "')"); - if(!isDefaultSettings) { - Object result = embeddedStateSettings.get(key); - if(result != null) - try { - return (Boolean) result; - } catch (Exception ignored) {} - } - return defaultSettings.getBoolean(key, defValue); - } - - - public void setDefaultSettings(boolean defaultSettings) { - isDefaultSettings = defaultSettings; + public void setIsDefaultSettings(boolean isDefaultSettings) { + this.isCommonSettings = isDefaultSettings; } private static String toJSON(Collection array) { @@ -340,26 +197,36 @@ public class Settings extends PreferenceDataStore { public void saveInStateFile(Context context, String url) { if(debug) Log.d(TAG, "saveInStateFile(url: '" + url + "')"); - Uri uri = Uri.parse(url); - try { - ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "wa"); - if(pfd != null) { - FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); - String json = toJSON(embeddedStateSettings); - byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); - int jsonLength = jsonBytes.length; - fileOutputStream.write(jsonBytes); - // The JSON text should not be more than 64KB - fileOutputStream.write((jsonLength >> 8) & 0xFF); - fileOutputStream.write(jsonLength & 0xFF); - for (int i = 0; i < magic.length(); i++) { - fileOutputStream.write(magic.charAt(i)); + + // Consolidate common and embedded settings but without the app only settings + Map stateSettings = new HashMap<>(); + stateSettings.putAll(commonSettings); + stateSettings.putAll(embeddedStateSettings); + + String json = toJSON(stateSettings); + byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); + int jsonLength = jsonBytes.length; + + if(jsonLength < 65536) { + Uri uri = Uri.parse(url); + try { + ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "wa"); + if (pfd != null) { + FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); + + fileOutputStream.write(jsonBytes); + // The JSON text should not be more than 64KB + fileOutputStream.write((jsonLength >> 8) & 0xFF); + fileOutputStream.write(jsonLength & 0xFF); + for (int i = 0; i < magic.length(); i++) { + fileOutputStream.write(magic.charAt(i)); + } + fileOutputStream.flush(); + fileOutputStream.close(); } - fileOutputStream.flush(); - fileOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); } - } catch (IOException e) { - e.printStackTrace(); } } @@ -367,6 +234,12 @@ public class Settings extends PreferenceDataStore { embeddedStateSettings.clear(); } + @SuppressLint("ApplySharedPref") + public void clearCommonDefaultSettings() { + embeddedStateSettings.clear(); + commonSettings.clear(); + } + @SuppressWarnings("ResultOfMethodCallIgnored") public void loadFromStateFile(Context context, String url) { if(debug) Log.d(TAG, "loadFromStateFile(url: '" + url + "')"); @@ -383,7 +256,7 @@ public class Settings extends PreferenceDataStore { fileInputStream.read(lastChunk, 0, lastChunk.length); } else { int lastChunkOffset = lastChunk.length - (int)fileSize; - fileInputStream.read(lastChunk, lastChunkOffset, lastChunk.length); + fileInputStream.read(lastChunk, lastChunkOffset, (int)fileSize); } fileInputStream.close(); @@ -408,4 +281,154 @@ public class Settings extends PreferenceDataStore { e.printStackTrace(); } } + + private void loadApplicationSettings() { + commonSettings.clear(); + Map keyValuePairs = androidSettings.getAll(); + for (String key : keyValuePairs.keySet()) { + if (applicationSettingKeys.indexOf(key) != -1) + applicationSettings.put(key, keyValuePairs.get(key)); + else + commonSettings.put(key, keyValuePairs.get(key)); + } + } + + public void saveApplicationSettings() { + if(debug) Log.d(TAG, "saveApplicationSettings()"); + + SharedPreferences.Editor settingsEditor = androidSettings.edit(); + for (String key : commonSettings.keySet()) { + Object value = commonSettings.get(key); + putKeyValueInEditor(settingsEditor, key, value); + } + for (String key : applicationSettingKeys) { + Object value = applicationSettings.get(key); + putKeyValueInEditor(settingsEditor, key, value); + } + + settingsEditor.apply(); + } + + private void putKeyValueInEditor(SharedPreferences.Editor settingsEditor, String key, Object value) { + if (value instanceof Integer) + settingsEditor.putInt(key, ((Number)value).intValue()); + else if (value instanceof Long) + settingsEditor.putLong(key, ((Number)value).longValue()); + else if (value instanceof Boolean) + settingsEditor.putBoolean(key, (Boolean) value); + else if (value instanceof Float || value instanceof Double) + settingsEditor.putFloat(key, ((Number)value).floatValue()); + else if (value instanceof String) + settingsEditor.putString(key, (String) value); + else if (value instanceof Set) + settingsEditor.putStringSet(key, (Set) value); + else + settingsEditor.putString(key, null); + } + + + // PreferenceDataStore + + @Override + public void putString(String key, @Nullable String value) { + if(debug) Log.d(TAG, (isCommonSettings ? "DEFAULT" : "LOCAL") + " putString(key: '" + key + "' value: '" + value + "')"); + putValue(key, value); + } + + @Override + public void putStringSet(String key, @Nullable Set value) { + if(debug) Log.d(TAG, (isCommonSettings ? "DEFAULT" : "LOCAL") + " putStringSet(key: '" + key + "' value: '" + "" + "')"); + putValue(key, value); + } + + @Override + public void putInt(String key, int value) { + if(debug) Log.d(TAG, (isCommonSettings ? "DEFAULT" : "LOCAL") + " putInt(key: '" + key + "' value: '" + value + "')"); + putValue(key, value); + } + + @Override + public void putLong(String key, long value){ + if(debug) Log.d(TAG, (isCommonSettings ? "DEFAULT" : "LOCAL") + " putLong(key: '" + key + "' value: '" + value + "')"); + putValue(key, value); + } + + @Override + public void putFloat(String key, float value){ + if(debug) Log.d(TAG, (isCommonSettings ? "DEFAULT" : "LOCAL") + " putFloat(key: '" + key + "' value: '" + value + "')"); + putValue(key, value); + } + + @Override + public void putBoolean(String key, boolean value){ + if(debug) Log.d(TAG, (isCommonSettings ? "DEFAULT" : "LOCAL") + " putBoolean(key: '" + key + "' value: '" + value + "')"); + putValue(key, value); + } + + @Nullable + @Override + public String getString(String key, @Nullable String defValue) { + if(debug) Log.d(TAG, "getString(key: '" + key + "')"); + Object result = getValue(key); + if(result instanceof String) + return (String) result; + return defValue; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public Set getStringSet(String key, @Nullable Set defValues) { + if(debug) Log.d(TAG, "getStringSet(key: '" + key + "')"); + Object result = getValue(key); + if(result instanceof Set) + try { + return (Set) result; + } catch (Exception ignored) {} + return defValues; + } + + @Override + public int getInt(String key, int defValue) { + if(debug) Log.d(TAG, "getInt(key: '" + key + "')"); + Object result = getValue(key); + if(result != null) + try { + return ((Number) result).intValue(); + } catch (Exception ignored) {} + return defValue; + } + + @Override + public long getLong(String key, long defValue) { + if(debug) Log.d(TAG, "getLong(key: '" + key + "')"); + Object result = getValue(key); + if(result != null) + try { + return ((Number) result).longValue(); + } catch (Exception ignored) {} + return defValue; + } + + @Override + public float getFloat(String key, float defValue) { + if(debug) Log.d(TAG, "getFloat(key: '" + key + "')"); + Object result = getValue(key); + if(result != null) + try { + return ((Number) result).floatValue(); + } catch (Exception ignored) {} + return defValue; + } + + @Override + public boolean getBoolean(String key, boolean defValue) { + if(debug) Log.d(TAG, "getBoolean(key: '" + key + "')"); + Object result = getValue(key); + if(result != null) + try { + return (Boolean) result; + } catch (Exception ignored) {} + return defValue; + } } diff --git a/app/src/main/java/org/emulator/calculator/Utils.java b/app/src/main/java/org/emulator/calculator/Utils.java index 7030c54..df6a4a0 100644 --- a/app/src/main/java/org/emulator/calculator/Utils.java +++ b/app/src/main/java/org/emulator/calculator/Utils.java @@ -16,17 +16,24 @@ package org.emulator.calculator; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.database.Cursor; +import android.graphics.BlendMode; +import android.graphics.BlendModeColorFilter; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.provider.OpenableColumns; import android.util.Log; +import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.Toast; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import javax.microedition.khronos.egl.EGL10; @@ -43,29 +50,49 @@ public class Utils { toast.show(); } - static int resId(Context context, String resourcename, String variableName) - { + static int resId(Context context, String resourceName, String variableName) { try { - return context.getResources().getIdentifier(variableName, resourcename, context.getApplicationContext().getPackageName()); + return context.getResources().getIdentifier(variableName, resourceName, context.getApplicationContext().getPackageName()); } catch (Exception e) { e.printStackTrace(); return -1; } } - static int resId(Fragment fragment, String resourcename, String variableName) - { + public static int resId(Fragment fragment, String resourceName, String variableName) { try { Context context = fragment.getContext(); if(context != null) - return fragment.getResources().getIdentifier(variableName, resourcename, context.getApplicationContext().getPackageName()); + return fragment.getResources().getIdentifier(variableName, resourceName, context.getApplicationContext().getPackageName()); } catch (Exception e) { e.printStackTrace(); } return -1; } - public static void makeUriPersistable(Context context, Intent data, Uri uri) { + public static int getThemedColor(Context context, int attr) { + Resources.Theme theme = context.getTheme(); + if (theme != null) { + TypedValue tv = new TypedValue(); + theme.resolveAttribute(attr, tv, true); + Resources resources = context.getResources(); + if(resources != null) + return ContextCompat.getColor(context, tv.resourceId); + } + return 0; + } + + public static void colorizeDrawableWithColor(Context context, Drawable icon, int colorAttribute) { + if(icon != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + icon.setColorFilter(new BlendModeColorFilter(Utils.getThemedColor(context, colorAttribute), BlendMode.SRC_ATOP)); + else + icon.setColorFilter(Utils.getThemedColor(context, colorAttribute), PorterDuff.Mode.SRC_ATOP); + } + } + + + public static void makeUriPersistable(Context context, Intent data, Uri uri) { int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) context.getContentResolver().takePersistableUriPermission(uri, takeFlags); diff --git a/app/src/main/java/org/emulator/forty/eight/MainActivity.java b/app/src/main/java/org/emulator/forty/eight/MainActivity.java index db26447..f036c46 100644 --- a/app/src/main/java/org/emulator/forty/eight/MainActivity.java +++ b/app/src/main/java/org/emulator/forty/eight/MainActivity.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.AssetManager; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; @@ -32,7 +31,6 @@ import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.util.Log; import android.util.SparseArray; -import android.util.TypedValue; import android.view.HapticFeedbackConstants; import android.view.Menu; import android.view.MenuItem; @@ -47,10 +45,8 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.core.content.FileProvider; import androidx.core.view.GravityCompat; import androidx.documentfile.provider.DocumentFile; @@ -59,8 +55,8 @@ import androidx.drawerlayout.widget.DrawerLayout; import com.google.android.material.navigation.NavigationView; import org.emulator.calculator.EmuApplication; -import org.emulator.calculator.InfoActivity; -import org.emulator.calculator.InfoWebActivity; +import org.emulator.calculator.InfoFragment; +import org.emulator.calculator.InfoWebFragment; import org.emulator.calculator.LCDOverlappingView; import org.emulator.calculator.MainScreenView; import org.emulator.calculator.NativeLib; @@ -96,7 +92,8 @@ import java.util.regex.Pattern; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private static final String TAG = "MainActivity"; - private Settings settings; + private boolean debug = false; + private Settings settings; private NavigationView navigationView; private DrawerLayout drawer; private MainScreenView mainScreenView; @@ -107,7 +104,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On public static final int INTENT_GETSAVEFILENAME = 2; public static final int INTENT_OBJECT_LOAD = 3; public static final int INTENT_OBJECT_SAVE = 4; - public static final int INTENT_SETTINGS = 5; public static final int INTENT_PORT2LOAD = 6; public static final int INTENT_PICK_KML_FOLDER_FOR_NEW_FILE = 7; public static final int INTENT_PICK_KML_FOLDER_FOR_CHANGING = 8; @@ -144,20 +140,14 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - toolbar.setVisibility(View.GONE); drawer = findViewById(R.id.drawer_layout); - ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); - drawer.addDrawerListener(toggle); - toggle.syncState(); navigationView = findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); settings = EmuApplication.getSettings(); - settings.setDefaultSettings(true); + settings.setIsDefaultSettings(true); ViewGroup mainScreenContainer = findViewById(R.id.main_screen_container); @@ -193,7 +183,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } } updateMRU(); - updateFromPreferences(null); + updateFromPreferences(null, false); updateNavigationDrawerItems(); @@ -240,7 +230,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On Utils.makeUriPersistable(this, intent, documentToOpenUri); } } catch (Exception e) { - Log.e(TAG, e.getMessage()); + if(debug) Log.e(TAG, e.getMessage()); } else if(drawer != null) drawer.openDrawer(GravityCompat.START); @@ -285,7 +275,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On protected void onStop() { //TODO We cannot make the difference between going to the settings or loading/saving a file and a real app stop/kill! // -> Maybe by settings some flags when loading/saving - settings.putStringSet("MRU", mruLinkedHashMap.keySet(), true); + settings.putStringSet("MRU", mruLinkedHashMap.keySet()); if(lcdOverlappingView != null) lcdOverlappingView.saveViewLayout(); @@ -295,6 +285,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On onFileSave(); } + settings.saveApplicationSettings(); + clearFolderCache(); super.onStop(); @@ -534,7 +526,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On String url = file.getUri().toString(); String name = file.getName(); String mime = file.getType(); - Log.d(TAG, "url: " + url + ", name: " + name + ", mime: " + mime); + if(debug) Log.d(TAG, "url: " + url + ", name: " + name + ", mime: " + mime); if(kmlMimeType.equals(mime)) { calculatorsAssetFilenames.add(url); } @@ -662,7 +654,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On private void newFileFromKML(String kmlScriptFilename) { int result = NativeLib.onFileNew(kmlScriptFilename); if(result > 0) { - settings.setDefaultSettings(false); + settings.setIsDefaultSettings(false); settings.clearEmbeddedStateSettings(); showCalculatorView(true); displayFilename(""); @@ -731,7 +723,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On private void OnFileClose() { ensureDocumentSaved(() -> { NativeLib.onFileClose(); - settings.setDefaultSettings(true); + settings.setIsDefaultSettings(true); settings.clearEmbeddedStateSettings(); showCalculatorView(false); saveLastDocument(""); @@ -744,7 +736,32 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } private void OnSettings() { - startActivityForResult(new Intent(this, SettingsActivity.class), INTENT_SETTINGS); + SettingsFragment settingsFragment = new SettingsFragment(); + settingsFragment.registerOnSettingsKeyChangedListener(settingsKeyChanged -> { + HashSet changedKeysCleaned = new HashSet<>(); + for (String key : settingsKeyChanged) { + if(debug) Log.d(TAG, "ChangedKey): " + key); + switch (key) { + case "settings_port1en": + case "settings_port1wr": + changedKeysCleaned.add("settings_port1"); + break; + case "settings_port2en": + case "settings_port2wr": + case "settings_port2load": + changedKeysCleaned.add("settings_port2"); + break; + default: + changedKeysCleaned.add(key); + break; + } + } + for (String key : changedKeysCleaned) { + updateFromPreferences(key, true); + } + settingsFragment.unregisterOnSettingsKeyChangedListener(); + }); + settingsFragment.show(getSupportFragmentManager(), "SettingsFragment"); } private void openDocument() { @@ -911,7 +928,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } } else if(which == lastIndex + 1) { // Reset to default KML folder - settings.putBoolean("settings_kml_default", true, true); + settings.putBoolean("settings_kml_default", true); updateFromPreferences("settings_kml", true); if(changeKML) OnViewScript(); @@ -1002,156 +1019,129 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } private void OnTopics() { - startActivity(new Intent(this, InfoWebActivity.class)); + new InfoWebFragment().show(getSupportFragmentManager(), "InfoWebFragment"); } private void OnAbout() { - startActivity(new Intent(this, InfoActivity.class)); + new InfoFragment().show(getSupportFragmentManager(), "InfoFragment"); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if(resultCode == Activity.RESULT_OK && data != null) { - if(requestCode == INTENT_SETTINGS) { - String[] changedKeys = data.getStringArrayExtra("changedKeys"); - if(changedKeys != null) { - HashSet changedKeysCleaned = new HashSet<>(); - for (String key : changedKeys) { - //Log.d(TAG, "ChangedKey): " + key); - switch (key) { - case "settings_port1en": - case "settings_port1wr": - changedKeysCleaned.add("settings_port1"); - break; - case "settings_port2en": - case "settings_port2wr": - case "settings_port2load": - changedKeysCleaned.add("settings_port2"); - break; - default: - changedKeysCleaned.add(key); - break; + Uri uri = data.getData(); + String url = null; + if (uri != null) + url = uri.toString(); + if (url != null) { + switch (requestCode) { + case INTENT_GETOPENFILENAME: { + if(debug) Log.d(TAG, "onActivityResult INTENT_GETOPENFILENAME " + url); + int openResult = onFileOpen(url); + if (openResult > 0) { + saveLastDocument(url); + Utils.makeUriPersistable(this, data, uri); + } else if(openResult == -2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // >= API 21 + // For security reason, you must select the folder where are the KML and ROM files and then, reopen this file! + new AlertDialog.Builder(this) + .setTitle(getString(R.string.message_open_security)) + .setMessage(getString(R.string.message_open_security_description)) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(intent, INTENT_PICK_KML_FOLDER_FOR_SECURITY); + }).show(); } + break; } - for (String key : changedKeysCleaned) { - updateFromPreferences(key, true); + case INTENT_GETSAVEFILENAME: { + if(debug) Log.d(TAG, "onActivityResult INTENT_GETSAVEFILENAME " + url); + if (NativeLib.onFileSaveAs(url) != 0) { + showAlert(getString(R.string.message_state_saved)); + settings.saveInStateFile(this, url); + saveLastDocument(url); + Utils.makeUriPersistable(this, data, uri); + displayFilename(url); + if (fileSaveAsCallback != null) + fileSaveAsCallback.run(); + } + break; } - } - } else { - Uri uri = data.getData(); - String url = null; - if (uri != null) - url = uri.toString(); - if (url != null) { - switch (requestCode) { - case INTENT_GETOPENFILENAME: { - //Log.d(TAG, "onActivityResult INTENT_GETOPENFILENAME " + url); - int openResult = onFileOpen(url); - if (openResult > 0) { - saveLastDocument(url); - Utils.makeUriPersistable(this, data, uri); - } else if(openResult == -2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // >= API 21 - // For security reason, you must select the folder where are the KML and ROM files and then, reopen this file! + case INTENT_OBJECT_LOAD: { + if(debug) Log.d(TAG, "onActivityResult INTENT_OBJECT_LOAD " + url); + NativeLib.onObjectLoad(url); + break; + } + case INTENT_OBJECT_SAVE: { + if(debug) Log.d(TAG, "onActivityResult INTENT_OBJECT_SAVE " + url); + NativeLib.onObjectSave(url, null); + break; + } + case INTENT_PICK_KML_FOLDER_FOR_NEW_FILE: + case INTENT_PICK_KML_FOLDER_FOR_CHANGING: + case INTENT_PICK_KML_FOLDER_FOR_SETTINGS: + case INTENT_PICK_KML_FOLDER_FOR_SECURITY: { + if(debug) Log.d(TAG, "onActivityResult INTENT_PICK_KML_FOLDER " + url); + settings.putBoolean("settings_kml_default", false); + settings.putString("settings_kml_folder", url); + updateFromPreferences("settings_kml", true); + Utils.makeUriPersistableReadOnly(this, data, uri); + + switch (requestCode) { + case INTENT_PICK_KML_FOLDER_FOR_NEW_FILE: + OnFileNew(); + break; + case INTENT_PICK_KML_FOLDER_FOR_CHANGING: + OnViewScript(); + break; + case INTENT_PICK_KML_FOLDER_FOR_SETTINGS: + break; + case INTENT_PICK_KML_FOLDER_FOR_SECURITY: new AlertDialog.Builder(this) - .setTitle(getString(R.string.message_open_security)) - .setMessage(getString(R.string.message_open_security_description)) + .setTitle(getString(R.string.message_open_security_retry)) + .setMessage(getString(R.string.message_open_security_retry_description)) .setPositiveButton(android.R.string.ok, (dialog, which) -> { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); - startActivityForResult(intent, INTENT_PICK_KML_FOLDER_FOR_SECURITY); }).show(); - } - break; + break; } - case INTENT_GETSAVEFILENAME: { - //Log.d(TAG, "onActivityResult INTENT_GETSAVEFILENAME " + url); - if (NativeLib.onFileSaveAs(url) != 0) { - showAlert(getString(R.string.message_state_saved)); - settings.saveInStateFile(this, url); - saveLastDocument(url); - Utils.makeUriPersistable(this, data, uri); - displayFilename(url); - if (fileSaveAsCallback != null) - fileSaveAsCallback.run(); - } - break; - } - case INTENT_OBJECT_LOAD: { - //Log.d(TAG, "onActivityResult INTENT_OBJECT_LOAD " + url); - NativeLib.onObjectLoad(url); - break; - } - case INTENT_OBJECT_SAVE: { - //Log.d(TAG, "onActivityResult INTENT_OBJECT_SAVE " + url); - NativeLib.onObjectSave(url, null); - break; - } - case INTENT_PICK_KML_FOLDER_FOR_NEW_FILE: - case INTENT_PICK_KML_FOLDER_FOR_CHANGING: - case INTENT_PICK_KML_FOLDER_FOR_SETTINGS: - case INTENT_PICK_KML_FOLDER_FOR_SECURITY: { - //Log.d(TAG, "onActivityResult INTENT_PICK_KML_FOLDER " + url); - settings.putBoolean("settings_kml_default", false, true); - settings.putString("settings_kml_folder", url, true); - updateFromPreferences("settings_kml", true); - Utils.makeUriPersistableReadOnly(this, data, uri); - - switch (requestCode) { - case INTENT_PICK_KML_FOLDER_FOR_NEW_FILE: - OnFileNew(); - break; - case INTENT_PICK_KML_FOLDER_FOR_CHANGING: - OnViewScript(); - break; - case INTENT_PICK_KML_FOLDER_FOR_SETTINGS: - break; - case INTENT_PICK_KML_FOLDER_FOR_SECURITY: - new AlertDialog.Builder(this) - .setTitle(getString(R.string.message_open_security_retry)) - .setMessage(getString(R.string.message_open_security_retry_description)) - .setPositiveButton(android.R.string.ok, (dialog, which) -> { - }).show(); - break; - } - break; - } - case INTENT_CREATE_RAM_CARD: { - //Log.d(TAG, "onActivityResult INTENT_CREATE_RAM_CARD " + url); - if(selectedRAMSize > 0) { - int size = 2 * selectedRAMSize; - FileOutputStream fileOutputStream; - try { - ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "w"); - if(pfd != null) { - fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); - byte[] zero = new byte[1024]; - Arrays.fill(zero, (byte) 0); - for (int i = 0; i < size; i++) - fileOutputStream.write(zero); - fileOutputStream.flush(); - fileOutputStream.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - selectedRAMSize = -1; - } - - break; - } - case INTENT_MACRO_LOAD: { - //Log.d(TAG, "onActivityResult INTENT_MACRO_LOAD " + url); - NativeLib.onToolMacroPlay(url); - updateNavigationDrawerItems(); - break; - } - case INTENT_MACRO_SAVE: { - //Log.d(TAG, "onActivityResult INTENT_MACRO_SAVE " + url); - NativeLib.onToolMacroNew(url); - updateNavigationDrawerItems(); - break; - } - default: - break; + break; } + case INTENT_CREATE_RAM_CARD: { + if(debug) Log.d(TAG, "onActivityResult INTENT_CREATE_RAM_CARD " + url); + if(selectedRAMSize > 0) { + int size = 2 * selectedRAMSize; + FileOutputStream fileOutputStream; + try { + ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "w"); + if(pfd != null) { + fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); + byte[] zero = new byte[1024]; + Arrays.fill(zero, (byte) 0); + for (int i = 0; i < size; i++) + fileOutputStream.write(zero); + fileOutputStream.flush(); + fileOutputStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + selectedRAMSize = -1; + } + + break; + } + case INTENT_MACRO_LOAD: { + if(debug) Log.d(TAG, "onActivityResult INTENT_MACRO_LOAD " + url); + NativeLib.onToolMacroPlay(url); + updateNavigationDrawerItems(); + break; + } + case INTENT_MACRO_SAVE: { + if(debug) Log.d(TAG, "onActivityResult INTENT_MACRO_SAVE " + url); + NativeLib.onToolMacroNew(url); + updateNavigationDrawerItems(); + break; + } + default: + break; } } } @@ -1160,7 +1150,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } private void saveLastDocument(String url) { - settings.putString("lastDocument", url, true); + settings.putString("lastDocument", url); if(url != null && !url.isEmpty()) mruLinkedHashMap.put(url, null); @@ -1177,14 +1167,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } else { mainScreenView.setEnablePanAndScale(false); mainScreenView.setVisibility(View.GONE); - - Resources.Theme theme = getTheme(); - if (theme != null) { - TypedValue tv = new TypedValue(); - theme.resolveAttribute(android.R.attr.colorForeground, tv, true); - int iconColor = getResources().getColor(tv.resourceId); - imageButtonMenu.setColorFilter(iconColor); - } + imageButtonMenu.setColorFilter(Utils.getThemedColor(this, android.R.attr.colorForeground)); } } @@ -1192,18 +1175,18 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On // Eventually, close the previous state file NativeLib.onFileClose(); - settings.setDefaultSettings(true); + settings.setIsDefaultSettings(true); showCalculatorView(false); displayFilename(""); // Pre-Load the embedded settings from the end of the classic state file - settings.setDefaultSettings(false); + settings.setIsDefaultSettings(false); settings.clearEmbeddedStateSettings(); settings.loadFromStateFile(this, url); // Update the Emu VM with the new settings - updateFromPreferences(null); + updateFromPreferences(null, false); // Load the genuine state file int result = NativeLib.onFileOpen(url); @@ -1214,7 +1197,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On showKMLLog(); } else { // Because it failed to load the state file, we switch to the default settings - settings.setDefaultSettings(true); + settings.setIsDefaultSettings(true); settings.clearEmbeddedStateSettings(); showKMLLogForce(); } @@ -1564,147 +1547,140 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On updateFromPreferences("settings_port1", true); } - private void updateFromPreferences(Set keys) { - if(keys != null) { - for (String settingKey : keys) - updateFromPreferences(settingKey, false); - } else { - String[] settingKeys = { - "settings_realspeed", "settings_grayscale", "settings_rotation", "settings_auto_layout", "settings_allow_pinch_zoom", "settings_lcd_overlapping_mode", "settings_lcd_pixel_borders", - "settings_hide_bar", "settings_hide_button_menu", "settings_sound_volume", "settings_haptic_feedback", - "settings_background_kml_color", "settings_background_fallback_color", - "settings_printer_model", "settings_printer_prevent_line_wrap", "settings_macro", - "settings_kml", "settings_port1", "settings_port2" }; - for (String settingKey : settingKeys) - updateFromPreferences(settingKey, false); - } - } private void updateFromPreferences(String key, boolean isDynamic) { int isDynamicValue = isDynamic ? 1 : 0; - switch (key) { - case "settings_realspeed": - NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null); - break; - case "settings_grayscale": - NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null); - break; + if(key == null) { + String[] settingKeys = { + "settings_realspeed", "settings_grayscale", "settings_rotation", "settings_auto_layout", "settings_allow_pinch_zoom", "settings_lcd_overlapping_mode", "settings_lcd_pixel_borders", + "settings_hide_bar", "settings_hide_button_menu", "settings_sound_volume", "settings_haptic_feedback", + "settings_background_kml_color", "settings_background_fallback_color", + "settings_printer_model", "settings_macro", + "settings_kml", "settings_port1", "settings_port2" }; + for (String settingKey : settingKeys) + updateFromPreferences(settingKey, false); + } else { + switch (key) { + case "settings_realspeed": + NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null); + break; + case "settings_grayscale": + NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null); + break; - case "settings_rotation": - int rotationMode = 0; - try { - rotationMode = Integer.parseInt(settings.getString("settings_rotation", "0")); - } catch (NumberFormatException ex) { - // Catch bad number format - } - mainScreenView.setRotationMode(rotationMode, isDynamic); - break; - case "settings_auto_layout": - int autoLayoutMode = 1; - try { - autoLayoutMode = Integer.parseInt(settings.getString("settings_auto_layout", "1")); - } catch (NumberFormatException ex) { - // Catch bad number format - } - mainScreenView.setAutoLayout(autoLayoutMode, isDynamic); - break; - case "settings_allow_pinch_zoom": - mainScreenView.setAllowPinchZoom(settings.getBoolean("settings_allow_pinch_zoom", true)); - break; - case "settings_lcd_overlapping_mode": - int overlappingLCDMode = LCDOverlappingView.OVERLAPPING_LCD_MODE_NONE; - try { - overlappingLCDMode = Integer.parseInt(settings.getString("settings_lcd_overlapping_mode", "0")); - } catch (NumberFormatException ex) { - // Catch bad number format - } - lcdOverlappingView.setOverlappingLCDMode(overlappingLCDMode); - break; - case "settings_lcd_pixel_borders": - boolean usePixelBorders = settings.getBoolean("settings_lcd_pixel_borders", false); - mainScreenView.setUsePixelBorders(usePixelBorders); - lcdOverlappingView.setUsePixelBorders(usePixelBorders); - break; - case "settings_hide_bar": - case "settings_hide_bar_status": - case "settings_hide_bar_nav": - if(settings.getBoolean("settings_hide_bar_status", false) - || settings.getBoolean("settings_hide_bar_nav", false)) - hideSystemUI(); - else - showSystemUI(); - break; - case "settings_hide_button_menu": - imageButtonMenu.setVisibility(settings.getBoolean("settings_hide_button_menu", false) ? View.GONE : View.VISIBLE); - break; + case "settings_rotation": + int rotationMode = 0; + try { + rotationMode = Integer.parseInt(settings.getString("settings_rotation", "0")); + } catch (NumberFormatException ex) { + // Catch bad number format + } + mainScreenView.setRotationMode(rotationMode, isDynamic); + break; + case "settings_auto_layout": + int autoLayoutMode = 1; + try { + autoLayoutMode = Integer.parseInt(settings.getString("settings_auto_layout", "1")); + } catch (NumberFormatException ex) { + // Catch bad number format + } + mainScreenView.setAutoLayout(autoLayoutMode, isDynamic); + break; + case "settings_allow_pinch_zoom": + mainScreenView.setAllowPinchZoom(settings.getBoolean("settings_allow_pinch_zoom", true)); + break; + case "settings_lcd_overlapping_mode": + int overlappingLCDMode = LCDOverlappingView.OVERLAPPING_LCD_MODE_NONE; + try { + overlappingLCDMode = Integer.parseInt(settings.getString("settings_lcd_overlapping_mode", "0")); + } catch (NumberFormatException ex) { + // Catch bad number format + } + lcdOverlappingView.setOverlappingLCDMode(overlappingLCDMode); + break; + case "settings_lcd_pixel_borders": + boolean usePixelBorders = settings.getBoolean("settings_lcd_pixel_borders", false); + mainScreenView.setUsePixelBorders(usePixelBorders); + lcdOverlappingView.setUsePixelBorders(usePixelBorders); + break; + case "settings_hide_bar": + case "settings_hide_bar_status": + case "settings_hide_bar_nav": + if (settings.getBoolean("settings_hide_bar_status", false) + || settings.getBoolean("settings_hide_bar_nav", false)) + hideSystemUI(); + else + showSystemUI(); + break; + case "settings_hide_button_menu": + imageButtonMenu.setVisibility(settings.getBoolean("settings_hide_button_menu", false) ? View.GONE : View.VISIBLE); + break; - case "settings_sound_volume": { - int volumeOption = settings.getInt("settings_sound_volume", 64); - NativeLib.setConfiguration("settings_sound_volume", isDynamicValue, volumeOption, 0, null); - break; - } - case "settings_haptic_feedback": - // Nothing to do - break; + case "settings_sound_volume": { + int volumeOption = settings.getInt("settings_sound_volume", 64); + NativeLib.setConfiguration("settings_sound_volume", isDynamicValue, volumeOption, 0, null); + break; + } + case "settings_haptic_feedback": + // Nothing to do + break; - case "settings_background_kml_color": - mainScreenView.setBackgroundKmlColor(settings.getBoolean("settings_background_kml_color", false)); - break; - case "settings_background_fallback_color": - try { - mainScreenView.setBackgroundFallbackColor(Integer.parseInt(settings.getString("settings_background_fallback_color", "0"))); - } catch (NumberFormatException ex) { - // Catch bad number format - } - break; - case "settings_printer_model": - try { - printerSimulator.setPrinterModel82240A(Integer.parseInt(settings.getString("settings_printer_model", "1")) == 0); - } catch (NumberFormatException ex) { - // Catch bad number format - } - break; - case "settings_printer_prevent_line_wrap": - printerSimulator.setPreventLineWrap(settings.getBoolean("settings_printer_prevent_line_wrap", false)); - break; + case "settings_background_kml_color": + mainScreenView.setBackgroundKmlColor(settings.getBoolean("settings_background_kml_color", false)); + break; + case "settings_background_fallback_color": + try { + mainScreenView.setBackgroundFallbackColor(Integer.parseInt(settings.getString("settings_background_fallback_color", "0"))); + } catch (NumberFormatException ex) { + // Catch bad number format + } + break; + case "settings_printer_model": + try { + printerSimulator.setPrinterModel82240A(Integer.parseInt(settings.getString("settings_printer_model", "1")) == 0); + } catch (NumberFormatException ex) { + // Catch bad number format + } + break; - case "settings_kml": - case "settings_kml_default": - case "settings_kml_folder": - kmlFolderUseDefault = settings.getBoolean("settings_kml_default", true); - if(!kmlFolderUseDefault) { - kmlFolderURL = settings.getString("settings_kml_folder", ""); - // https://github.com/googlesamples/android-DirectorySelection - // https://stackoverflow.com/questions/44185477/intent-action-open-document-tree-doesnt-seem-to-return-a-real-path-to-drive/44185706 - // https://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-android-5-0-lollipop - } - kmlFolderChange = true; - break; + case "settings_kml": + case "settings_kml_default": + case "settings_kml_folder": + kmlFolderUseDefault = settings.getBoolean("settings_kml_default", true); + if (!kmlFolderUseDefault) { + kmlFolderURL = settings.getString("settings_kml_folder", ""); + // https://github.com/googlesamples/android-DirectorySelection + // https://stackoverflow.com/questions/44185477/intent-action-open-document-tree-doesnt-seem-to-return-a-real-path-to-drive/44185706 + // https://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-android-5-0-lollipop + } + kmlFolderChange = true; + break; - case "settings_macro": - case "settings_macro_real_speed": - case "settings_macro_manual_speed": - boolean macroRealSpeed = settings.getBoolean("settings_macro_real_speed", true); - int macroManualSpeed = settings.getInt("settings_macro_manual_speed", 500); - NativeLib.setConfiguration("settings_macro", isDynamicValue, macroRealSpeed ? 1 : 0, macroManualSpeed, null); - break; + case "settings_macro": + case "settings_macro_real_speed": + case "settings_macro_manual_speed": + boolean macroRealSpeed = settings.getBoolean("settings_macro_real_speed", true); + int macroManualSpeed = settings.getInt("settings_macro_manual_speed", 500); + NativeLib.setConfiguration("settings_macro", isDynamicValue, macroRealSpeed ? 1 : 0, macroManualSpeed, null); + break; - case "settings_port1": - case "settings_port1en": - case "settings_port1wr": - NativeLib.setConfiguration("settings_port1", isDynamicValue, - settings.getBoolean("settings_port1en", false) ? 1 : 0, - settings.getBoolean("settings_port1wr", false) ? 1 : 0, - null); - break; - case "settings_port2": - case "settings_port2en": - case "settings_port2wr": - case "settings_port2load": - NativeLib.setConfiguration("settings_port2", isDynamicValue, - settings.getBoolean("settings_port2en", false) ? 1 : 0, - settings.getBoolean("settings_port2wr", false) ? 1 : 0, - settings.getString("settings_port2load", "")); - break; + case "settings_port1": + case "settings_port1en": + case "settings_port1wr": + NativeLib.setConfiguration("settings_port1", isDynamicValue, + settings.getBoolean("settings_port1en", false) ? 1 : 0, + settings.getBoolean("settings_port1wr", false) ? 1 : 0, + null); + break; + case "settings_port2": + case "settings_port2en": + case "settings_port2wr": + case "settings_port2load": + NativeLib.setConfiguration("settings_port2", isDynamicValue, + settings.getBoolean("settings_port2en", false) ? 1 : 0, + settings.getBoolean("settings_port2wr", false) ? 1 : 0, + settings.getString("settings_port2load", "")); + break; + } } } diff --git a/app/src/main/java/org/emulator/forty/eight/SettingsActivity.java b/app/src/main/java/org/emulator/forty/eight/SettingsActivity.java deleted file mode 100644 index 6ae39cc..0000000 --- a/app/src/main/java/org/emulator/forty/eight/SettingsActivity.java +++ /dev/null @@ -1,281 +0,0 @@ -// 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. - -package org.emulator.forty.eight; - -import android.app.Activity; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.text.InputType; -import android.util.Log; -import android.view.MenuItem; -import android.widget.EditText; - -import java.util.HashSet; -import java.util.Locale; -import java.util.Objects; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.preference.Preference; -import androidx.preference.PreferenceDataStore; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceManager; -import androidx.preference.SeekBarPreference; - -import org.emulator.calculator.EmuApplication; -import org.emulator.calculator.NativeLib; -import org.emulator.calculator.Settings; -import org.emulator.calculator.Utils; - -public class SettingsActivity extends AppCompatActivity { - - private static final String TAG = "SettingsActivity"; - protected final boolean debug = false; - - private static Settings settings; - private HashSet settingsKeyChanged = new HashSet<>(); - private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> settingsKeyChanged.add(key); - private GeneralPreferenceFragment generalPreferenceFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - settings = EmuApplication.getSettings(); - settings.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - // Show the Up button in the action bar. - actionBar.setDisplayHomeAsUpEnabled(true); - } - - generalPreferenceFragment = new GeneralPreferenceFragment(); - getSupportFragmentManager().beginTransaction().replace(android.R.id.content, generalPreferenceFragment).commit(); - } - - @Override - protected void onDestroy() { - settings.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - super.onDestroy(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - Intent resultIntent = new Intent(); - resultIntent.putExtra("changedKeys", settingsKeyChanged.toArray(new String[0])); - setResult(Activity.RESULT_OK, resultIntent); - finish(); - } - - /** - * This fragment shows general preferences only. It is used when the - * activity is showing a two-pane settings UI. - */ - public static class GeneralPreferenceFragment extends PreferenceFragmentCompat { - - Preference preferencePort2load = null; - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - getPreferenceManager().setPreferenceDataStore(EmuApplication.getSettings()); - - // Load the preferences from an XML resource - setPreferencesFromResource(R.xml.pref_general, rootKey); - - setHasOptionsMenu(true); - - // Sound settings - - SeekBarPreference preferenceSoundVolume = findPreference("settings_sound_volume"); - if(preferenceSoundVolume != null) { - if(!NativeLib.getSoundEnabled()) { - preferenceSoundVolume.setSummary("Cannot initialize the sound engine."); - preferenceSoundVolume.setEnabled(false); - } else { - preferenceSoundVolume.setOnPreferenceClickListener(preference -> { - AlertDialog.Builder alert = new AlertDialog.Builder(Objects.requireNonNull(getContext())); - alert.setTitle(R.string.settings_sound_volume_dialog_title); - final EditText input = new EditText(getContext()); - input.setInputType(InputType.TYPE_CLASS_NUMBER); - input.setRawInputType(Configuration.KEYBOARD_12KEY); - input.setFocusable(true); - input.setText(String.format(Locale.US,"%d", preferenceSoundVolume.getValue())); - alert.setView(input); - alert.setPositiveButton(R.string.message_ok, (dialog, whichButton) -> { - String newValueText = input.getText().toString(); - try { - int newValue = Integer.parseInt(newValueText); - if(newValue >= preferenceSoundVolume.getMin() && newValue <= preferenceSoundVolume.getMax()) - preferenceSoundVolume.setValue(newValue); - } catch (NumberFormatException ignored) {} - }); - alert.setNegativeButton(R.string.message_cancel, (dialog, whichButton) -> {}); - alert.show(); - return true; - }); - } - } - - // Background color settings - - Preference preferenceBackgroundFallbackColor = findPreference("settings_background_fallback_color"); -// final ColorPickerPreferenceCompat preferenceBackgroundCustomColor = (ColorPickerPreferenceCompat)findPreference("settings_background_custom_color"); - if(preferenceBackgroundFallbackColor != null /*&& preferenceBackgroundCustomColor != null*/) { - final String[] stringArrayBackgroundFallbackColor = getResources().getStringArray(R.array.settings_background_fallback_color_item); - Preference.OnPreferenceChangeListener onPreferenceChangeListenerBackgroundFallbackColor = (preference, value) -> { - if(value != null) { - String stringValue = value.toString(); - int backgroundFallbackColor = -1; - try { - backgroundFallbackColor = Integer.parseInt(stringValue); - } catch (NumberFormatException ignored) {} - if(backgroundFallbackColor >= 0 && backgroundFallbackColor < stringArrayBackgroundFallbackColor.length) - preference.setSummary(stringArrayBackgroundFallbackColor[backgroundFallbackColor]); -// preferenceBackgroundCustomColor.setEnabled(backgroundFallbackColor == 2); - } - return true; - }; - preferenceBackgroundFallbackColor.setOnPreferenceChangeListener(onPreferenceChangeListenerBackgroundFallbackColor); - onPreferenceChangeListenerBackgroundFallbackColor.onPreferenceChange(preferenceBackgroundFallbackColor, - settings.getString(preferenceBackgroundFallbackColor.getKey(), "0")); - - - //preferenceBackgroundCustomColor.setColorValue(customColor); - -// Preference.OnPreferenceChangeListener onPreferenceChangeListenerBackgroundCustomColor = new Preference.OnPreferenceChangeListener() { -// @Override -// public boolean onPreferenceChange(Preference preference, Object value) { -// if(value != null) { -// int customColor = (Integer)value; -// } -// return true; -// } -// }; -// preferenceBackgroundCustomColor.setOnPreferenceChangeListener(onPreferenceChangeListenerBackgroundCustomColor); -// onPreferenceChangeListenerBackgroundCustomColor.onPreferenceChange(preferenceBackgroundCustomColor, sharedPreferences.getBoolean(preferenceBackgroundCustomColor.getKey(), false)); - } - - // Macro - - Preference preferenceMacroRealSpeed = findPreference("settings_macro_real_speed"); - Preference preferenceMacroManualSpeed = findPreference("settings_macro_manual_speed"); - if(preferenceMacroRealSpeed != null && preferenceMacroManualSpeed != null) { - Preference.OnPreferenceChangeListener onPreferenceChangeListenerMacroRealSpeed = (preference, value) -> { - if(value != null) - preferenceMacroManualSpeed.setEnabled(!(Boolean) value); - return true; - }; - preferenceMacroRealSpeed.setOnPreferenceChangeListener(onPreferenceChangeListenerMacroRealSpeed); - onPreferenceChangeListenerMacroRealSpeed.onPreferenceChange(preferenceMacroRealSpeed, settings.getBoolean(preferenceMacroRealSpeed.getKey(), true)); - } - - // Ports 1 & 2 settings - - Preference preferencePort1en = findPreference("settings_port1en"); - Preference preferencePort1wr = findPreference("settings_port1wr"); - Preference preferencePort2en = findPreference("settings_port2en"); - Preference preferencePort2wr = findPreference("settings_port2wr"); - preferencePort2load = findPreference("settings_port2load"); - if(preferencePort1en != null && preferencePort1wr != null - && preferencePort2en != null && preferencePort2wr != null - && preferencePort2load != null) { - boolean enablePortPreferences = NativeLib.isPortExtensionPossible(); - - Preference.OnPreferenceChangeListener onPreferenceChangeListenerPort1en = (preference, value) -> { - preferencePort1en.setEnabled(enablePortPreferences); - preferencePort1wr.setEnabled(enablePortPreferences); - return true; - }; - preferencePort1en.setOnPreferenceChangeListener(onPreferenceChangeListenerPort1en); - onPreferenceChangeListenerPort1en.onPreferenceChange(preferencePort1en, settings.getBoolean(preferencePort1en.getKey(), false)); - - Preference.OnPreferenceChangeListener onPreferenceChangeListenerPort2en = (preference, value) -> { - preferencePort2en.setEnabled(enablePortPreferences); - preferencePort2wr.setEnabled(enablePortPreferences); - preferencePort2load.setEnabled(enablePortPreferences); - return true; - }; - preferencePort2en.setOnPreferenceChangeListener(onPreferenceChangeListenerPort2en); - onPreferenceChangeListenerPort2en.onPreferenceChange(preferencePort2en, settings.getBoolean(preferencePort2en.getKey(), false)); - - updatePort2LoadFilename(settings.getString(preferencePort2load.getKey(), "")); - preferencePort2load.setOnPreferenceClickListener(preference -> { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - intent.putExtra(Intent.EXTRA_TITLE, "shared.bin"); - Activity activity = getActivity(); - if (activity != null) - activity.startActivityForResult(intent, MainActivity.INTENT_PORT2LOAD); - return true; - }); - } - } - - void updatePort2LoadFilename(String port2Filename) { - if(preferencePort2load != null) { - String displayName = port2Filename; - try { - displayName = Utils.getFileName(getActivity(), port2Filename); - } catch (Exception e) { - // Do nothing - } - preferencePort2load.setSummary(displayName); - } - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if(resultCode == Activity.RESULT_OK && data != null) { - if(requestCode == MainActivity.INTENT_PORT2LOAD) { - Uri uri = data.getData(); - String url; - if (uri != null) { - if(debug) Log.d(TAG, "onActivityResult INTENT_PORT2LOAD " + uri.toString()); - url = uri.toString(); - settings.putString("settings_port2load", url); - makeUriPersistable(data, uri); - if(generalPreferenceFragment != null) - generalPreferenceFragment.updatePort2LoadFilename(url); - } - } - } - super.onActivityResult(requestCode, resultCode, data); - } - - private void makeUriPersistable(Intent data, Uri uri) { - int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) - getContentResolver().takePersistableUriPermission(uri, takeFlags); - } -} diff --git a/app/src/main/java/org/emulator/forty/eight/SettingsFragment.java b/app/src/main/java/org/emulator/forty/eight/SettingsFragment.java new file mode 100644 index 0000000..4d4bd4b --- /dev/null +++ b/app/src/main/java/org/emulator/forty/eight/SettingsFragment.java @@ -0,0 +1,343 @@ +// 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. + +package org.emulator.forty.eight; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.BlendMode; +import android.graphics.BlendModeColorFilter; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.InputType; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatDialog; +import androidx.appcompat.app.AppCompatDialogFragment; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SeekBarPreference; + +import org.emulator.calculator.EmuApplication; +import org.emulator.calculator.NativeLib; +import org.emulator.calculator.Settings; +import org.emulator.calculator.Utils; + +import java.util.HashSet; +import java.util.Locale; + +public class SettingsFragment extends AppCompatDialogFragment { + + private static final String TAG = "SettingsFragment"; + protected final boolean debug = false; + + private static Settings settings; + private HashSet settingsKeyChanged = new HashSet<>(); + private Settings.OnOneKeyChangedListener sharedPreferenceChangeListener = (key) -> settingsKeyChanged.add(key); + private GeneralPreferenceFragment generalPreferenceFragment; + + public interface OnSettingsKeyChangedListener { + void onSettingsKeyChanged(HashSet settingsKeyChanged); + } + + private OnSettingsKeyChangedListener onSettingsKeyChangedListener; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + settings = EmuApplication.getSettings(); + settings.registerOnOneKeyChangeListener(sharedPreferenceChangeListener); + + setStyle(AppCompatDialogFragment.STYLE_NO_FRAME, R.style.AppTheme); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Dialog dialog = new AppCompatDialog(getContext(), getTheme()) { + @Override + public void onBackPressed() { + dialogResult(); + dismiss(); + } + }; + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + return dialog; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + String title = getString(settings.getIsDefaultSettings() ? R.string.dialog_common_settings_title : R.string.dialog_state_settings_title); + Dialog dialog = getDialog(); + if(dialog != null) + dialog.setTitle(title); + + View view = inflater.inflate(R.layout.fragment_settings, container, false); + + // Configure the toolbar + + Toolbar toolbar = view.findViewById(R.id.my_toolbar); + toolbar.setTitle(title); + Utils.colorizeDrawableWithColor(requireContext(), toolbar.getNavigationIcon(), android.R.attr.colorForeground); + toolbar.setNavigationOnClickListener(v -> { + dialogResult(); + dismiss(); + }); + toolbar.inflateMenu(R.menu.fragment_settings); + Menu menu = toolbar.getMenu(); + menu.findItem(R.id.menu_settings_reset_to_default).setEnabled(settings.getIsDefaultSettings()); + menu.findItem(R.id.menu_settings_reset_to_common).setEnabled(!settings.getIsDefaultSettings()); + toolbar.setOnMenuItemClickListener(item -> { + int id = item.getItemId(); + if(id == R.id.menu_settings_reset_to_default) { + settings.clearCommonDefaultSettings(); + restartPreferenceFragment(); + } else if(id == R.id.menu_settings_reset_to_common) { + settings.clearEmbeddedStateSettings(); + restartPreferenceFragment(); + } + return true; + }); + + // Insert the Preference fragment + restartPreferenceFragment(); + return view; + } + + /** + * Start or restart the preference fragment to take into account the new settings. + */ + private void restartPreferenceFragment() { + if(generalPreferenceFragment != null) + getChildFragmentManager().beginTransaction().remove(generalPreferenceFragment).commit(); + generalPreferenceFragment = new GeneralPreferenceFragment(); + getChildFragmentManager().beginTransaction().replace(R.id.settingsContent, generalPreferenceFragment).commit(); + } + + /** + * Common method to handle the result of the dialog. + */ + private void dialogResult() { + if (onSettingsKeyChangedListener != null) + onSettingsKeyChangedListener.onSettingsKeyChanged(settingsKeyChanged); + } + + @Override + public void onDestroy() { + settings.unregisterOnOneKeyChangeListener(); + super.onDestroy(); + } + + void registerOnSettingsKeyChangedListener(OnSettingsKeyChangedListener listener) { + if(debug) Log.d(TAG, "registerOnSettingsKeyChangedListener()"); + onSettingsKeyChangedListener = listener; + } + + void unregisterOnSettingsKeyChangedListener() { + if(debug) Log.d(TAG, "unregisterOnSettingsKeyChangedListener()"); + onSettingsKeyChangedListener = null; + } + + public static class GeneralPreferenceFragment extends PreferenceFragmentCompat { + + Preference preferencePort2load = null; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + + // Register our own settings data store + getPreferenceManager().setPreferenceDataStore(EmuApplication.getSettings()); + + // Load the preferences from an XML resource + setPreferencesFromResource(R.xml.pref_general, rootKey); + + + // Sound settings + + SeekBarPreference preferenceSoundVolume = findPreference("settings_sound_volume"); + if(preferenceSoundVolume != null) { + if(!NativeLib.getSoundEnabled()) { + preferenceSoundVolume.setSummary("Cannot initialize the sound engine."); + preferenceSoundVolume.setEnabled(false); + } else { + preferenceSoundVolume.setOnPreferenceClickListener(preference -> { + AlertDialog.Builder alert = new AlertDialog.Builder(requireContext()); + alert.setTitle(R.string.settings_sound_volume_dialog_title); + final EditText input = new EditText(getContext()); + input.setInputType(InputType.TYPE_CLASS_NUMBER); + input.setRawInputType(Configuration.KEYBOARD_12KEY); + input.setFocusable(true); + input.setText(String.format(Locale.US,"%d", preferenceSoundVolume.getValue())); + alert.setView(input); + alert.setPositiveButton(R.string.message_ok, (dialog, whichButton) -> { + String newValueText = input.getText().toString(); + try { + int newValue = Integer.parseInt(newValueText); + if(newValue >= preferenceSoundVolume.getMin() && newValue <= preferenceSoundVolume.getMax()) + preferenceSoundVolume.setValue(newValue); + } catch (NumberFormatException ignored) {} + }); + alert.setNegativeButton(R.string.message_cancel, (dialog, whichButton) -> {}); + alert.show(); + return true; + }); + } + } + + // Background color settings + + Preference preferenceBackgroundFallbackColor = findPreference("settings_background_fallback_color"); +// final ColorPickerPreferenceCompat preferenceBackgroundCustomColor = (ColorPickerPreferenceCompat)findPreference("settings_background_custom_color"); + if(preferenceBackgroundFallbackColor != null /*&& preferenceBackgroundCustomColor != null*/) { + final String[] stringArrayBackgroundFallbackColor = getResources().getStringArray(R.array.settings_background_fallback_color_item); + Preference.OnPreferenceChangeListener onPreferenceChangeListenerBackgroundFallbackColor = (preference, value) -> { + if(value != null) { + String stringValue = value.toString(); + int backgroundFallbackColor = -1; + try { + backgroundFallbackColor = Integer.parseInt(stringValue); + } catch (NumberFormatException ignored) {} + if(backgroundFallbackColor >= 0 && backgroundFallbackColor < stringArrayBackgroundFallbackColor.length) + preference.setSummary(stringArrayBackgroundFallbackColor[backgroundFallbackColor]); +// preferenceBackgroundCustomColor.setEnabled(backgroundFallbackColor == 2); + } + return true; + }; + preferenceBackgroundFallbackColor.setOnPreferenceChangeListener(onPreferenceChangeListenerBackgroundFallbackColor); + onPreferenceChangeListenerBackgroundFallbackColor.onPreferenceChange(preferenceBackgroundFallbackColor, + settings.getString(preferenceBackgroundFallbackColor.getKey(), "0")); + + + //preferenceBackgroundCustomColor.setColorValue(customColor); + +// Preference.OnPreferenceChangeListener onPreferenceChangeListenerBackgroundCustomColor = new Preference.OnPreferenceChangeListener() { +// @Override +// public boolean onPreferenceChange(Preference preference, Object value) { +// if(value != null) { +// int customColor = (Integer)value; +// } +// return true; +// } +// }; +// preferenceBackgroundCustomColor.setOnPreferenceChangeListener(onPreferenceChangeListenerBackgroundCustomColor); +// onPreferenceChangeListenerBackgroundCustomColor.onPreferenceChange(preferenceBackgroundCustomColor, sharedPreferences.getBoolean(preferenceBackgroundCustomColor.getKey(), false)); + } + + // Macro + + Preference preferenceMacroRealSpeed = findPreference("settings_macro_real_speed"); + Preference preferenceMacroManualSpeed = findPreference("settings_macro_manual_speed"); + if(preferenceMacroRealSpeed != null && preferenceMacroManualSpeed != null) { + Preference.OnPreferenceChangeListener onPreferenceChangeListenerMacroRealSpeed = (preference, value) -> { + if(value != null) + preferenceMacroManualSpeed.setEnabled(!(Boolean) value); + return true; + }; + preferenceMacroRealSpeed.setOnPreferenceChangeListener(onPreferenceChangeListenerMacroRealSpeed); + onPreferenceChangeListenerMacroRealSpeed.onPreferenceChange(preferenceMacroRealSpeed, settings.getBoolean(preferenceMacroRealSpeed.getKey(), true)); + } + + // Ports 1 & 2 settings + + Preference preferencePort1en = findPreference("settings_port1en"); + Preference preferencePort1wr = findPreference("settings_port1wr"); + Preference preferencePort2en = findPreference("settings_port2en"); + Preference preferencePort2wr = findPreference("settings_port2wr"); + preferencePort2load = findPreference("settings_port2load"); + if(preferencePort1en != null && preferencePort1wr != null + && preferencePort2en != null && preferencePort2wr != null + && preferencePort2load != null) { + boolean enablePortPreferences = NativeLib.isPortExtensionPossible(); + + Preference.OnPreferenceChangeListener onPreferenceChangeListenerPort1en = (preference, value) -> { + preferencePort1en.setEnabled(enablePortPreferences); + preferencePort1wr.setEnabled(enablePortPreferences); + return true; + }; + preferencePort1en.setOnPreferenceChangeListener(onPreferenceChangeListenerPort1en); + onPreferenceChangeListenerPort1en.onPreferenceChange(preferencePort1en, settings.getBoolean(preferencePort1en.getKey(), false)); + + Preference.OnPreferenceChangeListener onPreferenceChangeListenerPort2en = (preference, value) -> { + preferencePort2en.setEnabled(enablePortPreferences); + preferencePort2wr.setEnabled(enablePortPreferences); + preferencePort2load.setEnabled(enablePortPreferences); + return true; + }; + preferencePort2en.setOnPreferenceChangeListener(onPreferenceChangeListenerPort2en); + onPreferenceChangeListenerPort2en.onPreferenceChange(preferencePort2en, settings.getBoolean(preferencePort2en.getKey(), false)); + + updatePort2LoadFilename(settings.getString(preferencePort2load.getKey(), "")); + preferencePort2load.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + intent.putExtra(Intent.EXTRA_TITLE, "shared.bin"); + Fragment parentFragment = getParentFragment(); + if (parentFragment != null) + parentFragment.startActivityForResult(intent, MainActivity.INTENT_PORT2LOAD); + return true; + }); + } + } + + void updatePort2LoadFilename(String port2Filename) { + if(preferencePort2load != null) { + String displayName = port2Filename; + try { + displayName = Utils.getFileName(getActivity(), port2Filename); + } catch (Exception e) { + // Do nothing + } + preferencePort2load.setSummary(displayName); + } + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + if(resultCode == Activity.RESULT_OK && data != null) { + if(requestCode == MainActivity.INTENT_PORT2LOAD) { + Uri uri = data.getData(); + String url; + if (uri != null) { + if(debug) Log.d(TAG, "onActivityResult INTENT_PORT2LOAD " + uri.toString()); + url = uri.toString(); + settings.putString("settings_port2load", url); + Utils.makeUriPersistable(requireContext(), data, uri); + if(generalPreferenceFragment != null) + generalPreferenceFragment.updatePort2LoadFilename(url); + } + } + } + super.onActivityResult(requestCode, resultCode, data); + } +} diff --git a/app/src/main/res/layout/activity_info.xml b/app/src/main/res/layout/activity_info.xml deleted file mode 100644 index 29b0d3f..0000000 --- a/app/src/main/res/layout/activity_info.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/app/src/main/res/layout/activity_web_info.xml b/app/src/main/res/layout/activity_web_info.xml deleted file mode 100644 index ab7bc58..0000000 --- a/app/src/main/res/layout/activity_web_info.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index 8898e60..59ab34e 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -5,17 +5,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_info.xml b/app/src/main/res/layout/fragment_info.xml new file mode 100644 index 0000000..6dee618 --- /dev/null +++ b/app/src/main/res/layout/fragment_info.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml new file mode 100644 index 0000000..856a2df --- /dev/null +++ b/app/src/main/res/layout/fragment_settings.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_web_info.xml b/app/src/main/res/layout/fragment_web_info.xml new file mode 100644 index 0000000..0154459 --- /dev/null +++ b/app/src/main/res/layout/fragment_web_info.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/menu/fragment_settings.xml b/app/src/main/res/menu/fragment_settings.xml new file mode 100644 index 0000000..4ed1c09 --- /dev/null +++ b/app/src/main/res/menu/fragment_settings.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4d27a0a..d9f235c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,17 +1,21 @@ - + - About + About ReadMe.txt - - Help + + Help file:///android_asset/Emu48.htm - + - Settings + Common Settings + Settings (Saved in state file) + + Reset to Default + Reset to Common @@ -129,7 +133,7 @@ Manual (Zoom or pan) Show the LCD pixel borders - Experimental feature which show a more realistic pixel. Note: Due to the difference in screen resolution between Android and the calculator, the pixels are not necessarily uniform in size. + Experimental feature which shows a more realistic pixel. Note: Due to the difference in screen resolution between Android and the calculator, the pixels are not necessarily uniform in size. Hide the status bar Hide the navigation bar @@ -162,8 +166,6 @@ HP82240A HP82240B (default) Generic Serial - Prevent Line Wrapping - Prevent the calc to wrap the line in the textual printer simulator Macro Use Real Replay Speed diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml index 4b0ce96..b024f74 100644 --- a/app/src/main/res/xml/pref_general.xml +++ b/app/src/main/res/xml/pref_general.xml @@ -121,12 +121,6 @@ android:entryValues="@array/settings_printer_model_value" android:defaultValue="1" /> - - - - - - diff --git a/build.gradle b/build.gradle index 2472675..235a161 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.2' + classpath 'com.android.tools.build:gradle:3.6.3' // NOTE: Do not place your application dependencies here; they belong