From 05e9e448b506d5ec474205f6663b2419c74f5ec3 Mon Sep 17 00:00:00 2001 From: dgis Date: Fri, 7 Dec 2018 22:57:35 +0000 Subject: [PATCH] Migrate to androidx. Add Drawer and Settings UIs. --- ReadMe.txt | 21 ++ app/build.gradle | 8 +- app/src/main/AndroidManifest.xml | 20 ++ app/src/main/cpp/pch.h | 2 +- app/src/main/cpp/win32-layer.c | 10 +- .../emu48/AppCompatPreferenceActivity.java | 110 ++++++++++ .../com/regis/cosnier/emu48/MainActivity.java | 69 +++++- .../regis/cosnier/emu48/MainScreenView.java | 50 ++--- .../com/regis/cosnier/emu48/NativeLib.java | 2 +- .../cosnier/emu48/SeekBarPreference.java | 167 ++++++++++++++ .../regis/cosnier/emu48/SettingsActivity.java | 203 ++++++++++++++++++ app/src/main/res/drawable/ic_menu_camera.xml | 12 ++ app/src/main/res/drawable/ic_menu_gallery.xml | 9 + app/src/main/res/drawable/ic_menu_manage.xml | 9 + app/src/main/res/drawable/ic_menu_send.xml | 9 + app/src/main/res/drawable/ic_menu_share.xml | 9 + .../main/res/drawable/ic_menu_slideshow.xml | 9 + app/src/main/res/drawable/side_nav_bar.xml | 9 + app/src/main/res/layout/activity_main.xml | 40 ++-- app/src/main/res/layout/app_bar_main.xml | 34 +++ app/src/main/res/layout/content_main.xml | 4 +- app/src/main/res/layout/nav_header_main.xml | 36 ++++ .../main/res/menu/activity_main_drawer.xml | 38 ++++ app/src/main/res/values/attrs.xml | 13 ++ app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 6 + app/src/main/res/xml/pref_general.xml | 95 ++++++++ app/src/main/res/xml/provider_paths.xml | 4 + gradle.properties | 2 + 29 files changed, 928 insertions(+), 77 deletions(-) create mode 100644 ReadMe.txt create mode 100644 app/src/main/java/com/regis/cosnier/emu48/AppCompatPreferenceActivity.java create mode 100644 app/src/main/java/com/regis/cosnier/emu48/SeekBarPreference.java create mode 100644 app/src/main/java/com/regis/cosnier/emu48/SettingsActivity.java create mode 100644 app/src/main/res/drawable/ic_menu_camera.xml create mode 100644 app/src/main/res/drawable/ic_menu_gallery.xml create mode 100644 app/src/main/res/drawable/ic_menu_manage.xml create mode 100644 app/src/main/res/drawable/ic_menu_send.xml create mode 100644 app/src/main/res/drawable/ic_menu_share.xml create mode 100644 app/src/main/res/drawable/ic_menu_slideshow.xml create mode 100644 app/src/main/res/drawable/side_nav_bar.xml create mode 100644 app/src/main/res/layout/app_bar_main.xml create mode 100644 app/src/main/res/layout/nav_header_main.xml create mode 100644 app/src/main/res/menu/activity_main_drawer.xml create mode 100644 app/src/main/res/values/attrs.xml create mode 100644 app/src/main/res/xml/pref_general.xml create mode 100644 app/src/main/res/xml/provider_paths.xml diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..9e8f6aa --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,21 @@ +ABOUT +This project ports the Windows application Emu48 written in C to Android. +It uses the Android NDK. The former Emu48 source code remains untouch because a thin win32 emulation layer above Linux/NDK! +This win32 layer will allow to update easily from the original source code. + +NOT WORKING +- Sound +- Disassembler +- Debugger +- Macro +- Infrared Printer +- Serial Ports (Wire or Ir) + +TODO +- Bitmap corruption when touching the buttons +- Android UI Settings +- Sound + +DONE +- Bug Red and Blue seems inverted. +- Multitouch diff --git a/app/build.gradle b/app/build.gradle index c1709b6..7ccb2de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" @@ -30,9 +30,9 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support.constraint:constraint-layout:1.1.3' - implementation 'com.android.support:design:28.0.0' + implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' + implementation 'com.google.android.material:material:1.1.0-alpha01' // testImplementation 'junit:junit:4.12' // androidTestImplementation 'com.android.support.test:runner:1.0.2' // androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bb97248..6bff32e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,10 +10,12 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" + android:resizeableActivity="true" android:theme="@style/AppTheme"> @@ -21,6 +23,24 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/cpp/pch.h b/app/src/main/cpp/pch.h index c613914..32a0944 100644 --- a/app/src/main/cpp/pch.h +++ b/app/src/main/cpp/pch.h @@ -2,7 +2,7 @@ // PCH.H // -#define DEBUG_DISPLAY 1 +//#define DEBUG_DISPLAY 1 #define _WIN32_IE 0x0200 #define _CRT_SECURE_NO_DEPRECATE diff --git a/app/src/main/cpp/win32-layer.c b/app/src/main/cpp/win32-layer.c index 8157133..ed955fb 100644 --- a/app/src/main/cpp/win32-layer.c +++ b/app/src/main/cpp/win32-layer.c @@ -821,8 +821,6 @@ BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdc int destinationHeight = androidBitmapInfo.height; //https://softwareengineering.stackexchange.com/questions/148123/what-is-the-algorithm-to-copy-a-region-of-one-bitmap-into-a-region-in-another -// float src_dx = wDest / wSrc; -// float src_dy = hDest / hSrc; float src_dx = (float)wSrc / (float)wDest; float src_dy = (float)hSrc / (float)hDest; float src_maxx = xSrc + wSrc; @@ -855,9 +853,9 @@ BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdc case 1: if(palPalEntry) { BYTE colorIndex = sourcePixel[0]; - destinationPixel[0] = palPalEntry[colorIndex].peRed; + destinationPixel[0] = palPalEntry[colorIndex].peBlue; destinationPixel[1] = palPalEntry[colorIndex].peGreen; - destinationPixel[2] = palPalEntry[colorIndex].peBlue; + destinationPixel[2] = palPalEntry[colorIndex].peRed; destinationPixel[3] = 255; } else { destinationPixel[0] = sourcePixel[0]; @@ -867,9 +865,9 @@ BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdc } break; case 3: - destinationPixel[0] = sourcePixel[0]; + destinationPixel[0] = sourcePixel[2]; destinationPixel[1] = sourcePixel[1]; - destinationPixel[2] = sourcePixel[2]; + destinationPixel[2] = sourcePixel[0]; destinationPixel[3] = 255; break; case 4: diff --git a/app/src/main/java/com/regis/cosnier/emu48/AppCompatPreferenceActivity.java b/app/src/main/java/com/regis/cosnier/emu48/AppCompatPreferenceActivity.java new file mode 100644 index 0000000..e997e3f --- /dev/null +++ b/app/src/main/java/com/regis/cosnier/emu48/AppCompatPreferenceActivity.java @@ -0,0 +1,110 @@ +package com.regis.cosnier.emu48; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.PreferenceActivity; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.Toolbar; + +/** + * A {@link PreferenceActivity} which implements and proxies the necessary calls + * to be used with AppCompat. + */ +public abstract class AppCompatPreferenceActivity extends PreferenceActivity { + + private AppCompatDelegate mDelegate; + + @Override + protected void onCreate(Bundle savedInstanceState) { + getDelegate().installViewFactory(); + getDelegate().onCreate(savedInstanceState); + super.onCreate(savedInstanceState); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + getDelegate().onPostCreate(savedInstanceState); + } + + public ActionBar getSupportActionBar() { + return getDelegate().getSupportActionBar(); + } + + public void setSupportActionBar(@Nullable Toolbar toolbar) { + getDelegate().setSupportActionBar(toolbar); + } + + @Override + public MenuInflater getMenuInflater() { + return getDelegate().getMenuInflater(); + } + + @Override + public void setContentView(@LayoutRes int layoutResID) { + getDelegate().setContentView(layoutResID); + } + + @Override + public void setContentView(View view) { + getDelegate().setContentView(view); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + getDelegate().setContentView(view, params); + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + getDelegate().addContentView(view, params); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getDelegate().onPostResume(); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + super.onTitleChanged(title, color); + getDelegate().setTitle(title); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getDelegate().onConfigurationChanged(newConfig); + } + + @Override + protected void onStop() { + super.onStop(); + getDelegate().onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + getDelegate().onDestroy(); + } + + public void invalidateOptionsMenu() { + getDelegate().invalidateOptionsMenu(); + } + + private AppCompatDelegate getDelegate() { + if (mDelegate == null) { + mDelegate = AppCompatDelegate.create(this, null); + } + return mDelegate; + } +} diff --git a/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java b/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java index 5b0b9cf..d258210 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java +++ b/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java @@ -1,20 +1,26 @@ package com.regis.cosnier.emu48; -import android.content.res.AssetManager; -import android.graphics.Bitmap; +import android.content.Intent; import android.os.Bundle; -import android.util.DisplayMetrics; import android.view.ViewGroup; -import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.navigation.NavigationView; +import com.google.android.material.snackbar.Snackbar; + +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; + import android.view.View; import android.view.Menu; import android.view.MenuItem; -public class MainActivity extends AppCompatActivity { +public class MainActivity extends AppCompatActivity + implements NavigationView.OnNavigationItemSelectedListener { + private static final int INTENT_SETTINGS = 1; private MainScreenView mainScreenView; @Override @@ -33,11 +39,32 @@ public class MainActivity extends AppCompatActivity { } }); + DrawerLayout drawer = (DrawerLayout) 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 navigationView = (NavigationView) findViewById(R.id.nav_view); + navigationView.setNavigationItemSelectedListener(this); + + + mainScreenView = new MainScreenView(this); //, currentProject); ViewGroup mainScreenContainer = (ViewGroup)findViewById(R.id.main_screen_container); mainScreenContainer.addView(mainScreenView, 0); } + @Override + public void onBackPressed() { + DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); + if (drawer.isDrawerOpen(GravityCompat.START)) { + drawer.closeDrawer(GravityCompat.START); + } else { + super.onBackPressed(); + } + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. @@ -54,12 +81,38 @@ public class MainActivity extends AppCompatActivity { //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { + startActivityForResult(new Intent(this, SettingsActivity.class), INTENT_SETTINGS); return true; } return super.onOptionsItemSelected(item); } + @SuppressWarnings("StatementWithEmptyBody") + @Override + public boolean onNavigationItemSelected(MenuItem item) { + // Handle navigation view item clicks here. + int id = item.getItemId(); + + if (id == R.id.nav_camera) { + // Handle the camera action + } else if (id == R.id.nav_gallery) { + + } else if (id == R.id.nav_slideshow) { + + } else if (id == R.id.nav_manage) { + + } else if (id == R.id.nav_share) { + + } else if (id == R.id.nav_send) { + + } + + DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); + drawer.closeDrawer(GravityCompat.START); + return true; + } + @Override protected void onDestroy() { diff --git a/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java b/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java index 065edda..d7917b2 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java +++ b/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java @@ -7,22 +7,15 @@ import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.support.v4.view.ViewCompat; + +import androidx.core.view.ViewCompat; import android.util.DisplayMetrics; import android.util.Log; -import android.view.GestureDetector; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; import android.view.SurfaceView; -import android.view.View; -import android.widget.OverScroller; import java.util.HashMap; -import java.util.Map; public class MainScreenView extends SurfaceView { @@ -140,33 +133,29 @@ public class MainScreenView extends SurfaceView { @SuppressLint("ClickableViewAccessibility") public boolean onTouchEvent(MotionEvent event) { - // Let the ScaleGestureDetector inspect all events. -// boolean retValScaleDetector = mScaleDetector.onTouchEvent(event); -// boolean retValGestureDetector = mGestureDetector.onTouchEvent(event); - boolean retVal = false; //retValGestureDetector || retValScaleDetector; - int touchCount = event.getPointerCount(); - if(touchCount == 1) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: - //Log.d(TAG, "ACTION_DOWN count: " + touchCount + ", PanPrevious: " + mPanPrevious.toString()); - NativeLib.buttonDown((int)((event.getX(0) - screenOffsetX) / screenScale), (int)((event.getY(0) - screenOffsetY) / screenScale)); - break; + int actionIndex = event.getActionIndex(); + int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + //Log.d(TAG, "ACTION_DOWN/ACTION_POINTER_DOWN count: " + touchCount + ", actionIndex: " + actionIndex); + NativeLib.buttonDown((int)((event.getX(actionIndex) - screenOffsetX) / screenScale), (int)((event.getY(actionIndex) - screenOffsetY) / screenScale)); + break; // case MotionEvent.ACTION_MOVE: // break; - case MotionEvent.ACTION_UP: - NativeLib.buttonUp((int)((event.getX(0) - screenOffsetX) / screenScale), (int)((event.getY(0) - screenOffsetY) / screenScale)); - break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + //Log.d(TAG, "ACTION_UP/ACTION_POINTER_UP count: " + touchCount + ", actionIndex: " + actionIndex); + NativeLib.buttonUp((int)((event.getX(actionIndex) - screenOffsetX) / screenScale), (int)((event.getY(actionIndex) - screenOffsetY) / screenScale)); + break; // case MotionEvent.ACTION_CANCEL: // break; // case MotionEvent.ACTION_OUTSIDE: // break; - default: - } - return true; + default: } - return retVal || super.onTouchEvent(event); + return true; } // @Override @@ -216,7 +205,7 @@ public class MainScreenView extends SurfaceView { float imageSizeY = bitmapMainScreen.getHeight(); if(imageSizeX > 0 && imageSizeY > 0 && viewWidth > 0.0f && viewHeight > 0.0f) { - // Find the scale factor and the translate offset to fit and to center the vectors in the view bounds. + // Find the scale factor and the translate offset to fit and to center the image in the view bounds. float translateX, translateY, scale; float viewRatio = (float)viewHeight / (float)viewWidth; float imageRatio = imageSizeY / imageSizeX; @@ -235,13 +224,12 @@ public class MainScreenView extends SurfaceView { screenOffsetY = translateY; } - NativeLib.resize(viewWidth, viewHeight); + //NativeLib.resize(viewWidth, viewHeight); } @Override protected void onDraw(Canvas canvas) { //Log.d(TAG, "onDraw() mIsScaling: " + mIsScaling + ", mIsPanning: " + mIsPanning + ", mIsFlinging: " + mIsFlinging); - //NativeLib.draw(); canvas.save(); canvas.translate(screenOffsetX, screenOffsetY); canvas.scale(screenScale, screenScale); diff --git a/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java b/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java index 2571cd1..45b058a 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java +++ b/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java @@ -12,7 +12,7 @@ public class NativeLib { public static native void start(AssetManager mgr, Bitmap bitmapMainScreen, MainScreenView view); public static native void stop(); - public static native void resize(int width, int height); + //public static native void resize(int width, int height); public static native void draw(); public static native void buttonDown(int x, int y); public static native void buttonUp(int x, int y); diff --git a/app/src/main/java/com/regis/cosnier/emu48/SeekBarPreference.java b/app/src/main/java/com/regis/cosnier/emu48/SeekBarPreference.java new file mode 100644 index 0000000..6ab5ab0 --- /dev/null +++ b/app/src/main/java/com/regis/cosnier/emu48/SeekBarPreference.java @@ -0,0 +1,167 @@ +package com.regis.cosnier.emu48; + +import android.content.Context; +import android.content.DialogInterface; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener +{ + private static final String androidns="http://schemas.android.com/apk/res/android"; + private static final String appdns="http://schemas.android.com/apk/res-auto"; + + private SeekBar mSeekBar; + private TextView mSplashText,mValueText; + private Context mContext; + + private String mDialogMessage, mSuffix, mSuffixes; + private int mDefault, mMin, mMax, mValue = 0; + private float mDisplayScale = 1.0f; + private String mDisplayFormat; + + public SeekBarPreference(Context context, AttributeSet attrs) { + super(context,attrs); + mContext = context; + + mDialogMessage = getAttributeValue(attrs, androidns, "dialogMessage"); + mValue = mDefault = attrs.getAttributeIntValue(androidns, "defaultValue", 0); + mDisplayScale = attrs.getAttributeFloatValue(appdns, "displayScale", 1.0f); + mSuffix = getAttributeValue(attrs, appdns, "suffix"); + mSuffixes = getAttributeValue(attrs, appdns, "suffixes"); + mDisplayFormat = attrs.getAttributeValue(appdns, "displayFormat"); + mMin = attrs.getAttributeIntValue(appdns, "min", 0); + mMax = attrs.getAttributeIntValue(androidns, "max", 100); + } + + private String getAttributeValue(AttributeSet attrs, String namespace, String name) { + String attributeValue = attrs.getAttributeValue(namespace, name); + String result = attributeValue; + if(attributeValue != null && attributeValue.length() > 1 && attributeValue.charAt(0) == '@') { + try { + int id = Integer.parseInt(attributeValue.substring(1)); + result = mContext.getString(id); + } catch (NumberFormatException e) {} + } + return result; + } + + @Override + protected View onCreateDialogView() { + LinearLayout layout = new LinearLayout(mContext); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(6, 6, 6, 6); + + mSplashText = new TextView(mContext); + if (mDialogMessage != null) + mSplashText.setText(mDialogMessage); + layout.addView(mSplashText); + + mValueText = new TextView(mContext); + mValueText.setGravity(Gravity.CENTER_HORIZONTAL); + mValueText.setTextSize(32); + layout.addView(mValueText, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + mSeekBar = new SeekBar(mContext); + mSeekBar.setOnSeekBarChangeListener(this); + layout.addView(mSeekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + if (shouldPersist()) + mValue = getPersistedInt(mDefault); + + mSeekBar.setMax(mMax - mMin); + mSeekBar.setProgress(mValue - mMin); + return layout; + } + @Override + protected void onBindDialogView(View v) { + super.onBindDialogView(v); + mSeekBar.setMax(mMax - mMin); + mSeekBar.setProgress(mValue - mMin); + } + @Override + protected void onSetInitialValue(boolean restore, Object defaultValue) + { + super.onSetInitialValue(restore, defaultValue); + if (restore) + mValue = shouldPersist() ? getPersistedInt(mDefault) : 0; + else + mValue = (Integer)defaultValue; + } + + public void setValueSummary() + { + setSummary(getValueSummary()); + } + + public String getValueSummary() + { + return getValueSummary(mValue); + } + + public String getValueSummary(int value) + { + String textValue; + if(mDisplayFormat != null) + textValue = String.format(mDisplayFormat, value * mDisplayScale); + else if(mDisplayScale != 1.0f) + textValue = String.valueOf(value * mDisplayScale); + else + textValue = String.valueOf(value); + + if(value * mDisplayScale > 1.0f) { + if(mSuffixes != null) + textValue += " " + mSuffixes; + else if(mSuffix != null) + textValue += " " + mSuffix; + } else if(mSuffix != null) + textValue += " " + mSuffix; + + return textValue; + } + + public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) + { + int theValue = mMin + value; + String textValue = getValueSummary(theValue); + mValueText.setText(textValue); + + if (shouldPersist()) + persistInt(theValue); + + //mValue = theValue; + //callChangeListener(Integer.valueOf(mMin + value)); + } + public void onStartTrackingTouch(SeekBar seek) {} + public void onStopTrackingTouch(SeekBar seek) {} + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + // save your new password here + mValue = mMin + mSeekBar.getProgress(); + callChangeListener(Integer.valueOf(mValue)); + break; + default: + // do something else... + break; + } + } + + public void setMin(int min) { mMin = min; } + public int getMin() { return mMin; } + public void setMax(int max) { mMax = max; } + public int getMax() { return mMax; } + + public void setProgress(int progress) { + mValue = progress; + if (mSeekBar != null) + mSeekBar.setProgress(progress - mMin); + } + public int getProgress() { return mValue; } +} diff --git a/app/src/main/java/com/regis/cosnier/emu48/SettingsActivity.java b/app/src/main/java/com/regis/cosnier/emu48/SettingsActivity.java new file mode 100644 index 0000000..8b40742 --- /dev/null +++ b/app/src/main/java/com/regis/cosnier/emu48/SettingsActivity.java @@ -0,0 +1,203 @@ +package com.regis.cosnier.emu48; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +import android.view.MenuItem; + +import androidx.appcompat.app.ActionBar; +import androidx.core.app.NavUtils; + +/** + * A {@link PreferenceActivity} that presents a set of application settings. On + * handset devices, settings are presented as a single list. On tablets, + * settings are split by category, with category headers shown to the left of + * the list of settings. + *

