1 /* Be aware that the original version of this file is located in
2  * src/arch/android/AnVICE/src-proto/com/locnet/vice/DosBoxLauncher.java
3  *
4  * when making changes only make them to the file in the proper location
5  */
6 
7 /*
8  * DosBoxLauncher.java
9  *
10  * Written by
11  *  Locnet <android.locnet@gmail.com>
12  *
13  * This file is part of VICE, the Versatile Commodore Emulator.
14  * See README for copyright notice.
15  *
16  *  This program is free software; you can redistribute it and/or modify
17  *  it under the terms of the GNU General Public License as published by
18  *  the Free Software Foundation; either version 2 of the License, or
19  *  (at your option) any later version.
20  *
21  *  This program is distributed in the hope that it will be useful,
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *  GNU General Public License for more details.
25  *
26  *  You should have received a copy of the GNU General Public License
27  *  along with this program; if not, write to the Free Software
28  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29  *  02111-1307  USA.
30  *
31  */
32 
33 package com.locnet.vice;
34 
35 import java.nio.Buffer;
36 import java.nio.ByteBuffer;
37 
38 import com.locnet.vice.Globals;
39 import com.locnet.vice.PreConfig;
40 
41 import android.app.Activity;
42 import android.content.Context;
43 import android.content.Intent;
44 import android.content.SharedPreferences;
45 import android.content.res.Configuration;
46 import android.graphics.Bitmap;
47 import android.os.Bundle;
48 import android.preference.PreferenceManager;
49 import android.view.ContextMenu;
50 import android.view.Menu;
51 import android.view.MenuItem;
52 import android.view.View;
53 import android.view.inputmethod.InputMethodManager;
54 
55 public class DosBoxLauncher extends Activity {
56     public static final int SPLASH_TIMEOUT_MESSAGE = -1;
57     public static final int SHOW_IM_PICKER_MESSAGE = -2;
58     public static final int TURBO_MESSAGE = -3;
59     public static final int RESET_JOY_BUTTON_MESSAGE = -4;
60     public static final int RESET_JOY_DIRECTION_MESSAGE = -5;
61 
nativeInit()62     public static native void nativeInit();
nativeShutDown()63     public static native void nativeShutDown();
nativeSetOption(int option, int value, String value2)64     public static native int nativeSetOption(int option, int value, String value2);
nativeStart(Bitmap bitmap, int width, int height)65     public native void nativeStart(Bitmap bitmap, int width, int height);
nativePause(int state)66     public static native void nativePause(int state);
nativeStop()67     public static native void nativeStop();
nativeReset()68     public static native void nativeReset();
nativeSaveState(String filename, int num)69     public static native void nativeSaveState(String filename, int num);
nativeLoadState(String filename, int num)70     public static native void nativeLoadState(String filename, int num);
nativeAudioWriteBuffer(short audioBuffer[])71     public static native int nativeAudioWriteBuffer(short audioBuffer[]);
nativeSetRomHandling(int state)72     public static native void nativeSetRomHandling(int state);
73 
74     public DosBoxSurfaceView mSurfaceView = null;
75     public DosBoxAudio mAudioDevice = null;
76     public DosBoxThread mDosBoxThread = null;
77 
78     public boolean mPrefRefreshHackOn = true;
79     public boolean mPrefCycleHackOn = true;
80     public boolean mPrefScaleFilterOn = false;
81     public boolean mPrefSoundModuleOn = true;
82     public boolean mPrefOnscreenButtonOn = true;
83     public boolean mPrefHardkeyOn = true;
84     public String mPrefKeyMapping = DosBoxMenuUtility.DEFAULT_KEY_MAPPING;
85     public int mPrefCycles = 0;
86     public int mPrefFrameskip = 0;
87     public int mPrefMemorySize = 4;
88     public int mPrefScaleFactor = 100;
89     public boolean mPrefTapClickOn = true;
90     public int mPrefMouseSensitivity = DosBoxMenuUtility.DEFAULT_MOUSE_SENSITIVITY;
91     public float mMouseScale = 1.0f;
92     public boolean mPrefForceKeyboardOn = false;
93     public boolean mPrefUseLeftAltOn = true;
94     public boolean mTurboOn = false;
95     public boolean mPrefSoundOn = true;
96     public boolean mPrefShowInfoOn = false;
97     public boolean mPrefFastMouseOn = false;
98     public int mPrefJoyKeySet = DosBoxMenuUtility.JOYKEY_SET_DPAD;
99     public boolean mPrefAlwaysShowJoystick = false;
100     public boolean mPrefLargeJoystick = false;
101     public boolean mPrefTrueDriveOn = false;
102     public boolean mPrefKeyUpDelay = true;
103     public boolean mPrefBetterVideoOn = false;
104     public int mPrefScaleMode = DosBoxSurfaceView.SCALE_MODE_CUSTOM;
105     public int mJoyPort = 0;
106 
107     @Override
onCreate(Bundle savedInstanceState)108     protected void onCreate(Bundle savedInstanceState) {
109         super.onCreate(savedInstanceState);
110         {
111             Intent intent = getIntent();
112             int message = intent.getIntExtra(PreConfig.EXTRA_MESSAGE, 0);
113 
114             if (PreConfig.MACHINE_TYPE != PreConfig.MACHINE_ALL) {
115                 /* @VICE@ will be replaced during build time with the name of the library needed by the android build script. */
116                 System.loadLibrary("@VICE@");
117             } else {
118                 if (message == PreConfig.MACHINE_X64) {
119                     System.loadLibrary("x64");
120                 }
121                 if (message == PreConfig.MACHINE_X64SC) {
122                     System.loadLibrary("x64sc");
123                 }
124                 if (message == PreConfig.MACHINE_XSCPU64) {
125                     System.loadLibrary("xscpu64");
126                 }
127                 if (message == PreConfig.MACHINE_X64DTV) {
128                     System.loadLibrary("x64dtv");
129                 }
130                 if (message == PreConfig.MACHINE_X128) {
131                     System.loadLibrary("x128");
132                 }
133                 if (message == PreConfig.MACHINE_XCBM2) {
134                     System.loadLibrary("xcbm2");
135                 }
136                 if (message == PreConfig.MACHINE_XCBM5X0) {
137                     System.loadLibrary("xcbm5x0");
138                 }
139                 if (message == PreConfig.MACHINE_XPET) {
140                     System.loadLibrary("xpet");
141                 }
142                 if (message == PreConfig.MACHINE_XPLUS4) {
143                     System.loadLibrary("xplus4");
144                 }
145                 if (message == PreConfig.MACHINE_XVIC) {
146                     System.loadLibrary("xvic");
147                 }
148             }
149         }
150 
151         nativeSetRomHandling(PreConfig.ROMS_TYPE);
152 
153         mSurfaceView = new DosBoxSurfaceView(this);
154         setContentView(mSurfaceView);
155         registerForContextMenu(mSurfaceView);
156 
157         DosBoxMenuUtility.loadPreference(this);
158 
159         //TODO
160         DosBoxMenuUtility.copyConfigFile(this);
161 
162         initDosBox();
163         startDosBox();
164     }
165 
166     @Override
onDestroy()167     protected void onDestroy() {
168         shutDownDosBox();
169 
170         mSurfaceView.shutDown();
171         mSurfaceView = null;
172 
173         super.onDestroy();
174     }
175 
176     @Override
onPause()177     protected void onPause() {
178         pauseDosBox(true);
179         super.onPause();
180     }
181 
182     @Override
onResume()183     protected void onResume() {
184         super.onResume();
185         pauseDosBox(false);
186     }
187 
188     @Override
onConfigurationChanged(Configuration newConfig)189     public void onConfigurationChanged(Configuration newConfig) {
190         super.onConfigurationChanged(newConfig);
191     }
192 
193     @Override
onCreateOptionsMenu(Menu menu)194     public boolean onCreateOptionsMenu(Menu menu) {
195         super.onCreateOptionsMenu(menu);
196         return DosBoxMenuUtility.doCreateOptionsMenu(menu);
197     }
198 
199     @Override
onPrepareOptionsMenu(Menu menu)200     public boolean onPrepareOptionsMenu (Menu menu) {
201         super.onPrepareOptionsMenu(menu);
202         return DosBoxMenuUtility.doPrepareOptionsMenu(this, menu);
203     }
204 
205     @Override
onOptionsItemSelected(MenuItem item)206     public boolean onOptionsItemSelected(MenuItem item) {
207         if (DosBoxMenuUtility.doOptionsItemSelected(this, item)) {
208             return true;
209         }
210         return super.onOptionsItemSelected(item);
211     }
212 
213     @Override
onMenuOpened(int featureId, Menu menu)214     public boolean onMenuOpened(int featureId, Menu menu) {
215         return super.onMenuOpened(featureId, menu);
216     }
217 
218     @Override
onOptionsMenuClosed(Menu menu)219     public void onOptionsMenuClosed(Menu menu) {
220         super.onOptionsMenuClosed(menu);
221     }
222 
223     @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)224     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
225         super.onCreateContextMenu(menu, v, menuInfo);
226         DosBoxMenuUtility.doCreateContextMenu(this, menu, v, menuInfo);
227     }
228 
229     @Override
onContextItemSelected(MenuItem item)230     public boolean onContextItemSelected(MenuItem item) {
231         if (DosBoxMenuUtility.doContextItemSelected(this, item)) {
232             return true;
233         }
234         return super.onOptionsItemSelected(item);
235     }
236 
237     @Override
onActivityResult(final int requestCode, final int resultCode, final Intent extras)238     protected void onActivityResult(final int requestCode, final int resultCode, final Intent extras) {
239         String path = null;
240 
241         if (requestCode == Globals.PREFKEY_F1_INT) {
242             path = (resultCode == RESULT_OK) ? extras.getStringExtra("currentFile") : "/sdcard/df0.adf";
243             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, 1, path);
244         } else if (requestCode == Globals.PREFKEY_F2_INT) {
245             path = (resultCode == RESULT_OK) ? extras.getStringExtra("currentFile") : "/sdcard/df1.adf";
246             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, 2, path);
247         } else if (requestCode == Globals.PREFKEY_F3_INT) {
248             path = (resultCode == RESULT_OK) ? extras.getStringExtra("currentFile") : "/sdcard/df2.adf";
249             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, 3, path);
250         } else if (requestCode == Globals.PREFKEY_F4_INT) {
251             path = (resultCode == RESULT_OK) ? extras.getStringExtra("currentFile") : "/sdcard/df3.adf";
252             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, 4, path);
253         }
254     }
255 
pauseDosBox(boolean pause)256     void pauseDosBox(boolean pause) {
257         if (pause) {
258             mDosBoxThread.mDosBoxRunning = false;
259             nativePause(1);
260             if (mAudioDevice != null) {
261                 mAudioDevice.pause();
262             }
263         } else {
264             nativePause(0);
265             mDosBoxThread.mDosBoxRunning = true;
266         }
267     }
268 
initDosBox()269     void initDosBox() {
270         mAudioDevice = new DosBoxAudio(this);
271 
272         nativeInit();
273 
274         //TODO
275         nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CYCLES, 0, null);
276         nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_FRAMESKIP, mPrefFrameskip, null);
277         nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_SOUND_ON, (mPrefSoundOn) ? 1 : 0, null);
278         nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_SHOW_INFO_ON, (mPrefShowInfoOn) ? 1 : 0, null);
279         {
280             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
281             String rPath = sp.getString(Globals.PREFKEY_ROM, null);
282             String f1P = sp.getString(Globals.PREFKEY_F1, null);
283             String f2P = sp.getString(Globals.PREFKEY_F2, null);
284             String f3P = sp.getString(Globals.PREFKEY_F3, null);
285             String f4P = sp.getString(Globals.PREFKEY_F4, null);
286             boolean ntsc = sp.getBoolean(PreConfig.PREF_KEY_NTSC_ON, getResources().getBoolean(R.bool.pref_default_ntsc_on));
287             boolean trueDrive = sp.getBoolean(PreConfig.PREF_KEY_TRUE_DRIVE_ON, getResources().getBoolean(R.bool.pref_default_true_drive_on));
288             boolean screenBorder = sp.getBoolean(PreConfig.PREF_KEY_SCREEN_BORDER_ON, getResources().getBoolean(R.bool.pref_default_screen_border_on));
289 
290             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_SCREEN_BORDER_ON, (screenBorder) ? 1 : -1, null);
291             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_TRUE_DRIVE_ON, (trueDrive) ? 1 : -1, null);
292             {
293                 if (PreConfig.ROMS_TYPE == PreConfig.ROMS_EXTERNAL) {
294                     if ((rPath == null) || (rPath.length() == 0)) {
295                         /* @VICE_DATA_PATH@ will be replaced during build time with the name of the path for the roms by the android build-script. */
296                         /* @VICE_DATA_FILE@ will be replaced during build time with the name of the kernal by the android build-script. */
297                         rPath = "/sdcard/@VICE_DATA_PATH@/@VICE_DATA_FILE@";
298                     }
299                     int pos = rPath.lastIndexOf('/');
300                     if (pos >= 0) {
301                         /* @VICE_DATA_PATH@ will be replaced during build time with the name of the path for the roms by the android build-script. */
302                         rPath = rPath.substring(0, pos); // /sdcard/@VICE_DATA_PATH@
303                     }
304                     pos = rPath.lastIndexOf('/');
305                     if (pos >= 0) {
306                         rPath = rPath.substring(0, pos); // /sdcard
307                     }
308                     rPath = rPath + "/";
309                     /* @VICE_DATA_PATH@ will be replaced during build time with the name of the path for the roms by the android build-script. */
310                     DosBoxMenuUtility.copyDataFile(this, rPath + "@VICE_DATA_PATH@/");
311                     nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_ROM, 0, rPath);
312                 }
313             }
314 
315             //TODO
316             int floppyCount = 4;
317 
318             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, -1, (floppyCount >= 1) ? f1P : null);
319             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, -2, (floppyCount >= 1) ? f2P : null);
320             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, -3, (floppyCount >= 1) ? f3P : null);
321             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_CHANGE_DISK, -4, (floppyCount >= 1) ? f4P : null);
322 
323             nativeSetOption(DosBoxMenuUtility.DOSBOX_OPTION_ID_NTSC, ntsc ? 1 : 0, null);
324         }
325         mDosBoxThread = new DosBoxThread(this);
326     }
327 
shutDownDosBox()328     void shutDownDosBox() {
329         boolean retry;
330         retry = true;
331         while (retry) {
332             try {
333                 mDosBoxThread.join();
334                 retry = false;
335             }
336             catch (InterruptedException e) { // try again shutting down the thread
337             }
338         }
339 
340         nativeShutDown();
341 
342         if (mAudioDevice != null) {
343             mAudioDevice.shutDownAudio();
344             mAudioDevice = null;
345         }
346         mDosBoxThread = null;
347     }
348 
startDosBox()349     void startDosBox() {
350         if (mDosBoxThread != null) {
351             mDosBoxThread.start();
352         }
353 
354         if ((mSurfaceView != null) && (mSurfaceView.mVideoThread != null)) {
355             mSurfaceView.mVideoThread.start();
356         }
357     }
358 
stopDosBox()359     void stopDosBox() {
360         nativePause(0);	//it won't die if not running
361 
362         //stop audio AFTER above
363         if (mAudioDevice != null) {
364             mAudioDevice.pause();
365         }
366 
367         mSurfaceView.mVideoThread.setRunning(false);
368 
369         nativeStop();
370     }
371 
resetDosBox()372     void resetDosBox() {
373         nativeReset();
374     }
375 
callbackExit()376     public void callbackExit() {
377         if (mDosBoxThread != null) {
378             mDosBoxThread.doExit();
379         }
380     }
381 
callbackVideoRedraw(int w, int h, int s, int e)382     public void callbackVideoRedraw(int w, int h, int s, int e) {
383         mSurfaceView.mSrc_width = w;
384         mSurfaceView.mSrc_height = h;
385         synchronized (mSurfaceView.mDirty) {
386             if (mSurfaceView.mDirty) {
387                 mSurfaceView.mStartLine = Math.min(mSurfaceView.mStartLine, s);
388                 mSurfaceView.mEndLine = Math.max(mSurfaceView.mEndLine, e);
389             } else {
390                 mSurfaceView.mStartLine = s;
391                 mSurfaceView.mEndLine = e;
392             }
393             mSurfaceView.mDirty = true;
394         }
395     }
396 
callbackVideoSetMode(int w, int h)397     public Bitmap callbackVideoSetMode(int w, int h) {
398         mSurfaceView.mSrc_width = w;
399         mSurfaceView.mSrc_height = h;
400         mSurfaceView.resetScreen(false);
401         Bitmap newBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
402         if (newBitmap != null) {
403             mSurfaceView.mBitmap = null;
404             mSurfaceView.mBitmap = newBitmap;
405 
406             //locnet, 2011-04-28, support 2.1 or below
407             mSurfaceView.mVideoBuffer = null;
408             mSurfaceView.mVideoBuffer = ByteBuffer.allocateDirect(w * h * 2);
409 
410             return mSurfaceView.mBitmap;
411         }
412         return null;
413     }
414 
415     //locnet, 2011-04-28, support 2.1 or below
callbackVideoGetBuffer()416     public Buffer callbackVideoGetBuffer() {
417         if (mSurfaceView != null) {
418             return mSurfaceView.mVideoBuffer;
419         } else {
420             return null;
421         }
422     }
423 
callbackAudioInit(int rate, int channels, int encoding, int bufSize)424     public int callbackAudioInit(int rate, int channels, int encoding, int bufSize) {
425         if (mAudioDevice != null) {
426             return mAudioDevice.initAudio(rate, channels, encoding, bufSize);
427         } else {
428             return 0;
429         }
430     }
431 
callbackAudioWriteBuffer(int size)432     public void callbackAudioWriteBuffer(int size) {
433         if (mAudioDevice != null) {
434             mAudioDevice.AudioWriteBuffer(size);
435         }
436     }
437 
callbackAudioGetBuffer()438     public short[] callbackAudioGetBuffer() {
439         if (mAudioDevice != null) {
440             return mAudioDevice.mAudioBuffer;
441         } else {
442             return null;
443         }
444     }
445 
446     class DosBoxThread extends Thread {
447         DosBoxLauncher mParent;
448         public boolean mDosBoxRunning = false;
449 
DosBoxThread(DosBoxLauncher parent)450         DosBoxThread(DosBoxLauncher parent) {
451             mParent = parent;
452         }
453 
run()454         public void run() {
455             mDosBoxRunning = true;
456             nativeStart(mSurfaceView.mBitmap, mSurfaceView.mBitmap.getWidth(), mSurfaceView.mBitmap.getHeight());
457             //will never return to here;
458         }
459 
doExit()460         public void doExit() {
461             if (mSurfaceView != null) {
462                 InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
463                 if (imm != null) {
464                     imm.hideSoftInputFromWindow(mSurfaceView.getWindowToken(), 0);
465                 }
466             }
467             mDosBoxRunning = false;
468         }
469     }
470 }
471