diff --git a/_Build_/AndroidStudio/app/build.gradle b/_Build_/AndroidStudio/app/build.gradle index 6490c3f34..786e0ea1d 100644 --- a/_Build_/AndroidStudio/app/build.gradle +++ b/_Build_/AndroidStudio/app/build.gradle @@ -6,7 +6,7 @@ android { defaultConfig { applicationId "com.newtonforever.einstein" minSdkVersion 15 - targetSdkVersion 22 + targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -18,7 +18,6 @@ android { } } ndk { - // abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a' abiFilters 'x86', 'armeabi-v7a' } @@ -34,9 +33,13 @@ android { path "CMakeLists.txt" } } - lintOptions{ + lintOptions { disable 'MissingTranslation' } + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } } dependencies { diff --git a/_Build_/AndroidStudio/app/src/main/AndroidManifest.xml b/_Build_/AndroidStudio/app/src/main/AndroidManifest.xml index 93742b675..cadda4e28 100644 --- a/_Build_/AndroidStudio/app/src/main/AndroidManifest.xml +++ b/_Build_/AndroidStudio/app/src/main/AndroidManifest.xml @@ -26,7 +26,7 @@ android:label="@string/app_name" android:launchMode="singleTop" android:screenOrientation="portrait" - android:theme="@android:style/Theme.NoTitleBar"> + android:theme="@style/AppTheme"> @@ -36,7 +36,7 @@ android:name="com.newtonforever.einstein.activity.ActionsActivity" android:label="@string/app_name" android:launchMode="singleInstance" - android:theme="@android:style/Theme.Dialog"> + android:theme="@style/Theme.AppCompat.Dialog"> @@ -44,7 +44,7 @@ android:name="com.newtonforever.einstein.activity.LoadPackageActivity" android:label="@string/app_name" android:launchMode="singleInstance" - android:theme="@android:style/Theme.Dialog"> + android:theme="@style/Theme.AppCompat.Dialog"> @@ -146,6 +146,7 @@ diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/Einstein.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/Einstein.java index 6aa5a20ce..4c6daa49f 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/Einstein.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/Einstein.java @@ -2,26 +2,28 @@ import com.newtonforever.einstein.jni.Native; -/** Class interfacing to the native Einstein emulator. - * @author Matthias Melcher */ -public class Einstein -{ - /** Load the entire native program as a library at startup. */ - static { - System.loadLibrary("native-lib"); - } - - private boolean pRunning = false; +/** + * Class interfacing to the native Einstein emulator. + * + * @author Matthias Melcher + */ +public class Einstein { + /* Load the entire native program as a library at startup. */ + static { + System.loadLibrary("native-lib"); + } - public void run(String dataPath, int screenWidth, int screenHeight) - { - Native.runEmulator(dataPath, screenWidth, screenHeight); - this.pRunning = true; - } - - /** Returns true if the emulator is currently running. */ - public boolean isRunning() - { - return this.pRunning; - } + private boolean isRunning = false; + + public void run(String dataPath, int screenWidth, int screenHeight) { + Native.runEmulator(dataPath, screenWidth, screenHeight); + isRunning = true; + } + + /** + * Returns true if the emulator is currently running. + */ + public boolean isRunning() { + return isRunning; + } } \ No newline at end of file diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinApplication.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinApplication.java index bbb7b156f..782b2d6b5 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinApplication.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinApplication.java @@ -82,69 +82,64 @@ - interface to Android API /** * This class provides resources that must be available for the lifetime of this app. - * - * @author Matthias Melcher * + * @author Matthias Melcher */ public class EinsteinApplication extends Application { - private Einstein pEinstein = null; - - /** - * Get a link to the native emulator interface. - * - * @return access to the emulator - */ - public Einstein getEinstein() - { - return pEinstein; - } - - /** - * Initialize what we need besides the Activity. - * - * Create the Einstein instance that is shared across Activities. - * Create a Service that will keep this app in the foreground as - * long as possible to avoid lengty emulator reboots. - */ - @Override - public void onCreate() - { - //Log.i("einstein", "--------> App.onCreate()"); - - super.onCreate(); - - // create and load the Emulator - pEinstein = new Einstein(); - - // create the keep-alive Service (will be created asynchronously) - Intent intent = new Intent(getApplicationContext(), EinsteinService.class); - intent.putExtra("task", EinsteinService.TASK_LAUNCH); - ComponentName name = startService(intent); - if (name==null) { - Log.i("einstein", "--------< App.onCreate() - CANT LAUNCH SERVICE"); - } - //Log.i("einstein", "--------< App.onCreate()"); - } - - /** - * Use the Service to keep this application around as long as possible. - */ - public void raisePriority() - { - Intent intent = new Intent(getApplicationContext(), EinsteinService.class); + private Einstein pEinstein = null; + + /** + * Get a link to the native emulator interface. + * + * @return access to the emulator + */ + public Einstein getEinstein() { + return pEinstein; + } + + /** + * Initialize what we need besides the Activity. + *

+ * Create the Einstein instance that is shared across Activities. + * Create a Service that will keep this app in the foreground as + * long as possible to avoid lengty emulator reboots. + */ + @Override + public void onCreate() { + //Log.i("einstein", "--------> App.onCreate()"); + + super.onCreate(); + + // create and load the Emulator + pEinstein = new Einstein(); + + // create the keep-alive Service (will be created asynchronously) + Intent intent = new Intent(getApplicationContext(), EinsteinService.class); + intent.putExtra("task", EinsteinService.TASK_LAUNCH); + ComponentName name = startService(intent); + if (name == null) { + Log.i("einstein", "--------< App.onCreate() - CANT LAUNCH SERVICE"); + } + //Log.i("einstein", "--------< App.onCreate()"); + } + + /** + * Use the Service to keep this application around as long as possible. + */ + public void raisePriority() { + Intent intent = new Intent(getApplicationContext(), EinsteinService.class); intent.putExtra("task", EinsteinService.TASK_RAISE_PRIORITY); - startService(intent); - } - - /** - * Return this app to normal priority by sending the service to the background. - */ - public void normalPriority() - { - Intent intent = new Intent(getApplicationContext(), EinsteinService.class); + startService(intent); + } + + /** + * Return this app to normal priority by sending the service to the background. + */ + public void normalPriority() { + Intent intent = new Intent(getApplicationContext(), EinsteinService.class); intent.putExtra("task", EinsteinService.TASK_NORMAL_PRIORITY); - startService(intent); - } + startService(intent); + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinService.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinService.java index 80206f2fc..ce6b434a9 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinService.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/EinsteinService.java @@ -2,117 +2,114 @@ package com.newtonforever.einstein; -import com.newtonforever.einstein.R; - -import com.newtonforever.einstein.activity.ActionsActivity; -import com.newtonforever.einstein.activity.EinsteinActivity; - import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import android.util.Log; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; +import android.util.Log; + +import com.newtonforever.einstein.activity.ActionsActivity; +import com.newtonforever.einstein.activity.EinsteinActivity; /** * A service that keeps the emulator alive in the background. - * + *

* It is impossible to store the state of the emulator when using native code. Android * however loves to destroy activities or apps whenever it needs resources, which * causes Einstein to go into a lengthy reboot of the MessagePad at the next start. - * + *

* This service makes sure that the emulator is not destroyed unless absolutely necessary. * An indicator in the task bar shows the user that Einstein is still available. - * + * * @todo This service should check if the MessagePad awoke due to an alarm and create - * a new Activity in case we are currently in the background. - * + * a new Activity in case we are currently in the background. * @todo Choosing "Quit" from the "Extras" [i] menu on the MP should quit the service. */ public class EinsteinService extends Service { - - public static final int TASK_LAUNCH = 0; - public static final int TASK_RAISE_PRIORITY = 1; - public static final int TASK_NORMAL_PRIORITY = 2; - - private static final String TAG = EinsteinService.class.getSimpleName(); - - public class LocalBinder extends Binder { + + public static final int TASK_LAUNCH = 0; + public static final int TASK_RAISE_PRIORITY = 1; + public static final int TASK_NORMAL_PRIORITY = 2; + + private static final String TAG = EinsteinService.class.getSimpleName(); + + public class LocalBinder extends Binder { } - - private final IBinder mBinder = new LocalBinder(); - - private NotificationManager mNM; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - @Override - public void onCreate() { - Log.i(TAG, "Einstein Service created."); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) - { - //Log.e(TAG, "SERVICE: Intent " + intent.getIntExtra("task", -1)); - - switch (intent.getIntExtra("task", -1)) { - case TASK_NORMAL_PRIORITY: - normalPriority(); - break; - case TASK_RAISE_PRIORITY: - raisePriority(); - break; - } - - // We want this service to continue running until it is explicitly - // stopped, so return sticky. - return START_STICKY; - } - - @Override - public void onDestroy() { - normalPriority(); - super.onDestroy(); - Log.i(TAG, "Service destroyed"); - } - - public void raisePriority() - { - mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); -// TODO: deprecated mBuilder.setSmallIcon(R.drawable.ic_stat_einstein); - mBuilder.setContentTitle("Einstein NewtonOS Emulator"); - mBuilder.setContentText("Options and Settings"); - - // Creates an explicit intent for an Activity in your app - Intent resultIntent = new Intent(this, ActionsActivity.class); - - // The stack builder object will contain an artificial back stack for the started Activity. - // The intention is that leaving the ActionActivity will go to the EinsteinActivity - TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); - // Adds the back stack for the Intent (but not the Intent itself) - stackBuilder.addParentStack(EinsteinActivity.class); - // Adds the Intent that starts the Activity to the top of the stack - stackBuilder.addNextIntent(resultIntent); - PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); - mBuilder.setContentIntent(resultPendingIntent); - - this.startForeground(0x4e256cc5, mBuilder.build()); + + private final IBinder mBinder = new LocalBinder(); + + private NotificationManager mNM; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; } - - public void normalPriority() - { - mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - mNM.cancel(0x4e256cc5); - this.stopForeground(true); + + @Override + public void onCreate() { + Log.i(TAG, "Einstein Service created."); } - + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + //Log.e(TAG, "SERVICE: Intent " + intent.getIntExtra("task", -1)); + + switch (intent.getIntExtra("task", -1)) { + case TASK_NORMAL_PRIORITY: + normalPriority(); + break; + case TASK_RAISE_PRIORITY: + raisePriority(); + break; + } + + // We want this service to continue running until it is explicitly + // stopped, so return sticky. + return START_STICKY; + } + + @Override + public void onDestroy() { + normalPriority(); + super.onDestroy(); + Log.i(TAG, "Service destroyed"); + } + + public void raisePriority() { + mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); + + mBuilder.setSmallIcon(R.drawable.ic_stat_einstein); + + mBuilder.setContentTitle("Einstein NewtonOS Emulator"); + mBuilder.setContentText("Options and Settings"); + + // Creates an explicit intent for an Activity in your app + Intent resultIntent = new Intent(this, ActionsActivity.class); + + // The stack builder object will contain an artificial back stack for the started Activity. + // The intention is that leaving the ActionActivity will go to the EinsteinActivity + TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(EinsteinActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); + mBuilder.setContentIntent(resultPendingIntent); + + startForeground(0x4e256cc5, mBuilder.build()); + } + + public void normalPriority() { + mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + mNM.cancel(0x4e256cc5); + stopForeground(true); + } + } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/action/EinsteinActionHandler.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/action/EinsteinActionHandler.java index a5fb3be2c..2f372ac4e 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/action/EinsteinActionHandler.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/action/EinsteinActionHandler.java @@ -1,20 +1,16 @@ package com.newtonforever.einstein.action; -import java.util.TimerTask; - -import android.media.AudioFormat; -import android.media.AudioManager; -import android.media.AudioTrack; -import android.media.ToneGenerator; - import com.newtonforever.einstein.jni.Native; import com.newtonforever.einstein.sound.SoundManager; -import com.newtonforever.einstein.startup.StartupConstants; -import com.newtonforever.einstein.utils.debug.DebugUtils; import com.newtonforever.einstein.view.EinsteinView; -/** Polls the C side and handles actions that the C side wants us to do. @author Frank Gruendel. */ -/** Currently our run method is called at every screen refresh request. This must urgently be changed. */ +import java.util.TimerTask; + +/** + * Polls the C side and handles actions that the C side wants us to do. @author Frank Gruendel. + * + * Currently our run method is called at every screen refresh request. This must urgently be changed. + */ // TODO FG 2013_10_19 Put sound issues into a separate Thread. */ public class EinsteinActionHandler extends TimerTask { @@ -34,16 +30,16 @@ public class EinsteinActionHandler extends TimerTask { private final int CHANGE_VOLUME_MASK = 0x08; /** Our Einstein view. */ - private final EinsteinView m_einsteinView; + private final EinsteinView einsteinView; /** The sound manager that takes care of all sound issues. */ - private final SoundManager m_soundManager = new SoundManager(); + private final SoundManager soundManager = new SoundManager(); /** A helper flag for logging a message the first time a screen refresh is requested. */ - private boolean m_screenRefreshStarted = false; + private boolean screenRefreshStarted = false; public EinsteinActionHandler(EinsteinView view) { - this.m_einsteinView = view; + einsteinView = view; } @Override @@ -54,54 +50,50 @@ public void run() { } // Note that multiple actions might be required if more than one bit is set in actionMask. // So don't even think of using else if here... - if (this.isPlaySound(actionMask)) { + if (isPlaySound(actionMask)) { // NewtonOS wants to start a sound or (if a sound is currently played) add more samples to the buffers. - DebugUtils.logGreen("EinsteinActionHandler: ", "Requesting sound output with " + actionMask); - this.m_soundManager.playSound(Native.getSoundBufferSize()); + soundManager.playSound(Native.getSoundBufferSize()); Native.soundBufferFinishedOrCanceled(); } - if (this.isStopSound(actionMask)) { + if (isStopSound(actionMask)) { // NewtonOS has stopped the current sound. This must be done before starting a new sound. - //DebugUtils.logGreen("EinsteinActionHandler: ", "Stopping sound output"); - this.m_soundManager.stopSound(); + soundManager.stopSound(); } - if (this.isVolumeChanged(actionMask)) { + if (isVolumeChanged(actionMask)) { // NewtonOS has changed the volume setting. Android must be notified. - this.m_soundManager.changeVolume(); + soundManager.changeVolume(); } - if (this.isScreenRefresh(actionMask)) { + if (isScreenRefresh(actionMask)) { // NewtonOS changed the Newton's screen content. Java must refresh the Android screen. - this.handleScreenRefresh(); + handleScreenRefresh(); } } /** Returns true if the bit for a screen refresh is set in mask */ private boolean isScreenRefresh(final int mask) { - return 0 != (mask & REFRESH_SCREEN_MASK); + return (mask & REFRESH_SCREEN_MASK) != 0; } /** Returns true if the bit for stopping the sound is set in mask */ private boolean isStopSound(final int mask) { - return 0 != (mask & STOP_SOUND_MASK); + return (mask & STOP_SOUND_MASK) != 0; } /** Returns true if the bit for starting or continuing a sound is set in mask */ private boolean isPlaySound(final int mask) { - return 0 != (mask & PLAY_SOUND_MASK); + return (mask & PLAY_SOUND_MASK) != 0; } /** Returns true if the bit for changing the volume is set in mask */ private boolean isVolumeChanged(final int mask) { - return 0 != (mask & CHANGE_VOLUME_MASK); + return (mask & CHANGE_VOLUME_MASK) != 0; } /** Refreshes the Android screen area inhabited by our Einstein view. */ private void handleScreenRefresh() { - if (!m_screenRefreshStarted) - { - //DebugUtils.logGreen("EinsteinActionHandler: ", "First time screen refresh"); - m_screenRefreshStarted = true; + if (!screenRefreshStarted) { + screenRefreshStarted = true; } - this.m_einsteinView.postInvalidate(); + einsteinView.postInvalidate(); } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/ActionsActivity.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/ActionsActivity.java index 399d169ab..7d6f70932 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/ActionsActivity.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/ActionsActivity.java @@ -1,100 +1,95 @@ -// TODO FG Review package com.newtonforever.einstein.activity; -import com.newtonforever.einstein.R; - import android.content.Intent; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; -import android.support.v4.content.IntentCompat; -import android.util.Log; -import android.view.KeyEvent; import android.view.View; import com.newtonforever.einstein.EinsteinApplication; -import com.newtonforever.einstein.dialog.DialogFragmentTags; +import com.newtonforever.einstein.R; import com.newtonforever.einstein.dialog.URLPickerFragment; import com.newtonforever.einstein.jni.Native; -import com.newtonforever.einstein.utils.debug.DebugUtils; -// Note that the names of the onClick methods must match those defined in actions.xml + public class ActionsActivity extends FragmentActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.actions); - } + private static final String URL_PICKER_FRAGMENT_TAG = "URL_PICKER"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.actions_activity); + + findViewById(R.id.toEmulatorAction) + .setOnClickListener(this::onClickToEmulator); + findViewById(R.id.installPackagesAction) + .setOnClickListener(this::onClickInstallPackages); + findViewById(R.id.openNewtonSiteAction) + .setOnClickListener(this::onClickOpenURL); + findViewById(R.id.insertNetworkCardAction) + .setOnClickListener(this::onClickInsertNetworkCard); + findViewById(R.id.backlightAction) + .setOnClickListener(this::onClickBacklight); + findViewById(R.id.preferencesAction) + .setOnClickListener(this::onClickPreferences); + findViewById(R.id.quitEinsteinAction) + .setOnClickListener(this::onClickQuit); + } + + private void backToEinstein() { + Intent intent = new Intent(this, EinsteinActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + startActivity(intent); + } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if ( keyCode == KeyEvent.KEYCODE_MENU ) { - super.finish(); - return true; - } - return super.onKeyDown(keyCode, event); - } + private void onClickToEmulator(View view) { + backToEinstein(); + } - public void backToEinstein(View v) { - Intent intent = new Intent(v.getContext(), EinsteinActivity.class); - // TODO FG Check if it is OK to use the class Intent with flags from the class IntentCompat. - // Since the flag wasn't available when the Intent class was written, it is difficult to - // believe that this will be able to do anything useful with this flag. - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - startActivity(intent); - } - - public void onClickToEmulator(View v) { - backToEinstein(v); - } + private void onClickInstallPackages(View view) { + Native.installNewPackages(); + } - public void onClickInstallPackages(View v) { - DebugUtils.appendLog("ActionsActivity.onClickInstallPackages: Installing new packages"); - Native.installNewPackages(); - backToEinstein(v); - } - public void onClickOpenURL(View v) { - DebugUtils.appendLog("ActionsActivity.onClickOpenURL: Invoking URLPickerFragment"); - final DialogFragment newFragment = new URLPickerFragment(); - newFragment.show(getSupportFragmentManager(), DialogFragmentTags.URLPickerFragmentTag); - DebugUtils.appendLog("ActionsActivity.onClickOpenURL: Leaving method"); - } + private void onClickOpenURL(View view) { + final DialogFragment newFragment = new URLPickerFragment(); + newFragment.show(getSupportFragmentManager(), + URL_PICKER_FRAGMENT_TAG); + } - public void onClickInsertNetworkCard(View v) { - Native.toggleNetworkCard(); - backToEinstein(v); - } + private void onClickInsertNetworkCard(View view) { + Native.toggleNetworkCard(); + backToEinstein(); + } - public void onClickBacklight(View v) { - // FIXME: this does not toggle the light, only switches it on. Somehow the backlight state is not not retained when the activity changes - if (Native.backlightIsOn()==1) - Native.setBacklight(0); - else - Native.setBacklight(1); - backToEinstein(v); - } + private void onClickBacklight(View view) { + // FIXME: this does not toggle the light, only switches it on. + // Somehow the backlight state is not not retained when the activity changes + boolean on = Native.backlightIsOn() == 1; + Native.setBacklight(on ? 0 : 1); + backToEinstein(); + } - public void onClickPreferences(View v) { - // FIXME: after preferences are closed, we end up in Actions again. We should probably be in Einstein instead. - Intent intent = new Intent(v.getContext(), EinsteinPreferencesActivity.class); - startActivity(intent); - this.finish(); - } + private void onClickPreferences(View view) { + // FIXME: after preferences are closed, we end up in Actions again. + // We should probably be in Einstein instead. + Intent intent = new Intent(this, EinsteinPreferencesActivity.class); + startActivity(intent); + finish(); + } - public void onClickQuit(View v) { - // FIXME: stop emulator - Log.e("ACTION", "onClickQuitEinstein"); - EinsteinApplication app = (EinsteinApplication)getApplication(); - Native.powerOffEmulator(); - app.normalPriority(); - Intent intent = new Intent(v.getContext(), EinsteinActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - intent.putExtra("EXIT", true); - startActivity(intent); - - // android.os.Process.killProcess(android.os.Process.myPid()); - // super.finish(); - } - + private void onClickQuit(View view) { + // FIXME: stop emulator + EinsteinApplication app = (EinsteinApplication) getApplication(); + Native.powerOffEmulator(); + app.normalPriority(); + Intent intent = new Intent(this, EinsteinActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + intent.putExtra("EXIT", true); + startActivity(intent); + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinActivity.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinActivity.java index a672aaf14..0a02b47d7 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinActivity.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinActivity.java @@ -2,163 +2,111 @@ package com.newtonforever.einstein.activity; import android.Manifest; -import android.annotation.TargetApi; import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; -import android.view.KeyEvent; -import android.view.Menu; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.Window; import android.view.WindowManager; import android.widget.Toast; import com.newtonforever.einstein.Einstein; import com.newtonforever.einstein.EinsteinApplication; -import com.newtonforever.einstein.R; import com.newtonforever.einstein.action.EinsteinActionHandler; import com.newtonforever.einstein.jni.Native; -import com.newtonforever.einstein.startup.IStartup.LoadResult; +import com.newtonforever.einstein.startup.LoadResult; import com.newtonforever.einstein.startup.Startup; import com.newtonforever.einstein.startup.StartupConstants; import com.newtonforever.einstein.utils.MiscUtils; -import com.newtonforever.einstein.utils.StringUtils; -import com.newtonforever.einstein.utils.debug.DebugUtils; import com.newtonforever.einstein.utils.screen.ScreenDimensions; import com.newtonforever.einstein.utils.screen.ScreenDimensionsInitializer; import com.newtonforever.einstein.view.EinsteinView; -import java.io.File; import java.util.Timer; /** * The main user interface to the emulator. - * + *

* This class manages the visual representation of the emulator and * the screen interface. - * + * * @author matt */ -public class EinsteinActivity extends Activity implements OnSharedPreferenceChangeListener -{ - // Be aware that dialog ID values are arbitrary, but need to be unique within the Activity. - private static final int DIALOG_DOWNLOAD_PROGRESS_ID = 0; +public class EinsteinActivity extends Activity implements OnSharedPreferenceChangeListener { + private static final String TAG = EinsteinActivity.class.toString(); + private static final int REQUEST_WRITE = 1; - private static EinsteinActivity pInstance = null; - private Einstein pEinstein = null; - private EinsteinView pEinsteinView = null; - private ProgressDialog mProgressDialog; - private Timer mScreenRefreshTimer = null; - private EinsteinActionHandler mScreenRefreshTask = null; + private Einstein einstein = null; + private EinsteinView einsteinView = null; + private Timer screenRefreshTimer = null; + private EinsteinActionHandler screenRefreshTask = null; private SharedPreferences sharedPrefs; private Startup startup; - // Used to load the 'native-lib' library on application startup. - /* - static { - System.loadLibrary("native-lib"); - } - */ - - public static EinsteinActivity getInstance() { - return pInstance; - } -/* - public void DownloadFile(String src, String dst){ - - try { - URL u = new URL(src); - InputStream is = u.openStream(); - - DataInputStream dis = new DataInputStream(is); - - byte[] buffer = new byte[1024]; - int length; - - FileOutputStream fos = new FileOutputStream(new File(dst)); - while ((length = dis.read(buffer))>0) { - fos.write(buffer, 0, length); - } - fos.close(); - - } catch (MalformedURLException mue) { - Log.e("SYNC getUpdate", "malformed url error", mue); - } catch (IOException ioe) { - Log.e("SYNC getUpdate", "io error", ioe); - } catch (SecurityException se) { - Log.e("SYNC getUpdate", "security error", se); - } -} -*/ // --- beginning of life cycle - /** + /** * \brief Android creates a new activity, launching or waking Einstein. - * + *

* If called for the first time, it starts Einstein. - * + *

* The Activity then creates a view and connect Einstein to that view. - * + *

* \todo Preferences are not managed well yet, just as proof of concept. * \todo No ROM management is implemented yet. */ @Override - public void onCreate(Bundle savedInstanceState) - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onCreate()."); - pInstance = this; + public void onCreate(Bundle savedInstanceState) { + Log.i(TAG, "Entering onCreate()."); super.onCreate(savedInstanceState); - // Download the ROM - //DebugUtils.logGreen("ERR", "A"); - //DownloadFile("http://www.matthiasm.com/717006", "/mnt/sdcard/Download/Einstein/717006.rom"); - //DebugUtils.logGreen("ERR", "B"); - // Create an instance of EinsteinPreferencesActivity. If we do not do this, the preferences that are calculated // at runtime wouldn't exist until the user has invoked the preferences window for the first time. - this.sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - this.startup = new Startup(this); + startup = new Startup(this); // Create view - this.pEinsteinView = new EinsteinView(this); + einsteinView = new EinsteinView(this); // Show or hide Android status bar. Note that this must take place before we call setContentView requestWindowFeature(Window.FEATURE_NO_TITLE); final boolean statusBarVisible = sharedPrefs.getBoolean("androidstatusbar", true); updateFullscreenStatus(statusBarVisible); - setContentView(pEinsteinView); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE); - return; - } + setContentView(einsteinView); + + int permission = + ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (permission != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + REQUEST_WRITE); + return; } + // Install all required assets, initialize host device dependent values, ... init(); } private void init() { - DebugUtils.logGreen("EinsteinActivity: ", "Creating Einstein application."); + Log.i(TAG, "Creating Einstein application."); final EinsteinApplication app = (EinsteinApplication) getApplication(); - pEinstein = app.getEinstein(); + einstein = app.getEinstein(); final LoadResult result = startup.installAssets(); if (LoadResult.OK != result) { - DebugUtils.logRed("EinsteinActivity: ", "Problem with installing assets."); + Log.e(TAG, "Problem with installing assets."); return; } @@ -166,293 +114,214 @@ private void init() { registerPreferenceChangeListener(); // Initialize emulator - if (!pEinstein.isRunning()) { + if (!einstein.isRunning()) { Native.initEmulator("CONSOLE"); } // Start the emulator - if (pEinstein.isRunning()) { // Wake up - Toast.makeText(getApplicationContext(), "Reconnecting to Einstein", Toast.LENGTH_SHORT).show(); + if (einstein.isRunning()) { // Wake up + Toast.makeText(getApplicationContext(), "Reconnecting to Einstein", Toast.LENGTH_SHORT).show(); } else { String id = sharedPrefs.getString("newtonid", StartupConstants.DEFAULT_NEWTON_ID); Native.setNewtonID(id); - pEinstein.run(StartupConstants.DATA_FILE_PATH, ScreenDimensions.NEWTON_SCREEN_WIDTH, ScreenDimensions.NEWTON_SCREEN_HEIGHT); + einstein.run(StartupConstants.DATA_FILE_PATH, ScreenDimensions.NEWTON_SCREEN_WIDTH, ScreenDimensions.NEWTON_SCREEN_HEIGHT); // TODO FG 2013_10_19 Only required when using Frank's Flash ROM board data. Remove in a final version. //MiscUtils.sleepForMillis(2000); - //DebugUtils.logGreen("EinsteinActivity: ", "Sleeping for 2s after calling run because we're using Frank's ROM..."); + //Log.i(TAG, "Sleeping for 2s after calling run because we're using Frank's ROM..."); } final int rate = Integer.valueOf(sharedPrefs.getString("screenrefreshrate", StartupConstants.DEFAULT_SCREEN_REFRESH_RATE)); startScreenRefresh(rate); // TODO FG 2013_10_19 Only required when using Frank's Flash ROM board data. Remove in a final version. //MiscUtils.sleepForMillis(2000); - //DebugUtils.logGreen("EinsteinActivity: ", "Sleeping for 2s after starting screen refresh because we're using Frank's ROM..."); + //Log.i(TAG, "Sleeping for 2s after starting screen refresh because we're using Frank's ROM..."); app.raisePriority(); - - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onCreate()."); + + Log.i(TAG, "Leaving onCreate()."); } @Override - public void onStart() - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onStart()."); + public void onStart() { + Log.i(TAG, "Entering onStart()."); super.onStart(); int rate = Integer.valueOf(sharedPrefs.getString("screenrefreshrate", StartupConstants.DEFAULT_SCREEN_REFRESH_RATE)); - startScreenRefresh(rate); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onStart()."); + startScreenRefresh(rate); + Log.i(TAG, "Leaving onStart()."); } @Override - public void onResume() - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onResume()."); + public void onResume() { + Log.i(TAG, "Entering onResume()."); super.onResume(); int rate = Integer.valueOf(sharedPrefs.getString("screenrefreshrate", StartupConstants.DEFAULT_SCREEN_REFRESH_RATE)); startScreenRefresh(rate); Native.powerOnEmulator(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onResume()."); + Log.i(TAG, "Leaving onResume()."); } @Override - public void onNewIntent(Intent intent) - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onNewIntent()."); + public void onNewIntent(Intent intent) { + Log.i(TAG, "Entering onNewIntent()."); if (intent.getBooleanExtra("EXIT", false)) { - DebugUtils.logGreen("EinsteinActivity: ", "We need to exit..."); + Log.i(TAG, "We need to exit..."); finish(); } - String file = intent.getStringExtra("FILE"); - if (file!=null) { + String file = intent.getStringExtra("FILE"); + if (file != null) { Native.installPackage(file); intent.removeExtra("FILE"); } - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onNewIntent()."); + Log.i(TAG, "Leaving onNewIntent()."); } @Override - public void onPause() - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onPause()."); + public void onPause() { + Log.i(TAG, "Entering onPause()."); super.onPause(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onPause()."); + Log.i(TAG, "Leaving onPause()."); } @Override - public void onStop() - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onStop()."); - stopScreenRefresh(); + public void onStop() { + Log.i(TAG, "Entering onStop()."); + stopScreenRefresh(); super.onStop(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onStop()."); + Log.i(TAG, "Leaving onStop()."); } @Override - public void onDestroy() - { - // December 2011 Frank Gruendel This is because Android Applications do not really stop. They only - // retreat into the background. To really stop them one has to use the Android Settings Manager. - DebugUtils.logGreen("EinsteinActivity: ", "Entering onDestroy()."); + public void onDestroy() { + // December 2011 Frank Gruendel This is because Android Applications do not really stop. + // They only retreat into the background. To really stop them one has to use the + // Android Settings Manager. + Log.i(TAG, "Entering onDestroy()."); Native.powerOffEmulator(); - stopScreenRefresh(); + stopScreenRefresh(); super.onDestroy(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onDestroy()."); + Log.i(TAG, "Leaving onDestroy()."); } // --- End of application life cycle - - // The following two methods aren't used yet, but we'll need them when we implement picking - // the ROM and REX files. Shamelessly copied from http://www.blackmoonit.com/android/filebrowser/intents#intent.pick_file - - @SuppressWarnings("unused") - private void pickFile(File aFile) { - Intent theIntent = new Intent(Intent.ACTION_PICK); - theIntent.setData(Uri.fromFile(aFile)); //default file / jump directly to this file/folder - theIntent.putExtra(Intent.EXTRA_TITLE,"A Custom Title"); //optional - theIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); //optional - try { - startActivityForResult(theIntent,Activity.RESULT_FIRST_USER); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data){ - final int PICK_FILE_RESULT_CODE = Activity.RESULT_FIRST_USER; // ?? - switch (requestCode) { - case PICK_FILE_RESULT_CODE: { - if (resultCode==RESULT_OK && data!=null && data.getData()!=null) { - //String theFilePath = data.getData().getPath(); - // TODO Check if we can use the file. If we can, copy it where it belongs - } - break; - } - } - } - - /** Updates the fullscreen status. The app is shown fullscreen if statusBarVisible is false. - * Note that this method must be called before invoking setContentView in the onCreate method. */ - private void updateFullscreenStatus(boolean statusBarVisible) - { - DebugUtils.logGreen("EinsteinActivity: ", "Entering updateFullscreenStatus()."); + /** + * Updates the fullscreen status. The app is shown fullscreen if statusBarVisible + * is false. Note that this method must be called before invoking + * setContentView in the onCreate method. + */ + private void updateFullscreenStatus(boolean statusBarVisible) { + Log.i(TAG, "Entering updateFullscreenStatus()."); final int fullscreen = WindowManager.LayoutParams.FLAG_FULLSCREEN; final int notFullscreen = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; getWindow().addFlags(statusBarVisible ? notFullscreen : fullscreen); getWindow().clearFlags(statusBarVisible ? fullscreen : notFullscreen); - pEinsteinView.requestLayout(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving updateFullscreenStatus()."); + einsteinView.requestLayout(); + Log.i(TAG, "Leaving updateFullscreenStatus()."); } private void registerPreferenceChangeListener() { - DebugUtils.logGreen("EinsteinActivity: ", "Entering registerPreferenceChangeListener()."); + Log.i(TAG, "Entering registerPreferenceChangeListener()."); sharedPrefs.registerOnSharedPreferenceChangeListener(this); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving registerPreferenceChangeListener()."); + Log.i(TAG, "Leaving registerPreferenceChangeListener()."); } - /** Callback method invoked whenever a preference changes. Note that this method might - * even be called if the actual value of the preference has not changed. */ + /** + * Callback method invoked whenever a preference changes. Note that this method might + * even be called if the actual value of the preference has not changed. + */ @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onSharedPreferenceChanged()."); + Log.i(TAG, "Entering onSharedPreferenceChanged()."); // The keys are defined in preferences.xml if ("keepnetworkcardpluggedin".equals(key)) { - DebugUtils.logGreen("EinsteinActivity: ", "Keep network card plugged in setting changed."); + Log.i(TAG, "Keep network card plugged in setting changed."); } else if ("screenpresets".equals(key)) { - DebugUtils.logGreen("EinsteinActivity: ", "Screen resolution setting changed."); + Log.i(TAG, "Screen resolution setting changed."); stopScreenRefresh(); // Send the emulator to sleep so that everything ist saved - if (Native.isPowerOn()!=0) { + if (Native.isPowerOn() != 0) { Native.sendPowerSwitchEvent(); - while (Native.isPowerOn()!=0) { + while (Native.isPowerOn() != 0) { MiscUtils.sleepForMillis(100); - DebugUtils.logGreen("EinsteinActivity: ", "Waiting for power down."); + Log.i(TAG, "Waiting for power down."); } } ScreenDimensionsInitializer.initNewtonScreenDimensions(this); - Native.changeScreenSize(ScreenDimensions.NEWTON_SCREEN_WIDTH, ScreenDimensions.NEWTON_SCREEN_HEIGHT); - pEinsteinView.updateDimensions(); - Toast.makeText(getApplicationContext(), "Rebooting NewtonOS", Toast.LENGTH_LONG).show(); + Native.changeScreenSize( + ScreenDimensions.NEWTON_SCREEN_WIDTH, + ScreenDimensions.NEWTON_SCREEN_HEIGHT + ); + einsteinView.updateDimensions(); + Toast.makeText(getApplicationContext(), "Rebooting NewtonOS", Toast.LENGTH_LONG).show(); Native.rebootEmulator(); Native.powerOnEmulator(); - while (Native.isPowerOn()==0) { + while (Native.isPowerOn() == 0) { MiscUtils.sleepForMillis(100); - DebugUtils.logGreen("EinsteinActivity: ", "Waiting for power up."); + Log.i(TAG, "Waiting for power up."); } final int rate = Integer.valueOf(sharedPrefs.getString("screenrefreshrate", StartupConstants.DEFAULT_SCREEN_REFRESH_RATE)); startScreenRefresh(rate); // TODO: reconnect the view somehow! } else if ("install_rom".equals(key)) { - DebugUtils.logGreen("EinsteinActivity: ", "ROM installation path setting changed."); + Log.i(TAG, "ROM installation path setting changed."); } else if ("androidstatusbar".equals(key)) { final boolean statusBarVisible = sharedPreferences.getBoolean("androidstatusbar", true); - DebugUtils.logGreen("EinsteinActivity: ", "Status bar visibility setting changed."); + Log.i(TAG, "Status bar visibility setting changed."); updateFullscreenStatus(statusBarVisible); } else if ("screenrefreshrate".equals(key)) { - DebugUtils.logGreen("EinsteinActivity: ", "Screen refresh rate setting changed."); + Log.i(TAG, "Screen refresh rate setting changed."); int rate = Integer.valueOf(sharedPrefs.getString("screenrefreshrate", StartupConstants.DEFAULT_SCREEN_REFRESH_RATE)); changeScreenRefresh(rate); } - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onSharedPreferenceChanged()."); - } - - @Override - /** Used to create the menu. */ - public boolean onCreateOptionsMenu(Menu menu) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onCreateOptionsMenu() and returning true."); - return true; - } - - @Override - protected Dialog onCreateDialog(int id) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onCreateDialog()."); - switch (id) { - case DIALOG_DOWNLOAD_PROGRESS_ID: - this.mProgressDialog = new ProgressDialog(this); - this.mProgressDialog.setMessage(StringUtils.getLocalizedString(this.getResources(), R.string.Startup_downloadingFile)); - this.mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - this.mProgressDialog.setCancelable(false); - this.mProgressDialog.show(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onCreateDialog()."); - return this.mProgressDialog; - default: - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onCreateDialog()."); - return null; - } + Log.i(TAG, "Leaving onSharedPreferenceChanged()."); } private void startScreenRefresh(int rate) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering startScreenRefresh()."); - if (mScreenRefreshTask==null) { - mScreenRefreshTask = new EinsteinActionHandler(pEinsteinView); + Log.i(TAG, "Entering startScreenRefresh()."); + if (screenRefreshTask == null) { + screenRefreshTask = new EinsteinActionHandler(einsteinView); } - if (mScreenRefreshTimer==null) { - mScreenRefreshTimer = new Timer(true); - mScreenRefreshTimer.schedule(mScreenRefreshTask, 1000, 1000/rate); + if (screenRefreshTimer == null) { + screenRefreshTimer = new Timer(true); + screenRefreshTimer.schedule(screenRefreshTask, 1000, 1000 / rate); } - DebugUtils.logGreen("EinsteinActivity: ", "Leaving startScreenRefresh()."); + Log.i(TAG, "Leaving startScreenRefresh()."); } private void changeScreenRefresh(int rate) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering changeScreenRefresh()."); - if (mScreenRefreshTimer!=null) { - mScreenRefreshTimer.cancel(); - mScreenRefreshTimer.purge(); - mScreenRefreshTimer = null; - mScreenRefreshTimer = new Timer(true); - mScreenRefreshTimer.schedule(mScreenRefreshTask, 1000/rate, 1000/rate); + Log.i(TAG, "Entering changeScreenRefresh()."); + if (screenRefreshTimer != null) { + screenRefreshTimer.cancel(); + screenRefreshTimer.purge(); + screenRefreshTimer = null; + screenRefreshTimer = new Timer(true); + screenRefreshTimer.schedule(screenRefreshTask, 1000 / rate, 1000 / rate); } - DebugUtils.logGreen("EinsteinActivity: ", "Leaving changeScreenRefresh()."); - } + Log.i(TAG, "Leaving changeScreenRefresh()."); + } private void stopScreenRefresh() { - DebugUtils.logGreen("EinsteinActivity: ", "Entering stopScreenRefresh()."); - if (mScreenRefreshTimer!=null) { - mScreenRefreshTimer.cancel(); - mScreenRefreshTimer.purge(); - mScreenRefreshTimer = null; + Log.i(TAG, "Entering stopScreenRefresh()."); + if (screenRefreshTimer != null) { + screenRefreshTimer.cancel(); + screenRefreshTimer.purge(); + screenRefreshTimer = null; } - mScreenRefreshTask = null; - DebugUtils.logGreen("EinsteinActivity: ", "Leaving stopScreenRefresh()."); - } - - void finishWithMessage(String msg) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering finishWithMessage()."); - class MyOnClickListener implements DialogInterface.OnClickListener { - Activity pv = null; - MyOnClickListener(Activity v) { pv = v; } - @Override public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - pv.finish(); - } - }; - AlertDialog ad = new AlertDialog.Builder(this).create(); - ad.setCancelable(false); - ad.setMessage(msg); - ad.setButton("Quit", new MyOnClickListener(this)); - ad.show(); - DebugUtils.logGreen("EinsteinActivity: ", "Leaving finishWithMessage()."); + screenRefreshTask = null; + Log.i(TAG, "Leaving stopScreenRefresh()."); } @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - DebugUtils.logGreen("EinsteinActivity: ", "Entering onKeyDown()."); - if ( keyCode == KeyEvent.KEYCODE_MENU ) { - Intent intent = new Intent(this, ActionsActivity.class); - startActivity(intent); - return true; - } - DebugUtils.logGreen("EinsteinActivity: ", "Leaving onKeyDown()."); - return super.onKeyDown(keyCode, event); - } + public void onRequestPermissionsResult(int requestCode, + @NonNull String[] permissions, + @NonNull int[] grantResults) { - @Override - @TargetApi(Build.VERSION_CODES.M) - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_WRITE) { - if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0]) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { + if (grantResults.length > 0 + && permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE) + && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { + init(); return; } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinPreferencesActivity.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinPreferencesActivity.java index 4e80bd02a..e98905f47 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinPreferencesActivity.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/EinsteinPreferencesActivity.java @@ -1,96 +1,84 @@ package com.newtonforever.einstein.activity; -import java.util.Vector; +import android.os.Bundle; +import android.preference.ListPreference; +import android.preference.PreferenceActivity; import com.newtonforever.einstein.R; - import com.newtonforever.einstein.utils.Dimension; -import com.newtonforever.einstein.utils.debug.DebugUtils; import com.newtonforever.einstein.utils.screen.ScreenDimensions; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.PreferenceActivity; -import android.util.Log; +import java.util.Vector; -/** - * This activity loads the "preferences.xml" file. - */ +/** + * This activity loads the "preferences.xml" file. + */ public class EinsteinPreferencesActivity extends PreferenceActivity { - - public EinsteinPreferencesActivity() { - super(); - DebugUtils.appendLog("EinsteinPreferencesActivity: Leaving constructor"); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - DebugUtils.appendLog("EinsteinPreferencesActivity.onCreate: Entered method"); - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.preferences); - DebugUtils.appendLog("EinsteinPreferencesActivity.onCreate: Calling initDeviceDependentPreferences"); - this.initDeviceDependentPreferences(); - } - - /** Initializes all preferences that we can only know at runtime. */ - public void initDeviceDependentPreferences() { - DebugUtils.appendLog("EinsteinPreferencesActivity.initDeviceDependentPreferences: Calling initScreenSizePreferences"); - this.initScreenSizePreferences(); - } - /** - * Initializes the emulator screen size preferences. - */ - private final void initScreenSizePreferences() { - DebugUtils.appendLog("EinsteinPreferencesActivity: Entering initScreenSizePreferences"); - final Dimension hostScreenSize = ScreenDimensions.HOST_SCREEN_SIZE; - final boolean isPortrait = hostScreenSize.width <= hostScreenSize.height; - final int minWidth = isPortrait ? 320 : 480; - final int minHeight = isPortrait ? 480 : 320; - int w = minWidth; - int h = minHeight; - DebugUtils.appendLog("EinsteinPreferencesActivity: Calculating entries"); - Log.i("SIZE", "Screen: " + hostScreenSize.width + " x " + hostScreenSize.height); - final Vectortemp = new Vector(); - int i, currentSize = 0; - temp.add(String.valueOf(w) + " x " + String.valueOf(h) + " (original size)"); // always add the native NewtonOS size - double d = Math.abs(ScreenDimensions.NEWTON_SCREEN_WIDTH-w) + Math.abs(ScreenDimensions.NEWTON_SCREEN_HEIGHT-h); - Log.i("SIZE", "Choice: " + w + " x " + h); - Log.i("SIZE", "Newton: " + ScreenDimensions.NEWTON_SCREEN_WIDTH + " x " + ScreenDimensions.NEWTON_SCREEN_HEIGHT); - for (i=10; i>=3; i--) { - int f = i/3; - switch (i%3) { - case 0: w = hostScreenSize.width/f; h = hostScreenSize.height/f; break; - case 1: w = hostScreenSize.width*3/4/f; h = hostScreenSize.height*3/4/f; break; - case 2: w = hostScreenSize.width*2/3/f; h = hostScreenSize.height*2/3/f; break; - } - w = w&0xfffffffe; // width must always be an even number - if (w<=minWidth || h<=minHeight) continue; - // Create a preference entry of the form "w x h", e. g. "320 x 480" - temp.add(String.valueOf(w) + " x " + String.valueOf(h)); - double d1 = Math.abs(ScreenDimensions.NEWTON_SCREEN_WIDTH-w) + Math.abs(ScreenDimensions.NEWTON_SCREEN_HEIGHT-h); - if (d1 temp = new Vector(); + int i, currentSize = 0; + temp.add(String.valueOf(w) + " x " + String.valueOf(h) + " (original size)"); // always add the native NewtonOS size + double d = Math.abs(ScreenDimensions.NEWTON_SCREEN_WIDTH - w) + Math.abs(ScreenDimensions.NEWTON_SCREEN_HEIGHT - h); + + for (i = 10; i >= 3; i--) { + int f = i / 3; + switch (i % 3) { + case 0: + w = hostScreenSize.width / f; + h = hostScreenSize.height / f; + break; + case 1: + w = hostScreenSize.width * 3 / 4 / f; + h = hostScreenSize.height * 3 / 4 / f; + break; + case 2: + w = hostScreenSize.width * 2 / 3 / f; + h = hostScreenSize.height * 2 / 3 / f; + break; + } + w = w & 0xfffffffe; // width must always be an even number + if (w <= minWidth || h <= minHeight) continue; + // Create a preference entry of the form "w x h", e. g. "320 x 480" + temp.add(String.valueOf(w) + " x " + String.valueOf(h)); + double d1 = Math.abs(ScreenDimensions.NEWTON_SCREEN_WIDTH - w) + Math.abs(ScreenDimensions.NEWTON_SCREEN_HEIGHT - h); + if (d1 < d) { + d = d1; + currentSize = temp.size() - 1; + } + } + final int entryCount = temp.size(); + final CharSequence[] entryValues = new CharSequence[entryCount]; + final CharSequence[] entries = new CharSequence[entryCount]; + // Note that entries only contains the string the user sees, whereas entryValues contains what will be returned + // when we query the preference. In our case both must be the same, since ScreenDimensionInitializer will query + // the preference and parse the string to determine the Newton screen size + for (i = 0; i < entryCount; i++) { + entryValues[i] = temp.get(i); + entries[i] = temp.get(i); + } + final ListPreference screenPresets = (ListPreference) (super.findPreference("screenpresets")); + screenPresets.setEntries(entries); + screenPresets.setEntryValues(entryValues); + screenPresets.setValue(temp.get(currentSize)); + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/LoadPackageActivity.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/LoadPackageActivity.java index f873d75da..f89895692 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/LoadPackageActivity.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/activity/LoadPackageActivity.java @@ -2,15 +2,6 @@ package com.newtonforever.einstein.activity; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLConnection; - - import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -20,212 +11,220 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; -import android.support.v4.content.IntentCompat; import android.util.Log; import android.widget.Toast; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; + /** - * Install packages and other files by slecting them in a file browser or clicking on them in a web browser. + * Install packages and other files by selecting them in a file browser or clicking on them in a web browser. */ public class LoadPackageActivity extends Activity { - ProgressDialog mProgressDialog; - String pFilename; - - class FinishActivity implements DialogInterface.OnClickListener { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - } - - private class DownloadFile extends AsyncTask { - - public Activity mActivity; - - public DownloadFile(Activity activity) { - super(); - mActivity = activity; - } - - @Override - protected String doInBackground(String... sUrls) { - try { - String sUrl = sUrls[0]; - // handle the destination filename - pFilename = Environment.getExternalStorageDirectory() + "/Download/"; - File folder = new File(Environment.getExternalStorageDirectory() + "/Download/"); - folder.mkdirs(); - pFilename += sUrl.substring( sUrl.lastIndexOf('/')+1); - Log.e("DOWNLOAD", "To: " + pFilename); - // handle the source URL - URL url = new URL(sUrl); - // connect and download - URLConnection connection = url.openConnection(); - connection.connect(); - // this will be useful so that you can show a typical 0-100% progress bar - int fileLength = connection.getContentLength(); - - // download the file - InputStream input = new BufferedInputStream(url.openStream()); - OutputStream output = new FileOutputStream(pFilename); - - byte data[] = new byte[1024]; - long total = 0; - int count; - while ((count = input.read(data)) != -1) { - total += count; - // publishing the progress.... - publishProgress((int) (total * 100 / fileLength)); - output.write(data, 0, count); - } - - output.flush(); - output.close(); - input.close(); - } catch (Exception e) { - return "ERROR"; - } - return null; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - mProgressDialog.show(); - } - - @Override - protected void onProgressUpdate(Integer... progress) { - super.onProgressUpdate(progress); - mProgressDialog.setProgress(progress[0]); - } - - @Override - protected void onPostExecute(String result) { - mProgressDialog.hide(); - if (result==null) { - Uri uri = Uri.parse("file://"+pFilename); - AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - builder.setTitle("Einstein Package Installer") - .setCancelable(true) - .setMessage("Do you want to install the package " + uri.getLastPathSegment()) - .setNegativeButton("Cancel", new FinishActivity()) - .setPositiveButton("OK", new InstallFromFile(uri)) - .show(); - } else { - showError("Download failed"); - } - } - } - - class InstallFromFile implements DialogInterface.OnClickListener { - public Uri pUri; - public InstallFromFile(Uri uri) { - pUri = uri; - } - @Override - public void onClick(DialogInterface dialog, int which) { - // call Einstein and install - Intent intent = new Intent(getApplicationContext(), EinsteinActivity.class); - intent.putExtra("FILE", pUri.getPath()); - // TODO FG Check if it is OK to use the class Intent with flags from the class IntentCompat. - // Since the flag wasn't available when the Intent class was written, it is difficult to - // believe that this will be able to do anything useful with this flag. - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - startActivity(intent); - finish(); - } - } - - class InstallFromWeb implements DialogInterface.OnClickListener { - public Uri pUri; - public InstallFromWeb(Uri uri) { - pUri = uri; - } - @Override - public void onClick(DialogInterface dialog, int which) { - // call Einstein and install - Intent intent = new Intent(getApplicationContext(), EinsteinActivity.class); - intent.putExtra("FILE", pUri.getPath()); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - startActivity(intent); - finish(); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - - String filePath = getIntent().getData().getEncodedPath(); - Log.i("GET FILE", filePath); - Log.i("GET FILE", "URI" + getIntent().getData().isRelative() + ":" + getIntent().getData().isAbsolute() + " " + getIntent().getData().toString()); - Log.i("GET FILE", getIntent().getData().getScheme()); - - Uri uri = getIntent().getData(); //.normalizeScheme(); - - if (uri.isRelative()) { - // we do not know how to handle a relative path - showError("Unsupported source:\n" + uri.toString()); - } else { - String scheme = uri.getScheme(); - if (scheme.equals("http") || scheme.equals("https")) { - installFromWeb(uri); - } else if (scheme.equals("file")) { - installFromFile(uri); - } else { - showError("Unsupported source scheme:\n" + uri.toString()); - } - } - - // setContentView(R.layout.load_package); - } - - void installFromWeb(Uri uri) - { - Toast.makeText(getApplicationContext(), - "Downloading " + uri.getLastPathSegment() + " from " + uri.getAuthority(), - Toast.LENGTH_LONG).show(); - - // instantiate it within the onCreate method - mProgressDialog = new ProgressDialog(this); - mProgressDialog.setMessage("Downloading " + uri.getLastPathSegment() + " from " + uri.getAuthority()); - mProgressDialog.setIndeterminate(false); - mProgressDialog.setMax(100); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - - // execute this when the downloader must be fired - DownloadFile downloadFile = new DownloadFile(this); - downloadFile.execute(uri.toString()); - } - - void installFromFile(Uri uri) - { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Einstein Package Installer") - .setCancelable(true) - .setMessage("Do you want to install the package " + uri.getLastPathSegment()) - .setNegativeButton("Cancel", new FinishActivity()) - .setPositiveButton("OK", new InstallFromFile(uri)) - .show(); - } - - void showError(String msg) - { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Einstein Package Installer") - .setMessage(msg) - .setCancelable(false) - .setPositiveButton("OK", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - finish(); - } - } - ) - .show(); - } - + ProgressDialog mProgressDialog; + String pFilename; + + class FinishActivity implements DialogInterface.OnClickListener { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + } + + private class DownloadFile extends AsyncTask { + + public Activity mActivity; + + public DownloadFile(Activity activity) { + super(); + mActivity = activity; + } + + @Override + protected String doInBackground(String... sUrls) { + try { + String sUrl = sUrls[0]; + // handle the destination filename + pFilename = Environment.getExternalStorageDirectory() + "/Download/"; + File folder = new File(Environment.getExternalStorageDirectory() + "/Download/"); + folder.mkdirs(); + pFilename += sUrl.substring(sUrl.lastIndexOf('/') + 1); + Log.e("DOWNLOAD", "To: " + pFilename); + // handle the source URL + URL url = new URL(sUrl); + // connect and download + URLConnection connection = url.openConnection(); + connection.connect(); + // this will be useful so that you can show a typical 0-100% progress bar + int fileLength = connection.getContentLength(); + + // download the file + InputStream input = new BufferedInputStream(url.openStream()); + OutputStream output = new FileOutputStream(pFilename); + + byte data[] = new byte[1024]; + long total = 0; + int count; + while ((count = input.read(data)) != -1) { + total += count; + // publishing the progress.... + publishProgress((int) (total * 100 / fileLength)); + output.write(data, 0, count); + } + + output.flush(); + output.close(); + input.close(); + } catch (Exception e) { + return "ERROR"; + } + return null; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + mProgressDialog.show(); + } + + @Override + protected void onProgressUpdate(Integer... progress) { + super.onProgressUpdate(progress); + mProgressDialog.setProgress(progress[0]); + } + + @Override + protected void onPostExecute(String result) { + mProgressDialog.hide(); + if (result == null) { + Uri uri = Uri.parse("file://" + pFilename); + AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); + builder.setTitle("Einstein Package Installer") + .setCancelable(true) + .setMessage("Do you want to install the package " + uri.getLastPathSegment()) + .setNegativeButton("Cancel", new FinishActivity()) + .setPositiveButton("OK", new InstallFromFile(uri)) + .show(); + } else { + showError("Download failed"); + } + } + } + + class InstallFromFile implements DialogInterface.OnClickListener { + public Uri pUri; + + public InstallFromFile(Uri uri) { + pUri = uri; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + // call Einstein and install + Intent intent = new Intent(getApplicationContext(), EinsteinActivity.class); + intent.putExtra("FILE", pUri.getPath()); + // TODO FG Check if it is OK to use the class Intent with flags from the class IntentCompat. + // Since the flag wasn't available when the Intent class was written, it is difficult to + // believe that this will be able to do anything useful with this flag. + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + startActivity(intent); + finish(); + } + } + + class InstallFromWeb implements DialogInterface.OnClickListener { + public Uri pUri; + + public InstallFromWeb(Uri uri) { + pUri = uri; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + // call Einstein and install + Intent intent = new Intent(getApplicationContext(), EinsteinActivity.class); + intent.putExtra("FILE", pUri.getPath()); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + startActivity(intent); + finish(); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + String filePath = getIntent().getData().getEncodedPath(); + Log.i("GET FILE", filePath); + Log.i("GET FILE", "URI" + getIntent().getData().isRelative() + ":" + getIntent().getData().isAbsolute() + " " + getIntent().getData().toString()); + Log.i("GET FILE", getIntent().getData().getScheme()); + + Uri uri = getIntent().getData(); //.normalizeScheme(); + + if (uri.isRelative()) { + // we do not know how to handle a relative path + showError("Unsupported source:\n" + uri.toString()); + } else { + String scheme = uri.getScheme(); + if (scheme.equals("http") || scheme.equals("https")) { + installFromWeb(uri); + } else if (scheme.equals("file")) { + installFromFile(uri); + } else { + showError("Unsupported source scheme:\n" + uri.toString()); + } + } + + // setContentView(R.layout.load_package); + } + + void installFromWeb(Uri uri) { + Toast.makeText(getApplicationContext(), + "Downloading " + uri.getLastPathSegment() + " from " + uri.getAuthority(), + Toast.LENGTH_LONG).show(); + + // instantiate it within the onCreate method + mProgressDialog = new ProgressDialog(this); + mProgressDialog.setMessage("Downloading " + uri.getLastPathSegment() + " from " + uri.getAuthority()); + mProgressDialog.setIndeterminate(false); + mProgressDialog.setMax(100); + mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + + // execute this when the downloader must be fired + DownloadFile downloadFile = new DownloadFile(this); + downloadFile.execute(uri.toString()); + } + + void installFromFile(Uri uri) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Einstein Package Installer") + .setCancelable(true) + .setMessage("Do you want to install the package " + uri.getLastPathSegment()) + .setNegativeButton("Cancel", new FinishActivity()) + .setPositiveButton("OK", new InstallFromFile(uri)) + .show(); + } + + void showError(String msg) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Einstein Package Installer") + .setMessage(msg) + .setCancelable(false) + .setPositiveButton("OK", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + finish(); + } + } + ) + .show(); + } + } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/DialogFragmentTags.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/DialogFragmentTags.java deleted file mode 100644 index 341d8db13..000000000 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/DialogFragmentTags.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.newtonforever.einstein.dialog; - -/** This is a container class for dialog fragment tags. These tags can be helpful for getting - * a handle to a fragment by calling findFragmentByTag(). @author Frank Gruendel. */ -public class DialogFragmentTags { - private DialogFragmentTags() - { - // No instantiation, please - } - - /** The dialog fragment used for the URLPickerFragment class. */ - public static String URLPickerFragmentTag = "URLPickerFragmentTag"; - -} diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/URLPickerFragment.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/URLPickerFragment.java index ca2c4826d..5d2f22201 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/URLPickerFragment.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/dialog/URLPickerFragment.java @@ -1,64 +1,62 @@ package com.newtonforever.einstein.dialog; -import com.newtonforever.einstein.R; - import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; -import com.newtonforever.einstein.utils.debug.DebugUtils; +import com.newtonforever.einstein.R; // A good tutorial on how to use picker dialogs can be found here: // http://developer.android.com/guide/topics/ui/dialogs.html -/** A dialog for selecting URLs and opening them in the Android Browser. Note that the DialogFragment - * class was originally added with Android 3.0 (API level 11), so what we use here is the DialogFragment class - * that's provided with the Support Library. Be sure that you import the android.support.v4.app.DialogFragment - * class and not the android.app.DialogFragment class. @author Frank Gruendel */ +/** + * A dialog for selecting URLs and opening them in the Android Browser. Note that the DialogFragment + * class was originally added with Android 3.0 (API level 11), so what we use here is the DialogFragment class + * that's provided with the Support Library. Be sure that you import the android.support.v4.app.DialogFragment + * class and not the android.app.DialogFragment class. @author Frank Gruendel + */ public class URLPickerFragment extends DialogFragment { - /** Currently defined URLs. If you add a URL here, you must also add an entry for it in array.xml. */ - private final String[] urls = { - "http://www.pda-soft.de", - "http://www.unna.org", - "http://www.newtontalk.net", - "http://myapplenewton.blogspot.com", - "http://40hz.org" + /** + * Currently defined URLs. If you add a URL here, you must also add an entry for it in array.xml. + */ + private final String[] urls = { + "http://www.pda-soft.de", + "http://www.unna.org", + "http://www.newtontalk.net", + "http://myapplenewton.blogspot.com", + "http://40hz.org" }; - /** Opens the URL selection dialog. The selected site is opened in the web browser. */ - public Dialog onCreateDialog(Bundle savedInstanceState) { - DebugUtils.appendLog("URLPickerFragment.onCreateDialog: Entering method"); - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.dialogs_urlpicker_title); - builder.setItems(R.array.entries_newtonsite_urls, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - final String url = urls[which]; - DebugUtils.appendLog("URLPickerFragment.onCreateDialog: User picked URL " + url); - openBrowserInURL(url); - }}); - builder.setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // When the user touches any of the action buttons created with an AlertDialog.Builder, - // the system dismisses the dialog for us. So there's nothing we need to do here unless - // we need to perform certain actions when the dialog goes away, in which case we'd have - // to implement onCancel() or onDismiss() in our class. - } - }); - DebugUtils.appendLog("URLPickerFragment.onCreateDialog: Leaving method"); - return builder.create(); + /** + * Opens the URL selection dialog. The selected site is opened in the web browser. + */ + @NonNull + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.dialogs_urlpicker_title) + .setItems(R.array.entries_newtonsite_urls, (dialog, which) -> + openBrowserInURL(urls[which])) + .setNegativeButton(R.string.common_cancel, (dialog, id) -> { + // When the user touches any of the action buttons created with + // an AlertDialog.Builder, the system dismisses the dialog for us. + // So there's nothing we need to do here unless we need to perform + // certain actions when the dialog goes away, in which case we'd have + // to implement onCancel() or onDismiss() in our class. + }) + .create(); } - /** Opens the browser and directs it to url. */ + /** + * Opens the browser and directs it to url. + */ private void openBrowserInURL(final String url) { - DebugUtils.appendLog("URLPickerFragment.openBrowserInURL: Entering method"); - final Intent browserIntent = new Intent("android.intent.action.VIEW", Uri.parse(url)); + final Intent browserIntent = new Intent(Intent.ACTION_VIEW , Uri.parse(url)); startActivity(browserIntent); - DebugUtils.appendLog("URLPickerFragment.openBrowserInURL: Leaving method"); - } + } } \ No newline at end of file diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/jni/Native.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/jni/Native.java index e58961bcb..32fd07d8f 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/jni/Native.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/jni/Native.java @@ -2,95 +2,148 @@ import android.graphics.Bitmap; -/** Container class for all native methods we need in Einstein. @author Frank Gruendel. */ +/** + * Container class for all native methods we need in Einstein. @author Frank Gruendel. + */ public class Native { - private Native() { - // No instantiation, please - } - - /** Initializes the emulator. - * @param logPath can be any path name in the Android file sytem. Special values for logPath are "NULL" - * or "" for no log, "STDOUT" for logging to some stdout device, and "CONSOLE" for logging to the - * Android debugging log (LogCat on Eclipse). - */ - public static native void initEmulator(String logPath); - - /** Launches the emulator. */ - public static native void runEmulator(String dataPath, int screenWidth, int screenHeight); - - /** Stops the emulator. */ - public static native void stopEmulator(); - - /** Wakes the emulator from sleep. */ - public static native void powerOnEmulator(); - - /** Sends emulator to sleep. */ - public static native void powerOffEmulator(); - - /** Checks if the power is currently on. */ - public static native int isPowerOn(); - - /** Sends a power switch event. */ - public static native void sendPowerSwitchEvent(); - - /** Reboots the emulator. */ - public static native void rebootEmulator(); - - /** Changes the screen size (requires reboot). */ - public static native void changeScreenSize(int w, int h); - - /** Toggles the network card in and out of the PCMCIA slot. */ - public static native void toggleNetworkCard(); - - /** Checks if the screen contents has changed since the last call - * @return 0 if the screen hasn't changed since the last call */ - //public static native int screenIsDirty(); - - /** Switches the backlight on or off. - * @param v 0 to switch backlight off */ - public static native void setBacklight(int v); - - /** Checks if backlight is on. - * @return 0 if the backlight is currently off */ - public static native int backlightIsOn(); - - /** Installs packages that are new in the Einstein directory. - * @TODO find a better way to do this */ - public static native void installNewPackages(); - - /** Installs a package from a file. */ - public static native void installPackage(String filename); - - /** Sets the Newton ID. */ - public static native void setNewtonID(String id); - - /** Sends refresh requests */ - public static native int renderEinsteinView(Bitmap bitmap); - - /** Sends a pen down event. */ - public static native void penDown(int x, int y); - - /** Sends a pen down event. */ - public static native void penUp(); - - /** Java requests a bitmap of required actions from C */ - public static native int getRequiredActions(); - - /** Java requests the number of samples needed to fill the sound buffer. */ - public static native int getSoundBufferSize(); - - /** Java asks C to fill the sound buffer with samples. */ - public static native int fillSoundBuffer(short[] soundBuffer); - - /** Java requests the current sound volume from C. Values range from 0 for off to 100 for full volume. */ - public static native int getSoundVolume(); - - /** Java tells C that a new sound buffer became available. */ - public static native void soundBufferAvailable(); - - /** Java tells C that the last sound finished playing, and no more filled buffers are pending. */ - public static native void soundBufferFinishedOrCanceled(); + private Native() { + // No instantiation, please + } + + /** + * Initializes the emulator. + * + * @param logPath can be any path name in the Android file sytem. Special values for logPath are "NULL" + * or "" for no log, "STDOUT" for logging to some stdout device, and "CONSOLE" for logging to the + * Android debugging log (LogCat on Eclipse). + */ + public static native void initEmulator(String logPath); + + /** + * Launches the emulator. + */ + public static native void runEmulator(String dataPath, int screenWidth, int screenHeight); + + /** + * Stops the emulator. + */ + public static native void stopEmulator(); + + /** + * Wakes the emulator from sleep. + */ + public static native void powerOnEmulator(); + + /** + * Sends emulator to sleep. + */ + public static native void powerOffEmulator(); + + /** + * Checks if the power is currently on. + */ + public static native int isPowerOn(); + + /** + * Sends a power switch event. + */ + public static native void sendPowerSwitchEvent(); + + /** + * Reboots the emulator. + */ + public static native void rebootEmulator(); + + /** + * Changes the screen size (requires reboot). + */ + public static native void changeScreenSize(int w, int h); + + /** + * Toggles the network card in and out of the PCMCIA slot. + */ + public static native void toggleNetworkCard(); + + /** Checks if the screen contents has changed since the last call + * @return 0 if the screen hasn't changed since the last call */ + //public static native int screenIsDirty(); + + /** + * Switches the backlight on or off. + * + * @param v 0 to switch backlight off + */ + public static native void setBacklight(int v); + + /** + * Checks if backlight is on. + * + * @return 0 if the backlight is currently off + */ + public static native int backlightIsOn(); + + /** + * Installs packages that are new in the Einstein directory. + * + * @TODO find a better way to do this + */ + public static native void installNewPackages(); + + /** + * Installs a package from a file. + */ + public static native void installPackage(String filename); + + /** + * Sets the Newton ID. + */ + public static native void setNewtonID(String id); + + /** + * Sends refresh requests + */ + public static native int renderEinsteinView(Bitmap bitmap); + + /** + * Sends a pen down event. + */ + public static native void penDown(int x, int y); + + /** + * Sends a pen down event. + */ + public static native void penUp(); + + /** + * Java requests a bitmap of required actions from C + */ + public static native int getRequiredActions(); + + /** + * Java requests the number of samples needed to fill the sound buffer. + */ + public static native int getSoundBufferSize(); + + /** + * Java asks C to fill the sound buffer with samples. + */ + public static native int fillSoundBuffer(short[] soundBuffer); + + /** + * Java requests the current sound volume from C. Values range from 0 for off to 100 for full volume. + */ + public static native int getSoundVolume(); + + /** + * Java tells C that a new sound buffer became available. + */ + public static native void soundBufferAvailable(); + + /** + * Java tells C that the last sound finished playing, and no more filled buffers are pending. + */ + public static native void soundBufferFinishedOrCanceled(); } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/sound/SoundManager.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/sound/SoundManager.java index 4fb10a51e..6f421a9aa 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/sound/SoundManager.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/sound/SoundManager.java @@ -1,7 +1,5 @@ package com.newtonforever.einstein.sound; -import java.util.Calendar; - import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; @@ -10,61 +8,61 @@ import com.newtonforever.einstein.jni.Native; import com.newtonforever.einstein.startup.StartupConstants; -import com.newtonforever.einstein.utils.debug.DebugUtils; public class SoundManager { - private ToneGenerator m_toneGenerator; + private static final String TAG = SoundManager.class.toString(); - private final AudioTrack m_audioTrack; - - private int m_volume; + private ToneGenerator toneGenerator; + private final AudioTrack audioTrack; + private int volume; public SoundManager() { - super(); - m_volume = 100; //Native.getSoundVolume(); - this.m_toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, m_volume); + volume = 100; + toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, volume); final int streamType = AudioManager.STREAM_MUSIC; final int sampleRateInHz = 22050; final int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; final int minBufferSize = StartupConstants.AUDIO_TRACK_MIN_BUFFER_SIZE; final int bufferMode = AudioTrack.MODE_STREAM; - this.m_audioTrack = new AudioTrack(streamType, sampleRateInHz, channelConfig, audioFormat, minBufferSize, bufferMode); - this.m_audioTrack.setStereoVolume(m_volume/100.0f, m_volume/100.0f); - this.m_audioTrack.play(); // Note that this only puts the AudioTrack into play mode. It won't play anything yet. + audioTrack = new AudioTrack(streamType, sampleRateInHz, channelConfig, audioFormat, minBufferSize, bufferMode); + audioTrack.setStereoVolume(volume / 100.0f, volume / 100.0f); + + // Put AudioTrack into play mode (it won't play anything yet) + audioTrack.play(); } public void playSound(final int soundBufferSize) { if (0 == soundBufferSize) { return; } - DebugUtils.logGreen("SoundManager: ", "Entering playSound()"); - DebugUtils.logGreen("SoundManager: ", "Sound buffer size: " + soundBufferSize); + final short[] soundBuffer = new short[soundBufferSize]; final int bytesReceived = Native.fillSoundBuffer(soundBuffer); final int samplesReceived = bytesReceived / 2; - final int samplesWritten = m_audioTrack.write(soundBuffer, 0, samplesReceived); + final int samplesWritten = audioTrack.write(soundBuffer, 0, samplesReceived); final int bytesWritten = 2 * samplesWritten; - // AudioTrack does not start playing a sound until the buffer is half full. This is a hack to flush the buffer. + + // AudioTrack does not start playing a sound until the buffer is half full. + // This is a hack to flush the buffer. if (bytesWritten < StartupConstants.AUDIO_TRACK_MIN_BUFFER_SIZE) { - final int tmpBufferSize = (StartupConstants.AUDIO_TRACK_MIN_BUFFER_SIZE - bytesWritten) / 2; + final int tmpBufferSize = + (StartupConstants.AUDIO_TRACK_MIN_BUFFER_SIZE - bytesWritten) / 2; final short[] tmpBuffer = new short[tmpBufferSize]; - m_audioTrack.setStereoVolume(m_volume/100.0f, m_volume/100.0f); - m_audioTrack.write(tmpBuffer, 0, tmpBufferSize); - m_audioTrack.flush(); + audioTrack.setStereoVolume(volume / 100.0f, volume / 100.0f); + audioTrack.write(tmpBuffer, 0, tmpBufferSize); + audioTrack.flush(); } - DebugUtils.logGreen("SoundManager: ", "Leaving playSound()"); } public void stopSound() { - DebugUtils.logRed("SoundManager: ", "Entering stopSound()"); - this.m_toneGenerator.stopTone(); + toneGenerator.stopTone(); } public void changeVolume() { - m_volume = Native.getSoundVolume(); - Log.e("SoundManager.changeVolume", "Changed volume to " + m_volume); + volume = Native.getSoundVolume(); + Log.i(TAG, "changeVolume: Changed volume to " + volume); } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/IStartup.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/IStartup.java deleted file mode 100644 index 02952aef8..000000000 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/IStartup.java +++ /dev/null @@ -1,10 +0,0 @@ -// TODO FG Review - -package com.newtonforever.einstein.startup; - -public interface IStartup { - - /** Return values for file loads */ - public enum LoadResult{OK, ROM_FILE_MISSING, REX_FILE_MISSING, APPLICATION_ICON_MISSING}; - -} diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/LoadResult.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/LoadResult.java new file mode 100644 index 000000000..8bd0b6f8a --- /dev/null +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/LoadResult.java @@ -0,0 +1,11 @@ +package com.newtonforever.einstein.startup; + +/** + * Return values for file loads + */ +public enum LoadResult { + OK, + ROM_FILE_MISSING, + REX_FILE_MISSING, + APPLICATION_ICON_MISSING +} diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/Startup.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/Startup.java index 3e26ccc63..479063960 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/Startup.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/Startup.java @@ -1,63 +1,82 @@ -// TODO FG Review package com.newtonforever.einstein.startup; +import android.app.AlertDialog; import android.content.Context; import android.content.res.Resources; +import android.util.Log; import com.newtonforever.einstein.R; -import com.newtonforever.einstein.startup.IStartup.LoadResult; import com.newtonforever.einstein.utils.StringUtils; -import com.newtonforever.einstein.utils.debug.DebugUtils; import com.newtonforever.einstein.utils.screen.ScreenDimensionsInitializer; import java.io.File; public class Startup { - private final Context context; - - public Startup(final Context context) { - super(); - this.context = context; - ScreenDimensionsInitializer.initScreenDimensions(context); - } - - /** Checks if we have a ROM file, a REX file and an application icon in the folder where we expect them. */ - public final LoadResult installAssets() { - final Resources resources = context.getResources(); - final File dataDir = new File(StartupConstants.DATA_FILE_PATH); - dataDir.mkdirs(); - final String line2 = StringUtils.getLocalizedString(resources, R.string.Startup_expectedPath); - // Make sure we have a ROM file - if (!this.romFileAvailable(dataDir)) { - DebugUtils.appendLog("Startup.installAssets: ROM file not found"); - final String line1 = StringUtils.getLocalizedString(resources, R.string.Startup_romFileMissing); - final String message = line1 + "\n" + line2; - DebugUtils.showInfoDialog(context, message); - return LoadResult.ROM_FILE_MISSING; - } - // Make sure we have a REX file - if (!this.rexFileAvailable(dataDir)) { - DebugUtils.appendLog("Startup.installAssets: REX file not found"); - final String line1 = StringUtils.getLocalizedString(resources, R.string.Startup_rexFileMissing); - final String message = line1 + "\n" + line2; - DebugUtils.showInfoDialog(context, message); - return LoadResult.REX_FILE_MISSING; - } - return LoadResult.OK; - } - - /** Returns true if a ROM file was found in dataDir */ - private final boolean romFileAvailable(final File dataDir) { - final File romFile = new File(dataDir + File.separator + StartupConstants.ROM_FILE_NAME); - return romFile.exists(); - } - - /** Returns true if a REX file was found in dataDir */ - private final boolean rexFileAvailable(final File dataDir) { - final File rexFile = new File(dataDir + File.separator + StartupConstants.REX_FILE_NAME); - return rexFile.exists(); - } + private static final String TAG = Startup.class.toString(); + private final Context context; + + public Startup(final Context context) { + super(); + this.context = context; + ScreenDimensionsInitializer.initScreenDimensions(context); + } + + /** + * Checks if we have a ROM file, a REX file and an application icon in the folder where we expect them. + */ + public final LoadResult installAssets() { + final Resources resources = context.getResources(); + final File dataDir = new File(StartupConstants.DATA_FILE_PATH); + dataDir.mkdirs(); + final String line2 = StringUtils.getLocalizedString(resources, R.string.Startup_expectedPath); + + // Make sure we have a ROM file + if (!romFileAvailable(dataDir)) { + Log.e(TAG, "installAssets: ROM file not found"); + final String line1 = StringUtils.getLocalizedString(resources, R.string.Startup_romFileMissing); + final String message = line1 + "\n" + line2; + showInfoDialog(context, message); + return LoadResult.ROM_FILE_MISSING; + } + + // Make sure we have a REX file + if (!rexFileAvailable(dataDir)) { + Log.e(TAG, "installAssets: REX file not found"); + final String line1 = StringUtils.getLocalizedString(resources, R.string.Startup_rexFileMissing); + final String message = line1 + "\n" + line2; + showInfoDialog(context, message); + return LoadResult.REX_FILE_MISSING; + } + return LoadResult.OK; + } + + /** + * Returns true if a ROM file was found in dataDir + */ + private boolean romFileAvailable(final File dataDir) { + final File romFile = new File(dataDir + File.separator + StartupConstants.ROM_FILE_NAME); + return romFile.exists(); + } + + /** + * Returns true if a REX file was found in dataDir + */ + private boolean rexFileAvailable(final File dataDir) { + final File rexFile = new File(dataDir + File.separator + StartupConstants.REX_FILE_NAME); + return rexFile.exists(); + } + + /** + * Shows a message in a dialog and waits for the dialog to be dismissed. + */ + private static void showInfoDialog(final Context context, final String text) { + new AlertDialog.Builder(context) + .setCancelable(false) + .setMessage(text) + .setPositiveButton("OK", (dialog1, which) -> dialog1.dismiss()) + .show(); + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/StartupConstants.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/StartupConstants.java index 4bae769f4..a73a0739d 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/StartupConstants.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/startup/StartupConstants.java @@ -2,56 +2,76 @@ package com.newtonforever.einstein.startup; -import java.io.File; - import android.media.AudioFormat; import android.media.AudioTrack; import android.os.Environment; +import java.io.File; + public class StartupConstants { - - /** Standard directory in which to place files that have been downloaded by the user */ - public static final File EXTERNAL_STORAGE_PUBLIC_DIR; - - /** The sub-directory in which the Newton emulator expects its files */ - public static final String APPLICATION_SUBDIR; - - /** The name of the Newton ROM file */ - public static final String ROM_FILE_NAME; - - /** The name of the Newton REX file */ - public static final String REX_FILE_NAME; - - /** The absolute path to the Newton Emulator data files */ - public static final String DATA_FILE_PATH; - - /** The folder in the SD card in which to put the log file */ - public static final String LOG_FOLDER; - - /** The name of the log file */ - public static final String LOG_FILE_NAME; - - /** The default Newton ID if no ID has been set in the preferences. */ + + /** + * Standard directory in which to place files that have been downloaded by the user + */ + public static final File EXTERNAL_STORAGE_PUBLIC_DIR; + + /** + * The sub-directory in which the Newton emulator expects its files + */ + public static final String APPLICATION_SUBDIR; + + /** + * The name of the Newton ROM file + */ + public static final String ROM_FILE_NAME; + + /** + * The name of the Newton REX file + */ + public static final String REX_FILE_NAME; + + /** + * The absolute path to the Newton Emulator data files + */ + public static final String DATA_FILE_PATH; + + /** + * The folder in the SD card in which to put the log file + */ + public static final String LOG_FOLDER; + + /** + * The name of the log file + */ + public static final String LOG_FILE_NAME; + + /** + * The default Newton ID if no ID has been set in the preferences. + */ public static final String DEFAULT_NEWTON_ID; - - /** The default screen refresh rate if no rate has been set in the preferences. */ + + /** + * The default screen refresh rate if no rate has been set in the preferences. + */ public static final String DEFAULT_SCREEN_REFRESH_RATE; - - /** The minimum buffer size required for the successful creation of an AudioTrack object created in MODE_STREAM mode */ + + /** + * The minimum buffer size required for the successful creation of an AudioTrack object created in MODE_STREAM mode + */ public static final int AUDIO_TRACK_MIN_BUFFER_SIZE; - - static { - EXTERNAL_STORAGE_PUBLIC_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); - APPLICATION_SUBDIR = "Einstein"; // TODO Change this? - ROM_FILE_NAME = "717006.rom"; - //ROM_FILE_NAME = "FranksFlashRomBoard.rom"; - REX_FILE_NAME = "Einstein.rex"; - DATA_FILE_PATH = EXTERNAL_STORAGE_PUBLIC_DIR + File.separator + APPLICATION_SUBDIR; - LOG_FOLDER = "log"; - LOG_FILE_NAME = "noselog.txt"; - DEFAULT_NEWTON_ID = "00004E6577746F6E"; - DEFAULT_SCREEN_REFRESH_RATE = "10"; - AUDIO_TRACK_MIN_BUFFER_SIZE = AudioTrack.getMinBufferSize(22050, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); - } + + static { + EXTERNAL_STORAGE_PUBLIC_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + APPLICATION_SUBDIR = "Einstein"; // TODO Change this? + ROM_FILE_NAME = "717006.rom"; + //ROM_FILE_NAME = "FranksFlashRomBoard.rom"; + REX_FILE_NAME = "Einstein.rex"; + DATA_FILE_PATH = EXTERNAL_STORAGE_PUBLIC_DIR + File.separator + APPLICATION_SUBDIR; + LOG_FOLDER = "log"; + LOG_FILE_NAME = "noselog.txt"; + DEFAULT_NEWTON_ID = "00004E6577746F6E"; + DEFAULT_SCREEN_REFRESH_RATE = "10"; + AUDIO_TRACK_MIN_BUFFER_SIZE = AudioTrack.getMinBufferSize(22050, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/Dimension.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/Dimension.java index 79c1f500f..12655261e 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/Dimension.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/Dimension.java @@ -1,23 +1,25 @@ -/** A Dimension class that encapsulates width and height values. This class is here because Android - * surprisingly does not know the java.awt.Dimension class. */ +/** + * A Dimension class that encapsulates width and height values. This class is here because Android + * surprisingly does not know the java.awt.Dimension class. + */ package com.newtonforever.einstein.utils; - + public class Dimension { - - /** The width. 0 by default. */ - public int width = 0; - - /** The height. 0 by default. */ - public int height = 0; - - public Dimension(int width, int height) { - this.width = width; - this.height = height; - } - - public String toString() { - return ("Dimension (width = " + width + " height = " + height + ")"); - } + + /** The width. 0 by default. */ + public int width = 0; + + /** The height. 0 by default. */ + public int height = 0; + + public Dimension(int width, int height) { + this.width = width; + this.height = height; + } + + public String toString() { + return ("Dimension (width = " + width + " height = " + height + ")"); + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/MiscUtils.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/MiscUtils.java index 90e7e7340..23b07fe9c 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/MiscUtils.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/MiscUtils.java @@ -1,15 +1,18 @@ package com.newtonforever.einstein.utils; -/** A class for miscellaneous utilities. @author Frank Gruendel. */ +/** + * A class for miscellaneous utilities. @author Frank Gruendel. + */ public class MiscUtils { - + private MiscUtils() { // No instances, please } - /** This class allows putting our thread to sleep without having to code try/catch statements all the time. */ - public static void sleepForMillis(int millis) - { + /** + * This class allows putting our thread to sleep without having to code try/catch statements all the time. + */ + public static void sleepForMillis(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/StringUtils.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/StringUtils.java index 655cf1d46..d9b069a46 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/StringUtils.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/StringUtils.java @@ -3,15 +3,19 @@ import android.content.res.Resources; import android.content.res.Resources.NotFoundException; -/** Utility class for string issues. @author Frank Gruendel. */ +/** + * Utility class for string issues. @author Frank Gruendel. + */ public class StringUtils { - /** Returns the string depicted by id in the current locale. */ - public static String getLocalizedString(Resources resources, int id) { - try { - return resources.getString(id); - } catch (final NotFoundException e) { - return "Text resource not found"; - } - } + /** + * Returns the string depicted by id in the current locale. + */ + public static String getLocalizedString(Resources resources, int id) { + try { + return resources.getString(id); + } catch (final NotFoundException e) { + return "Text resource not found"; + } + } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/debug/DebugUtils.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/debug/DebugUtils.java deleted file mode 100644 index 50a23cc5b..000000000 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/debug/DebugUtils.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.newtonforever.einstein.utils.debug; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Date; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Environment; -import android.util.Log; -import android.widget.Toast; - -import com.newtonforever.einstein.startup.StartupConstants; - -/** A small helper class for debugging the Einstein app. @author Frank Gruendel */ -public class DebugUtils { - - private static final String EINSTEIN_LOG_PREFIX = "--- "; - - private DebugUtils() { - // No instances, please - } - - public static void logGreen(String tag, String message) { - Log.i(EINSTEIN_LOG_PREFIX + tag, message); - } - - public static void logRed(String tag, String message) { - Log.e(EINSTEIN_LOG_PREFIX + tag, message); - } - - private static File logFile = null; - - /** Show a quick message and pause execution for a short moment. */ - public static void debugTextOnScreen(final Context context, final String text) { - Toast.makeText(context, text, Toast.LENGTH_LONG).show(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - appendLog(e.getMessage()); - } - } - - /** Shows a message in a dialog and waits for the dialog to be dismissed. */ - public static void showInfoDialog(final Context context, final String text) { - final AlertDialog dialog = new AlertDialog.Builder(context).create(); - dialog.setCancelable(false); - dialog.setMessage(text); - dialog.setButton("OK", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - dialog.show(); - } - - /** Appends text to the end of the log file. */ - public static void appendLog(final String text) { - if (null == logFile) { - logFile = getLogFile(); - } - BufferedWriter bufferedWriter = null; - try { - bufferedWriter = new BufferedWriter(new FileWriter(logFile, true)); - bufferedWriter.append(new Date().toGMTString() + ": " + text); - bufferedWriter.append("\r\n"); // Add line feed. Do not use buf.newLine() since it'll only add hex 0A, which doesn't help under Windows - bufferedWriter.close(); - } - catch (IOException e) { - e.printStackTrace(); - } - finally { - try { - if (null != bufferedWriter) { - bufferedWriter.close(); - } - } - catch (IOException e) { - e.printStackTrace(); - } - } - } - - - /** Creates and returns an empty text file for log output. This file can be found in the folder Download\Einstein. */ - private static File getLogFile() { - // TODO: write log to a better location, for example getApplicationContext().getFilesDir().getPath() - if (null != logFile) { - return logFile; - } - String logFolderName = StartupConstants.DATA_FILE_PATH + File.separator + StartupConstants.LOG_FOLDER; - if (logFolderName.startsWith("/mnt/")) { - logFolderName = logFolderName.substring(4); - } - final File logFolder = new File(logFolderName); - if (!logFolder.exists()) { - createLogFolderPath(logFolderName); - } - final String logFileName = logFolderName + File.separator + StartupConstants.LOG_FILE_NAME; - logFile = new File(logFileName); - if (logFile.exists()) { - logFile.delete(); - } - try { - logFile.createNewFile(); - } - catch (IOException e) { - e.printStackTrace(); - return null; - } - return logFile; - } - - private static void createLogFolderPath(final String path) { - File dir = new File(path); - dir.mkdirs(); - if (!dir.isDirectory()) { - Log.e("ERROR", "Can't create path: " + path); - } - } - -} diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensions.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensions.java index 5eb6a92ff..4f4595e55 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensions.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensions.java @@ -3,23 +3,35 @@ import com.newtonforever.einstein.utils.Dimension; public class ScreenDimensions { - - /** The width of the host device's screen. This value depends on the screen orientation. */ - public static int HOST_SCREEN_WIDTH = -1; - - /** The height of the host device's screen. This value depends on the screen orientation. */ - public static int HOST_SCREEN_HEIGHT = -1; - - /** The size of the host device's screen. */ - public static Dimension HOST_SCREEN_SIZE = null; - - /** The width of the Newton emulator window. */ - public static int NEWTON_SCREEN_WIDTH = -1; - - /** The height of the Newton emulator window. */ - public static int NEWTON_SCREEN_HEIGHT = -1; - - /** The size of the Newton emulator window. */ - public static Dimension NEWTON_SCREEN_SIZE = null; - - } + + /** + * The width of the host device's screen. This value depends on the screen orientation. + */ + public static int HOST_SCREEN_WIDTH = -1; + + /** + * The height of the host device's screen. This value depends on the screen orientation. + */ + public static int HOST_SCREEN_HEIGHT = -1; + + /** + * The size of the host device's screen. + */ + public static Dimension HOST_SCREEN_SIZE = null; + + /** + * The width of the Newton emulator window. + */ + public static int NEWTON_SCREEN_WIDTH = -1; + + /** + * The height of the Newton emulator window. + */ + public static int NEWTON_SCREEN_HEIGHT = -1; + + /** + * The size of the Newton emulator window. + */ + public static Dimension NEWTON_SCREEN_SIZE = null; + +} diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensionsInitializer.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensionsInitializer.java index edf5295b1..bd5271f9a 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensionsInitializer.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/utils/screen/ScreenDimensionsInitializer.java @@ -1,4 +1,3 @@ -// TODO FG Review package com.newtonforever.einstein.utils.screen; @@ -6,75 +5,81 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.DisplayMetrics; +import android.util.Log; import com.newtonforever.einstein.utils.Dimension; -import com.newtonforever.einstein.utils.debug.DebugUtils; /** - * @brief Find the sizes of the Newton and the host screen. - * + * @author matt + * Find the sizes of the Newton and the host screen. + *

* This class uses the preferences to find the size of the Newton screen. * It also searches the Display Metrics database to initialize the Host screen size. - * - * @author matt - * */ public class ScreenDimensionsInitializer { - + + private static final String TAG = ScreenDimensionsInitializer.class.toString(); + private ScreenDimensionsInitializer() { - // No instances, please; + // No instances, please; } - + public static void initScreenDimensions(Context context) { - initHostScreenDimensions(context); - initNewtonScreenDimensions(context); + initHostScreenDimensions(context); + initNewtonScreenDimensions(context); } - - /** Returns the size of the Newton screen. This value depends on the setting in the preferences. */ - public static Dimension getNewtonScreenSize(SharedPreferences prefs) { - final String value = prefs.getString("screenpresets", "1"); - DebugUtils.appendLog("ScreenDimensionInitializer.getNewtonScreenSize: Currently set preference is " + value); - final int separatorPosition = value.indexOf(" x "); - final String sw = value.substring(0, separatorPosition - 1); - DebugUtils.appendLog("ScreenDimensionInitializer.getNewtonScreenSize: Width got from preference string is " + sw); - final String sh = value.substring(separatorPosition + 3, value.length() - 1); - DebugUtils.appendLog("ScreenDimensionInitializer.getNewtonScreenSize: Height got from preference string is " + sh); - final int w = Integer.valueOf(sw); - final int h = Integer.valueOf(sh); - final Dimension size = new Dimension(w, h); - DebugUtils.appendLog("ScreenDimensionInitializer.getNewtonScreenSize: Returning " + size); - return size; - } - - /** Initializes the host screen dimensions. */ + + /** + * Returns the size of the Newton screen. This value depends on the setting in the preferences. + */ + public static Dimension getNewtonScreenSize(SharedPreferences prefs) { + final String value = prefs.getString("screenpresets", "1"); + Log.i(TAG, "getNewtonScreenSize: Currently set preference is " + value); + final int separatorPosition = value.indexOf(" x "); + final String sw = value.substring(0, separatorPosition - 1); + Log.i(TAG, "getNewtonScreenSize: Width got from preference string is " + sw); + final String sh = value.substring(separatorPosition + 3, value.length() - 1); + Log.i(TAG, "getNewtonScreenSize: Height got from preference string is " + sh); + final int w = Integer.valueOf(sw); + final int h = Integer.valueOf(sh); + final Dimension size = new Dimension(w, h); + Log.i(TAG, "getNewtonScreenSize: Returning " + size); + return size; + } + + /** + * Initializes the host screen dimensions. + */ private static void initHostScreenDimensions(Context context) { - if (null == context) { - DebugUtils.appendLog("ScreenDimensionInitializer.initHostScreenDimensions: context is null"); - return; - } - final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - ScreenDimensions.HOST_SCREEN_WIDTH = metrics.widthPixels; - ScreenDimensions.HOST_SCREEN_HEIGHT = metrics.heightPixels; - ScreenDimensions.HOST_SCREEN_SIZE = new Dimension(metrics.widthPixels, metrics.heightPixels); - DebugUtils.appendLog("ScreenDimensionInitializer.initHostScreenDimensions: Host screen size is " + ScreenDimensions.HOST_SCREEN_SIZE ); + if (null == context) { + Log.i(TAG, "initHostScreenDimensions: context is null"); + return; + } + final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + ScreenDimensions.HOST_SCREEN_WIDTH = metrics.widthPixels; + ScreenDimensions.HOST_SCREEN_HEIGHT = metrics.heightPixels; + ScreenDimensions.HOST_SCREEN_SIZE = new Dimension(metrics.widthPixels, metrics.heightPixels); + Log.i(TAG, "initHostScreenDimensions: Host screen size is " + ScreenDimensions.HOST_SCREEN_SIZE); } - - /** Initializes the host screen dimensions. */ + + /** + * Initializes the host screen dimensions. + */ public static void initNewtonScreenDimensions(Context context) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - final String value = prefs.getString("screenpresets", "320 x 480"); - DebugUtils.appendLog("ScreenDimensionInitializer.initNewtonScreenDimensions: Current preference is " + value); - final int separatorPosition = value.indexOf(" x "); - final String sw = value.substring(0, separatorPosition); - DebugUtils.appendLog("ScreenDimensionInitializer.initNewtonScreenDimensions: Width got from preference string is " + sw); - String sh = value.substring(separatorPosition + 3, value.length()); - final int endPosition = sh.indexOf(" "); - if (endPosition!=-1) sh = sh.substring(0, endPosition); - DebugUtils.appendLog("ScreenDimensionInitializer.initNewtonScreenDimensions: Height got from preference string is " + sh); - ScreenDimensions.NEWTON_SCREEN_WIDTH = Integer.valueOf(sw); - ScreenDimensions.NEWTON_SCREEN_HEIGHT = Integer.valueOf(sh); - ScreenDimensions.NEWTON_SCREEN_SIZE = new Dimension(ScreenDimensions.NEWTON_SCREEN_WIDTH, ScreenDimensions.NEWTON_SCREEN_HEIGHT); - DebugUtils.appendLog("ScreenDimensionInitializer.initNewtonScreenDimensions: Newton window size is " + ScreenDimensions.NEWTON_SCREEN_SIZE ); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + final String value = prefs.getString("screenpresets", "320 x 480"); + Log.i(TAG, "initNewtonScreenDimensions: Current preference is " + value); + final int separatorPosition = value.indexOf(" x "); + final String sw = value.substring(0, separatorPosition); + Log.i(TAG, "initNewtonScreenDimensions: Width got from preference string is " + sw); + String sh = value.substring(separatorPosition + 3, value.length()); + final int endPosition = sh.indexOf(" "); + if (endPosition != -1) sh = sh.substring(0, endPosition); + Log.i(TAG, "initNewtonScreenDimensions: Height got from preference string is " + sh); + ScreenDimensions.NEWTON_SCREEN_WIDTH = Integer.valueOf(sw); + ScreenDimensions.NEWTON_SCREEN_HEIGHT = Integer.valueOf(sh); + ScreenDimensions.NEWTON_SCREEN_SIZE = new Dimension(ScreenDimensions.NEWTON_SCREEN_WIDTH, ScreenDimensions.NEWTON_SCREEN_HEIGHT); + Log.i(TAG, "initNewtonScreenDimensions: Newton window size is " + ScreenDimensions.NEWTON_SCREEN_SIZE); } } diff --git a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/view/EinsteinView.java b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/view/EinsteinView.java index d9145cd77..d76b7bbee 100644 --- a/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/view/EinsteinView.java +++ b/_Build_/AndroidStudio/app/src/main/java/com/newtonforever/einstein/view/EinsteinView.java @@ -1,5 +1,6 @@ package com.newtonforever.einstein.view; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -13,80 +14,90 @@ /** - * @brief A View class that forwards events to native code and displays pixels from the native side. - * - * This class implements a view that renders the contents of the emulated - * Newton screen. The Java side of this class generates a bitmap in the size + * @author matt + * A View class that forwards events to native code and displays pixels from the native side. + *

+ * This class implements a view that renders the contents of the emulated + * Newton screen. The Java side of this class generates a bitmap in the size * of the Newton screen. This bitmap is filled with pixel data on the native side * whenever Android requires a refresh. - * + *

* Android takes care of scaling the Newton screen to fit the device view. - * + *

* This class also manages touch and pen input and forwards the corresponding * events to the native side. - * - * @todo In this class, we probably have to handle input from a physical keyboard as well. - * - * @author matt - * + * @todo In this class, we probably have to handle input from a physical keyboard as well. */ public class EinsteinView extends View { - private Bitmap mBitmap; - private Dimension emulatorWindowSize; - private Rect emulatorWindowBounds; - final Rect dstRect = new Rect(); - public EinsteinView(Context context) { - super(context); - updateDimensions(); - } + private Bitmap mBitmap; + private Dimension emulatorWindowSize; + private Rect emulatorWindowBounds; + private final Rect dstRect = new Rect(); + + public EinsteinView(Context context) { + super(context); + updateDimensions(); + } + + /** Called by Android whenever we need to refresh the screen, or whenever the + * TimerTask ScreenRefresh tells Android to post a refresh request. + */ + @Override + protected void onDraw(Canvas canvas) { + // Copy the NewtonOS screen content from the emulated RAM into mBitmap. + // Both have the same resolution, but different color formats. + // NewtonOS uses grey nibbles (4 bit per color). + // We requested RGB_565 on the Android side (16 bit per color). + Native.renderEinsteinView(mBitmap); + + // Request the Android display size minus some Android components like + // the Android status bar, if it is visible. + super.getDrawingRect(dstRect); - @Override - /** Called by Android whenever we need to refresh the screen, or whenever the TimerTask ScreenRefresh - * tells Android to post a refresh request. */ - protected void onDraw(Canvas canvas) { - // Copy the NewtonOS screen content from the emulated RAM into mBitmap. Both have the same resolution, - // but different color formats. NewtonOS uses grey nibbles (4 bit per color). We requested RGB_565 on - // the Android side (16 bit per color). - Native.renderEinsteinView(mBitmap); - // Request the Android display size minus some Android components like the Android status bar, if it is visible. - super.getDrawingRect(dstRect); - // The Rect emulatorWindowBounds has its origin at 0/0, and is exactly as big as the NewtonOS screen - // (or mBitmap for that matter, so it could actually be null). - // Canvas.drawBitmap copies and scales all pixels form mBitmap onto the Canvas, which in our case should - // be most or all of the Android screen. - // The last argument of the call can hold a Paint class which can add more details on how the bitmap is - // copied (clipped, scaled, antialiased, etc.). At its simplest, this operation should be performed by - // the Android video card without the help of the CPU. - canvas.drawBitmap(mBitmap, this.emulatorWindowBounds, dstRect, null); - } + // The Rect emulatorWindowBounds has its origin at 0/0, and is exactly + // as big as the NewtonOS screen (or mBitmap for that matter, so it + // could actually be null). Canvas.drawBitmap copies and scales all + // pixels form mBitmap onto the Canvas, which in our case should be + // most or all of the Android screen. + // + // The last argument of the call can hold a Paint class which can add + // more details on how the bitmap is copied (clipped, scaled, antialiased, etc.). + // At its simplest, this operation should be performed by the Android + // video card without the help of the CPU. + canvas.drawBitmap(mBitmap, emulatorWindowBounds, dstRect, null); + } - @Override - public boolean onTouchEvent(MotionEvent ev) { - // See http://developer.android.com/reference/android/view/MotionEvent.html - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_MOVE: - final Rect dstRect = new Rect(); - this.getDrawingRect(dstRect); - final int x = (int)(ev.getX()*this.emulatorWindowSize.width/dstRect.width()); - final int y = (int)(ev.getY()*this.emulatorWindowSize.height/dstRect.height()); - Native.penDown(x, y); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - Native.penUp(); - break; - } - return true; - } + @Override + public boolean onTouchEvent(MotionEvent ev) { + // See http://developer.android.com/reference/android/view/MotionEvent.html + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + final Rect dstRect = new Rect(); + getDrawingRect(dstRect); + final int x = (int) (ev.getX() * emulatorWindowSize.width / dstRect.width()); + final int y = (int) (ev.getY() * emulatorWindowSize.height / dstRect.height()); + Native.penDown(x, y); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + Native.penUp(); + break; + } + return true; + } - /** Updates the size and location of the emulator window. */ - public void updateDimensions() { - this.mBitmap = null; - this.emulatorWindowBounds = null; - this.emulatorWindowSize = ScreenDimensions.NEWTON_SCREEN_SIZE; - this.mBitmap = Bitmap.createBitmap(emulatorWindowSize.width, emulatorWindowSize.height, Bitmap.Config.RGB_565); - this.emulatorWindowBounds = new Rect(0, 0, this.emulatorWindowSize.width, this.emulatorWindowSize.height); - } + /** + * Updates the size and location of the emulator window. + */ + public void updateDimensions() { + mBitmap = null; + emulatorWindowBounds = null; + emulatorWindowSize = ScreenDimensions.NEWTON_SCREEN_SIZE; + final int width = emulatorWindowSize.width; + final int height = emulatorWindowSize.height; + mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + emulatorWindowBounds = new Rect(0, 0, width, height); + } } diff --git a/_Build_/AndroidStudio/app/src/main/res/layout/actions.xml b/_Build_/AndroidStudio/app/src/main/res/layout/actions_activity.xml similarity index 86% rename from _Build_/AndroidStudio/app/src/main/res/layout/actions.xml rename to _Build_/AndroidStudio/app/src/main/res/layout/actions_activity.xml index ac27e94fe..0185787f8 100644 --- a/_Build_/AndroidStudio/app/src/main/res/layout/actions.xml +++ b/_Build_/AndroidStudio/app/src/main/res/layout/actions_activity.xml @@ -9,7 +9,6 @@ android:id="@+id/toEmulatorAction" android:layout_width="match_parent" android:layout_height="wrap_content" - android:onClick="onClickToEmulator" android:text="@string/mainmenu.toEmulator.title" />