+ * See + * Android Design: Settings for design guidelines and the Settings + * API Guide for more information on developing a Settings UI. + */ +public class SettingsActivity extends AppCompatPreferenceActivity { + + /** + * A preference value change listener that updates the preference's summary + * to reflect its new value. + */ + private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + String stringValue = value.toString(); + + if (preference instanceof ListPreference) { + // For list preferences, look up the correct display value in + // the preference's 'entries' list. + ListPreference listPreference = (ListPreference) preference; + int index = listPreference.findIndexOfValue(stringValue); + + // Set the summary to reflect the new value. + preference.setSummary( + index >= 0 + ? listPreference.getEntries()[index] + : null); + + } else { + // For all other preferences, set the summary to the value's + // simple string representation. + preference.setSummary(stringValue); + } + return true; + } + }; + + /** + * Helper method to determine if the device has an extra-large screen. For + * example, 10" tablets are extra-large. + */ + private static boolean isXLargeTablet(Context context) { + return (context.getResources().getConfiguration().screenLayout + & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; + } + + /** + * Binds a preference's summary to its value. More specifically, when the + * preference's value is changed, its summary (line of text below the + * preference title) is updated to reflect the value. The summary is also + * immediately updated upon calling this method. The exact display format is + * dependent on the type of preference. + * + * @see #sBindPreferenceSummaryToValueListener + */ + private static void bindPreferenceSummaryToStringValue(Preference preference) { + // Set the listener to watch for value changes. + preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(preference.getContext()); + + // Trigger the listener immediately with the preference's + // current value. + sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, sharedPreferences.getString(preference.getKey(), "")); + } + + /** + * Binds a preference's summary to its value. More specifically, when the + * preference's value is changed, its summary (line of text below the + * preference title) is updated to reflect the value. The summary is also + * immediately updated upon calling this method. The exact display format is + * dependent on the type of preference. + * + * @see #sBindPreferenceSummaryToValueListener + */ + private static void bindPreferenceSummaryToIntValue(Preference preference) { + // Set the listener to watch for value changes. + preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(preference.getContext()); + + // Trigger the listener immediately with the preference's + // current value. + sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, sharedPreferences.getInt(preference.getKey(), 0)); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + // Show the Up button in the action bar. + actionBar.setDisplayHomeAsUpEnabled(true); + } + + getFragmentManager().beginTransaction().replace(android.R.id.content, new GeneralPreferenceFragment()).commit(); + + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + if (!super.onMenuItemSelected(featureId, item)) { + NavUtils.navigateUpFromSameTask(this); + } + return true; + } + return super.onMenuItemSelected(featureId, item); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean onIsMultiPane() { + return isXLargeTablet(this); + } + +// /** +// * {@inheritDoc} +// */ +// @Override +// @TargetApi(Build.VERSION_CODES.HONEYCOMB) +// public void onBuildHeaders(List

target) { +// loadHeadersFromResource(R.xml.pref_headers, target); +// } + + /** + * This method stops fragment injection in malicious applications. + * Make sure to deny any unknown fragments here. + */ + protected boolean isValidFragment(String fragmentName) { + return PreferenceFragment.class.getName().equals(fragmentName) + || GeneralPreferenceFragment.class.getName().equals(fragmentName) +// || DataSyncPreferenceFragment.class.getName().equals(fragmentName) +// || NotificationPreferenceFragment.class.getName().equals(fragmentName) + ; + } + + /** + * This fragment shows general preferences only. It is used when the + * activity is showing a two-pane settings UI. + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class GeneralPreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.pref_general); + setHasOptionsMenu(true); + + // Bind the summaries of EditText/List/Dialog/Ringtone preferences + // to their values. When their values change, their summaries are + // updated to reflect the new value, per the Android Design + // guidelines. +// bindPreferenceSummaryToStringValue(findPreference("settings_input")); +// bindPreferenceSummaryToIntValue(findPreference("settings_audio_input")); +// bindPreferenceSummaryToStringValue(findPreference("settings_sample_rate")); +// bindPreferenceSummaryToStringValue(findPreference("settings_fft_size")); +// bindPreferenceSummaryToIntValue(findPreference("settings_volume_scale")); + bindPreferenceSummaryToIntValue(findPreference("settings_tempo")); +// bindPreferenceSummaryToIntValue(findPreference("settings_intensity_minimum")); +// bindPreferenceSummaryToIntValue(findPreference("settings_translation")); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + startActivity(new Intent(getActivity(), SettingsActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + } +} diff --git a/app/src/main/res/drawable/ic_menu_camera.xml b/app/src/main/res/drawable/ic_menu_camera.xml new file mode 100644 index 0000000..634fe92 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_camera.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_menu_gallery.xml b/app/src/main/res/drawable/ic_menu_gallery.xml new file mode 100644 index 0000000..03c7709 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_gallery.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_manage.xml b/app/src/main/res/drawable/ic_menu_manage.xml new file mode 100644 index 0000000..aeb047d --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_manage.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_menu_send.xml b/app/src/main/res/drawable/ic_menu_send.xml new file mode 100644 index 0000000..fdf1c90 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_send.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_share.xml b/app/src/main/res/drawable/ic_menu_share.xml new file mode 100644 index 0000000..338d95a --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_slideshow.xml b/app/src/main/res/drawable/ic_menu_slideshow.xml new file mode 100644 index 0000000..5e9e163 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_slideshow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml new file mode 100644 index 0000000..6d81870 --- /dev/null +++ b/app/src/main/res/drawable/side_nav_bar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c59318f..fd5480f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,34 +1,26 @@ - + tools:context=".MainActivity" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + android:layout_height="match_parent" /> - - - - - - - + android:layout_height="match_parent" + android:layout_gravity="start" + android:fitsSystemWindows="true" + app:headerLayout="@layout/nav_header_main" + app:menu="@menu/activity_main_drawer" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml new file mode 100644 index 0000000..2aa1a4f --- /dev/null +++ b/app/src/main/res/layout/app_bar_main.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index e389dcc..196c71a 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml new file mode 100644 index 0000000..c8943ea --- /dev/null +++ b/app/src/main/res/layout/nav_header_main.xml @@ -0,0 +1,36 @@ + + + + + + + + + + diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml new file mode 100644 index 0000000..27db2c0 --- /dev/null +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..b83c366 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 2c00107..d1da4b2 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,3 +1,8 @@ + + 16dp + 16dp + 8dp + 176dp 16dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 61d234e..762c11d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,10 @@ Emu48 + Open navigation drawer + Close navigation drawer + Android Studio + android.studio@android.com + Navigation header Settings + Settings diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml new file mode 100644 index 0000000..552dace --- /dev/null +++ b/app/src/main/res/xml/pref_general.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000..74a5cde --- /dev/null +++ b/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 9f85f38..461e8f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,6 +6,8 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. +android.enableJetifier=true +android.useAndroidX=true org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit