Compare commits
399 Commits
android-1.
...
android-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b901dff07 | ||
|
|
8b554083b4 | ||
|
|
cd6eb65fc5 | ||
|
|
4bc61b6216 | ||
|
|
20b085d9f7 | ||
|
|
a0c26386e8 | ||
|
|
1ff7bfe4bf | ||
|
|
7a99b72f20 | ||
|
|
021604471b | ||
|
|
dc5e7eee25 | ||
|
|
c3ea8c5aea | ||
|
|
53459c9e78 | ||
|
|
570147712c | ||
|
|
a9755215bf | ||
|
|
981cff845b | ||
|
|
b5b79faf1d | ||
|
|
dd02333eae | ||
|
|
a055ae8b8d | ||
|
|
25e4fd0eba | ||
|
|
58d2392eac | ||
|
|
ae76537a19 | ||
|
|
8e6701bcbb | ||
|
|
2517b45720 | ||
|
|
d35d87af9f | ||
|
|
2d5c47d534 | ||
|
|
85dc4e5132 | ||
|
|
861cb3320c | ||
|
|
d226db8021 | ||
|
|
f8b4602fca | ||
|
|
0801c9f010 | ||
|
|
72c5c550fe | ||
|
|
11cf51753b | ||
|
|
98aecedd65 | ||
|
|
bcbf5ac234 | ||
|
|
1716dd35be | ||
|
|
153f1434db | ||
|
|
51a5f5fcf7 | ||
|
|
3b1c72e872 | ||
|
|
3c1dcd4a69 | ||
|
|
97a98f0c86 | ||
|
|
bdbe544c3b | ||
|
|
13bf93e5ca | ||
|
|
2836d903d9 | ||
|
|
a09d08c079 | ||
|
|
4885388a2d | ||
|
|
aefe243620 | ||
|
|
5102706441 | ||
|
|
55cba116e4 | ||
|
|
f8b570869f | ||
|
|
ccfaa0544a | ||
|
|
c00a52cbc6 | ||
|
|
b9c4ec4cc3 | ||
|
|
d872ad3cdd | ||
|
|
c30c50be06 | ||
|
|
25a0f69a5f | ||
|
|
7411a987fa | ||
|
|
d98c4afa84 | ||
|
|
dacf0de80e | ||
|
|
8e91d1f7de | ||
|
|
dd0de51d64 | ||
|
|
2a263e2418 | ||
|
|
c731c2a310 | ||
|
|
e020817068 | ||
|
|
91fdf7b8e5 | ||
|
|
55ec0c7034 | ||
|
|
033dbf71ea | ||
|
|
0468cea2d4 | ||
|
|
b300e60e2a | ||
|
|
399daf16fa | ||
|
|
8873fe09d1 | ||
|
|
5dfa2e8797 | ||
|
|
4c893cc197 | ||
|
|
e1f0557b87 | ||
|
|
3de4a181eb | ||
|
|
9bd59661ed | ||
|
|
2ca742650f | ||
|
|
31aca92ffd | ||
|
|
6bfbe3cc88 | ||
|
|
14a40e055e | ||
|
|
bf0e61c9ea | ||
|
|
96611beab9 | ||
|
|
086c7e585a | ||
|
|
a13caa8bd1 | ||
|
|
6a630714ed | ||
|
|
9cc3603d73 | ||
|
|
c0a4ced573 | ||
|
|
1bb3f75a06 | ||
|
|
ddcef734c7 | ||
|
|
07c2f3cba8 | ||
|
|
d6656a4fff | ||
|
|
2f8381e4df | ||
|
|
85668fbe35 | ||
|
|
db04d330c7 | ||
|
|
bea9e1ee31 | ||
|
|
3def67975c | ||
|
|
300c292ec5 | ||
|
|
a6516fc1ad | ||
|
|
d2e61e5091 | ||
|
|
f6e2ebc028 | ||
|
|
039063d9b0 | ||
|
|
97d538c4d2 | ||
|
|
5ab68b5503 | ||
|
|
a417249691 | ||
|
|
1be2c6fd27 | ||
|
|
37df740fd3 | ||
|
|
bb93b5c243 | ||
|
|
c80e16de3b | ||
|
|
0be555d7e9 | ||
|
|
1294485a02 | ||
|
|
ccd05e52fe | ||
|
|
4fd6a87340 | ||
|
|
3edb24ea3b | ||
|
|
3a6c033077 | ||
|
|
d0b3f632e1 | ||
|
|
4bdabcaa9a | ||
|
|
c4e3dccc38 | ||
|
|
ba09a6aba9 | ||
|
|
faab9fa04a | ||
|
|
fe63695f81 | ||
|
|
6daa1aa010 | ||
|
|
781cc60d8c | ||
|
|
88ca414f80 | ||
|
|
5805822bd4 | ||
|
|
8c244486e8 | ||
|
|
6e09383504 | ||
|
|
e479a861d7 | ||
|
|
07e1c4ed83 | ||
|
|
b37c94f404 | ||
|
|
3ba0f43dc5 | ||
|
|
57dd816d61 | ||
|
|
daddf5f287 | ||
|
|
b04e4ab348 | ||
|
|
bc8091cde3 | ||
|
|
f3324c0b2b | ||
|
|
cb31ccaf9c | ||
|
|
fc3df8c6b6 | ||
|
|
721ea2c172 | ||
|
|
99953ea90a | ||
|
|
8921f79a14 | ||
|
|
5883545390 | ||
|
|
d4581eb492 | ||
|
|
94ca64f08d | ||
|
|
74457c4cda | ||
|
|
bc46b2d24e | ||
|
|
35e3d6a969 | ||
|
|
1a6c1292f3 | ||
|
|
838bf0496a | ||
|
|
b4c72c15c6 | ||
|
|
fe894b6ac2 | ||
|
|
1f79edca1d | ||
|
|
eeba82ba24 | ||
|
|
7a82bbf471 | ||
|
|
7ad7b65d11 | ||
|
|
2f156d4262 | ||
|
|
fc9ad6d4e1 | ||
|
|
cc9a164bec | ||
|
|
06f8015959 | ||
|
|
19178b751c | ||
|
|
fc5734fedc | ||
|
|
4457e9e722 | ||
|
|
59e6c4fabc | ||
|
|
b4925292e1 | ||
|
|
635075f34b | ||
|
|
ab3392a8f8 | ||
|
|
8d2142592c | ||
|
|
ed8942f82d | ||
|
|
bfb7ab3d5f | ||
|
|
d7413dae01 | ||
|
|
4ca642a715 | ||
|
|
b62f5e9e7f | ||
|
|
ddd03ca4d0 | ||
|
|
c393ea81a0 | ||
|
|
4fee1ee0be | ||
|
|
b0a2a34d6a | ||
|
|
7af88b3568 | ||
|
|
3b6b568fc2 | ||
|
|
2560a45e37 | ||
|
|
4aa78f7a65 | ||
|
|
d3b87e5c05 | ||
|
|
19d427ac6e | ||
|
|
ca73750c44 | ||
|
|
f4354e2171 | ||
|
|
e06620b57d | ||
|
|
bc6719d712 | ||
|
|
0eb4dad0da | ||
|
|
fd5b97189a | ||
|
|
b7a49137c0 | ||
|
|
54712f8423 | ||
|
|
8ce1fffe89 | ||
|
|
7dc83521ec | ||
|
|
28ecb323ba | ||
|
|
ac912ffd54 | ||
|
|
95e7964912 | ||
|
|
abfa461227 | ||
|
|
b8ab6e2be0 | ||
|
|
9f1f6e4fe1 | ||
|
|
093c99466f | ||
|
|
254e013342 | ||
|
|
b0c1703b23 | ||
|
|
9e9d0333cc | ||
|
|
dadf5e02a1 | ||
|
|
44b2e564d4 | ||
|
|
edaab3e110 | ||
|
|
2de03fd849 | ||
|
|
7d21391efe | ||
|
|
aad2f0a71e | ||
|
|
ab59b089d9 | ||
|
|
d2261815a1 | ||
|
|
13701b5497 | ||
|
|
fd0611f3a1 | ||
|
|
85d1af95f6 | ||
|
|
fd3708f0df | ||
|
|
36626fc201 | ||
|
|
3c45c455ec | ||
|
|
70e203303e | ||
|
|
7b3eabb12f | ||
|
|
da4e5eb75a | ||
|
|
30b203e3da | ||
|
|
e5b3099b04 | ||
|
|
747a469241 | ||
|
|
e7b2dd3ad1 | ||
|
|
28cdb24d18 | ||
|
|
14108fb97b | ||
|
|
ae75ce2798 | ||
|
|
98e5c883f9 | ||
|
|
a77075c881 | ||
|
|
90b52702d6 | ||
|
|
a5a498f96c | ||
|
|
b2acb4a1ed | ||
|
|
2bf379aad4 | ||
|
|
399617e77f | ||
|
|
d416edc7d8 | ||
|
|
7607126f7c | ||
|
|
76f29d0865 | ||
|
|
3ed159dd0b | ||
|
|
13184ec4be | ||
|
|
9c9ba6e7ef | ||
|
|
dcb35226b7 | ||
|
|
f53dbea81e | ||
|
|
65882152a8 | ||
|
|
04f22686fa | ||
|
|
fd7578a862 | ||
|
|
23a874456c | ||
|
|
2a405f028f | ||
|
|
9c1cfedf7d | ||
|
|
db816ad502 | ||
|
|
b59e1ca7ab | ||
|
|
a03c074a52 | ||
|
|
b065da9f4b | ||
|
|
74a5b74ae3 | ||
|
|
87ae0f08e0 | ||
|
|
163035b0c7 | ||
|
|
8b74dafc6f | ||
|
|
2da23f717a | ||
|
|
fdfe312a2b | ||
|
|
10d9cc3c66 | ||
|
|
c57bf83514 | ||
|
|
b6d20bbe3b | ||
|
|
48c6515790 | ||
|
|
a87092bbd8 | ||
|
|
01b25527fe | ||
|
|
b87273e742 | ||
|
|
0663141589 | ||
|
|
6e978810db | ||
|
|
b5dfd86310 | ||
|
|
3120b75e00 | ||
|
|
c5ed0bb5c6 | ||
|
|
44b9c4c408 | ||
|
|
03930d6acb | ||
|
|
15d64cf24e | ||
|
|
dcbf1ace18 | ||
|
|
f0e55af6f0 | ||
|
|
699f4697df | ||
|
|
efcf0afa4e | ||
|
|
00a5f6e102 | ||
|
|
e073954ec8 | ||
|
|
afeaba8b2a | ||
|
|
a2b7603e53 | ||
|
|
0dbcfbc9a2 | ||
|
|
89d12ce29d | ||
|
|
fccd2629d4 | ||
|
|
bac745845b | ||
|
|
545376b1be | ||
|
|
7ef70e7943 | ||
|
|
5ce91fa96d | ||
|
|
829291feba | ||
|
|
bd9b38cd65 | ||
|
|
5354b0cfd5 | ||
|
|
70afe71c82 | ||
|
|
5bb65e3fc3 | ||
|
|
261ae2efae | ||
|
|
5fec80a33a | ||
|
|
edaae0bc89 | ||
|
|
51fb905260 | ||
|
|
8414dea54c | ||
|
|
c0b7b8dd9b | ||
|
|
e638c13d9d | ||
|
|
2c07a0fe94 | ||
|
|
433f4baafa | ||
|
|
8f03d0ca6f | ||
|
|
c29daf006e | ||
|
|
ac151ae9e9 | ||
|
|
c5298eb6f0 | ||
|
|
1912428ed3 | ||
|
|
ba07bcc274 | ||
|
|
b5fbf29f21 | ||
|
|
661b4220ef | ||
|
|
1358a52eee | ||
|
|
b9acdc7d4c | ||
|
|
dfbccaeb7f | ||
|
|
d44aad062a | ||
|
|
f8e4ba3551 | ||
|
|
175df18401 | ||
|
|
edfd5243ff | ||
|
|
090f5f4db4 | ||
|
|
37e5143d73 | ||
|
|
a8e6f4fc92 | ||
|
|
8626215205 | ||
|
|
1dc08f4a25 | ||
|
|
c6503021c2 | ||
|
|
4eaa7137a0 | ||
|
|
e7eb467f4f | ||
|
|
0c77e4a659 | ||
|
|
e1adc07db0 | ||
|
|
144086c667 | ||
|
|
b2824e9145 | ||
|
|
a64941694f | ||
|
|
9bbfca3193 | ||
|
|
18c02d3673 | ||
|
|
659a338d26 | ||
|
|
4436b9b7ca | ||
|
|
3089b98a30 | ||
|
|
94882c48bc | ||
|
|
f7cb3da434 | ||
|
|
281fccb73b | ||
|
|
086f7d0da2 | ||
|
|
c5256dde85 | ||
|
|
1b2c6fff83 | ||
|
|
5f21ef14a4 | ||
|
|
4de4fa6685 | ||
|
|
680fbea853 | ||
|
|
29e6dcde2f | ||
|
|
0fee86bc3c | ||
|
|
b6a9f667ef | ||
|
|
7008d21fcf | ||
|
|
f05ce4d247 | ||
|
|
6445546ff9 | ||
|
|
672d824946 | ||
|
|
4d89d173f4 | ||
|
|
86064cf1c6 | ||
|
|
b60a697b86 | ||
|
|
3cea55cc40 | ||
|
|
f722725992 | ||
|
|
28875b5e76 | ||
|
|
a3040dfb05 | ||
|
|
d23b0593fb | ||
|
|
97700bbff6 | ||
|
|
b9a6f0060d | ||
|
|
4522fa98ac | ||
|
|
bf341731f0 | ||
|
|
b04e7760c2 | ||
|
|
f984bfc5b0 | ||
|
|
b251e122e2 | ||
|
|
4d1224ce29 | ||
|
|
746dcb2e3d | ||
|
|
5d86735a69 | ||
|
|
f4258ade45 | ||
|
|
40129d9a14 | ||
|
|
e7e6af1335 | ||
|
|
97f52ef2ff | ||
|
|
5737e89150 | ||
|
|
6af1309e2d | ||
|
|
042edd8bab | ||
|
|
0b7f3a75b5 | ||
|
|
0bb0df0960 | ||
|
|
64338d30c3 | ||
|
|
bda8efeb45 | ||
|
|
5a2529651c | ||
|
|
08a6d99334 | ||
|
|
c89ee87bd4 | ||
|
|
d8fc04ec2e | ||
|
|
42feeb1bd3 | ||
|
|
c2014e2cde | ||
|
|
29282dcac6 | ||
|
|
9219fa7053 | ||
|
|
2ec88ad433 | ||
|
|
691dbd5ac2 | ||
|
|
8b3f288018 | ||
|
|
7ca679350d | ||
|
|
b59672815f | ||
|
|
904d89aff8 | ||
|
|
39c654ae9d | ||
|
|
b1cbe44a05 | ||
|
|
f5bbda4c6e | ||
|
|
a54a69efcc | ||
|
|
abae59767c | ||
|
|
fce1f010b0 | ||
|
|
b445c2dcf1 | ||
|
|
9955abb9e7 |
11
.apple2
@@ -1,11 +0,0 @@
|
||||
speed = 1.00
|
||||
altspeed = 4.00
|
||||
disk path = /usr/local/games/apple2/disks
|
||||
color = interpolated
|
||||
video = 1X
|
||||
volume = 8
|
||||
caps lock = 1
|
||||
joystick = joy keypad
|
||||
system path = /usr/local/games/apple2/rom
|
||||
pc joystick parms = 128 128 255 1 255 1
|
||||
keypad joystick parms = 8 1
|
||||
3
.gitignore
vendored
@@ -51,9 +51,6 @@ src/rom.c
|
||||
src/x86/glue.S
|
||||
src/arm/glue.S
|
||||
|
||||
# sub{tree,module}
|
||||
src/rom
|
||||
|
||||
# generated binaries
|
||||
/apple2ix
|
||||
genfont
|
||||
|
||||
1
Android/.idea/.name
generated
@@ -1 +0,0 @@
|
||||
Android
|
||||
1
Android/.idea/compiler.xml
generated
@@ -11,6 +11,7 @@
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
|
||||
9
Android/.idea/copyright/deadc0de_org.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="Copyright (c) deadc0de.org" />
|
||||
<option name="keyword" value="Copyright" />
|
||||
<option name="allowReplaceKeyword" value="" />
|
||||
<option name="myName" value="deadc0de.org" />
|
||||
<option name="myLocal" value="true" />
|
||||
</copyright>
|
||||
</component>
|
||||
6
Android/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
4
Android/.idea/gradle.xml
generated
@@ -5,14 +5,14 @@
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="LOCAL" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.4" />
|
||||
<option name="gradleJvm" value="1.7" />
|
||||
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.14.1" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
49
Android/.idea/misc.xml
generated
@@ -27,25 +27,6 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
<profile-state>
|
||||
<expanded-state>
|
||||
<State>
|
||||
<id />
|
||||
</State>
|
||||
<State>
|
||||
<id>Spelling</id>
|
||||
</State>
|
||||
</expanded-state>
|
||||
<selected-state>
|
||||
<State>
|
||||
<id>Spelling</id>
|
||||
</State>
|
||||
</selected-state>
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
@@ -56,38 +37,10 @@
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="Copyright.UI">
|
||||
<settings>
|
||||
<last-edited>deadc0de.org</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>Android API 21 Platform</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
||||
2
Android/.idea/vcs.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="" />
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -13,7 +13,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -9,13 +9,9 @@
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
|
||||
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugAndroidTestSources</task>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
@@ -28,19 +24,21 @@
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
@@ -48,50 +46,63 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.1.0/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.1.0/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-23.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-23.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-23.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-media-compat-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-compat-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-core-ui-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-core-utils-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-fragment-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-vector-drawable-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="animated-vector-drawable-24.2.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,8 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "21.1.2"
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion '25.0.0'
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file("release2.keystore")
|
||||
@@ -22,13 +22,16 @@ android {
|
||||
jniDebuggable true
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.deadc0de.apple2ix.basic"
|
||||
minSdkVersion 10
|
||||
targetSdkVersion 23
|
||||
versionCode 13
|
||||
versionName "1.1.3"
|
||||
targetSdkVersion 24
|
||||
versionCode 21
|
||||
versionName "1.2.1"
|
||||
ndk {
|
||||
moduleName "apple2ix"
|
||||
}
|
||||
@@ -37,5 +40,5 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:23.1.0'
|
||||
compile 'com.android.support:appcompat-v7:24.2.0'
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="@xml/a2backupscheme"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name" >
|
||||
|
||||
@@ -21,7 +22,8 @@
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:windowSoftInputMode="adjustResize" >
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="stateHidden|adjustNothing" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -29,26 +31,23 @@
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.nib\\.gz" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.dsk\\.gz" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.do\\.gz" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.po\\.gz" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="file" /> <!-- catch-all since I can't get the following to work because ... Android -->
|
||||
<!--
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.nib" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.dsk" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.do" />
|
||||
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.po" />
|
||||
-->
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="apple2ix" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.deadc0de.apple2ix.Apple2DiskChooserActivity" />
|
||||
|
||||
<provider
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths"/>
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*/
|
||||
|
||||
package android.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class VerticalSeekBar extends SeekBar {
|
||||
|
||||
public VerticalSeekBar(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public VerticalSeekBar(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(h, w, oldh, oldw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
|
||||
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
|
||||
}
|
||||
|
||||
protected void onDraw(Canvas c) {
|
||||
c.rotate(-90);
|
||||
c.translate(-getHeight(), 0);
|
||||
super.onDraw(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (!isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
case MotionEvent.ACTION_UP:
|
||||
int i = 0;
|
||||
i = getMax() - (int) (getMax() * event.getY() / getHeight());
|
||||
setProgress(i);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setProgress(int progress) {
|
||||
super.setProgress(progress);
|
||||
onSizeChanged(getWidth(), getHeight(), 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,12 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView {
|
||||
|
||||
public String getSummary(final Apple2Activity activity);
|
||||
|
||||
public String getPrefDomain();
|
||||
|
||||
public String getPrefKey();
|
||||
|
||||
public Object getPrefDefault();
|
||||
|
||||
public View getView(final Apple2Activity activity, View convertView);
|
||||
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked);
|
||||
|
||||
@@ -14,9 +14,7 @@ package org.deadc0de.apple2ix;
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
@@ -27,22 +25,20 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
public class Apple2Activity extends Activity {
|
||||
public class Apple2Activity extends Activity implements Apple2DiskChooserActivity.Callback {
|
||||
|
||||
private final static String TAG = "Apple2Activity";
|
||||
|
||||
private static volatile boolean DEBUG_STRICT = false;
|
||||
|
||||
private Apple2View mView = null;
|
||||
private Runnable mGraphicsInitializedRunnable = null;
|
||||
private Apple2SplashScreen mSplashScreen = null;
|
||||
private Apple2MainMenu mMainMenu = null;
|
||||
private Apple2SettingsMenu mSettingsMenu = null;
|
||||
@@ -52,6 +48,9 @@ public class Apple2Activity extends Activity {
|
||||
private ArrayList<AlertDialog> mAlertDialogs = new ArrayList<AlertDialog>();
|
||||
|
||||
private AtomicBoolean mPausing = new AtomicBoolean(false);
|
||||
private AtomicBoolean mSwitchingToPortrait = new AtomicBoolean(false);
|
||||
|
||||
private static DiskArgs sDisksChosen = null;
|
||||
|
||||
// non-null if we failed to load/link the native code ... likely we are running on some bizarre 'droid variant
|
||||
private static Throwable sNativeBarfedThrowable = null;
|
||||
@@ -68,34 +67,33 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
public final static int REQUEST_PERMISSION_RWSTORE = 42;
|
||||
|
||||
|
||||
private static native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
|
||||
|
||||
private static native void nativeOnKeyDown(int keyCode, int metaState);
|
||||
|
||||
private static native void nativeOnKeyUp(int keyCode, int metaState);
|
||||
|
||||
private static native void nativeSaveState(String path);
|
||||
private static native void nativeSaveState(String saveStateJson);
|
||||
|
||||
private static native String nativeLoadState(String path);
|
||||
private static native String nativeStateExtractDiskPaths(String extractStateJson);
|
||||
|
||||
private static native void nativeEmulationResume();
|
||||
private static native String nativeLoadState(String loadStateJson);
|
||||
|
||||
private static native void nativeEmulationPause();
|
||||
private static native boolean nativeEmulationResume();
|
||||
|
||||
private static native boolean nativeEmulationPause();
|
||||
|
||||
private static native void nativeOnQuit();
|
||||
|
||||
private static native void nativeReboot();
|
||||
|
||||
private static native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
|
||||
|
||||
private static native void nativeEjectDisk(boolean driveA);
|
||||
private static native void nativeReboot(int resetState);
|
||||
|
||||
public final static boolean isNativeBarfed() {
|
||||
return sNativeBarfed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
if (Apple2Activity.DEBUG_STRICT && BuildConfig.DEBUG) {
|
||||
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
|
||||
.detectDiskReads()
|
||||
@@ -130,18 +128,26 @@ public class Apple2Activity extends Activity {
|
||||
int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
|
||||
Log.d(TAG, "Device sampleRate:" + sampleRate + " mono bufferSize:" + monoBufferSize + " stereo bufferSize:" + stereoBufferSize);
|
||||
|
||||
String dataDir = Apple2DisksMenu.getDataDir(this);
|
||||
String dataDir = Apple2Utils.getDataDir(this);
|
||||
nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize);
|
||||
|
||||
final boolean firstTime = (Apple2Preferences.EMULATOR_VERSION.intValue(this) != BuildConfig.VERSION_CODE);
|
||||
if (firstTime) {
|
||||
// allow for primitive migrations as needed
|
||||
Apple2Preferences.EMULATOR_VERSION.saveInt(this, BuildConfig.VERSION_CODE);
|
||||
Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME);
|
||||
}
|
||||
// NOTE: ordering here is important!
|
||||
Apple2Preferences.load(this);
|
||||
final boolean firstTime = Apple2Preferences.migrate(this);
|
||||
mSwitchingToPortrait.set(false);
|
||||
boolean switchingToPortrait = Apple2VideoSettingsMenu.SETTINGS.applyLandscapeMode(this);
|
||||
Apple2Preferences.sync(this, null);
|
||||
|
||||
Apple2DisksMenu.insertDisk(this, new DiskArgs((String) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A)), /*driveA:*/true, /*isReadOnly:*/(boolean) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO), /*onLaunch:*/true);
|
||||
Apple2DisksMenu.insertDisk(this, new DiskArgs((String) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B)), /*driveA:*/false, /*isReadOnly:*/(boolean) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO), /*onLaunch:*/true);
|
||||
|
||||
showSplashScreen(!firstTime);
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this);
|
||||
|
||||
// Is there a way to persist the user orientation setting such that we launch in the previously set orientation and avoid getting multiple onCreate() onResume()?! ... Android lifecycle edge cases are so damn kludgishly annoying ...
|
||||
mSwitchingToPortrait.set(switchingToPortrait);
|
||||
if (!switchingToPortrait) {
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this);
|
||||
}
|
||||
|
||||
boolean extperm = true;
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
@@ -164,25 +170,15 @@ public class Apple2Activity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
mGraphicsInitializedRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (firstTime) {
|
||||
Apple2Preferences.KeypadPreset.IJKM_SPACE.apply(Apple2Activity.this);
|
||||
}
|
||||
Apple2Preferences.loadPreferences(Apple2Activity.this);
|
||||
}
|
||||
};
|
||||
|
||||
// first-time initializations
|
||||
final boolean externalStoragePermission = extperm;
|
||||
if (firstTime) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Apple2DisksMenu.exposeAPKAssets(Apple2Activity.this);
|
||||
Apple2Utils.exposeAPKAssets(Apple2Activity.this);
|
||||
if (externalStoragePermission) {
|
||||
Apple2DisksMenu.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||
}
|
||||
mSplashScreen.setDismissable(true);
|
||||
Log.d(TAG, "Finished first time copying...");
|
||||
@@ -192,17 +188,15 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
mSettingsMenu = new Apple2SettingsMenu(this);
|
||||
mDisksMenu = new Apple2DisksMenu(this);
|
||||
}
|
||||
|
||||
Intent intent = getIntent();
|
||||
String path = null;
|
||||
if (intent != null) {
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
path = data.getPath();
|
||||
}
|
||||
}
|
||||
if (path != null && Apple2DisksMenu.hasDiskExtension(path)) {
|
||||
handleInsertDiskIntent(path);
|
||||
@Override
|
||||
public void onDisksChosen(DiskArgs args) {
|
||||
final String name = args.name;
|
||||
if (Apple2DisksMenu.hasDiskExtension(name) || Apple2DisksMenu.hasStateExtension(name)) {
|
||||
sDisksChosen = args;
|
||||
} else if (!name.equals("")) {
|
||||
Toast.makeText(this, R.string.disk_insert_toast_cannot, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,8 +212,9 @@ public class Apple2Activity extends Activity {
|
||||
}
|
||||
}
|
||||
if (grantedPermissions) {
|
||||
// this will force copying APK files (now that we have permission
|
||||
Apple2DisksMenu.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||
// perform migration(s) and assets exposure now
|
||||
Apple2Utils.migrateToExternalStorage(Apple2Activity.this);
|
||||
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||
} // else ... we keep nagging on app startup ...
|
||||
} else {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
@@ -229,14 +224,63 @@ public class Apple2Activity extends Activity {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (sNativeBarfed) {
|
||||
Apple2CrashHandler.getInstance().abandonAllHope(this, sNativeBarfedThrowable);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "onResume()");
|
||||
showSplashScreen(/*dismissable:*/true);
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
|
||||
do {
|
||||
if (sNativeBarfed) {
|
||||
Apple2CrashHandler.getInstance().abandonAllHope(this, sNativeBarfedThrowable);
|
||||
break;
|
||||
}
|
||||
|
||||
Log.d(TAG, "onResume()");
|
||||
showSplashScreen(/*dismissable:*/true);
|
||||
if (!mSwitchingToPortrait.get()) {
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
|
||||
}
|
||||
|
||||
if (mDisksMenu == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sDisksChosen == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
DiskArgs args = sDisksChosen;
|
||||
sDisksChosen = null;
|
||||
|
||||
if (args.pfd == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
String name = args.name;
|
||||
|
||||
if (Apple2DisksMenu.hasStateExtension(name)) {
|
||||
boolean restored = Apple2MainMenu.restoreEmulatorState(this, args);
|
||||
dismissAllMenus();
|
||||
if (!restored) {
|
||||
Toast.makeText(this, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
final String[] prefices = {"content://com.android.externalstorage.documents/document", "content://com.android.externalstorage.documents", "content://com.android.externalstorage.documents", "content://"};
|
||||
for (String prefix : prefices) {
|
||||
if (name.startsWith(prefix)) {
|
||||
name = name.substring(prefix.length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// strip out URL-encoded '/' directory separators
|
||||
String nameLower = name.toLowerCase();
|
||||
int idx = nameLower.lastIndexOf("%2f", /*fromIndex:*/name.length() - 3);
|
||||
if (idx >= 0) {
|
||||
name = name.substring(idx + 3);
|
||||
}
|
||||
|
||||
mDisksMenu.showDiskInsertionAlertDialog(name, args);
|
||||
|
||||
} while (false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -251,6 +295,12 @@ public class Apple2Activity extends Activity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmulationPaused()) {
|
||||
Apple2Preferences.save(this);
|
||||
} else {
|
||||
Log.d(TAG, "Letting native save preferences...");
|
||||
}
|
||||
|
||||
Log.d(TAG, "onPause()");
|
||||
if (mView != null) {
|
||||
mView.onPause();
|
||||
@@ -260,7 +310,8 @@ public class Apple2Activity extends Activity {
|
||||
// Dismiss these popups to avoid android.view.WindowLeaked issues
|
||||
synchronized (this) {
|
||||
dismissAllMenus();
|
||||
nativeEmulationPause();
|
||||
dismissAllMenus(); // 2nd time should full exit calibration mode (if present)
|
||||
pauseEmulation();
|
||||
}
|
||||
|
||||
mPausing.set(false);
|
||||
@@ -324,59 +375,6 @@ public class Apple2Activity extends Activity {
|
||||
return mSettingsMenu;
|
||||
}
|
||||
|
||||
private void handleInsertDiskIntent(final String path) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (Apple2Activity.this) {
|
||||
if (mMainMenu == null) {
|
||||
return;
|
||||
}
|
||||
String diskPath = path;
|
||||
File diskFile = new File(diskPath);
|
||||
if (!diskFile.canRead()) {
|
||||
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_could_not_read), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(Apple2Activity.this, true);
|
||||
final int len = diskPath.length();
|
||||
final String suffix = diskPath.substring(len - 3, len);
|
||||
if (suffix.equalsIgnoreCase(".gz")) { // HACK FIXME TODO : small amount of code duplication of Apple2DisksMenu
|
||||
diskPath = diskPath.substring(0, len - 3);
|
||||
}
|
||||
Apple2Preferences.CURRENT_DISK_A.saveString(Apple2Activity.this, diskPath);
|
||||
|
||||
while (mDisksMenu.popPathStack() != null) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
File storageDir = Apple2DisksMenu.getExternalStorageDirectory(Apple2Activity.this);
|
||||
if (storageDir != null) {
|
||||
String storagePath = storageDir.getAbsolutePath();
|
||||
if (diskPath.contains(storagePath)) {
|
||||
diskPath = diskPath.replace(storagePath + File.separator, "");
|
||||
mDisksMenu.pushPathStack(storagePath);
|
||||
}
|
||||
}
|
||||
StringTokenizer tokenizer = new StringTokenizer(diskPath, File.separator);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
if (token.equals("")) {
|
||||
continue;
|
||||
}
|
||||
if (Apple2DisksMenu.hasDiskExtension(token)) {
|
||||
continue;
|
||||
}
|
||||
mDisksMenu.pushPathStack(token);
|
||||
}
|
||||
|
||||
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_toast), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Apple2SplashScreen getSplashScreen() {
|
||||
return mSplashScreen;
|
||||
}
|
||||
@@ -385,6 +383,7 @@ public class Apple2Activity extends Activity {
|
||||
if (mSplashScreen != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSplashScreen = new Apple2SplashScreen(this, dismissable);
|
||||
mSplashScreen.show();
|
||||
}
|
||||
@@ -394,8 +393,7 @@ public class Apple2Activity extends Activity {
|
||||
boolean glViewFirstTime = false;
|
||||
if (mView == null) {
|
||||
glViewFirstTime = true;
|
||||
mView = new Apple2View(this, mGraphicsInitializedRunnable);
|
||||
mGraphicsInitializedRunnable = null;
|
||||
mView = new Apple2View(this);
|
||||
mMainMenu = new Apple2MainMenu(this, mView);
|
||||
}
|
||||
|
||||
@@ -416,7 +414,7 @@ public class Apple2Activity extends Activity {
|
||||
//
|
||||
mMenuStack.add(apple2MenuView);
|
||||
View menuView = apple2MenuView.getView();
|
||||
nativeEmulationPause();
|
||||
pauseEmulation();
|
||||
addContentView(menuView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
@@ -490,7 +488,7 @@ public class Apple2Activity extends Activity {
|
||||
if (dismissedSplashScreen) {
|
||||
setupGLView();
|
||||
} else {
|
||||
nativeEmulationResume();
|
||||
maybeResumeEmulation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,32 +502,32 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
public void maybeResumeEmulation() {
|
||||
if (mMenuStack.size() == 0 && !mPausing.get()) {
|
||||
Apple2Preferences.sync(this, null);
|
||||
nativeEmulationResume();
|
||||
}
|
||||
}
|
||||
|
||||
public void pauseEmulation() {
|
||||
nativeEmulationPause();
|
||||
boolean previouslyRunning = nativeEmulationPause();
|
||||
if (previouslyRunning) {
|
||||
Apple2Preferences.load(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void rebootEmulation() {
|
||||
nativeReboot();
|
||||
public void rebootEmulation(int resetState) {
|
||||
nativeReboot(resetState);
|
||||
}
|
||||
|
||||
public void saveState(String stateFile) {
|
||||
nativeSaveState(stateFile);
|
||||
public void saveState(String saveStateJson) {
|
||||
nativeSaveState(saveStateJson);
|
||||
}
|
||||
|
||||
public String loadState(String stateFile) {
|
||||
return Apple2Activity.nativeLoadState(stateFile);
|
||||
public String stateExtractDiskPaths(String extractStateJson) {
|
||||
return nativeStateExtractDiskPaths(extractStateJson);
|
||||
}
|
||||
|
||||
public void chooseDisk(String path, boolean driveA, boolean readOnly) {
|
||||
nativeChooseDisk(path, driveA, readOnly);
|
||||
}
|
||||
|
||||
public void ejectDisk(boolean driveA) {
|
||||
nativeEjectDisk(driveA);
|
||||
public String loadState(String loadStateJson) {
|
||||
return nativeLoadState(loadStateJson);
|
||||
}
|
||||
|
||||
public void quitEmulator() {
|
||||
|
||||
@@ -17,13 +17,19 @@ import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONArray;
|
||||
|
||||
public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "Apple2AudioSettingsMenu";
|
||||
|
||||
public final static int AUDIO_LATENCY_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
|
||||
private static int sSampleRateCanary = 0;
|
||||
|
||||
public Apple2AudioSettingsMenu(Apple2Activity activity) {
|
||||
super(activity);
|
||||
sSampleRateCanary = DevicePropertyCalculator.getRecommendedSampleRate(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,6 +55,27 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
return position == SETTINGS.MOCKINGBOARD_ENABLED.ordinal();
|
||||
}
|
||||
|
||||
public enum Volume {
|
||||
OFF(0),
|
||||
ONE(1),
|
||||
TWO(2),
|
||||
THREE(3),
|
||||
FOUR(4),
|
||||
MEDIUM(5),
|
||||
FIVE(5),
|
||||
SIX(6),
|
||||
SEVEN(7),
|
||||
EIGHT(8),
|
||||
NINE(9),
|
||||
MAX(10),
|
||||
ELEVEN(11); // Ours goes to eleven...
|
||||
private int vol;
|
||||
|
||||
Volume(int vol) {
|
||||
this.vol = vol;
|
||||
}
|
||||
}
|
||||
|
||||
enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
SPEAKER_VOLUME {
|
||||
@Override
|
||||
@@ -61,17 +88,28 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.speaker_volume_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "speakerVolume";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return Volume.MEDIUM.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.Volume.MAX.ordinal() - 1, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, Volume.MAX.ordinal() - 1, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.SPEAKER_VOLUME.saveVolume(activity, Apple2Preferences.Volume.values()[progress]);
|
||||
Apple2Preferences.setJSONPref(self, Volume.values()[progress].ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.SPEAKER_VOLUME.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,14 +130,25 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.mockingboard_enable_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "mbEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.MOCKINGBOARD_ENABLED.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.MOCKINGBOARD_ENABLED.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
@@ -116,17 +165,28 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.mockingboard_volume_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "mbVolume";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return Volume.MEDIUM.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.Volume.MAX.ordinal() - 1, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, Volume.MAX.ordinal() - 1, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.MOCKINGBOARD_VOLUME.saveVolume(activity, Apple2Preferences.Volume.values()[progress]);
|
||||
Apple2Preferences.setJSONPref(self, Volume.values()[progress].ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.MOCKINGBOARD_VOLUME.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,26 +218,46 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.audio_latency_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "audioLatency";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
int defaultLatency;
|
||||
if (Apple2AudioSettingsMenu.sSampleRateCanary == DevicePropertyCalculator.defaultSampleRate) {
|
||||
// quite possibly an audio-challenged device
|
||||
defaultLatency = 8; // /AUDIO_LATENCY_NUM_CHOICES -> 0.4f
|
||||
} else {
|
||||
// reasonable default for high-end devices
|
||||
defaultLatency = 5; // /AUDIO_LATENCY_NUM_CHOICES -> 0.25f
|
||||
}
|
||||
return ((float) defaultLatency) / AUDIO_LATENCY_NUM_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.AUDIO_LATENCY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, AUDIO_LATENCY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
if (progress == 0) {
|
||||
// disallow 0-length buffer ...
|
||||
progress = 1;
|
||||
}
|
||||
Apple2Preferences.AUDIO_LATENCY.saveInt(activity, progress);
|
||||
Apple2Preferences.setJSONPref(self, ((float) progress) / AUDIO_LATENCY_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.AUDIO_LATENCY.intValue(activity);
|
||||
float pref = Apple2Preferences.getFloatJSONPref(self);
|
||||
return (int) (pref * AUDIO_LATENCY_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
seekBarValue.setText("" + ((float) progress / Apple2Preferences.AUDIO_LATENCY_NUM_CHOICES));
|
||||
seekBarValue.setText("" + ((float) progress / AUDIO_LATENCY_NUM_CHOICES));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -185,9 +265,23 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_AUDIO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,21 +14,22 @@ package org.deadc0de.apple2ix;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
@@ -43,6 +44,67 @@ public class Apple2CrashHandler {
|
||||
return sCrashHandler;
|
||||
}
|
||||
|
||||
public enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
GL_VENDOR {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "glVendor";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return "unknown";
|
||||
}
|
||||
},
|
||||
GL_RENDERER {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "glRenderer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return "unknown";
|
||||
}
|
||||
},
|
||||
GL_VERSION {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "glVersion";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public enum CrashType {
|
||||
JAVA_CRASH {
|
||||
@Override
|
||||
@@ -67,6 +129,18 @@ public class Apple2CrashHandler {
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_stackbuf_overflow);
|
||||
}
|
||||
},
|
||||
SIGABRT {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_sigabrt);
|
||||
}
|
||||
},
|
||||
SIGFPE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_sigfpe);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -87,7 +161,7 @@ public class Apple2CrashHandler {
|
||||
public synchronized void initializeAndSetCustomExceptionHandler(Apple2Activity activity) {
|
||||
synchronized (this) {
|
||||
if (homeDir == null) {
|
||||
homeDir = Apple2DisksMenu.getDataDir(activity);
|
||||
homeDir = Apple2Utils.getDataDir(activity);
|
||||
}
|
||||
}
|
||||
if (mDefaultExceptionHandler != null) {
|
||||
@@ -135,7 +209,8 @@ public class Apple2CrashHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Apple2Preferences.CRASH_CHECK.booleanValue(activity)) {
|
||||
Apple2Preferences.load(activity);
|
||||
if (!(boolean) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CRASH)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,7 +242,9 @@ public class Apple2CrashHandler {
|
||||
}
|
||||
|
||||
// remove previous log file
|
||||
_writeTempLogFile(activity, new StringBuilder());
|
||||
File allCrashFile = _getCrashFile(activity);
|
||||
Apple2Utils.writeFile(new StringBuilder(), allCrashFile);
|
||||
allCrashFile.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -214,9 +291,16 @@ public class Apple2CrashHandler {
|
||||
summary.append("SAMPLE RATE: ").append(sampleRate).append("\n");
|
||||
summary.append("MONO BUFSIZE: ").append(monoBufferSize).append("\n");
|
||||
summary.append("STEREO BUFSIZE: ").append(stereoBufferSize).append("\n");
|
||||
summary.append("GPU VENDOR: ").append(Apple2Preferences.GL_VENDOR.stringValue(activity)).append("\n");
|
||||
summary.append("GPU RENDERER: ").append(Apple2Preferences.GL_RENDERER.stringValue(activity)).append("\n");
|
||||
summary.append("GPU VERSION: ").append(Apple2Preferences.GL_VERSION.stringValue(activity)).append("\n");
|
||||
summary.append("GPU VENDOR: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_VENDOR)).append("\n");
|
||||
summary.append("GPU RENDERER: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_RENDERER)).append("\n");
|
||||
summary.append("GPU VERSION: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_VERSION)).append("\n");
|
||||
|
||||
try {
|
||||
PackageInfo pInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
|
||||
summary.append("APP VERSION: ").append(pInfo.versionName).append("\n");
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ...
|
||||
}
|
||||
|
||||
allCrashData.append(summary);
|
||||
|
||||
@@ -237,7 +321,7 @@ public class Apple2CrashHandler {
|
||||
});
|
||||
|
||||
if (len > 0) {
|
||||
Apple2DisksMenu.exposeSymbols(activity);
|
||||
Apple2Utils.exposeSymbols(activity);
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@@ -265,7 +349,7 @@ public class Apple2CrashHandler {
|
||||
}
|
||||
|
||||
StringBuilder crashData = new StringBuilder();
|
||||
if (!_readFile(new File(processedPath), crashData)) {
|
||||
if (!Apple2Utils.readEntireFile(new File(processedPath), crashData)) {
|
||||
Log.e(TAG, "Error processing crash : " + crashPath);
|
||||
}
|
||||
allCrashData.append(">>>>>>> NATIVE CRASH [").append(crashPath).append("]\n");
|
||||
@@ -327,7 +411,7 @@ public class Apple2CrashHandler {
|
||||
File javaCrashFile = _javaCrashFile(activity);
|
||||
if (javaCrashFile.exists()) {
|
||||
Log.d(TAG, "Reading java crashes file");
|
||||
if (!_readFile(javaCrashFile, javaCrashData)) {
|
||||
if (!Apple2Utils.readEntireFile(javaCrashFile, javaCrashData)) {
|
||||
Log.e(TAG, "Error processing java crash : " + javaCrashFileName);
|
||||
}
|
||||
}
|
||||
@@ -347,7 +431,23 @@ public class Apple2CrashHandler {
|
||||
}
|
||||
});
|
||||
|
||||
Apple2DisksMenu.unexposeSymbols(activity);
|
||||
StringBuilder jsonData = new StringBuilder();
|
||||
if (Apple2Utils.readEntireFile(new File(homeDir, Apple2Preferences.PREFS_FILE), jsonData)) {
|
||||
JSONObject obj = null;
|
||||
try {
|
||||
obj = new JSONObject(jsonData.toString());
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "Error reading preferences : " + e);
|
||||
}
|
||||
if (obj != null) {
|
||||
summary.append("PREFS:\n");
|
||||
summary.append(obj.toString());
|
||||
allCrashData.append(">>>>>>> PREFS\n");
|
||||
allCrashData.append(obj.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Apple2Utils.unexposeSymbols(activity);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -456,76 +556,15 @@ public class Apple2CrashHandler {
|
||||
return crashPath.substring(0, crashPath.length() - 4) + ".txt";
|
||||
}
|
||||
|
||||
private boolean _readFile(File file, StringBuilder fileData) {
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
char[] buf = new char[1024];
|
||||
int numRead = 0;
|
||||
while ((numRead = reader.read(buf)) != -1) {
|
||||
String readData = String.valueOf(buf, 0, numRead);
|
||||
fileData.append(readData);
|
||||
}
|
||||
reader.close();
|
||||
break;
|
||||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Error reading file at path : " + file.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException e) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
return attempts < maxAttempts;
|
||||
}
|
||||
|
||||
private File _writeTempLogFile(Apple2Activity activity, StringBuilder allCrashData) {
|
||||
|
||||
File allCrashFile = null;
|
||||
|
||||
private File _getCrashFile(Apple2Activity activity) {
|
||||
File allCrashFile;
|
||||
String storageState = Environment.getExternalStorageState();
|
||||
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
|
||||
allCrashFile = new File(Environment.getExternalStorageDirectory(), "apple2ix_crash.txt");
|
||||
} else {
|
||||
allCrashFile = new File(Apple2DisksMenu.getDataDir(activity), "apple2ix_crash.txt");
|
||||
allCrashFile = new File(Apple2Utils.getDataDir(activity), "apple2ix_crash.txt");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Writing all crashes to temp file : " + allCrashFile.getAbsolutePath());
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(allCrashFile));
|
||||
writer.append(allCrashData);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
break;
|
||||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception attempting to write data : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException e) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
if (!allCrashFile.setReadable(true, /*ownerOnly:*/false)) {
|
||||
Log.d(TAG, "Oops, could not set all crash data readable!");
|
||||
}
|
||||
|
||||
return allCrashFile;
|
||||
}
|
||||
|
||||
@@ -544,9 +583,14 @@ public class Apple2CrashHandler {
|
||||
int len = summary.length();
|
||||
len = len < maxCharsEmail ? len : maxCharsEmail;
|
||||
String summaryData = summary.substring(0, len);
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, "The app crashed, please help!\n\n"+summaryData);
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, "The app crashed, please help!\n\n" + summaryData);
|
||||
|
||||
File allCrashFile = _getCrashFile(activity);
|
||||
Apple2Utils.writeFile(allCrashData, allCrashFile);
|
||||
if (!allCrashFile.setReadable(true, /*ownerOnly:*/false)) {
|
||||
Log.d(TAG, "Oops, could not set file data readable!");
|
||||
}
|
||||
|
||||
File allCrashFile = _writeTempLogFile(activity, allCrashData);
|
||||
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(allCrashFile));
|
||||
|
||||
Log.d(TAG, "STARTING CHOOSER FOR EMAIL ...");
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2017 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Apple2DiskChooserActivity extends Activity {
|
||||
|
||||
public static final AtomicBoolean sDiskChooserIsChoosing = new AtomicBoolean(false);
|
||||
public static Callback sDisksCallback;
|
||||
|
||||
public interface Callback {
|
||||
void onDisksChosen(DiskArgs args);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ParcelFileDescriptor openFileDescriptorFromUri(Context ctx, Uri uri) {
|
||||
|
||||
ParcelFileDescriptor pfd = null;
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
throw new RuntimeException("SDK Version not allowed access");
|
||||
}
|
||||
|
||||
if (!DocumentsContract.isDocumentUri(ctx, uri)) {
|
||||
throw new RuntimeException("Not a Document URI for " + uri);
|
||||
}
|
||||
|
||||
ContentResolver resolver = ctx.getContentResolver();
|
||||
resolver.takePersistableUriPermission(uri, (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
|
||||
pfd = resolver.openFileDescriptor(uri, "rw");
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "OOPS, could not get appropriate access to URI ( " + uri + " ) : " + t);
|
||||
}
|
||||
|
||||
return pfd;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putBoolean("ran", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
|
||||
Bundle b;
|
||||
{
|
||||
Intent intent = getIntent();
|
||||
Bundle extras = null;
|
||||
if (intent != null) {
|
||||
extras = intent.getExtras();
|
||||
}
|
||||
|
||||
if (savedState != null) {
|
||||
b = savedState;
|
||||
} else if (extras != null) {
|
||||
b = extras;
|
||||
} else {
|
||||
b = new Bundle();
|
||||
}
|
||||
}
|
||||
|
||||
boolean ran = b.getBoolean("ran");
|
||||
if (ran) {
|
||||
Log.e(TAG, "OOPS, already ran...");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
////Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
Intent pickIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
|
||||
try {
|
||||
pickIntent.setType("*/*");
|
||||
pickIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
/* FIXME TODO : currently we don't have decent UI/UX for multi-select ...
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
pickIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}*/
|
||||
|
||||
if (!ran) {
|
||||
startActivityForResult(pickIntent, EDIT_REQUEST_CODE);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "OOPS : " + t);
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (resultCode != RESULT_CANCELED) {
|
||||
|
||||
/* FIXME TODO : currently we don't have decent UI/UX for multi-select ...
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
|
||||
ClipData clipData = null;
|
||||
if (data != null) {
|
||||
clipData = data.getClipData();
|
||||
}
|
||||
|
||||
if (clipData != null && clipData.getItemCount() > 1) {
|
||||
uris = new Uri[2];
|
||||
uris[0] = clipData.getItemAt(0).getUri();
|
||||
uris[1] = clipData.getItemAt(1).getUri();
|
||||
}
|
||||
}*/
|
||||
|
||||
if (chosenUri == null) {
|
||||
if (data != null) {
|
||||
chosenUri = data.getData();
|
||||
}
|
||||
}
|
||||
|
||||
if (chosenUri != null) {
|
||||
chosenPfd = openFileDescriptorFromUri(this, chosenUri);
|
||||
}
|
||||
}
|
||||
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
sDiskChooserIsChoosing.set(false);
|
||||
String name = chosenUri == null ? "" : chosenUri.toString();
|
||||
if (sDisksCallback != null) {
|
||||
sDisksCallback.onDisksChosen(new DiskArgs(name, chosenUri, chosenPfd));
|
||||
}
|
||||
super.finish();
|
||||
}
|
||||
|
||||
private Uri chosenUri;
|
||||
|
||||
private ParcelFileDescriptor chosenPfd;
|
||||
|
||||
private static final String TAG = "A2DiskChooserActivity";
|
||||
|
||||
private static final int EDIT_REQUEST_CODE = 44;
|
||||
}
|
||||
|
||||
class DiskArgs {
|
||||
public String name;
|
||||
public String path;
|
||||
public Uri uri;
|
||||
public ParcelFileDescriptor pfd;
|
||||
|
||||
public DiskArgs(String name, Uri uri, ParcelFileDescriptor pfd) {
|
||||
this.name = name;
|
||||
this.uri = uri;
|
||||
this.pfd = pfd;
|
||||
}
|
||||
|
||||
public DiskArgs(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,10 @@ package org.deadc0de.apple2ix;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Environment;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -26,43 +25,161 @@ import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Apple2DisksMenu implements Apple2MenuView {
|
||||
|
||||
private final static String TAG = "Apple2DisksMenu";
|
||||
private static String sDataDir = null;
|
||||
|
||||
public final static String EXTERNAL_CHOOSER_SENTINEL = "apple2ix://";
|
||||
|
||||
private Apple2Activity mActivity = null;
|
||||
private View mDisksView = null;
|
||||
|
||||
private final ArrayList<String> mPathStack = new ArrayList<String>();
|
||||
|
||||
private static File sExternalFilesDir = null;
|
||||
private static File sDownloadFilesDir = null;
|
||||
private static boolean sInitializedPath = false;
|
||||
|
||||
private static native String nativeChooseDisk(String jsonData);
|
||||
|
||||
private static native void nativeEjectDisk(boolean isDriveA);
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
CURRENT_DISK_SEARCH_PATH {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "diskPathStack";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return new JSONArray();
|
||||
}
|
||||
},
|
||||
CURRENT_DRIVE_A {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "driveACurrent";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_RO_BUTTON {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "driveRO";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_PATH_A {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "driveAInsertedDisk";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_PATH_A_RO {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "driveAInsertedDiskRO";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_PATH_B {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "driveBInsertedDisk";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_PATH_B_RO {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "driveBInsertedDiskRO";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
USE_NEWSCHOOL_DISK_SELECTION {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "useNewSchoolDiskSelection";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
// 2017/06/30 NOTE : keep this default false to accommodate initial installs that only have access to shipped public domain images
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_VM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public Apple2DisksMenu(Apple2Activity activity) {
|
||||
mActivity = activity;
|
||||
|
||||
@@ -77,150 +194,45 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
}
|
||||
});
|
||||
|
||||
getExternalStorageDirectory(activity);
|
||||
}
|
||||
|
||||
public static File getExternalStorageDirectory(Apple2Activity activity) {
|
||||
|
||||
do {
|
||||
if (sExternalFilesDir != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
String storageState = Environment.getExternalStorageState();
|
||||
if (!storageState.equals(Environment.MEDIA_MOUNTED)) {
|
||||
// 2015/10/28 : do not expose sExternalFilesDir/sDownloadFilesDir unless they are writable
|
||||
break;
|
||||
}
|
||||
|
||||
File externalStorageDir = Environment.getExternalStorageDirectory();
|
||||
if (externalStorageDir == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
File externalDir = new File(externalStorageDir, "apple2ix"); // /sdcard/apple2ix
|
||||
if (!externalDir.exists()) {
|
||||
boolean made = externalDir.mkdirs();
|
||||
if (!made) {
|
||||
Log.d(TAG, "WARNING: could not make directory : " + sExternalFilesDir);
|
||||
break;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final Button ejectButton = (Button) mDisksView.findViewById(i == 0 ? R.id.ejectButton1 : R.id.ejectButton2);
|
||||
final int idx = i;
|
||||
ejectButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ejectDisk(/*isDriveA:*/idx == 0);
|
||||
dynamicSetup();
|
||||
}
|
||||
}
|
||||
|
||||
sExternalFilesDir = externalDir;
|
||||
sDownloadFilesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
} while (false);
|
||||
|
||||
return sExternalFilesDir;
|
||||
}
|
||||
|
||||
// HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources
|
||||
// out of the APK and into the /data/data/... for ease of access. Because this is FOSS software we don't care about
|
||||
// security or DRM for these assets =)
|
||||
public static String getDataDir(Apple2Activity activity) {
|
||||
|
||||
if (sDataDir != null) {
|
||||
return sDataDir;
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
PackageManager pm = activity.getPackageManager();
|
||||
PackageInfo pi = pm.getPackageInfo(activity.getPackageName(), 0);
|
||||
sDataDir = pi.applicationInfo.dataDir;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "" + e);
|
||||
if (sDataDir == null) {
|
||||
sDataDir = "/data/local/tmp";
|
||||
}
|
||||
}
|
||||
|
||||
return sDataDir;
|
||||
}
|
||||
|
||||
public static void exposeAPKAssetsToExternal(Apple2Activity activity) {
|
||||
getExternalStorageDirectory(activity);
|
||||
if (sExternalFilesDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
final CheckBox newschoolSelection = (CheckBox) mDisksView.findViewById(R.id.newschoolDiskSelectionButton);
|
||||
newschoolSelection.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
bar.setIndeterminate(true);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #1");
|
||||
}
|
||||
public void onClick(View v) {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION, newschoolSelection.isChecked());
|
||||
dynamicSetup();
|
||||
}
|
||||
});
|
||||
|
||||
Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ...");
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath(), false);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
final View newschoolChooser = mDisksView.findViewById(R.id.disk_selection_newschool_chooser);
|
||||
newschoolChooser.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #2");
|
||||
public void onClick(View v) {
|
||||
final boolean alreadyChoosing = Apple2DiskChooserActivity.sDiskChooserIsChoosing.getAndSet(true);
|
||||
if (alreadyChoosing) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void exposeAPKAssets(Apple2Activity activity) {
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
bar.setIndeterminate(true);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
Intent chooserIntent = new Intent(mActivity, Apple2DiskChooserActivity.class);
|
||||
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION/* | Intent.FLAG_ACTIVITY_CLEAR_TOP */);
|
||||
|
||||
Apple2DiskChooserActivity.sDisksCallback = mActivity;
|
||||
mActivity.startActivity(chooserIntent);
|
||||
}
|
||||
});
|
||||
|
||||
getDataDir(activity);
|
||||
|
||||
// FIXME TODO : Heavy-handed migration to 1.1.3 ...
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "blanks"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "demo"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "eamon"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "logo"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "miscgame"));
|
||||
|
||||
Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access...");
|
||||
|
||||
getExternalStorageDirectory(activity);
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath(), true);
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath(), false);
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath(), false);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void exposeSymbols(Apple2Activity activity) {
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"symbols", /*to location:*/new File(sDataDir, "symbols").getAbsolutePath(), false);
|
||||
}
|
||||
|
||||
public static void unexposeSymbols(Apple2Activity activity) {
|
||||
recursivelyDelete(new File(sDataDir, "symbols"));
|
||||
Apple2Utils.getExternalStorageDirectory(activity);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -240,14 +252,18 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
}
|
||||
if (!sInitializedPath) {
|
||||
sInitializedPath = true;
|
||||
Apple2Preferences.CURRENT_DISK_PATH.load(mActivity);
|
||||
setPathStackJSON((JSONArray) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_SEARCH_PATH));
|
||||
}
|
||||
dynamicSetup();
|
||||
mActivity.pushApple2View(this);
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
String path = popPathStack();
|
||||
String path = null;
|
||||
if (!(boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION)) {
|
||||
path = popPathStack();
|
||||
}
|
||||
|
||||
if (path == null) {
|
||||
mActivity.popApple2View(this);
|
||||
} else {
|
||||
@@ -272,15 +288,13 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
// ------------------------------------------------------------------------
|
||||
// path stack methods
|
||||
|
||||
public String getPathStackJSON() {
|
||||
JSONArray jsonArray = new JSONArray(Arrays.asList(mPathStack.toArray()));
|
||||
return jsonArray.toString();
|
||||
public JSONArray getPathStackJSON() {
|
||||
return new JSONArray(Arrays.asList(mPathStack.toArray()));
|
||||
}
|
||||
|
||||
public void setPathStackJSON(String pathStackJSON) {
|
||||
public void setPathStackJSON(JSONArray jsonArray) {
|
||||
mPathStack.clear();
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(pathStackJSON);
|
||||
for (int i = 0, count = jsonArray.length(); i < count; i++) {
|
||||
String pathComponent = jsonArray.getString(i);
|
||||
mPathStack.add(pathComponent);
|
||||
@@ -292,7 +306,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
|
||||
public void pushPathStack(String path) {
|
||||
mPathStack.add(path);
|
||||
Apple2Preferences.CURRENT_DISK_PATH.saveString(mActivity, getPathStackJSON());
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_SEARCH_PATH, getPathStackJSON());
|
||||
}
|
||||
|
||||
public String popPathStack() {
|
||||
@@ -300,10 +314,144 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
return null;
|
||||
}
|
||||
String path = mPathStack.remove(mPathStack.size() - 1);
|
||||
Apple2Preferences.CURRENT_DISK_PATH.saveString(mActivity, getPathStackJSON());
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_SEARCH_PATH, getPathStackJSON());
|
||||
return path;
|
||||
}
|
||||
|
||||
public static void insertDisk(Apple2Activity activity, DiskArgs diskArgs, boolean isDriveA, boolean isReadOnly, boolean onLaunch) {
|
||||
try {
|
||||
JSONObject map = new JSONObject();
|
||||
|
||||
ejectDisk(isDriveA);
|
||||
|
||||
String imageName = diskArgs.path;
|
||||
|
||||
if (imageName == null) {
|
||||
imageName = EXTERNAL_CHOOSER_SENTINEL + diskArgs.uri.toString();
|
||||
}
|
||||
|
||||
if (imageName.startsWith(EXTERNAL_CHOOSER_SENTINEL)) {
|
||||
if (!Apple2Utils.isExternalStorageAccessible(activity)) {
|
||||
// disallow access if we cannot access external storage
|
||||
throw new Exception("External storage not accessible");
|
||||
}
|
||||
if (diskArgs.pfd == null) {
|
||||
if (diskArgs.uri == null) {
|
||||
String uriString = imageName.substring(EXTERNAL_CHOOSER_SENTINEL.length());
|
||||
diskArgs.uri = Uri.parse(uriString);
|
||||
}
|
||||
diskArgs.pfd = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, diskArgs.uri);
|
||||
}
|
||||
|
||||
int fd = diskArgs.pfd.getFd(); // NPE thrown if diskArgs.pfd is null
|
||||
map.put("fd", fd);
|
||||
} else {
|
||||
File file = new File(imageName);
|
||||
if (!file.exists()) {
|
||||
throw new RuntimeException("cannot insert : " + imageName);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDriveA) {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A_RO, isReadOnly);
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, imageName);
|
||||
} else {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B_RO, isReadOnly);
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, imageName);
|
||||
}
|
||||
|
||||
map.put("disk", imageName);
|
||||
map.put("drive", isDriveA ? "0" : "1");
|
||||
map.put("readOnly", isReadOnly ? "true" : "false");
|
||||
|
||||
String jsonString = nativeChooseDisk(map.toString());
|
||||
|
||||
if (diskArgs.pfd != null) {
|
||||
try {
|
||||
diskArgs.pfd.close();
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Error attempting to close PFD : " + ioe);
|
||||
}
|
||||
}
|
||||
diskArgs.pfd = null;
|
||||
|
||||
map = new JSONObject(jsonString);
|
||||
boolean inserted = map.getBoolean("inserted");
|
||||
if (!inserted) {
|
||||
ejectDisk(isDriveA);
|
||||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
Log.d(TAG, "OOPS: " + t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ejectDisk(boolean isDriveA) {
|
||||
if (isDriveA) {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, "");
|
||||
} else {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, "");
|
||||
}
|
||||
nativeEjectDisk(isDriveA);
|
||||
}
|
||||
|
||||
public void showDiskInsertionAlertDialog(String title, final DiskArgs diskArgs) {
|
||||
|
||||
title = mActivity.getResources().getString(R.string.header_disks) + " " + title;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setCancelable(true).setMessage(title);
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
final View diskConfirmationView = inflater.inflate(R.layout.a2disk_confirmation, null, false);
|
||||
builder.setView(diskConfirmationView);
|
||||
|
||||
final RadioButton driveA = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskA);
|
||||
boolean driveAChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DRIVE_A);
|
||||
driveA.setChecked(driveAChecked);
|
||||
driveA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DRIVE_A, isChecked);
|
||||
}
|
||||
});
|
||||
final RadioButton driveB = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskB);
|
||||
driveB.setChecked(!driveAChecked);
|
||||
|
||||
final RadioButton readOnly = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readOnly);
|
||||
boolean roChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON);
|
||||
readOnly.setChecked(roChecked);
|
||||
readOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON, isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
|
||||
readWrite.setChecked(!roChecked);
|
||||
|
||||
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
boolean isDriveA = driveA.isChecked();
|
||||
boolean diskReadOnly = readOnly.isChecked();
|
||||
|
||||
insertDisk(mActivity, diskArgs, isDriveA, diskReadOnly, /*onLaunch:*/false);
|
||||
|
||||
dialog.dismiss();
|
||||
mActivity.dismissAllMenus();
|
||||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
mActivity.registerAndShowDialog(dialog);
|
||||
}
|
||||
|
||||
public static boolean hasDiskExtension(String name) {
|
||||
|
||||
// check file extensions ... sigh ... no String.endsWithIgnoreCase() ?
|
||||
@@ -345,6 +493,20 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
return (suffix.equalsIgnoreCase(".dsk.gz") || suffix.equalsIgnoreCase(".nib.gz"));
|
||||
}
|
||||
|
||||
public static boolean hasStateExtension(String name) {
|
||||
|
||||
// check file extensions ... sigh ... no String.endsWithIgnoreCase() ?
|
||||
|
||||
final int extLen = Apple2MainMenu.SAVE_FILE_EXTENSION.length();
|
||||
final int len = name.length();
|
||||
if (len <= extLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String suffix = name.substring(len - extLen, len);
|
||||
return suffix.equalsIgnoreCase(Apple2MainMenu.SAVE_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// internals ...
|
||||
|
||||
@@ -360,133 +522,99 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
return pathBuffer.toString();
|
||||
}
|
||||
|
||||
// TODO FIXME : WARNING : this is super dangerous if there are symlinks !!!
|
||||
private static void recursivelyDelete(File file) {
|
||||
if (file.isDirectory()) {
|
||||
for (File f : file.listFiles()) {
|
||||
recursivelyDelete(f);
|
||||
}
|
||||
}
|
||||
if (!file.delete()) {
|
||||
Log.d(TAG, "Failed to delete file: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void recursivelyCopyAPKAssets(Apple2Activity activity, String srcFileOrDir, String dstFileOrDir, boolean shouldGzip) {
|
||||
AssetManager assetManager = activity.getAssets();
|
||||
|
||||
final int maxAttempts = 5;
|
||||
String[] files = null;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
files = assetManager.list(srcFileOrDir);
|
||||
break;
|
||||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "OOPS exception attempting to list APK files at : " + srcFileOrDir + " : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException ie) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
if (files == null) {
|
||||
Log.d(TAG, "OOPS, could not list APK assets at : " + srcFileOrDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (files.length > 0) {
|
||||
// ensure destination directory exists
|
||||
File dstPath = new File(dstFileOrDir);
|
||||
if (!dstPath.mkdirs()) {
|
||||
if (!dstPath.exists()) {
|
||||
Log.d(TAG, "OOPS, could not mkdirs on " + dstPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (String filename : files) {
|
||||
// iterate on files and subdirectories
|
||||
recursivelyCopyAPKAssets(activity, srcFileOrDir + File.separator + filename, dstFileOrDir + File.separator + filename, shouldGzip);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// presumably this is a file, not a subdirectory
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
attempts = 0;
|
||||
do {
|
||||
try {
|
||||
is = assetManager.open(srcFileOrDir);
|
||||
if (shouldGzip) {
|
||||
os = new GZIPOutputStream(new FileOutputStream(dstFileOrDir + ".gz"));
|
||||
} else {
|
||||
os = new FileOutputStream(dstFileOrDir);
|
||||
}
|
||||
copyFile(is, os);
|
||||
break;
|
||||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to copy asset file: " + srcFileOrDir, e);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException ie) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
}
|
||||
|
||||
private static void copyFile(InputStream is, OutputStream os) throws IOException {
|
||||
final int BUF_SZ = 4096;
|
||||
byte[] buf = new byte[BUF_SZ];
|
||||
while (true) {
|
||||
int len = is.read(buf, 0, BUF_SZ);
|
||||
if (len < 0) {
|
||||
break;
|
||||
}
|
||||
os.write(buf, 0, len);
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
|
||||
private void dynamicSetup() {
|
||||
|
||||
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
|
||||
disksList.setEnabled(true);
|
||||
|
||||
final boolean useNewschoolSelection = (boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION);
|
||||
|
||||
final CheckBox newschoolSelection = (CheckBox) mDisksView.findViewById(R.id.newschoolDiskSelectionButton);
|
||||
newschoolSelection.setChecked(useNewschoolSelection);
|
||||
|
||||
final boolean isKitKatOrBetter = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT);
|
||||
|
||||
final boolean includeExternalFileChooser = Apple2Utils.isExternalStorageAccessible(mActivity) && isKitKatOrBetter;
|
||||
|
||||
final View newschoolChooser = mDisksView.findViewById(R.id.disk_selection_newschool_chooser);
|
||||
|
||||
if (!includeExternalFileChooser || !useNewschoolSelection) {
|
||||
disksList.setEnabled(true);
|
||||
disksList.setVisibility(View.VISIBLE);
|
||||
newschoolChooser.setVisibility(View.INVISIBLE);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
|
||||
layout.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (!includeExternalFileChooser) {
|
||||
newschoolSelection.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
Apple2Preferences.setJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION, false);
|
||||
oldschoolDynamicSetup();
|
||||
return;
|
||||
}
|
||||
|
||||
disksList.setEnabled(false);
|
||||
disksList.setVisibility(View.INVISIBLE);
|
||||
newschoolChooser.setVisibility(View.VISIBLE);
|
||||
|
||||
// new external file chooser activity can allow navigation to restricted external SD Card(s) ...
|
||||
newschoolSelection.setVisibility(View.VISIBLE);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
String imageName = null;
|
||||
do {
|
||||
String diskPath = (String) Apple2Preferences.getJSONPref((i == 0) ? SETTINGS.CURRENT_DISK_PATH_A : SETTINGS.CURRENT_DISK_PATH_B);
|
||||
|
||||
if (diskPath == null || diskPath.equals("")) {
|
||||
break;
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(diskPath);
|
||||
if (uri == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
diskPath = uri.getPath();
|
||||
int idx = diskPath.lastIndexOf("/");
|
||||
if (idx < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
imageName = diskPath.substring(idx + 1);
|
||||
} while (false);
|
||||
|
||||
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
|
||||
|
||||
if (imageName == null || imageName.equals("")) {
|
||||
layout.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
layout.setVisibility(View.VISIBLE);
|
||||
|
||||
boolean readOnly = (boolean) Apple2Preferences.getJSONPref((i == 0) ? SETTINGS.CURRENT_DISK_PATH_A_RO : SETTINGS.CURRENT_DISK_PATH_B_RO);
|
||||
imageName = "(" + mActivity.getResources().getString((readOnly ? R.string.disk_read_only : R.string.disk_read_write)) + "): " + imageName;
|
||||
TextView textView = (TextView) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_diskA : R.id.a2_newschool_diskB);
|
||||
textView.setText(imageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void oldschoolDynamicSetup() {
|
||||
|
||||
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
|
||||
|
||||
String disksDir = pathStackAsDirectory();
|
||||
boolean isRootPath = false;
|
||||
if (disksDir == null) {
|
||||
isRootPath = true;
|
||||
disksDir = sDataDir + File.separator + "disks"; // default path
|
||||
final boolean isRootPath = (disksDir == null);
|
||||
if (isRootPath) {
|
||||
disksDir = Apple2Utils.getDataDir(mActivity) + File.separator + "disks"; // default path
|
||||
}
|
||||
|
||||
while (disksDir.charAt(disksDir.length() - 1) == File.separatorChar) {
|
||||
disksDir = disksDir.substring(0, disksDir.length() - 1);
|
||||
}
|
||||
|
||||
File dir = new File(disksDir);
|
||||
|
||||
final File[] files = dir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
name = name.toLowerCase();
|
||||
@@ -497,7 +625,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
return false;
|
||||
}
|
||||
File file = new File(dir, name);
|
||||
return file.isDirectory() || hasDiskExtension(name);
|
||||
return file.isDirectory() || hasDiskExtension(name) || hasStateExtension(name);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -511,28 +639,41 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
|
||||
Arrays.sort(files);
|
||||
|
||||
getExternalStorageDirectory(mActivity);
|
||||
final boolean includeExternalStoragePath = (sExternalFilesDir != null && isRootPath);
|
||||
final boolean includeDownloadsPath = (sDownloadFilesDir != null && isRootPath);
|
||||
final int offset = includeExternalStoragePath ? (includeDownloadsPath ? 2 : 1) : (includeDownloadsPath ? 1 : 0);
|
||||
final File realExtStorageDir = Apple2Utils.getRealExternalStorageDirectory(mActivity);
|
||||
final boolean isStoragePath = !isRootPath && (realExtStorageDir != null) && disksDir.equalsIgnoreCase(realExtStorageDir.getAbsolutePath());
|
||||
if (isStoragePath) {
|
||||
// promote apple2ix directory to top of list
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].getName().equals("apple2ix")) {
|
||||
if (i > 0) {
|
||||
System.arraycopy(/*src:*/files, /*srcPos:*/0, /*dst:*/files, /*dstPos:*/1, /*length:*/i);
|
||||
files[0] = new File(realExtStorageDir, "apple2ix");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final boolean includeExternalStoragePath = (Apple2Utils.isExternalStorageAccessible(mActivity) && isRootPath);
|
||||
|
||||
final int offset = includeExternalStoragePath ? 1 : 0;
|
||||
final String[] fileNames = new String[files.length + offset];
|
||||
final String[] filePaths = new String[files.length + offset];
|
||||
final boolean[] isDirectory = new boolean[files.length + offset];
|
||||
|
||||
int idx = 0;
|
||||
|
||||
if (includeExternalStoragePath) {
|
||||
fileNames[idx] = sExternalFilesDir.getAbsolutePath();
|
||||
isDirectory[idx] = true;
|
||||
++idx;
|
||||
}
|
||||
if (includeDownloadsPath) {
|
||||
fileNames[idx] = sDownloadFilesDir.getAbsolutePath();
|
||||
filePaths[idx] = Apple2Utils.getRealExternalStorageDirectory(mActivity).getAbsolutePath();
|
||||
fileNames[idx] = mActivity.getResources().getString(R.string.storage);
|
||||
isDirectory[idx] = true;
|
||||
++idx;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
isDirectory[idx] = file.isDirectory();
|
||||
fileNames[idx] = file.getName();
|
||||
filePaths[idx] = file.getName();
|
||||
fileNames[idx] = filePaths[idx];
|
||||
if (isDirectory[idx]) {
|
||||
fileNames[idx] += File.separator;
|
||||
}
|
||||
@@ -563,33 +704,25 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
} else {
|
||||
|
||||
String imageName = files[position - offset].getAbsolutePath();
|
||||
final int len = imageName.length();
|
||||
final String suffix = imageName.substring(len - 3, len);
|
||||
if (suffix.equalsIgnoreCase(".gz")) {
|
||||
imageName = files[position - offset].getAbsolutePath().substring(0, len - 3);
|
||||
}
|
||||
|
||||
String eject = mActivity.getResources().getString(R.string.disk_eject);
|
||||
if (imageName.equals(Apple2Preferences.CURRENT_DISK_A.stringValue(mActivity))) {
|
||||
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_A))) {
|
||||
Button ejectButton = new Button(mActivity);
|
||||
ejectButton.setText(eject + " 1");
|
||||
ejectButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mActivity.ejectDisk(/*driveA:*/true);
|
||||
Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, "");
|
||||
ejectDisk(/*driveA:*/true);
|
||||
dynamicSetup();
|
||||
}
|
||||
});
|
||||
layout.addView(ejectButton);
|
||||
} else if (imageName.equals(Apple2Preferences.CURRENT_DISK_B.stringValue(mActivity))) {
|
||||
} else if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_B))) {
|
||||
Button ejectButton = new Button(mActivity);
|
||||
ejectButton.setText(eject + " 2");
|
||||
ejectButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mActivity.ejectDisk(/*driveA:*/false);
|
||||
Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, "");
|
||||
ejectDisk(/*driveA:*/false);
|
||||
dynamicSetup();
|
||||
}
|
||||
});
|
||||
@@ -609,11 +742,11 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
|
||||
if (isDirectory[position]) {
|
||||
Log.d(TAG, "Descending to path : " + fileNames[position]);
|
||||
if (parentIsRootPath && !new File(fileNames[position]).isAbsolute()) {
|
||||
pushPathStack(parentDisksDir + File.separator + fileNames[position]);
|
||||
Log.d(TAG, "Descending to path : " + filePaths[position]);
|
||||
if (parentIsRootPath && !new File(filePaths[position]).isAbsolute()) {
|
||||
pushPathStack(parentDisksDir + File.separator + filePaths[position]);
|
||||
} else {
|
||||
pushPathStack(fileNames[position]);
|
||||
pushPathStack(filePaths[position]);
|
||||
}
|
||||
dynamicSetup();
|
||||
ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
|
||||
@@ -621,84 +754,29 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
||||
return;
|
||||
}
|
||||
|
||||
String str = files[position - offset].getAbsolutePath();
|
||||
final int len = str.length();
|
||||
final String suffix = str.substring(len - 3, len);
|
||||
if (suffix.equalsIgnoreCase(".gz")) {
|
||||
str = files[position - offset].getAbsolutePath().substring(0, len - 3);
|
||||
}
|
||||
final String imageName = str;
|
||||
|
||||
if (imageName.equals(Apple2Preferences.CURRENT_DISK_A.stringValue(mActivity))) {
|
||||
mActivity.ejectDisk(/*driveA:*/true);
|
||||
Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, "");
|
||||
final String imageName = files[position - offset].getAbsolutePath();
|
||||
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_A))) {
|
||||
ejectDisk(/*isDriveA:*/true);
|
||||
dynamicSetup();
|
||||
return;
|
||||
}
|
||||
if (imageName.equals(Apple2Preferences.CURRENT_DISK_B.stringValue(mActivity))) {
|
||||
mActivity.ejectDisk(/*driveA:*/false);
|
||||
Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, "");
|
||||
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_B))) {
|
||||
ejectDisk(/*isDriveA:*/false);
|
||||
dynamicSetup();
|
||||
return;
|
||||
}
|
||||
|
||||
String title = mActivity.getResources().getString(R.string.header_disks);
|
||||
title = title + " " + fileNames[position];
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setCancelable(true).setMessage(title);
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
final View diskConfirmationView = inflater.inflate(R.layout.a2disk_confirmation, null, false);
|
||||
builder.setView(diskConfirmationView);
|
||||
|
||||
final RadioButton diskA = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskA);
|
||||
diskA.setChecked(Apple2Preferences.CURRENT_DRIVE_A_BUTTON.booleanValue(mActivity));
|
||||
diskA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.CURRENT_DRIVE_A_BUTTON.saveBoolean(mActivity, isChecked);
|
||||
if (hasStateExtension(imageName)) {
|
||||
final String jsonString = "{ \"stateFile\" : \"" + imageName + "\" }";
|
||||
final boolean restored = Apple2MainMenu.restoreEmulatorState(mActivity, jsonString);
|
||||
mActivity.dismissAllMenus();
|
||||
if (!restored) {
|
||||
Toast.makeText(mActivity, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
final RadioButton diskB = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskB);
|
||||
diskB.setChecked(!Apple2Preferences.CURRENT_DRIVE_A_BUTTON.booleanValue(mActivity));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final RadioButton readOnly = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readOnly);
|
||||
readOnly.setChecked(Apple2Preferences.CURRENT_DISK_RO_BUTTON.booleanValue(mActivity));
|
||||
readOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.CURRENT_DISK_RO_BUTTON.saveBoolean(mActivity, isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
|
||||
readWrite.setChecked(!Apple2Preferences.CURRENT_DISK_RO_BUTTON.booleanValue(mActivity));
|
||||
|
||||
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
boolean isDriveA = diskA.isChecked();
|
||||
boolean diskReadOnly = readOnly.isChecked();
|
||||
if (isDriveA) {
|
||||
Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(mActivity, diskReadOnly);
|
||||
Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, imageName);
|
||||
} else {
|
||||
Apple2Preferences.CURRENT_DISK_B_RO.saveBoolean(mActivity, diskReadOnly);
|
||||
Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, imageName);
|
||||
}
|
||||
dialog.dismiss();
|
||||
mActivity.dismissAllMenus();
|
||||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
mActivity.registerAndShowDialog(dialog);
|
||||
showDiskInsertionAlertDialog(/*title:*/fileNames[position], /*diskPath:*/new DiskArgs(imageName));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,23 +24,26 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
||||
|
||||
private final static String TAG = "Apple2JoystickCalibration";
|
||||
|
||||
public final static int JOYSTICK_DIVIDER_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
public final static String PREF_SCREEN_DIVISION = "screenDivider";
|
||||
|
||||
private Apple2Activity mActivity = null;
|
||||
private View mSettingsView = null;
|
||||
private ArrayList<Apple2MenuView> mViewStack = null;
|
||||
private boolean mTouchMenuEnabled = false;
|
||||
private int mSavedTouchDevice = Apple2Preferences.TouchDeviceVariant.NONE.ordinal();
|
||||
private int mSavedTouchDevice = Apple2SettingsMenu.TouchDeviceVariant.NONE.ordinal();
|
||||
|
||||
public Apple2JoystickCalibration(Apple2Activity activity, ArrayList<Apple2MenuView> viewStack, Apple2Preferences.TouchDeviceVariant variant) {
|
||||
public Apple2JoystickCalibration(Apple2Activity activity, ArrayList<Apple2MenuView> viewStack, Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
mActivity = activity;
|
||||
mViewStack = viewStack;
|
||||
if (!(variant == Apple2Preferences.TouchDeviceVariant.JOYSTICK || variant == Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD)) {
|
||||
if (!(variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK || variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD)) {
|
||||
throw new RuntimeException("You're doing it wrong");
|
||||
}
|
||||
|
||||
setup(variant);
|
||||
}
|
||||
|
||||
private void setup(Apple2Preferences.TouchDeviceVariant variant) {
|
||||
private void setup(Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mSettingsView = inflater.inflate(R.layout.activity_calibrate_joystick, null, false);
|
||||
|
||||
@@ -51,7 +54,8 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
||||
if (!fromUser) {
|
||||
return;
|
||||
}
|
||||
Apple2Preferences.JOYSTICK_DIVIDER.saveInt(mActivity, progress);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_SCREEN_DIVISION, (float) progress / JOYSTICK_DIVIDER_NUM_CHOICES);
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_JOYSTICK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,20 +68,17 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
||||
});
|
||||
|
||||
sb.setMax(0); // http://stackoverflow.com/questions/10278467/seekbar-not-setting-actual-progress-setprogress-not-working-on-early-android
|
||||
sb.setMax(Apple2Preferences.JOYSTICK_DIVIDER_NUM_CHOICES);
|
||||
sb.setProgress(Apple2Preferences.JOYSTICK_DIVIDER.intValue(mActivity));
|
||||
sb.setMax(JOYSTICK_DIVIDER_NUM_CHOICES);
|
||||
float val = Apple2Preferences.getFloatJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_SCREEN_DIVISION, (JOYSTICK_DIVIDER_NUM_CHOICES >> 1) / (float) JOYSTICK_DIVIDER_NUM_CHOICES);
|
||||
sb.setProgress((int) (val * JOYSTICK_DIVIDER_NUM_CHOICES));
|
||||
|
||||
mTouchMenuEnabled = Apple2Preferences.TOUCH_MENU_ENABLED.booleanValue(mActivity);
|
||||
Apple2Preferences.nativeSetTouchMenuEnabled(false);
|
||||
mSavedTouchDevice = Apple2Preferences.CURRENT_TOUCH_DEVICE.intValue(mActivity);
|
||||
Apple2Preferences.nativeSetCurrentTouchDevice(variant.ordinal());
|
||||
if (variant == Apple2Preferences.TouchDeviceVariant.JOYSTICK) {
|
||||
Apple2Preferences.loadAllJoystickButtons(mActivity);
|
||||
} else {
|
||||
Apple2Preferences.loadAllKeypadKeys(mActivity);
|
||||
}
|
||||
mTouchMenuEnabled = (boolean) Apple2Preferences.getJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED);
|
||||
Apple2Preferences.setJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED, false);
|
||||
mSavedTouchDevice = (int) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, variant.ordinal());
|
||||
|
||||
Apple2Preferences.nativeTouchDeviceBeginCalibrationMode();
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN, Apple2Preferences.PREF_CALIBRATING, true);
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
}
|
||||
|
||||
public final boolean isCalibrating() {
|
||||
@@ -85,7 +86,6 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
||||
}
|
||||
|
||||
public void onKeyTapCalibrationEvent(char ascii, int scancode) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
public void show() {
|
||||
@@ -102,9 +102,11 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
||||
}
|
||||
}
|
||||
|
||||
Apple2Preferences.nativeTouchDeviceEndCalibrationMode();
|
||||
Apple2Preferences.nativeSetTouchMenuEnabled(mTouchMenuEnabled);
|
||||
Apple2Preferences.nativeSetCurrentTouchDevice(mSavedTouchDevice);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN, Apple2Preferences.PREF_CALIBRATING, false);
|
||||
Apple2Preferences.setJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED, mTouchMenuEnabled);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, mSavedTouchDevice);
|
||||
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
|
||||
mActivity.popApple2View(this);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
@@ -24,6 +25,21 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "Apple2JoystickSettingsMenu";
|
||||
|
||||
public final static int JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
|
||||
public final static float JOYSTICK_AXIS_SENSITIVITY_MIN = 0.25f;
|
||||
public final static float JOYSTICK_AXIS_SENSITIVITY_DEFAULT = 1.f;
|
||||
public final static float JOYSTICK_AXIS_SENSITIVITY_MAX = 4.f;
|
||||
public final static float JOYSTICK_AXIS_SENSITIVITY_DEC_STEP = 0.05f;
|
||||
public final static float JOYSTICK_AXIS_SENSITIVITY_INC_STEP = 0.25f;
|
||||
public final static int JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES = (int) ((JOYSTICK_AXIS_SENSITIVITY_DEFAULT - JOYSTICK_AXIS_SENSITIVITY_MIN) / JOYSTICK_AXIS_SENSITIVITY_DEC_STEP); // 15
|
||||
public final static int JOYSTICK_AXIS_SENSITIVITY_INC_NUMCHOICES = (int) ((JOYSTICK_AXIS_SENSITIVITY_MAX - JOYSTICK_AXIS_SENSITIVITY_DEFAULT) / JOYSTICK_AXIS_SENSITIVITY_INC_STEP); // 12
|
||||
public final static int JOYSTICK_AXIS_SENSITIVITY_NUM_CHOICES = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES + JOYSTICK_AXIS_SENSITIVITY_INC_NUMCHOICES; // 15 + 12
|
||||
|
||||
public final static int TAPDELAY_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
public final static float TAPDELAY_SCALE = 0.5f;
|
||||
|
||||
|
||||
public Apple2JoystickSettingsMenu(Apple2Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
@@ -51,6 +67,18 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return true;
|
||||
}
|
||||
|
||||
public enum TouchJoystickButtons {
|
||||
NONE(0),
|
||||
BUTTON1(1),
|
||||
BUTTON2(2),
|
||||
BOTH(3);
|
||||
private int butt;
|
||||
|
||||
TouchJoystickButtons(int butt) {
|
||||
this.butt = butt;
|
||||
}
|
||||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
JOYSTICK_TAP_BUTTON {
|
||||
@Override
|
||||
@@ -63,6 +91,16 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_button_tap_button_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "jsTouchDownChar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return TouchJoystickButtons.BUTTON1.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
@@ -72,6 +110,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.joystick_button_tap_button, new String[]{
|
||||
activity.getResources().getString(R.string.joystick_button_button_none),
|
||||
activity.getResources().getString(R.string.joystick_button_button1),
|
||||
@@ -80,12 +119,12 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.JOYSTICK_TAP_BUTTON.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.JOYSTICK_TAP_BUTTON.saveTouchJoystickButtons(activity, Apple2Preferences.TouchJoystickButtons.values()[value]);
|
||||
Apple2Preferences.setJSONPref(self, TouchJoystickButtons.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -101,6 +140,16 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_button_swipe_up_button_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "jsSwipeNorthChar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return TouchJoystickButtons.BOTH.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
@@ -110,6 +159,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.joystick_button_swipe_up_button, new String[]{
|
||||
activity.getResources().getString(R.string.joystick_button_button_none),
|
||||
activity.getResources().getString(R.string.joystick_button_button1),
|
||||
@@ -118,12 +168,12 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.JOYSTICK_SWIPEUP_BUTTON.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.JOYSTICK_SWIPEUP_BUTTON.saveTouchJoystickButtons(activity, Apple2Preferences.TouchJoystickButtons.values()[value]);
|
||||
Apple2Preferences.setJSONPref(self, TouchJoystickButtons.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -139,6 +189,16 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_button_swipe_down_button_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "jsSwipeSouthChar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return TouchJoystickButtons.BUTTON2.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
@@ -148,6 +208,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.joystick_button_swipe_down_button, new String[]{
|
||||
activity.getResources().getString(R.string.joystick_button_button_none),
|
||||
activity.getResources().getString(R.string.joystick_button_button1),
|
||||
@@ -156,12 +217,12 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.JOYSTICK_SWIPEDOWN_BUTTON.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.JOYSTICK_SWIPEDOWN_BUTTON.saveTouchJoystickButtons(activity, Apple2Preferences.TouchJoystickButtons.values()[value]);
|
||||
Apple2Preferences.setJSONPref(self, TouchJoystickButtons.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -192,7 +253,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
}
|
||||
}
|
||||
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, Apple2Preferences.TouchDeviceVariant.JOYSTICK);
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK);
|
||||
|
||||
// show this new view...
|
||||
calibration.show();
|
||||
@@ -214,22 +275,33 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_button_tapdelay_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "jsTapDelaySecs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return ((float) 8 / TAPDELAY_NUM_CHOICES * TAPDELAY_SCALE); // -> 0.2f
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.TAPDELAY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, TAPDELAY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.JOYSTICK_TAPDELAY.saveInt(activity, progress);
|
||||
Apple2Preferences.setJSONPref(self, ((float) progress / TAPDELAY_NUM_CHOICES * TAPDELAY_SCALE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.JOYSTICK_TAPDELAY.intValue(activity);
|
||||
return (int) (Apple2Preferences.getFloatJSONPref(self) / TAPDELAY_SCALE * TAPDELAY_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
seekBarValue.setText("" + (((float) progress / Apple2Preferences.TAPDELAY_NUM_CHOICES) * Apple2Preferences.TAPDELAY_SCALE));
|
||||
seekBarValue.setText("" + (((float) progress / TAPDELAY_NUM_CHOICES) * TAPDELAY_SCALE));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -253,9 +325,23 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_JOYSTICK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -316,14 +402,25 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_visible_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "showControls";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.JOYSTICK_VISIBILITY.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.JOYSTICK_VISIBILITY.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
@@ -340,20 +437,31 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_axisleft_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "axisIsOnLeft";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.JOYSTICK_AXIS_ON_LEFT.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.JOYSTICK_AXIS_ON_LEFT.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
JOYSTICK_AXIS_SENSITIVIY {
|
||||
JOYSTICK_AXIS_SENSITIVITY {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return "";
|
||||
@@ -364,23 +472,51 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_axis_sensitivity_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "axisSensitivity";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.JOYSTICK_AXIS_SENSITIVITY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, JOYSTICK_AXIS_SENSITIVITY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.JOYSTICK_AXIS_SENSITIVIY.saveInt(activity, progress);
|
||||
final int pivot = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
float sensitivity = 1.f;
|
||||
if (progress < pivot) {
|
||||
int decAmount = (pivot - progress);
|
||||
sensitivity -= (JOYSTICK_AXIS_SENSITIVITY_DEC_STEP * decAmount);
|
||||
} else if (progress > pivot) {
|
||||
int incAmount = (progress - pivot);
|
||||
sensitivity += (JOYSTICK_AXIS_SENSITIVITY_INC_STEP * incAmount);
|
||||
}
|
||||
Apple2Preferences.setJSONPref(self, sensitivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.JOYSTICK_AXIS_SENSITIVIY.intValue(activity);
|
||||
float sensitivity = Apple2Preferences.getFloatJSONPref(self);
|
||||
int pivot = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
if (sensitivity < 1.f) {
|
||||
pivot = Math.round((sensitivity - JOYSTICK_AXIS_SENSITIVITY_MIN) / JOYSTICK_AXIS_SENSITIVITY_DEC_STEP);
|
||||
} else if (sensitivity > 1.f) {
|
||||
sensitivity -= 1.f;
|
||||
pivot += Math.round(sensitivity / JOYSTICK_AXIS_SENSITIVITY_INC_STEP);
|
||||
}
|
||||
return pivot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
saveInt(progress);
|
||||
int percent = (int) (Apple2Preferences.JOYSTICK_AXIS_SENSITIVIY.floatValue(activity) * 100.f);
|
||||
int percent = (int) (Apple2Preferences.getFloatJSONPref(self) * 100.f);
|
||||
seekBarValue.setText("" + percent + "%");
|
||||
}
|
||||
});
|
||||
@@ -397,25 +533,38 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.joystick_button_threshold_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "switchThreshold";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
if (progress == 0) {
|
||||
progress = 1;
|
||||
}
|
||||
Apple2Preferences.JOYSTICK_BUTTON_THRESHOLD.saveInt(activity, progress);
|
||||
progress *= getJoystickButtonSwitchThresholdScale(activity);
|
||||
Apple2Preferences.setJSONPref(self, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.JOYSTICK_BUTTON_THRESHOLD.intValue(activity);
|
||||
int progress = (int) Apple2Preferences.getJSONPref(self);
|
||||
return (progress / getJoystickButtonSwitchThresholdScale(activity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
int threshold = progress * Apple2Preferences.JOYSTICK_BUTTON_THRESHOLD_STEP;
|
||||
int threshold = progress * getJoystickButtonSwitchThresholdScale(activity);
|
||||
seekBarValue.setText("" + threshold + " pts");
|
||||
}
|
||||
});
|
||||
@@ -424,9 +573,13 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_JOYSTICK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -444,4 +597,17 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getJoystickButtonSwitchThresholdScale(Apple2Activity activity) {
|
||||
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
|
||||
|
||||
int smallScreenAxis = dm.widthPixels < dm.heightPixels ? dm.widthPixels : dm.heightPixels;
|
||||
int oneThirdScreenAxis = smallScreenAxis / 3;
|
||||
|
||||
// largest switch threshold value is 1/3 small dimension of screen
|
||||
return oneThirdScreenAxis / JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
@@ -91,10 +92,50 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
if (position < 0 || position >= SETTINGS.size) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return true;
|
||||
return (position != SETTINGS.KEYBOARD_VISIBILITY_INACTIVE.ordinal() && position != SETTINGS.KEYBOARD_VISIBILITY_ACTIVE.ordinal());
|
||||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
TOUCH_MENU_ENABLED {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_menu_enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_menu_enable_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_KEYBOARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "touchMenuEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
KEYBOARD_VISIBILITY_INACTIVE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
@@ -106,17 +147,28 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keyboard_visibility_inactive_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "minAlpha";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return (float) 5 / Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.KEYBOARD_VISIBILITY_INACTIVE.saveInt(activity, progress);
|
||||
Apple2Preferences.setJSONPref(self, (float) progress / Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.KEYBOARD_VISIBILITY_INACTIVE.intValue(activity);
|
||||
return Math.round(Apple2Preferences.getFloatJSONPref(self) * (Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,17 +189,28 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keyboard_visibility_active_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "maxAlpha";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.KEYBOARD_VISIBILITY_ACTIVE.saveInt(activity, progress);
|
||||
Apple2Preferences.setJSONPref(self, (float) progress / Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.KEYBOARD_VISIBILITY_ACTIVE.intValue(activity);
|
||||
return Math.round(Apple2Preferences.getFloatJSONPref(self) * (Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,14 +231,25 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keyboard_click_enabled_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "keyClickEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
final IMenuEnum self = this;
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.KEYBOARD_CLICK_ENABLED.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
@@ -192,14 +266,25 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keyboard_lowercase_enabled_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "lowercaseEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.KEYBOARD_LOWERCASE_ENABLED.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
final IMenuEnum self = this;
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.KEYBOARD_LOWERCASE_ENABLED.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
@@ -216,6 +301,16 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keyboard_choose_alt_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "altPathIndex";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
@@ -226,7 +321,7 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
|
||||
File extKeyboardDir = Apple2DisksMenu.getExternalStorageDirectory(activity);
|
||||
File extKeyboardDir = Apple2Utils.getExternalStorageDirectory(activity);
|
||||
|
||||
FilenameFilter kbdJsonFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
@@ -255,7 +350,7 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
}
|
||||
if (files == null) {
|
||||
// read keyboard data from /data/data/...
|
||||
File keyboardDir = new File(Apple2DisksMenu.getDataDir(activity) + File.separator + "keyboards");
|
||||
File keyboardDir = new File(Apple2Utils.getDataDir(activity) + File.separator + "keyboards");
|
||||
files = keyboardDir.listFiles(kbdJsonFilter);
|
||||
if (files == null) {
|
||||
Log.e(TAG, "OOPS, could not read keyboard data directory");
|
||||
@@ -275,27 +370,81 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
final String keyboardDirName = extKeyboardDir == null ? "Keyboards" : extKeyboardDir.getPath();
|
||||
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, keyboardDirName, titles, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.KEYBOARD_ALT.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.KEYBOARD_ALT.saveInt(activity, value);
|
||||
Apple2Preferences.setJSONPref(self, value);
|
||||
String path = allFiles[value].getPath();
|
||||
Apple2Preferences.KEYBOARD_ALT_PATH.saveString(activity, path);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_KEYBOARD, "altPath", path);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
KEYBOARD_GLYPH_SCALE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_glyph_scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_glyph_scale_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "glyphMultiplier";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
int glyphScale = (int) Apple2Preferences.getJSONPref(this);
|
||||
if (glyphScale <= 0) {
|
||||
glyphScale = 1;
|
||||
}
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, glyphScale > 1);
|
||||
final IMenuEnum self = this;
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(self, isChecked ? 2 : 1);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
};
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_KEYBOARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,8 @@ import android.widget.TextView;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
|
||||
@@ -33,12 +35,10 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
private ArrayList<Apple2MenuView> mViewStack = null;
|
||||
private TextView mCurrentChoicePrompt = null;
|
||||
|
||||
private String[] foo = null;
|
||||
|
||||
private STATE_MACHINE mChooserState = STATE_MACHINE.CHOOSE_NORTHWEST;
|
||||
|
||||
private boolean mTouchMenuEnabled = false;
|
||||
private int mSavedTouchDevice = Apple2Preferences.TouchDeviceVariant.NONE.ordinal();
|
||||
private int mSavedTouchDevice = Apple2SettingsMenu.TouchDeviceVariant.NONE.ordinal();
|
||||
|
||||
public Apple2KeypadChooser(Apple2Activity activity, ArrayList<Apple2MenuView> viewStack) {
|
||||
mActivity = activity;
|
||||
@@ -60,8 +60,13 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
|
||||
String asciiStr = asciiRepresentation(ascii);
|
||||
Log.d(TAG, "ascii:'" + asciiStr + "' scancode:" + scancode);
|
||||
mChooserState.setValues(mActivity, ascii, scancode);
|
||||
Apple2Preferences.nativeSetCurrentTouchDevice(Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD.ordinal());
|
||||
if (ascii == ' ') {
|
||||
ascii = Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE;
|
||||
}
|
||||
mChooserState.setKey(mActivity, ascii, scancode);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD.ordinal());
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
|
||||
mCurrentChoicePrompt.setText(getNextChoiceString() + asciiStr);
|
||||
switch (mChooserState) {
|
||||
case CHOOSE_TAP:
|
||||
@@ -82,13 +87,22 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
break;
|
||||
}
|
||||
|
||||
calibrationContinue();
|
||||
}
|
||||
|
||||
private void calibrationContinue() {
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mChooserState = mChooserState.next();
|
||||
mCurrentChoicePrompt.setText(getNextChoiceString());
|
||||
Apple2Preferences.nativeSetCurrentTouchDevice(Apple2Preferences.TouchDeviceVariant.KEYBOARD.ordinal());
|
||||
if (mChooserState.ordinal() == 0) {
|
||||
dismiss();
|
||||
} else {
|
||||
mCurrentChoicePrompt.setText(getNextChoiceString());
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, Apple2SettingsMenu.TouchDeviceVariant.KEYBOARD.ordinal());
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
@@ -101,15 +115,19 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
|
||||
for (Apple2MenuView apple2MenuView : mViewStack) {
|
||||
if (apple2MenuView != this) {
|
||||
mActivity.pushApple2View(apple2MenuView);
|
||||
}
|
||||
}
|
||||
|
||||
Apple2Preferences.nativeTouchDeviceEndCalibrationMode();
|
||||
Apple2Preferences.nativeSetTouchMenuEnabled(mTouchMenuEnabled);
|
||||
Apple2Preferences.nativeSetCurrentTouchDevice(mSavedTouchDevice);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN, Apple2Preferences.PREF_CALIBRATING, false);
|
||||
|
||||
Apple2Preferences.setJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED, mTouchMenuEnabled);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, mSavedTouchDevice);
|
||||
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
|
||||
mActivity.popApple2View(this);
|
||||
}
|
||||
@@ -130,6 +148,8 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
// internals
|
||||
|
||||
private void setup() {
|
||||
mChooserState.start();
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mSettingsView = inflater.inflate(R.layout.activity_chooser_keypad, null, false);
|
||||
|
||||
@@ -140,17 +160,28 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
skipButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Apple2KeypadChooser.this.onKeyTapCalibrationEvent((char)Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD.ordinal());
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
calibrationContinue();
|
||||
}
|
||||
});
|
||||
|
||||
Button noneButton = (Button) mSettingsView.findViewById(R.id.noneButton);
|
||||
noneButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onKeyTapCalibrationEvent((char) Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
}
|
||||
});
|
||||
|
||||
// temporarily undo these native touch settings while calibrating...
|
||||
mTouchMenuEnabled = Apple2Preferences.TOUCH_MENU_ENABLED.booleanValue(mActivity);
|
||||
Apple2Preferences.nativeSetTouchMenuEnabled(false);
|
||||
mSavedTouchDevice = Apple2Preferences.CURRENT_TOUCH_DEVICE.intValue(mActivity);
|
||||
Apple2Preferences.nativeSetCurrentTouchDevice(Apple2Preferences.TouchDeviceVariant.KEYBOARD.ordinal());
|
||||
mTouchMenuEnabled = (boolean) Apple2Preferences.getJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED);
|
||||
Apple2Preferences.setJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED, false);
|
||||
mSavedTouchDevice = (int) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, Apple2SettingsMenu.TouchDeviceVariant.KEYBOARD.ordinal());
|
||||
|
||||
Apple2Preferences.nativeTouchDeviceBeginCalibrationMode();
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN, Apple2Preferences.PREF_CALIBRATING, true);
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
}
|
||||
|
||||
private String asciiRepresentation(char ascii) {
|
||||
@@ -194,140 +225,133 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_ul);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_NORTHWEST_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_NORTH {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_up);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_NORTH_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_NORTHEAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_ur);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_NORTHEAST_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_WEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_WEST_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_CENTER {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_CENTER_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_EAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_EAST_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_SOUTHWEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_SOUTHWEST_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_SOUTH {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_SOUTH_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_SOUTHEAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_SOUTHEAST_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_TAP {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_button_tap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_TAP_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_SWIPEUP {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_button_swipeup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_SWIPEUP_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
},
|
||||
CHOOSE_SWIPEDOWN {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_button_swipedown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(Apple2Activity activity, char ascii, int scancode) {
|
||||
Apple2Preferences.KEYPAD_SWIPEDOWN_KEY.saveChosenKey(activity, ascii, scancode);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int size = STATE_MACHINE.values().length;
|
||||
|
||||
public abstract void setValues(Apple2Activity activity, char ascii, int scancode);
|
||||
private static ArrayList<String> chars = null;
|
||||
private static ArrayList<String> scans = null;
|
||||
|
||||
public void setKey(Apple2Activity activity, int ascii, int scancode) {
|
||||
int ord = ordinal();
|
||||
if (ord < CHOOSE_TAP.ordinal()) {
|
||||
chars.set(ord, "" + ascii);
|
||||
scans.set(ord, "" + scancode);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveRosettes(chars, scans);
|
||||
} else if (ord == CHOOSE_TAP.ordinal()) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveTouchDownKey(ascii, scancode);
|
||||
} else if (ord == CHOOSE_SWIPEUP.ordinal()) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveSwipeNorthKey(ascii, scancode);
|
||||
} else if (ord == CHOOSE_SWIPEDOWN.ordinal()) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveSwipeSouthKey(ascii, scancode);
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
Apple2Preferences.sync(activity, Apple2Preferences.PREF_DOMAIN_JOYSTICK);
|
||||
}
|
||||
|
||||
public abstract String getKeyName(Apple2Activity activity);
|
||||
|
||||
public void start() {
|
||||
|
||||
JSONArray jsonChars = (JSONArray) Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, Apple2KeypadSettingsMenu.PREF_KPAD_ROSETTE_CHAR_ARRAY, null);
|
||||
JSONArray jsonScans = (JSONArray) Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, Apple2KeypadSettingsMenu.PREF_KPAD_ROSETTE_SCAN_ARRAY, null);
|
||||
|
||||
if (jsonChars == null || jsonScans == null) {
|
||||
Log.v(TAG, "Creating new keypad joystick JSON...");
|
||||
jsonChars = new JSONArray();
|
||||
jsonScans = new JSONArray();
|
||||
for (int i = 0; i < Apple2KeypadSettingsMenu.ROSETTE_SIZE; i++) {
|
||||
jsonChars.put(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
jsonScans.put(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int len = jsonChars.length();
|
||||
if (len != Apple2KeypadSettingsMenu.ROSETTE_SIZE) {
|
||||
throw new RuntimeException("jsonChars not expected length");
|
||||
}
|
||||
if (len != jsonScans.length()) {
|
||||
throw new RuntimeException("jsonScans not expected length");
|
||||
}
|
||||
|
||||
chars = new ArrayList<String>();
|
||||
scans = new ArrayList<String>();
|
||||
try {
|
||||
for (int i = 0; i < len; i++) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.addRosetteKey(chars, scans, jsonChars.getInt(i), jsonScans.getInt(i));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public STATE_MACHINE next() {
|
||||
int nextOrd = this.ordinal() + 1;
|
||||
if (nextOrd >= size) {
|
||||
|
||||
@@ -17,11 +17,25 @@ import android.widget.TextView;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONArray;
|
||||
|
||||
public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "Apple2KeypadSettingsMenu";
|
||||
|
||||
public final static int KEYREPEAT_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
|
||||
public final static String PREF_KPAD_ROSETTE_CHAR_ARRAY = "kpAxisRosetteChars";
|
||||
public final static String PREF_KPAD_ROSETTE_SCAN_ARRAY = "kpAxisRosetteScancodes";
|
||||
public final static String PREF_KPAD_SWIPE_NORTH_CHAR = "kpSwipeNorthChar";
|
||||
public final static String PREF_KPAD_SWIPE_NORTH_SCAN = "kpSwipeNorthScancode";
|
||||
public final static String PREF_KPAD_SWIPE_SOUTH_CHAR = "kpSwipeSouthChar";
|
||||
public final static String PREF_KPAD_SWIPE_SOUTH_SCAN = "kpSwipeSouthScancode";
|
||||
public final static String PREF_KPAD_TOUCHDOWN_CHAR = "kpTouchDownChar";
|
||||
public final static String PREF_KPAD_TOUCHDOWN_SCAN = "kpTouchDownScancode";
|
||||
|
||||
public final static int ROSETTE_SIZE = 9;
|
||||
|
||||
public Apple2KeypadSettingsMenu(Apple2Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
@@ -49,6 +63,212 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
return true;
|
||||
}
|
||||
|
||||
public enum KeypadPreset {
|
||||
ARROWS_SPACE {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_arrows_space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_UP, Apple2KeyboardSettingsMenu.SCANCODE_UP);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_DOWN, Apple2KeyboardSettingsMenu.SCANCODE_DOWN);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
}
|
||||
},
|
||||
AZ_LEFT_RIGHT_SPACE {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_az_left_right_space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'A', Apple2KeyboardSettingsMenu.SCANCODE_A);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'Z', Apple2KeyboardSettingsMenu.SCANCODE_Z);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
}
|
||||
},
|
||||
LEFT_RIGHT_SPACE {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_left_right_space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
}
|
||||
},
|
||||
IJKM_SPACE {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_ijkm_space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'I', Apple2KeyboardSettingsMenu.SCANCODE_I);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'J', Apple2KeyboardSettingsMenu.SCANCODE_J);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'K', Apple2KeyboardSettingsMenu.SCANCODE_K);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'M', Apple2KeyboardSettingsMenu.SCANCODE_M);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
}
|
||||
},
|
||||
WADX_SPACE {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_wadx_space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'W', Apple2KeyboardSettingsMenu.SCANCODE_W);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'A', Apple2KeyboardSettingsMenu.SCANCODE_A);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'D', Apple2KeyboardSettingsMenu.SCANCODE_D);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'X', Apple2KeyboardSettingsMenu.SCANCODE_X);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
}
|
||||
},
|
||||
CRAZY_SEAFOX_KEYS {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_crazy_seafox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
// Heh, the entire purpose of the keypad-variant touch joystick is to make this possible ;-)
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, 'Y', Apple2KeyboardSettingsMenu.SCANCODE_Y);
|
||||
addRosetteKey(chars, scans, 'U', Apple2KeyboardSettingsMenu.SCANCODE_U);
|
||||
addRosetteKey(chars, scans, 'I', Apple2KeyboardSettingsMenu.SCANCODE_I);
|
||||
addRosetteKey(chars, scans, 'H', Apple2KeyboardSettingsMenu.SCANCODE_H);
|
||||
addRosetteKey(chars, scans, 'J', Apple2KeyboardSettingsMenu.SCANCODE_J);
|
||||
addRosetteKey(chars, scans, 'K', Apple2KeyboardSettingsMenu.SCANCODE_K);
|
||||
addRosetteKey(chars, scans, 'N', Apple2KeyboardSettingsMenu.SCANCODE_N);
|
||||
addRosetteKey(chars, scans, 'M', Apple2KeyboardSettingsMenu.SCANCODE_M);
|
||||
addRosetteKey(chars, scans, ',', Apple2KeyboardSettingsMenu.SCANCODE_COMMA);
|
||||
saveRosettes(chars, scans);
|
||||
|
||||
saveTouchDownKey('D', Apple2KeyboardSettingsMenu.SCANCODE_D);
|
||||
saveSwipeSouthKey('F', Apple2KeyboardSettingsMenu.SCANCODE_F);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
}
|
||||
};
|
||||
|
||||
public static void addRosetteKey(ArrayList<String> chars, ArrayList<String> scans, int aChar, int aScan) {
|
||||
chars.add("" + aChar);
|
||||
scans.add("" + aScan);
|
||||
}
|
||||
|
||||
public static void saveRosettes(ArrayList<String> chars, ArrayList<String> scans) {
|
||||
if (chars.size() != 9) {
|
||||
throw new RuntimeException("rosette chars is not correct size");
|
||||
}
|
||||
if (scans.size() != 9) {
|
||||
throw new RuntimeException("rosette scans is not correct size");
|
||||
}
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_ROSETTE_CHAR_ARRAY, new JSONArray(chars));
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_ROSETTE_SCAN_ARRAY, new JSONArray(scans));
|
||||
}
|
||||
|
||||
public static void saveTouchDownKey(int aChar, int aScan) {
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_TOUCHDOWN_CHAR, aChar);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_TOUCHDOWN_SCAN, aScan);
|
||||
}
|
||||
|
||||
public static void saveSwipeSouthKey(int aChar, int aScan) {
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_SOUTH_CHAR, aChar);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_SOUTH_SCAN, aScan);
|
||||
}
|
||||
|
||||
public static void saveSwipeNorthKey(int aChar, int aScan) {
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_NORTH_CHAR, aChar);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_NORTH_SCAN, aScan);
|
||||
}
|
||||
|
||||
public abstract String getTitle(Apple2Activity activity);
|
||||
|
||||
public abstract void apply(Apple2Activity activity);
|
||||
|
||||
public static final int size = KeypadPreset.values().length;
|
||||
|
||||
public static String[] titles(Apple2Activity activity) {
|
||||
String[] titles = new String[size];
|
||||
int i = 0;
|
||||
for (KeypadPreset preset : values()) {
|
||||
titles[i++] = preset.getTitle(activity);
|
||||
}
|
||||
return titles;
|
||||
}
|
||||
}
|
||||
|
||||
enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
KEYPAD_CHOOSE_KEYS {
|
||||
@Override
|
||||
@@ -61,6 +281,16 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keypad_choose_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "kpPresetChoice";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return KeypadPreset.IJKM_SPACE.ordinal() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
@@ -70,24 +300,25 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
String[] titles = new String[Apple2Preferences.KeypadPreset.size + 1];
|
||||
final IMenuEnum self = this;
|
||||
String[] titles = new String[KeypadPreset.size + 1];
|
||||
titles[0] = activity.getResources().getString(R.string.keypad_preset_custom);
|
||||
System.arraycopy(Apple2Preferences.KeypadPreset.titles(activity), 0, titles, 1, Apple2Preferences.KeypadPreset.size);
|
||||
System.arraycopy(KeypadPreset.titles(activity), 0, titles, 1, KeypadPreset.size);
|
||||
|
||||
_alertDialogHandleSelection(activity, R.string.keypad_choose_title, titles, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.KEYPAD_KEYS.intValue(activity);
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.KEYPAD_KEYS.saveInt(activity, value);
|
||||
Apple2Preferences.setJSONPref(self, value);
|
||||
if (value == 0) {
|
||||
Apple2KeypadSettingsMenu keypadSettingsMenu = (Apple2KeypadSettingsMenu) settingsMenu;
|
||||
keypadSettingsMenu.chooseKeys(activity);
|
||||
} else {
|
||||
Apple2Preferences.KeypadPreset.values()[value - 1].apply(activity);
|
||||
KeypadPreset.values()[value - 1].apply(activity);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -119,7 +350,7 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
}
|
||||
}
|
||||
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD);
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD);
|
||||
|
||||
// show this new view...
|
||||
calibration.show();
|
||||
@@ -149,9 +380,23 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_JOYSTICK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,7 +442,7 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
}
|
||||
}
|
||||
|
||||
protected static class KeypadAdvanced extends Apple2AbstractMenu {
|
||||
public static class KeypadAdvanced extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "KeypadAdvanced";
|
||||
|
||||
@@ -240,22 +485,33 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.keypad_repeat_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "keyRepeatThresholdSecs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return (float) 4 / KEYREPEAT_NUM_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.KEYREPEAT_NUM_CHOICES, new IPreferenceSlider() {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, KEYREPEAT_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.KEYREPEAT_THRESHOLD.saveInt(activity, progress);
|
||||
Apple2Preferences.setJSONPref(self, (float) progress / KEYREPEAT_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.KEYREPEAT_THRESHOLD.intValue(activity);
|
||||
return (int) (Apple2Preferences.getFloatJSONPref(self) * KEYREPEAT_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
seekBarValue.setText("" + ((float) progress / Apple2Preferences.KEYREPEAT_NUM_CHOICES));
|
||||
seekBarValue.setText("" + ((float) progress / KEYREPEAT_NUM_CHOICES));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -279,9 +535,23 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_JOYSTICK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,7 +15,9 @@ import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -26,18 +28,23 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Apple2MainMenu {
|
||||
|
||||
private final static String SAVE_FILE = "emulator.state";
|
||||
public final static String OLD_SAVE_FILE = "emulator.state";
|
||||
public final static String SAVE_FILE_EXTENSION = ".a2state";
|
||||
public final static String SAVE_FILE = "emulator" + SAVE_FILE_EXTENSION;
|
||||
private final static String TAG = "Apple2MainMenu";
|
||||
|
||||
private Apple2Activity mActivity = null;
|
||||
@@ -100,7 +107,7 @@ public class Apple2MainMenu {
|
||||
@Override
|
||||
public void handleSelection(Apple2MainMenu mainMenu) {
|
||||
if (!mainMenu.mShowingSaveRestore.compareAndSet(false, true)) {
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race around save/restore");
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race around sync/restore");
|
||||
return;
|
||||
}
|
||||
mainMenu.maybeSaveRestore();
|
||||
@@ -250,14 +257,30 @@ public class Apple2MainMenu {
|
||||
|
||||
final AtomicBoolean selectionAlreadyHandled = new AtomicBoolean(false);
|
||||
|
||||
AlertDialog rebootQuitDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setPositiveButton(R.string.reboot, new DialogInterface.OnClickListener() {
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
final View resetConfirmationView = inflater.inflate(R.layout.a2reset_confirmation, null, false);
|
||||
|
||||
final RadioButton openAppleSelected = (RadioButton) resetConfirmationView.findViewById(R.id.radioButton_openApple);
|
||||
openAppleSelected.setChecked(true);
|
||||
final RadioButton closedAppleSelected = (RadioButton) resetConfirmationView.findViewById(R.id.radioButton_closedApple);
|
||||
closedAppleSelected.setChecked(false);
|
||||
final RadioButton noAppleSelected = (RadioButton) resetConfirmationView.findViewById(R.id.radioButton_noApple);
|
||||
noAppleSelected.setChecked(false);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setPositiveButton(R.string.reset, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race in reboot/quit onClick()");
|
||||
return;
|
||||
}
|
||||
mActivity.rebootEmulation();
|
||||
int resetState = 0;
|
||||
if (openAppleSelected.isChecked()) {
|
||||
resetState = 1;
|
||||
} else if (closedAppleSelected.isChecked()) {
|
||||
resetState = 2;
|
||||
}
|
||||
mActivity.rebootEmulation(resetState);
|
||||
Apple2MainMenu.this.dismiss();
|
||||
}
|
||||
}).setNeutralButton(R.string.quit, new DialogInterface.OnClickListener() {
|
||||
@@ -269,16 +292,149 @@ public class Apple2MainMenu {
|
||||
}
|
||||
mActivity.quitEmulator();
|
||||
}
|
||||
}).setNegativeButton(R.string.cancel, null).create();
|
||||
}).setNegativeButton(R.string.cancel, null);
|
||||
|
||||
builder.setView(resetConfirmationView);
|
||||
AlertDialog rebootQuitDialog = builder.create();
|
||||
|
||||
mActivity.registerAndShowDialog(rebootQuitDialog);
|
||||
}
|
||||
|
||||
public static boolean restoreEmulatorState(Apple2Activity activity, DiskArgs diskArgs) {
|
||||
boolean restored = false;
|
||||
|
||||
public void maybeSaveRestore() {
|
||||
try {
|
||||
String stateFile = diskArgs.path;
|
||||
|
||||
if (stateFile == null) {
|
||||
stateFile = Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL + diskArgs.uri.toString();
|
||||
}
|
||||
|
||||
JSONObject map = new JSONObject();
|
||||
map.put("stateFile", stateFile);
|
||||
|
||||
if (stateFile.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
|
||||
if (!Apple2Utils.isExternalStorageAccessible(activity)) {
|
||||
// disallow access if we cannot access external storage
|
||||
throw new Exception("External storage not accessible for state load");
|
||||
}
|
||||
if (diskArgs.pfd == null) {
|
||||
if (diskArgs.uri == null) {
|
||||
String uriString = stateFile.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
|
||||
diskArgs.uri = Uri.parse(uriString);
|
||||
}
|
||||
diskArgs.pfd = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, diskArgs.uri);
|
||||
}
|
||||
|
||||
int fd = diskArgs.pfd.getFd(); // NPE thrown if diskArgs.pfd is null
|
||||
map.put("fdState", fd);
|
||||
} else {
|
||||
File file = new File(stateFile);
|
||||
if (!file.exists()) {
|
||||
throw new RuntimeException("cannot insert state file : " + stateFile);
|
||||
}
|
||||
}
|
||||
|
||||
restored = restoreEmulatorState(activity, map.toString());
|
||||
|
||||
try {
|
||||
diskArgs.pfd.close(); // at this point diskArgs.pfd !null
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Error attempting to close PFD : " + ioe);
|
||||
}
|
||||
diskArgs.pfd = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "OOPS: " + e);
|
||||
}
|
||||
|
||||
return restored;
|
||||
}
|
||||
|
||||
public static boolean restoreEmulatorState(Apple2Activity activity, String jsonString) {
|
||||
|
||||
boolean restored = false;
|
||||
|
||||
Apple2DisksMenu.ejectDisk(/*isDriveA:*/true);
|
||||
Apple2DisksMenu.ejectDisk(/*isDriveA:*/false);
|
||||
|
||||
// First we extract and open the emulator.a2state disk paths (which could be in a restricted location)
|
||||
jsonString = activity.stateExtractDiskPaths(jsonString);
|
||||
try {
|
||||
|
||||
JSONObject map = new JSONObject(jsonString);
|
||||
|
||||
final String[] diskPathKeys = new String[]{"diskA", "diskB"};
|
||||
final String[] readOnlyKeys = new String[]{"readOnlyA", "readOnlyB"};
|
||||
final String[] fdKeys = new String[]{"fdA", "fdB"};
|
||||
|
||||
ParcelFileDescriptor[] pfds = {null, null};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
String diskPath = map.getString(diskPathKeys[i]);
|
||||
boolean readOnly = map.getBoolean(readOnlyKeys[i]);
|
||||
|
||||
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B, diskPath);
|
||||
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO, readOnly);
|
||||
|
||||
if (diskPath.equals("")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (diskPath.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
|
||||
String uriString = diskPath.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
|
||||
|
||||
Uri uri = Uri.parse(uriString);
|
||||
|
||||
pfds[i] = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, uri);
|
||||
if (pfds[i] == null) {
|
||||
Log.e(TAG, "Did not find URI for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||
} else {
|
||||
int fd = pfds[i].getFd();
|
||||
map.put(fdKeys[i], fd);
|
||||
}
|
||||
} else {
|
||||
boolean exists = new File(diskPath).exists();
|
||||
if (!exists) {
|
||||
Log.e(TAG, "Did not find path for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsonString = activity.loadState(map.toString());
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
try {
|
||||
if (pfds[i] != null) {
|
||||
pfds[i].close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Error attempting to close PFD #" + i + " : " + ioe);
|
||||
}
|
||||
}
|
||||
map = new JSONObject(jsonString);
|
||||
|
||||
restored = map.getBoolean("loadStateSuccess");
|
||||
|
||||
} catch (Throwable t) {
|
||||
Log.v(TAG, "OOPS : " + t);
|
||||
}
|
||||
|
||||
return restored;
|
||||
}
|
||||
|
||||
private void maybeSaveRestore() {
|
||||
mActivity.pauseEmulation();
|
||||
|
||||
final String quickSavePath = Apple2DisksMenu.getDataDir(mActivity) + File.separator + SAVE_FILE;
|
||||
final String quickSavePath;
|
||||
final File extStorage = Apple2Utils.getExternalStorageDirectory(mActivity);
|
||||
|
||||
if (extStorage != null) {
|
||||
quickSavePath = extStorage + File.separator + SAVE_FILE;
|
||||
} else {
|
||||
quickSavePath = Apple2Utils.getDataDir(mActivity) + File.separator + SAVE_FILE;
|
||||
}
|
||||
|
||||
final AtomicBoolean selectionAlreadyHandled = new AtomicBoolean(false);
|
||||
|
||||
@@ -286,34 +442,27 @@ public class Apple2MainMenu {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race in save/restore onClick()");
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race in sync/restore onClick()");
|
||||
return;
|
||||
}
|
||||
mActivity.saveState(quickSavePath);
|
||||
|
||||
String jsonString = "{ \"stateFile\" : \"" + quickSavePath + "\" }";
|
||||
mActivity.saveState(jsonString);
|
||||
Apple2MainMenu.this.dismiss();
|
||||
}
|
||||
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race in save/restore onClick()");
|
||||
Log.v(TAG, "OMG, avoiding nasty UI race in sync/restore onClick()");
|
||||
return;
|
||||
}
|
||||
|
||||
String jsonData = mActivity.loadState(quickSavePath);
|
||||
try {
|
||||
JSONObject map = new JSONObject(jsonData);
|
||||
String diskPath1 = map.getString("disk1");
|
||||
boolean readOnly1 = map.getBoolean("readOnly1");
|
||||
Apple2Preferences.CURRENT_DISK_A.setPath(mActivity, diskPath1);
|
||||
Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(mActivity, readOnly1);
|
||||
|
||||
String diskPath2 = map.getString("disk2");
|
||||
boolean readOnly2 = map.getBoolean("readOnly2");
|
||||
Apple2Preferences.CURRENT_DISK_B.setPath(mActivity, diskPath2);
|
||||
Apple2Preferences.CURRENT_DISK_B_RO.saveBoolean(mActivity, readOnly2);
|
||||
} catch (JSONException je) {
|
||||
Log.v(TAG, "OOPS : " + je);
|
||||
final String jsonString = "{ \"stateFile\" : \"" + quickSavePath + "\" }";
|
||||
boolean restored = restoreEmulatorState(mActivity, jsonString);
|
||||
if (!restored) {
|
||||
Toast.makeText(mActivity, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
Apple2MainMenu.this.dismiss();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.VerticalSeekBar;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Apple2PortraitCalibration implements Apple2MenuView {
|
||||
|
||||
public enum States implements Apple2AbstractMenu.IMenuEnum {
|
||||
CALIBRATE_KEYBOARD_HEIGHT_SCALE {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "portraitHeightScale";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return (float) (PORTRAIT_CALIBRATE_NUM_CHOICES >> 1) / PORTRAIT_CALIBRATE_NUM_CHOICES;
|
||||
}
|
||||
},
|
||||
CALIBRATE_FRAMEBUFFER_POSITION_SCALE {
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_VIDEO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "portraitPositionScale";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 3.f / 4;
|
||||
}
|
||||
},
|
||||
CALIBRATE_KEYBOARD_POSITION_SCALE {
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "portraitPositionScale";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 0.f;
|
||||
}
|
||||
};
|
||||
|
||||
public static final int size = States.values().length;
|
||||
|
||||
States next() {
|
||||
int ord = (ordinal() + 1) % size;
|
||||
return States.values()[ord];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_KEYBOARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private final static String TAG = "Apple2PortraitCalibration";
|
||||
|
||||
public final static int PORTRAIT_CALIBRATE_NUM_CHOICES = 100;
|
||||
|
||||
private Apple2Activity mActivity = null;
|
||||
private View mSettingsView = null;
|
||||
private ArrayList<Apple2MenuView> mViewStack = null;
|
||||
private int mSavedTouchDevice = Apple2SettingsMenu.TouchDeviceVariant.NONE.ordinal();
|
||||
private States mStateMachine = States.CALIBRATE_KEYBOARD_HEIGHT_SCALE;
|
||||
|
||||
public Apple2PortraitCalibration(Apple2Activity activity, ArrayList<Apple2MenuView> viewStack) {
|
||||
mActivity = activity;
|
||||
mViewStack = viewStack;
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mSettingsView = inflater.inflate(R.layout.activity_calibrate_portrait, null, false);
|
||||
|
||||
final Button calibrateButton = (Button) mSettingsView.findViewById(R.id.button_calibrate);
|
||||
final VerticalSeekBar vsb = (VerticalSeekBar) mSettingsView.findViewById(R.id.seekbar_vertical);
|
||||
|
||||
final int firstProgress = Math.round(Apple2Preferences.getFloatJSONPref(States.CALIBRATE_KEYBOARD_HEIGHT_SCALE) * PORTRAIT_CALIBRATE_NUM_CHOICES);
|
||||
vsb.setProgress(firstProgress);
|
||||
|
||||
calibrateButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mStateMachine = mStateMachine.next();
|
||||
switch (mStateMachine) {
|
||||
case CALIBRATE_KEYBOARD_HEIGHT_SCALE:
|
||||
calibrateButton.setText(R.string.portrait_calibrate_keyboard_height);
|
||||
vsb.setProgress(Math.round(Apple2Preferences.getFloatJSONPref(States.CALIBRATE_KEYBOARD_HEIGHT_SCALE) * PORTRAIT_CALIBRATE_NUM_CHOICES));
|
||||
break;
|
||||
case CALIBRATE_FRAMEBUFFER_POSITION_SCALE:
|
||||
calibrateButton.setText(R.string.portrait_calibrate_framebuffer);
|
||||
vsb.setProgress(Math.round(Apple2Preferences.getFloatJSONPref(States.CALIBRATE_FRAMEBUFFER_POSITION_SCALE) * PORTRAIT_CALIBRATE_NUM_CHOICES));
|
||||
break;
|
||||
case CALIBRATE_KEYBOARD_POSITION_SCALE:
|
||||
default:
|
||||
calibrateButton.setText(R.string.portrait_calibrate_keyboard_position);
|
||||
vsb.setProgress(Math.round(Apple2Preferences.getFloatJSONPref(States.CALIBRATE_KEYBOARD_POSITION_SCALE) * PORTRAIT_CALIBRATE_NUM_CHOICES));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
vsb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
switch (mStateMachine) {
|
||||
case CALIBRATE_KEYBOARD_HEIGHT_SCALE:
|
||||
Apple2Preferences.setJSONPref(States.CALIBRATE_KEYBOARD_HEIGHT_SCALE, (float) progress / PORTRAIT_CALIBRATE_NUM_CHOICES);
|
||||
break;
|
||||
case CALIBRATE_FRAMEBUFFER_POSITION_SCALE:
|
||||
Apple2Preferences.setJSONPref(States.CALIBRATE_FRAMEBUFFER_POSITION_SCALE, (float) progress / PORTRAIT_CALIBRATE_NUM_CHOICES);
|
||||
break;
|
||||
case CALIBRATE_KEYBOARD_POSITION_SCALE:
|
||||
default:
|
||||
Apple2Preferences.setJSONPref(States.CALIBRATE_KEYBOARD_POSITION_SCALE, (float) progress / PORTRAIT_CALIBRATE_NUM_CHOICES);
|
||||
break;
|
||||
}
|
||||
Apple2Preferences.sync(mActivity, mStateMachine.getPrefDomain());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
});
|
||||
|
||||
mSavedTouchDevice = (int) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, Apple2SettingsMenu.TouchDeviceVariant.KEYBOARD.ordinal());
|
||||
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN, Apple2Preferences.PREF_CALIBRATING, true);
|
||||
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
}
|
||||
|
||||
public final boolean isCalibrating() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onKeyTapCalibrationEvent(char ascii, int scancode) {
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (isShowing()) {
|
||||
return;
|
||||
}
|
||||
mActivity.pushApple2View(this);
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
for (Apple2MenuView apple2MenuView : mViewStack) {
|
||||
if (apple2MenuView != this) {
|
||||
mActivity.pushApple2View(apple2MenuView);
|
||||
}
|
||||
}
|
||||
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN, Apple2Preferences.PREF_CALIBRATING, false);
|
||||
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, mSavedTouchDevice);
|
||||
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
|
||||
mActivity.popApple2View(this);
|
||||
}
|
||||
|
||||
public void dismissAll() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mSettingsView.getParent() != null;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return mSettingsView;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,30 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
if (position < 0 || position >= SETTINGS.size) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return position != SETTINGS.TOUCH_MENU_VISIBILITY.ordinal();
|
||||
return true;
|
||||
}
|
||||
|
||||
public enum TouchDeviceVariant {
|
||||
NONE(0),
|
||||
JOYSTICK(1),
|
||||
JOYSTICK_KEYPAD(2),
|
||||
KEYBOARD(3),
|
||||
TOPMENU(4),
|
||||
ALERT(5);
|
||||
private int dev;
|
||||
|
||||
public static final TouchDeviceVariant FRAMEBUFFER = NONE;
|
||||
|
||||
public static final int size = TouchDeviceVariant.values().length;
|
||||
|
||||
TouchDeviceVariant(int dev) {
|
||||
this.dev = dev;
|
||||
}
|
||||
|
||||
static TouchDeviceVariant next(int ord) {
|
||||
ord = (ord + 1) % size;
|
||||
return TouchDeviceVariant.values()[ord];
|
||||
}
|
||||
}
|
||||
|
||||
enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
@@ -67,6 +90,21 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.input_current_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "screenOwner";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return TouchDeviceVariant.KEYBOARD.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
@@ -76,6 +114,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.input_current, new String[]{
|
||||
activity.getResources().getString(R.string.joystick),
|
||||
activity.getResources().getString(R.string.keypad),
|
||||
@@ -83,16 +122,33 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.CURRENT_TOUCH_DEVICE.intValue(activity) - 1;
|
||||
int val = (int) Apple2Preferences.getJSONPref(self);
|
||||
return val - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(activity, Apple2Preferences.TouchDeviceVariant.values()[value + 1]);
|
||||
Apple2Preferences.setJSONPref(self, TouchDeviceVariant.values()[value].ordinal() + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
VIDEO_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.video_configure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.video_configure_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
new Apple2VideoSettingsMenu(activity).show();
|
||||
}
|
||||
},
|
||||
JOYSTICK_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
@@ -157,98 +213,6 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
new Apple2AudioSettingsMenu(activity).show();
|
||||
}
|
||||
},
|
||||
VIDEO_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.video_configure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.video_configure_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
_alertDialogHandleSelection(activity, R.string.video_configure, new String[]{
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_bw),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_color),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_interpolated),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.HIRES_COLOR.intValue(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.HIRES_COLOR.saveHiresColor(settingsMenu.mActivity, Apple2Preferences.HiresColor.values()[value]);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
TOUCH_MENU_ENABLED {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_menu_enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_menu_enable_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.TOUCH_MENU_ENABLED.booleanValue(activity));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.TOUCH_MENU_ENABLED.saveBoolean(activity, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
TOUCH_MENU_VISIBILITY {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_menu_visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_menu_visibility_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
return _sliderView(activity, this, Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.TOUCH_MENU_VISIBILITY.saveInt(activity, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return Apple2Preferences.TOUCH_MENU_VISIBILITY.intValue(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
seekBarValue.setText("" + ((float) progress / Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
SHOW_DISK_OPERATIONS {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
@@ -260,14 +224,25 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
return activity.getResources().getString(R.string.disk_show_operation_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "diskAnimationsEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.SHOW_DISK_OPERATIONS.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.SHOW_DISK_OPERATIONS.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
@@ -286,7 +261,26 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
String url = "http://deadc0de.org/apple2ix/android/";
|
||||
String url = "https://deadc0de.org/apple2ix/android/";
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(url));
|
||||
activity.startActivity(i);
|
||||
}
|
||||
},
|
||||
LICENSES {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.about_apple2ix_licenses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.about_apple2ix_licenses_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
String url = "https://deadc0de.org/apple2ix/licenses/";
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(url));
|
||||
activity.startActivity(i);
|
||||
@@ -309,7 +303,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
Apple2Preferences.resetPreferences(activity);
|
||||
Apple2Preferences.reset(activity);
|
||||
}
|
||||
}).setNegativeButton(R.string.no, null);
|
||||
AlertDialog dialog = builder.create();
|
||||
@@ -336,15 +330,26 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "sendCrashReports";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
if (!BuildConfig.DEBUG) {
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.CRASH_CHECK.booleanValue(activity));
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
final IMenuEnum self = this;
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.CRASH_CHECK.saveBoolean(activity, isChecked);
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -388,9 +393,23 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
@@ -44,12 +46,19 @@ public class Apple2SplashScreen implements Apple2MenuView {
|
||||
}
|
||||
});
|
||||
|
||||
Button prefsButton = (Button) mSettingsView.findViewById(R.id.prefsButton);
|
||||
Button prefsButton = (Button) mSettingsView.findViewById(R.id.resetButton);
|
||||
prefsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Apple2SettingsMenu settingsMenu = mActivity.getSettingsMenu();
|
||||
settingsMenu.show();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.preferences_reset_really).setMessage(R.string.preferences_reset_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
Apple2Preferences.reset(mActivity);
|
||||
}
|
||||
}).setNegativeButton(R.string.no, null);
|
||||
AlertDialog dialog = builder.create();
|
||||
mActivity.registerAndShowDialog(dialog);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -70,7 +79,7 @@ public class Apple2SplashScreen implements Apple2MenuView {
|
||||
public void run() {
|
||||
Button startButton = (Button) mSettingsView.findViewById(R.id.startButton);
|
||||
startButton.setEnabled(mDismissable);
|
||||
Button prefsButton = (Button) mSettingsView.findViewById(R.id.prefsButton);
|
||||
Button prefsButton = (Button) mSettingsView.findViewById(R.id.resetButton);
|
||||
prefsButton.setEnabled(mDismissable);
|
||||
Button disksButton = (Button) mSettingsView.findViewById(R.id.disksButton);
|
||||
disksButton.setEnabled(mDismissable);
|
||||
|
||||
507
Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Utils.java
Normal file
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2016 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class Apple2Utils {
|
||||
|
||||
public final static String TAG = "Apple2Utils";
|
||||
|
||||
private static String sDataDir = null;
|
||||
private static File sExternalFilesDir = null;
|
||||
private static File sRealExternalFilesDir = null;
|
||||
|
||||
public static boolean readEntireFile(File file, StringBuilder fileData) {
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
char[] buf = new char[1024];
|
||||
int numRead = 0;
|
||||
while ((numRead = reader.read(buf)) != -1) {
|
||||
String readData = String.valueOf(buf, 0, numRead);
|
||||
fileData.append(readData);
|
||||
}
|
||||
reader.close();
|
||||
break;
|
||||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Error reading file at path : " + file.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException e) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
return attempts < maxAttempts;
|
||||
}
|
||||
|
||||
public static boolean writeFile(final StringBuilder data, File file) {
|
||||
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
|
||||
writer.append(data);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
break;
|
||||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception attempting to write data : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException e) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
return attempts < maxAttempts;
|
||||
}
|
||||
|
||||
public static void migrateToExternalStorage(Apple2Activity activity) {
|
||||
|
||||
do {
|
||||
if (BuildConfig.VERSION_CODE >= 18) {
|
||||
|
||||
// Rename old emulator state file
|
||||
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
|
||||
|
||||
final File srcFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.OLD_SAVE_FILE);
|
||||
if (!srcFile.exists()) {
|
||||
break;
|
||||
}
|
||||
|
||||
final File dstFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE);
|
||||
final boolean success = copyFile(srcFile, dstFile);
|
||||
if (success) {
|
||||
srcFile.delete();
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
|
||||
final File extStorage = Apple2Utils.getExternalStorageDirectory(activity);
|
||||
if (extStorage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (BuildConfig.VERSION_CODE >= 18) {
|
||||
|
||||
// Migrate old emulator state file from internal path to external storage to allow user manipulation
|
||||
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
|
||||
|
||||
final File srcFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE);
|
||||
if (!srcFile.exists()) {
|
||||
break;
|
||||
}
|
||||
|
||||
final File dstFile = new File(extStorage + File.separator + Apple2MainMenu.SAVE_FILE);
|
||||
final boolean success = copyFile(srcFile, dstFile);
|
||||
if (success) {
|
||||
srcFile.delete();
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
do {
|
||||
if (BuildConfig.VERSION_CODE >= 20) {
|
||||
|
||||
// Recursively rename all *.state files found in /sdcard/apple2ix
|
||||
// TODO FIXME : Remove this migration code when all/most users are on version >= 20
|
||||
|
||||
recursivelyRenameEmulatorStateFiles(extStorage);
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
|
||||
public static File getExternalStorageDirectory(Apple2Activity activity) {
|
||||
|
||||
do {
|
||||
if (sExternalFilesDir != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
String storageState = Environment.getExternalStorageState();
|
||||
if (!Environment.MEDIA_MOUNTED.equals(storageState)) {
|
||||
// 2015/10/28 : do not expose sExternalFilesDir unless it is writable
|
||||
break;
|
||||
}
|
||||
|
||||
File realExternalStorageDir = Environment.getExternalStorageDirectory();
|
||||
if (realExternalStorageDir == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
File externalDir = new File(realExternalStorageDir, "apple2ix"); // /sdcard/apple2ix
|
||||
if (!externalDir.exists()) {
|
||||
boolean made = externalDir.mkdirs();
|
||||
if (!made) {
|
||||
Log.d(TAG, "WARNING: could not make directory : " + sExternalFilesDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sExternalFilesDir = externalDir;
|
||||
sRealExternalFilesDir = realExternalStorageDir;
|
||||
} while (false);
|
||||
|
||||
return sExternalFilesDir;
|
||||
}
|
||||
|
||||
public static File getRealExternalStorageDirectory(Apple2Activity activity) {
|
||||
getExternalStorageDirectory(activity);
|
||||
return sRealExternalFilesDir;
|
||||
}
|
||||
|
||||
public static boolean isExternalStorageAccessible(Apple2Activity activity) {
|
||||
getExternalStorageDirectory(activity);
|
||||
return (sRealExternalFilesDir != null) && (new File(sRealExternalFilesDir.getAbsolutePath()).listFiles() != null);
|
||||
}
|
||||
|
||||
// HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources
|
||||
// out of the APK and into the /data/data/... for ease of access. Because this is FOSS software we don't care about
|
||||
// security or DRM for these assets =)
|
||||
public static String getDataDir(Apple2Activity activity) {
|
||||
|
||||
if (sDataDir != null) {
|
||||
return sDataDir;
|
||||
}
|
||||
|
||||
try {
|
||||
PackageManager pm = activity.getPackageManager();
|
||||
PackageInfo pi = pm.getPackageInfo(activity.getPackageName(), 0);
|
||||
sDataDir = pi.applicationInfo.dataDir;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "" + e);
|
||||
if (sDataDir == null) {
|
||||
sDataDir = "/data/local/tmp";
|
||||
}
|
||||
}
|
||||
|
||||
return sDataDir;
|
||||
}
|
||||
|
||||
public static void exposeAPKAssetsToExternal(Apple2Activity activity) {
|
||||
getExternalStorageDirectory(activity);
|
||||
if (sExternalFilesDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
bar.setIndeterminate(true);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ...");
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath(), false);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #2");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void exposeAPKAssets(Apple2Activity activity) {
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
bar.setIndeterminate(true);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
getDataDir(activity);
|
||||
|
||||
// FIXME TODO : Heavy-handed migration to 1.1.3 ...
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "blanks"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "demo"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "eamon"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "logo"));
|
||||
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "miscgame"));
|
||||
|
||||
Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access...");
|
||||
|
||||
getExternalStorageDirectory(activity);
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath(), true);
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath(), false);
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath(), false);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void exposeSymbols(Apple2Activity activity) {
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"symbols", /*to location:*/new File(sDataDir, "symbols").getAbsolutePath(), false);
|
||||
}
|
||||
|
||||
public static void unexposeSymbols(Apple2Activity activity) {
|
||||
recursivelyDelete(new File(sDataDir, "symbols"));
|
||||
}
|
||||
|
||||
// TODO FIXME : WARNING : this is super dangerous if there are symlinks !!!
|
||||
private static void recursivelyDelete(File file) {
|
||||
if (file.isDirectory()) {
|
||||
for (File f : file.listFiles()) {
|
||||
recursivelyDelete(f);
|
||||
}
|
||||
}
|
||||
if (!file.delete()) {
|
||||
Log.d(TAG, "Failed to delete file: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void recursivelyCopyAPKAssets(Apple2Activity activity, String srcFileOrDir, String dstFileOrDir, boolean shouldGzip) {
|
||||
AssetManager assetManager = activity.getAssets();
|
||||
|
||||
final int maxAttempts = 5;
|
||||
String[] files = null;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
files = assetManager.list(srcFileOrDir);
|
||||
break;
|
||||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "OOPS exception attempting to list APK files at : " + srcFileOrDir + " : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException ie) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
if (files == null) {
|
||||
Log.d(TAG, "OOPS, could not list APK assets at : " + srcFileOrDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (files.length > 0) {
|
||||
// ensure destination directory exists
|
||||
File dstPath = new File(dstFileOrDir);
|
||||
if (!dstPath.mkdirs()) {
|
||||
if (!dstPath.exists()) {
|
||||
Log.d(TAG, "OOPS, could not mkdirs on " + dstPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (String filename : files) {
|
||||
// iterate on files and subdirectories
|
||||
recursivelyCopyAPKAssets(activity, srcFileOrDir + File.separator + filename, dstFileOrDir + File.separator + filename, shouldGzip);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// presumably this is a file, not a subdirectory
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
attempts = 0;
|
||||
do {
|
||||
try {
|
||||
is = assetManager.open(srcFileOrDir);
|
||||
if (shouldGzip) {
|
||||
os = new GZIPOutputStream(new FileOutputStream(dstFileOrDir + ".gz"));
|
||||
} else {
|
||||
os = new FileOutputStream(dstFileOrDir);
|
||||
}
|
||||
copyFile(is, os);
|
||||
break;
|
||||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to copy asset file: " + srcFileOrDir, e);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException ie) {
|
||||
/* ... */
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
}
|
||||
|
||||
private static void recursivelyRenameEmulatorStateFiles(File directory) {
|
||||
try {
|
||||
if (!directory.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int oldSuffixLen = 6;
|
||||
|
||||
File[] files = directory.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
|
||||
if (name.equals(".") || name.equals("..")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final File file = new File(dir, name);
|
||||
if (file.isDirectory()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final int len = name.length();
|
||||
if (len < oldSuffixLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String suffix = name.substring(len - oldSuffixLen, len);
|
||||
return suffix.equalsIgnoreCase(".state");
|
||||
}
|
||||
});
|
||||
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
recursivelyRenameEmulatorStateFiles(file);
|
||||
} else {
|
||||
final File srcFile = file;
|
||||
final String oldName = file.getName();
|
||||
final String newName = oldName.substring(0, oldName.length() - oldSuffixLen) + Apple2MainMenu.SAVE_FILE_EXTENSION;
|
||||
boolean success = file.renameTo(new File(file.getParentFile(), newName));
|
||||
if (success) {
|
||||
srcFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "OOPS : {e}");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean copyFile(final File srcFile, final File dstFile) {
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
FileInputStream is = new FileInputStream(srcFile);
|
||||
FileOutputStream os = new FileOutputStream(dstFile);
|
||||
copyFile(is, os);
|
||||
break;
|
||||
} catch (InterruptedIOException e) {
|
||||
// EINTR, EAGAIN ...
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "OOPS exception attempting to copy emulator state file : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException ie) {
|
||||
// ...
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
return attempts < maxAttempts;
|
||||
}
|
||||
|
||||
private static void copyFile(InputStream is, OutputStream os) throws IOException {
|
||||
final int BUF_SZ = 4096;
|
||||
byte[] buf = new byte[BUF_SZ];
|
||||
while (true) {
|
||||
int len = is.read(buf, 0, BUF_SZ);
|
||||
if (len < 0) {
|
||||
break;
|
||||
}
|
||||
os.write(buf, 0, len);
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "Apple2VideoSettingsMenu";
|
||||
|
||||
public Apple2VideoSettingsMenu(Apple2Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String[] allTitles() {
|
||||
return SETTINGS.titles(mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IMenuEnum[] allValues() {
|
||||
return SETTINGS.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean areAllItemsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isEnabled(int position) {
|
||||
if (position < 0 || position >= SETTINGS.size) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (position == SETTINGS.PORTRAIT_CALIBRATE.ordinal()) {
|
||||
if ((boolean) Apple2Preferences.getJSONPref(SETTINGS.LANDSCAPE_MODE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public enum HiresColor {
|
||||
BW,
|
||||
COLOR,
|
||||
INTERPOLATED
|
||||
}
|
||||
|
||||
// must match interface_colorscheme_t
|
||||
public enum DeviceColor {
|
||||
GREEN_ON_BLACK(0),
|
||||
GREEN_ON_BLUE(1), // ...
|
||||
RED_ON_BLACK(2),
|
||||
BLUE_ON_BLACK(3),
|
||||
WHITE_ON_BLACK(4);
|
||||
|
||||
private int val;
|
||||
|
||||
DeviceColor(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
LANDSCAPE_MODE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.mode_landscape);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.mode_landscape_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "landscapeEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(final Apple2Activity activity, View convertView) {
|
||||
final Object self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref((IMenuEnum) self, isChecked);
|
||||
applyLandscapeMode(activity);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
PORTRAIT_CALIBRATE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.portrait_calibrate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.portrait_calibrate_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
ArrayList<Apple2MenuView> viewStack = new ArrayList<Apple2MenuView>();
|
||||
{
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
Apple2MenuView apple2MenuView = activity.peekApple2View(idx);
|
||||
if (apple2MenuView == null) {
|
||||
break;
|
||||
}
|
||||
viewStack.add(apple2MenuView);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
// switch to portrait
|
||||
Apple2Preferences.setJSONPref(SETTINGS.LANDSCAPE_MODE, false);
|
||||
applyLandscapeMode(activity);
|
||||
Apple2PortraitCalibration calibration = new Apple2PortraitCalibration(activity, viewStack);
|
||||
|
||||
// show this new view...
|
||||
calibration.show();
|
||||
|
||||
// ...with nothing else underneath 'cept the emulator OpenGL layer
|
||||
for (Apple2MenuView apple2MenuView : viewStack) {
|
||||
activity.popApple2View(apple2MenuView);
|
||||
}
|
||||
}
|
||||
},
|
||||
COLOR_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.color_configure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.color_configure_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_VIDEO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "colorMode";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return HiresColor.INTERPOLATED.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final Apple2AbstractMenu.IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.video_configure, new String[]{
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_bw),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_color),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_interpolated),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, HiresColor.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
COLOR_DEVICE_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_device_color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_device_color_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "hudColorMode";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return DeviceColor.RED_ON_BLACK.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final Apple2AbstractMenu.IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.touch_device_color_configure, new String[]{
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_red_on_black),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_green_on_black),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_blue_on_black),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_white_on_black),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
int colorscheme = (int) Apple2Preferences.getJSONPref(self);
|
||||
if (colorscheme == DeviceColor.GREEN_ON_BLACK.ordinal()) {
|
||||
return 1;
|
||||
} else if (colorscheme == DeviceColor.BLUE_ON_BLACK.ordinal()) {
|
||||
return 2;
|
||||
} else if (colorscheme == DeviceColor.WHITE_ON_BLACK.ordinal()) {
|
||||
return 3;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
switch (value) {
|
||||
case 1:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.GREEN_ON_BLACK.ordinal());
|
||||
break;
|
||||
case 2:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.BLUE_ON_BLACK.ordinal());
|
||||
break;
|
||||
case 3:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.WHITE_ON_BLACK.ordinal());
|
||||
break;
|
||||
default:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.RED_ON_BLACK.ordinal());
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
return _basicView(activity, this, convertView);
|
||||
}
|
||||
|
||||
public static boolean applyLandscapeMode(final Apple2Activity activity) {
|
||||
if ((boolean) Apple2Preferences.getJSONPref(SETTINGS.LANDSCAPE_MODE)) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
return false;
|
||||
} else {
|
||||
int orientation = activity.getRequestedOrientation();
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
return orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] titles(Apple2Activity activity) {
|
||||
String[] titles = new String[size];
|
||||
int i = 0;
|
||||
for (SETTINGS setting : values()) {
|
||||
titles[i++] = setting.getTitle(activity);
|
||||
}
|
||||
return titles;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.example.inputmanagercompat.InputManagerCompat;
|
||||
|
||||
@@ -42,6 +43,7 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
|
||||
public final static long NATIVE_TOUCH_HANDLED = (1 << 0);
|
||||
public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1);
|
||||
public final static long NATIVE_TOUCH_REQUEST_SHOW_SYSTEM_KBD = (1 << 2);
|
||||
|
||||
public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4);
|
||||
public final static long NATIVE_TOUCH_KBD = (1 << 5);
|
||||
@@ -50,8 +52,6 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
public final static long NATIVE_TOUCH_JOY_KPAD = (1 << 8);
|
||||
|
||||
public final static long NATIVE_TOUCH_INPUT_DEVICE_CHANGED = (1 << 16);
|
||||
public final static long NATIVE_TOUCH_CPU_SPEED_DEC = (1 << 17);
|
||||
public final static long NATIVE_TOUCH_CPU_SPEED_INC = (1 << 18);
|
||||
|
||||
public final static long NATIVE_TOUCH_ASCII_SCANCODE_SHIFT = 32;
|
||||
public final static long NATIVE_TOUCH_ASCII_SCANCODE_MASK = 0xFFFFL;
|
||||
@@ -60,16 +60,15 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
|
||||
|
||||
private Apple2Activity mActivity;
|
||||
private Runnable mGraphicsInitializedRunnable;
|
||||
private final InputManagerCompat mInputManager;
|
||||
|
||||
private float[] mXCoords = new float[MAX_FINGERS];
|
||||
private float[] mYCoords = new float[MAX_FINGERS];
|
||||
|
||||
private int mWidth = 0;
|
||||
private int mHeight = 0;
|
||||
|
||||
private static native void nativeGraphicsInitialized(int width, int height);
|
||||
|
||||
private static native void nativeGraphicsChanged(int width, int height);
|
||||
private static native void nativeGraphicsInitialized();
|
||||
|
||||
private static native void nativeRender();
|
||||
|
||||
@@ -78,10 +77,9 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
public static native long nativeOnTouch(int action, int pointerCount, int pointerIndex, float[] xCoords, float[] yCoords);
|
||||
|
||||
|
||||
public Apple2View(Apple2Activity activity, Runnable graphicsInitializedRunnable) {
|
||||
public Apple2View(Apple2Activity activity) {
|
||||
super(activity.getApplication());
|
||||
mActivity = activity;
|
||||
mGraphicsInitializedRunnable = graphicsInitializedRunnable;
|
||||
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
@@ -123,13 +121,12 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
Apple2View.this.getWindowVisibleDisplayFrame(rect);
|
||||
int h = rect.height();
|
||||
int w = rect.width();
|
||||
if (w < h) {
|
||||
// assure landscape dimensions
|
||||
final int w_ = w;
|
||||
w = h;
|
||||
h = w_;
|
||||
if (w != mWidth || h != mHeight) {
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_DEVICE_WIDTH, mWidth);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_DEVICE_HEIGHT, mHeight);
|
||||
}
|
||||
nativeGraphicsChanged(w, h);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -358,25 +355,17 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
Apple2Preferences.GL_VENDOR.saveString(mActivity, GLES20.glGetString(GLES20.GL_VENDOR));
|
||||
Apple2Preferences.GL_RENDERER.saveString(mActivity, GLES20.glGetString(GLES20.GL_RENDERER));
|
||||
Apple2Preferences.GL_VERSION.saveString(mActivity, GLES20.glGetString(GLES20.GL_VERSION));
|
||||
Apple2Preferences.setJSONPref(Apple2CrashHandler.SETTINGS.GL_VENDOR, GLES20.glGetString(GLES20.GL_VENDOR));
|
||||
Apple2Preferences.setJSONPref(Apple2CrashHandler.SETTINGS.GL_RENDERER, GLES20.glGetString(GLES20.GL_RENDERER));
|
||||
Apple2Preferences.setJSONPref(Apple2CrashHandler.SETTINGS.GL_VERSION, GLES20.glGetString(GLES20.GL_VERSION));
|
||||
|
||||
Log.v(TAG, "graphicsInitialized(" + width + ", " + height + ")");
|
||||
|
||||
if (width < height) {
|
||||
// assure landscape dimensions
|
||||
final int w_ = width;
|
||||
width = height;
|
||||
height = w_;
|
||||
}
|
||||
|
||||
nativeGraphicsInitialized(width, height);
|
||||
|
||||
if (Apple2View.this.mGraphicsInitializedRunnable != null) {
|
||||
Apple2View.this.mGraphicsInitializedRunnable.run();
|
||||
Apple2View.this.mGraphicsInitializedRunnable = null;
|
||||
}
|
||||
Apple2View.this.mWidth = width;
|
||||
Apple2View.this.mHeight = height;
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_DEVICE_WIDTH, mWidth);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_DEVICE_HEIGHT, mHeight);
|
||||
nativeGraphicsInitialized();
|
||||
|
||||
Apple2View.this.mActivity.maybeResumeEmulation();
|
||||
}
|
||||
@@ -517,7 +506,7 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
}
|
||||
|
||||
if ((nativeFlags & NATIVE_TOUCH_KEY_TAP) != 0) {
|
||||
if (Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(mActivity)) {
|
||||
if ((boolean) Apple2Preferences.getJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_ENABLE_CLICK)) {
|
||||
AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
|
||||
if (am != null) {
|
||||
am.playSoundEffect(AudioManager.FX_KEY_CLICK);
|
||||
@@ -533,44 +522,15 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
||||
}
|
||||
}
|
||||
|
||||
if ((nativeFlags & NATIVE_TOUCH_MENU) == 0) {
|
||||
break;
|
||||
if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_SYSTEM_KBD) != 0) {
|
||||
clearFocus();
|
||||
requestFocus();
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (inputMethodManager != null) {
|
||||
inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_FORCED);
|
||||
}
|
||||
}
|
||||
|
||||
// handle menu-specific actions
|
||||
|
||||
if ((nativeFlags & NATIVE_TOUCH_INPUT_DEVICE_CHANGED) != 0) {
|
||||
Apple2Preferences.TouchDeviceVariant nextVariant;
|
||||
if ((nativeFlags & NATIVE_TOUCH_KBD) != 0) {
|
||||
nextVariant = Apple2Preferences.TouchDeviceVariant.KEYBOARD;
|
||||
} else if ((nativeFlags & NATIVE_TOUCH_JOY) != 0) {
|
||||
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK;
|
||||
} else if ((nativeFlags & NATIVE_TOUCH_JOY_KPAD) != 0) {
|
||||
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD;
|
||||
} else {
|
||||
int touchDevice = Apple2Preferences.nativeGetCurrentTouchDevice();
|
||||
nextVariant = Apple2Preferences.TouchDeviceVariant.next(touchDevice);
|
||||
}
|
||||
Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(mActivity, nextVariant);
|
||||
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_DEC) != 0) {
|
||||
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
|
||||
if (percentSpeed > 400) { // HACK: max value from native side
|
||||
percentSpeed = 375;
|
||||
} else if (percentSpeed > 100) {
|
||||
percentSpeed -= 25;
|
||||
} else {
|
||||
percentSpeed -= 5;
|
||||
}
|
||||
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(mActivity, percentSpeed);
|
||||
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_INC) != 0) {
|
||||
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
|
||||
if (percentSpeed >= 100) {
|
||||
percentSpeed += 25;
|
||||
} else {
|
||||
percentSpeed += 5;
|
||||
}
|
||||
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(mActivity, percentSpeed);
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/a2preference_title"
|
||||
android:layout_alignLeft="@id/a2preference_title"
|
||||
android:layout_alignStart="@id/a2preference_title"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:maxLines="4" />
|
||||
|
||||
|
||||
37
Android/app/src/main/res/layout/a2reset_confirmation.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton_openApple"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/reboot" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton_closedApple"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/reset_self_test" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton_noApple"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/reset_soft" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/calibratePortrait"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/preference_margin_bottom"
|
||||
android:layout_marginEnd="@dimen/preference_margin_right"
|
||||
android:layout_marginLeft="@dimen/preference_margin_left"
|
||||
android:layout_marginRight="@dimen/preference_margin_right"
|
||||
android:layout_marginStart="@dimen/preference_margin_left"
|
||||
android:layout_marginTop="@dimen/preference_margin_top"
|
||||
android:layout_weight="1">
|
||||
|
||||
<android.widget.VerticalSeekBar
|
||||
android:id="@+id/seekbar_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_alignTop="@+id/button_calibrate" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_calibrate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/portrait_calibrate_keyboard_height"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -20,11 +20,26 @@
|
||||
android:layout_marginLeft="@dimen/preference_margin_left"
|
||||
android:layout_marginStart="@dimen/preference_margin_left"
|
||||
android:layout_marginTop="@dimen/preference_margin_top"
|
||||
android:background="@color/white"
|
||||
android:textColor="@color/black"
|
||||
android:text="@string/keypad_choose_current" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/noneButton"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginEnd="@dimen/preference_margin_right"
|
||||
android:layout_marginRight="@dimen/preference_margin_right"
|
||||
android:layout_marginTop="@dimen/preference_margin_top"
|
||||
android:text="@string/key_none" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/skipButton"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_below="@id/noneButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
|
||||
@@ -1,39 +1,212 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:background="@color/black"
|
||||
android:orientation="vertical"
|
||||
android:baselineAligned="false"
|
||||
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" >
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginBottom="5dip"
|
||||
android:layout_marginLeft="5dip"
|
||||
android:layout_marginStart="5dip"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_marginEnd="5dip"
|
||||
android:layout_marginTop="5dip"
|
||||
android:background="@color/black"
|
||||
android:layout_weight="1">
|
||||
|
||||
<!-- disk selection header -->
|
||||
<LinearLayout
|
||||
android:background="@color/black"
|
||||
android:orientation="horizontal"
|
||||
android:baselineAligned="false"
|
||||
android:id="@+id/disks_selection_header"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- newschool checkbox -->
|
||||
<CheckBox
|
||||
android:id="@+id/newschoolDiskSelectionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disk_selection_newschoool" />
|
||||
|
||||
<!-- spacer that works with API 10 ... -->
|
||||
<TextView
|
||||
android:id="@+id/header_disks"
|
||||
style="?android:attr/listSeparatorTextViewStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/header_disks" />
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/ejectButton1"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@android:drawable/ic_menu_close_clear_cancel"
|
||||
android:drawableStart="@android:drawable/ic_menu_close_clear_cancel"
|
||||
android:id="@+id/cancelButton" />
|
||||
android:text="@string/header_eject_1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/ejectButton2"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/header_eject_2" />
|
||||
|
||||
<!-- spacer that works with API 10 ... -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancelButton"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableEnd="@android:drawable/ic_menu_close_clear_cancel"
|
||||
android:drawableRight="@android:drawable/ic_menu_close_clear_cancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- oldschool list view -->
|
||||
<ListView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/listView_settings"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_alignLeft="@id/disks_selection_header"
|
||||
android:layout_alignStart="@id/disks_selection_header"
|
||||
android:layout_below="@id/disks_selection_header"
|
||||
android:visibility="invisible"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- newschool file chooser -->
|
||||
<LinearLayout
|
||||
android:id="@+id/disk_selection_newschool_chooser"
|
||||
android:layout_alignLeft="@id/disks_selection_header"
|
||||
android:layout_alignStart="@id/disks_selection_header"
|
||||
android:layout_below="@id/disks_selection_header"
|
||||
android:layout_marginLeft="5dip"
|
||||
android:layout_marginStart="5dip"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_marginEnd="5dip"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dip"
|
||||
android:layout_marginTop="20dip"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:text="@+string/file_chooser"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<!-- spacer that works with API 10 ... -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:src="@android:drawable/ic_menu_save"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- newschool drive A selection -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/a2_newschool_driveA_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/disk_selection_newschool_chooser"
|
||||
android:layout_alignStart="@id/disk_selection_newschool_chooser"
|
||||
android:layout_below="@id/disk_selection_newschool_chooser"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingRight="?android:attr/scrollbarSize"
|
||||
android:paddingEnd="?android:attr/scrollbarSize">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dip"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_marginEnd="5dip"
|
||||
android:layout_marginTop="5dip"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/a2_newschool_driveA"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:text="@+string/diskA"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/a2_newschool_diskA"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/a2_newschool_driveA"
|
||||
android:layout_alignStart="@id/a2_newschool_driveA"
|
||||
android:layout_below="@id/a2_newschool_driveA"
|
||||
android:maxLines="4"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- newschool drive B selection -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/a2_newschool_driveB_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/a2_newschool_driveA_layout"
|
||||
android:layout_alignStart="@id/a2_newschool_driveA_layout"
|
||||
android:layout_below="@id/a2_newschool_driveA_layout"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingRight="?android:attr/scrollbarSize"
|
||||
android:paddingEnd="?android:attr/scrollbarSize">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dip"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_marginTop="5dip"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/a2_newschool_driveB"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:text="@+string/diskB"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/a2_newschool_diskB"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/a2_newschool_driveB"
|
||||
android:layout_alignStart="@id/a2_newschool_driveB"
|
||||
android:layout_below="@id/a2_newschool_driveB"
|
||||
android:maxLines="4"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -45,8 +45,8 @@
|
||||
<Button
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:text="@string/emulation_settings"
|
||||
android:id="@+id/prefsButton"
|
||||
android:text="@string/reset_preferences"
|
||||
android:id="@+id/resetButton"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_below="@+id/startButton"
|
||||
android:layout_alignRight="@+id/startButton"
|
||||
@@ -60,7 +60,7 @@
|
||||
android:text="@string/emulation_disks"
|
||||
android:id="@+id/disksButton"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_below="@+id/prefsButton"
|
||||
android:layout_below="@+id/resetButton"
|
||||
android:layout_alignRight="@+id/startButton"
|
||||
android:layout_alignEnd="@+id/startButton"
|
||||
android:layout_alignLeft="@+id/startButton"
|
||||
|
||||
192
Android/app/src/main/res/values-de/strings.xml
Normal file
@@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<color name="black">#000000</color>
|
||||
<color name="white">#ffffff</color>
|
||||
|
||||
<!-- developer-only options -->
|
||||
<string name="crasher_summary">Test crash generation</string>
|
||||
<string name="crasher_title">Crash emulator</string>
|
||||
<string name="crash_null">NULL-deref</string>
|
||||
<string name="crash_java_npe">Java NPE</string>
|
||||
<string name="crash_stackcall_overflow">stack call overflow</string>
|
||||
<string name="crash_stackbuf_overflow">stack buffer overflow</string>
|
||||
|
||||
<!-- main options -->
|
||||
<string name="about_apple2ix">Über Apple2ix…</string>
|
||||
<string name="about_apple2ix_summary">Über diese Software</string>
|
||||
<string name="about_apple2ix_licenses">Licenses…</string>
|
||||
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
|
||||
<string name="app_name">Apple2ix</string>
|
||||
<string name="audio_configure">Audio-Konfiguration…</string>
|
||||
<string name="audio_configure_summary">Lautstärke, Mockingboard, etc</string>
|
||||
<string name="audio_latency">Audio Latency</string>
|
||||
<string name="audio_latency_summary">Audio Latency in Sek.</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="color_bw">Schwarz/Weiss</string>
|
||||
<string name="color_color">Farbe</string>
|
||||
<string name="color_interpolated">Interpolierte Farben</string>
|
||||
<string name="crasher">Abstürze</string>
|
||||
<string name="crasher_check_title">Prüfe auf Absturz-Berichte</string>
|
||||
<string name="crasher_check_summary">Prüfe auf Absturz-Berichte zum Versand an den Entwickler</string>
|
||||
<string name="crasher_send">Sende Absturz-Bericht?</string>
|
||||
<string name="crasher_send_message">Entschuldigung. es gab ein Problemm. Möchten Sie einen Absturz-Bericht an den Entwickler senden?</string>
|
||||
<string name="diskA">Laufwerk 1</string>
|
||||
<string name="diskB">Laufwerk 2</string>
|
||||
<string name="disk_eject">Auswerfen</string>
|
||||
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
|
||||
<string name="disk_read_only">Schreibgeschützt</string>
|
||||
<string name="disk_read_write">Lesen/Schreiben</string>
|
||||
<string name="disk_selection_newschoool">System chooser</string>
|
||||
<string name="disk_show_operation">Zeige Disk ][ Aktivität</string>
|
||||
<string name="disk_show_operation_summary">Zeigt wenn die Laufwerke lesen oder schreiben</string>
|
||||
<string name="emulation_continue">Fortsetzen…</string>
|
||||
<string name="emulation_disks">Lade Disk-Image…</string>
|
||||
<string name="file_chooser">Choose disk image or state file…</string>
|
||||
<string name="header_disks">Diskette einlegen:</string>
|
||||
<string name="header_eject_1">Auswerfen 1</string>
|
||||
<string name="header_eject_2">Auswerfen 2</string>
|
||||
<string name="input_current">Aktuelles Touch Device</string>
|
||||
<string name="input_current_summary">Wähle ein aktuelles Touch Device</string>
|
||||
<string name="joystick">Joystick</string>
|
||||
<string name="joystick_axis_sensitivity_summary">Empfindlichkeiteinstellung der Joystickachsen (verlangsamen or beschleunigen)</string>
|
||||
<string name="joystick_button_button1">Button 1 (Offener Apfel)</string>
|
||||
<string name="joystick_button_button2">Button 2 (Geschlossener Apfel)</string>
|
||||
<string name="joystick_button_button_both">Beide</string>
|
||||
<string name="joystick_button_button_none">Keine</string>
|
||||
<string name="joystick_button_tap_button">Drücke den Feuerknopf</string>
|
||||
<string name="joystick_button_tap_button_summary">Ausgewählter Feuerknopf</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystickknopf-Zeitverzögerung in Sek.</string>
|
||||
<string name="joystick_button_swipe_up_button">Aufwärts wischen zum feuern</string>
|
||||
<string name="joystick_button_swipe_up_button_summary">Feuerknopf zum feuern beim aufwärts wischen</string>
|
||||
<string name="joystick_button_swipe_down_button">Abwärts wischen zum feuern</string>
|
||||
<string name="joystick_button_swipe_down_button_summary">Feuerknopf zum feuern beim abwärts wischen</string>
|
||||
<string name="joystick_button_threshold_summary">Joystick/Keypad Knopf Schaltschwellwert in pts</string>
|
||||
<string name="joystick_calibrate">Kalibrieren…</string>
|
||||
<string name="joystick_calibrate_summary">Konfiguriere und teste die aktuellen Einstellungen</string>
|
||||
<string name="joystick_configure">Joystickkonfiguration…</string>
|
||||
<string name="joystick_configure_summary">Achsen Touch, Knöpfe, etc</string>
|
||||
<string name="joystick_axisleft">Joystick/Keypad Achse links</string>
|
||||
<string name="joystick_axisleft_summary">Joystick/Keypad Achse links (Knöpfe rechts)</string>
|
||||
<string name="joystick_visible">Sichtbarkeit Joystick/Keypad</string>
|
||||
<string name="joystick_visible_summary">Zeige die Kontrollen als Overlay wenn aktiviert</string>
|
||||
<string name="key_closed_apple">[GeschlossenerApfel]</string>
|
||||
<string name="key_ctrl">[Strg]</string>
|
||||
<string name="key_down">↓</string>
|
||||
<string name="key_esc">[ESC]</string>
|
||||
<string name="key_left">←</string>
|
||||
<string name="key_none">[Keine]</string>
|
||||
<string name="key_open_apple">[OffenerApfel]</string>
|
||||
<string name="key_ret">[Return]</string>
|
||||
<string name="key_right">→</string>
|
||||
<string name="key_space">[Space]</string>
|
||||
<string name="key_up">↑</string>
|
||||
<string name="keyboard">Tastatur</string>
|
||||
<string name="keyboard_choose_alt">Wähle alternative Tastatur…</string>
|
||||
<string name="keyboard_choose_alt_summary">Wähle alternativ konfiguriertes Layout</string>
|
||||
<string name="keyboard_click_enabled">Tastenton einschalten</string>
|
||||
<string name="keyboard_click_enabled_summary">Aktiviert Tastenton wenn verfügbar</string>
|
||||
<string name="keyboard_configure">Tastatur-Konfiguration…</string>
|
||||
<string name="keyboard_configure_summary">Transparenz, Kleinbuchstaben, eigene Tasten</string>
|
||||
<string name="keyboard_glyph_scale">Tastatur-Glyphenskalierung 2x</string>
|
||||
<string name="keyboard_glyph_scale_summary">(Lässt die Tastaur weniger pixelig erscheinen auf grossen Bildschirmen)</string>
|
||||
<string name="keyboard_lowercase_enabled">Kleinbuchstaben aktivieren</string>
|
||||
<string name="keyboard_lowercase_enabled_summary">Aktiviren der Tasten für Kleinbuchstaben</string>
|
||||
<string name="keyboard_visibility_active">Sichtbarkeit wenn aktiviert</string>
|
||||
<string name="keyboard_visibility_active_summary">Sichtbarkeit des Keyboard und Touch Menüs wenn aktiviert</string>
|
||||
<string name="keyboard_visibility_inactive">Sichtbarkeit wenn deaktiviert</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Sichtbarkeit des Keyboard und Touch Menüs wenn deaktiviert</string>
|
||||
<string name="keypad">Keypad Joystick</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
<string name="keypad_choose">Auswahl der Keypad Tasten…</string>
|
||||
<string name="keypad_choose_summary">Auswahl der Achsen und Knopf Tasten</string>
|
||||
<string name="keypad_choose_title">Achse & Knöpfe</string>
|
||||
<string name="keypad_choose_current">Wähle XXX Taste: </string>
|
||||
<string name="keypad_configure">Konfiguration Joystick Keypad…</string>
|
||||
<string name="keypad_configure_summary">@string/joystick_configure_summary</string>
|
||||
<string name="keypad_key_axis_c">Mitte</string>
|
||||
<string name="keypad_key_axis_dn">Unten</string>
|
||||
<string name="keypad_key_axis_dl">Unten und Links</string>
|
||||
<string name="keypad_key_axis_dr">Unten und Rechts</string>
|
||||
<string name="keypad_key_axis_l">Links</string>
|
||||
<string name="keypad_key_axis_r">Rechts</string>
|
||||
<string name="keypad_key_axis_ul">Oben und Links</string>
|
||||
<string name="keypad_key_axis_up">Oben</string>
|
||||
<string name="keypad_key_axis_ur">Oben und Rechts</string>
|
||||
<string name="keypad_key_button_tap">antippen</string>
|
||||
<string name="keypad_key_button_swipeup">Nach oben wischen</string>
|
||||
<string name="keypad_key_button_swipedown">Nach unten wischen</string>
|
||||
<string name="keypad_preset_crazy_seafox">Seafox Tasten ;-)…</string>
|
||||
<string name="keypad_preset_custom">Auswahl einer Anpassung…</string>
|
||||
<string name="keypad_preset_arrows_space">↑,←,→,↓, tippe auf die Leerstaste</string>
|
||||
<string name="keypad_preset_az_left_right_space">A,Z,←,→, tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_ijkm_space">I,J,K,M, tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_left_right_space">←,→, tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_wadx_space">W,A,D,X, tippe auf die Leertaste</string>
|
||||
<string name="keypad_repeat_summary">Tastenwiederholungsschwellwert in Sek.</string>
|
||||
<string name="menu_disks">Lade Disk-Image…</string>
|
||||
<string name="menu_disks_summary">Einlegen eines Disk ][ Image</string>
|
||||
<string name="menu_settings">Emulator Einstellungen…</string>
|
||||
<string name="menu_settings_summary">Allgemeine Einstellungen, Joystick, Tastatur</string>
|
||||
<string name="mockingboard_disabled_title">Mockingboard deaktiviert</string>
|
||||
<string name="mockingboard_disabled_mesg">Mockingboard konnte nicht aktiviert werden</string>
|
||||
<string name="mockingboard_enable">Aktiviere Mockingboard</string>
|
||||
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (evtl. wird ein Restart benötigt)</string>
|
||||
<string name="mockingboard_volume">Mockingboard Lautstärke</string>
|
||||
<string name="mockingboard_volume_summary">Einstellen der Mockingboard Lautstärke</string>
|
||||
<string name="no">Nein</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="preferences_reset_title">Einstellungen zurücksetzen</string>
|
||||
<string name="preferences_reset_summary">Einstellungen auf Standard zurücksetzen und Emulator beenden</string>
|
||||
<string name="preferences_reset_really">Wollen Sie wirklich resetten und beenden?</string>
|
||||
<string name="preferences_reset_warning">Sie werden alle Ihre Einstellungen verlieren</string>
|
||||
<string name="quit">Beenden</string>
|
||||
<string name="quit_reboot">Neustart oder beenden des Emulators…</string>
|
||||
<string name="quit_reboot_choice">Neustart oder beenden?</string>
|
||||
<string name="reboot">Neustart</string>
|
||||
<string name="restore">Schnelle Wiederherstellung</string>
|
||||
<string name="save">Schnelle Speicherung</string>
|
||||
<string name="saverestore">Speichern & wiederherstellen…</string>
|
||||
<string name="saverestore_choice">Aktuellen Status sichern oder vorherigen wiederherstellen?</string>
|
||||
<string name="saverestore_summary">Schnellspeicherung und Wiederherstellung</string>
|
||||
<string name="skip">Überspringen→</string>
|
||||
<string name="speaker_volume">Lautsprecherlautstärke</string>
|
||||
<string name="speaker_volume_summary">Lautsprecherlautstärke einstellen</string>
|
||||
<string name="settings">Apple2ix Emulator Einstellungen</string>
|
||||
<string name="settings_advanced">Erweiterte Einstellungen</string>
|
||||
<string name="settings_advanced_summary">Warnung: diese Einstellungen verschlechtern die Performance</string>
|
||||
<string name="settings_advanced_joystick">Erweiterte Joystick/Keypad Einstellungen</string>
|
||||
<string name="settings_advanced_joystick_summary">Erweiterte Einstellungen für das Performance-Tuning</string>
|
||||
<string name="touch_menu_enable">Aktiviere Touch Menüs</string>
|
||||
<string name="touch_menu_enable_summary">Aktiviere Softmenü Knöpfe in den oberen Ecken des Bildschirms</string>
|
||||
<string name="video_configure">Video-Konfiguration…</string>
|
||||
<string name="video_configure_summary">Farbeinstellungen</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
<string name="mode_landscape_summary">Enable landscape or portrait mode</string>
|
||||
<string name="portrait_calibrate">Calibrate portrait mode</string>
|
||||
<string name="portrait_calibrate_framebuffer">Display position</string>
|
||||
<string name="portrait_calibrate_keyboard_height">Keyboard height</string>
|
||||
<string name="portrait_calibrate_keyboard_position">Keyboard position</string>
|
||||
<string name="portrait_calibrate_summary">Adjust keyboard size, framebuffer position, etc</string>
|
||||
<string name="crash_sigabrt">SIGABRT</string>
|
||||
<string name="crash_sigfpe">SIGFPE</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
|
||||
</resources>
|
||||
@@ -15,6 +15,8 @@
|
||||
<!-- main options -->
|
||||
<string name="about_apple2ix">Acerca de Apple2ix…</string>
|
||||
<string name="about_apple2ix_summary">Acerca de este software</string>
|
||||
<string name="about_apple2ix_licenses">Licenses…</string>
|
||||
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
|
||||
<string name="app_name">Apple2ix</string>
|
||||
<string name="audio_configure">Configurar audio…</string>
|
||||
<string name="audio_configure_summary">Ajustar el volumen del altavoz, "Mockingboard", etc</string>
|
||||
@@ -32,16 +34,18 @@
|
||||
<string name="diskA">Disquetera 1</string>
|
||||
<string name="diskB">Disquetera 2</string>
|
||||
<string name="disk_eject">Eyectar</string>
|
||||
<string name="disk_insert_toast">Disco insertado en la disquetera de sólo lectura</string>
|
||||
<string name="disk_insert_could_not_read">Lo sentimos, no se puede leer la imagen de disquete!</string>
|
||||
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
|
||||
<string name="disk_read_only">Sólo leer</string>
|
||||
<string name="disk_read_write">Leer y escribir</string>
|
||||
<string name="disk_selection_newschoool">System chooser</string>
|
||||
<string name="disk_show_operation">Mostrar las operaciones de "Disk ]["</string>
|
||||
<string name="disk_show_operation_summary">Shows when disk drives are reading or writing</string>
|
||||
<string name="emulation_continue">Continuar…</string>
|
||||
<string name="emulation_settings">Configuración…</string>
|
||||
<string name="emulation_disks">Insertar imagen de disquete…</string>
|
||||
<string name="file_chooser">Choose disk image or state file…</string>
|
||||
<string name="header_disks">Insertar imagen de disquete:</string>
|
||||
<string name="header_eject_1">Eyectar 1</string>
|
||||
<string name="header_eject_2">Eyectar 2</string>
|
||||
<string name="input_current">Unidad de entrada actual</string>
|
||||
<string name="input_current_summary">Elija unidad de entrada</string>
|
||||
<string name="joystick">"Joystick"</string>
|
||||
@@ -87,9 +91,9 @@
|
||||
<string name="keyboard_lowercase_enabled">Habilitar minúsculas</string>
|
||||
<string name="keyboard_lowercase_enabled_summary">Utilice las teclas minúsculas</string>
|
||||
<string name="keyboard_visibility_active">Visibilidad cuando está activo</string>
|
||||
<string name="keyboard_visibility_active_summary">Visibilidad del teclado cuando está activo</string>
|
||||
<string name="keyboard_visibility_active_summary">Visibilidad del teclado y menú cuando está activo</string>
|
||||
<string name="keyboard_visibility_inactive">Visibilidad cuando está inactivo</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Visibilidad del teclado cuando está inactivo</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Visibilidad del teclado y menú cuando está inactivo</string>
|
||||
<string name="keypad">Joystick como teclado numérico</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
@@ -154,9 +158,35 @@
|
||||
<string name="settings_advanced_joystick_summary">Configuración avanzada y optimización del rendimiento</string>
|
||||
<string name="touch_menu_enable">Activar menús táctiles</string>
|
||||
<string name="touch_menu_enable_summary">Los botones del menú en la parte superior de la pantalla</string>
|
||||
<string name="touch_menu_visibility">Visibilidad del menú</string>
|
||||
<string name="touch_menu_visibility_summary">Visibilidad del menú cuando está inactivo</string>
|
||||
<string name="video_configure">Configurar el video…</string>
|
||||
<string name="video_configure_summary">Ajustes de color</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
<string name="mode_landscape_summary">Enable landscape or portrait mode</string>
|
||||
<string name="portrait_calibrate">Calibrate portrait mode</string>
|
||||
<string name="portrait_calibrate_framebuffer">Display position</string>
|
||||
<string name="portrait_calibrate_keyboard_height">Keyboard height</string>
|
||||
<string name="portrait_calibrate_keyboard_position">Keyboard position</string>
|
||||
<string name="portrait_calibrate_summary">Adjust keyboard size, framebuffer position, etc</string>
|
||||
<string name="keyboard_glyph_scale">Keyboard glyphs scaled 2x</string>
|
||||
<string name="keyboard_glyph_scale_summary">(Makes keyboard appear less pixelated on large screens)</string>
|
||||
<string name="crash_sigabrt">SIGABRT</string>
|
||||
<string name="crash_sigfpe">SIGFPE</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
<!-- main options -->
|
||||
<string name="about_apple2ix">A propos d\'Apple2ix…</string>
|
||||
<string name="about_apple2ix_summary">A propos de ce logiciel</string>
|
||||
<string name="about_apple2ix_licenses">Licenses…</string>
|
||||
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
|
||||
<string name="app_name">Apple2ix</string>
|
||||
<string name="audio_configure">Configuration audio…</string>
|
||||
<string name="audio_configure_summary">Volume du haut-parleur, Mockingboard, etc</string>
|
||||
@@ -32,16 +34,18 @@
|
||||
<string name="diskA">Lecteur 1</string>
|
||||
<string name="diskB">Lecteur 2</string>
|
||||
<string name="disk_eject">Ejecter</string>
|
||||
<string name="disk_insert_toast">Insérer la disquette dans le drive en lecture seulement</string>
|
||||
<string name="disk_insert_could_not_read">Désolé, impossible de lire l\'image disque!</string>
|
||||
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
|
||||
<string name="disk_selection_newschoool">System chooser</string>
|
||||
<string name="disk_read_only">Lecture seulement</string>
|
||||
<string name="disk_read_write">Lecture/Ecriture</string>
|
||||
<string name="disk_show_operation">Afficher les opérations (disque) ][</string>
|
||||
<string name="disk_show_operation_summary">Indique si les disques sont en lecture ou en écriture</string>
|
||||
<string name="emulation_continue">Continuer…</string>
|
||||
<string name="emulation_settings">Configurations…</string>
|
||||
<string name="emulation_disks">Chargement de l\'image disque…</string>
|
||||
<string name="file_chooser">Choose disk image or state file…</string>
|
||||
<string name="header_disks">Insérer la disquettte :</string>
|
||||
<string name="header_eject_1">Ejecter 1</string>
|
||||
<string name="header_eject_2">Ejecter 2</string>
|
||||
<string name="input_current">Tactile</string>
|
||||
<string name="input_current_summary">Choisir l\'appareil courant</string>
|
||||
<string name="joystick">Joystick</string>
|
||||
@@ -87,9 +91,9 @@
|
||||
<string name="keyboard_lowercase_enabled">Permettre les minuscules</string>
|
||||
<string name="keyboard_lowercase_enabled_summary">Permettre les touches en minuscules</string>
|
||||
<string name="keyboard_visibility_active">Visibilité quand actif</string>
|
||||
<string name="keyboard_visibility_active_summary">Voir le clavier quand actif</string>
|
||||
<string name="keyboard_visibility_active_summary">Clavier et menu tactile visible quand actif</string>
|
||||
<string name="keyboard_visibility_inactive">Visibilité quand inactif</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Clavier visible quand inactif</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Clavier et menu tactile visible quand inactif</string>
|
||||
<string name="keypad">Keypad Joystick</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
@@ -154,9 +158,35 @@
|
||||
<string name="settings_advanced_joystick_summary">Configuration avancée et tuning de performance</string>
|
||||
<string name="touch_menu_enable">Activation des menus tactiles</string>
|
||||
<string name="touch_menu_enable_summary">Activation soft des bouton du menu dans les coins en haut de l\'écran</string>
|
||||
<string name="touch_menu_visibility">Visibilité du menu tactile</string>
|
||||
<string name="touch_menu_visibility_summary">Menu tactile visible quand inactif</string>
|
||||
<string name="video_configure">Configuration de la vidéo…</string>
|
||||
<string name="video_configure_summary">Configuration des couleurs</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
<string name="mode_landscape_summary">Enable landscape or portrait mode</string>
|
||||
<string name="portrait_calibrate">Calibrate portrait mode</string>
|
||||
<string name="portrait_calibrate_framebuffer">Display position</string>
|
||||
<string name="portrait_calibrate_keyboard_height">Keyboard height</string>
|
||||
<string name="portrait_calibrate_keyboard_position">Keyboard position</string>
|
||||
<string name="portrait_calibrate_summary">Adjust keyboard size, framebuffer position, etc</string>
|
||||
<string name="keyboard_glyph_scale">Keyboard glyphs scaled 2x</string>
|
||||
<string name="keyboard_glyph_scale_summary">(Makes keyboard appear less pixelated on large screens)</string>
|
||||
<string name="crash_sigabrt">SIGABRT</string>
|
||||
<string name="crash_sigfpe">SIGFPE</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -9,18 +9,24 @@
|
||||
<string name="crasher_title">Crash emulator</string>
|
||||
<string name="crash_null">NULL-deref</string>
|
||||
<string name="crash_java_npe">Java NPE</string>
|
||||
<string name="crash_sigabrt">SIGABRT</string>
|
||||
<string name="crash_sigfpe">SIGFPE</string>
|
||||
<string name="crash_stackcall_overflow">stack call overflow</string>
|
||||
<string name="crash_stackbuf_overflow">stack buffer overflow</string>
|
||||
|
||||
<!-- main options -->
|
||||
<string name="about_apple2ix">About Apple2ix…</string>
|
||||
<string name="about_apple2ix_summary">About this software</string>
|
||||
<string name="about_apple2ix_licenses">Licenses…</string>
|
||||
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
|
||||
<string name="app_name">Apple2ix</string>
|
||||
<string name="audio_configure">Configure audio…</string>
|
||||
<string name="audio_configure_summary">Speaker volume, Mockingboard, etc</string>
|
||||
<string name="audio_latency">Audio latency</string>
|
||||
<string name="audio_latency_summary">Audio latency in secs</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="color_bw">Black/white</string>
|
||||
<string name="color_color">Color</string>
|
||||
<string name="color_interpolated">Interpolated color</string>
|
||||
@@ -32,16 +38,18 @@
|
||||
<string name="diskA">Drive 1</string>
|
||||
<string name="diskB">Drive 2</string>
|
||||
<string name="disk_eject">Eject</string>
|
||||
<string name="disk_insert_toast">Inserted disk in drive read-only</string>
|
||||
<string name="disk_insert_could_not_read">Sorry, could not read the disk image!</string>
|
||||
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
|
||||
<string name="disk_read_only">Read only</string>
|
||||
<string name="disk_read_write">Read/write</string>
|
||||
<string name="disk_selection_newschoool">System chooser</string>
|
||||
<string name="disk_show_operation">Show Disk ][ operations</string>
|
||||
<string name="disk_show_operation_summary">Shows when disk drives are reading or writing</string>
|
||||
<string name="emulation_continue">Continue…</string>
|
||||
<string name="emulation_settings">Settings…</string>
|
||||
<string name="emulation_disks">Load disk image…</string>
|
||||
<string name="emulation_disks">Load disk image</string>
|
||||
<string name="file_chooser">Choose disk image or state file…</string>
|
||||
<string name="header_disks">Insert disk:</string>
|
||||
<string name="header_eject_1">Eject 1</string>
|
||||
<string name="header_eject_2">Eject 2</string>
|
||||
<string name="input_current">Current touch device</string>
|
||||
<string name="input_current_summary">Choose current touch device</string>
|
||||
<string name="joystick">Joystick</string>
|
||||
@@ -57,13 +65,15 @@
|
||||
<string name="joystick_button_swipe_up_button_summary">Button to fire on swipe up</string>
|
||||
<string name="joystick_button_swipe_down_button">Swipe down fire</string>
|
||||
<string name="joystick_button_swipe_down_button_summary">Button to fire on swipe down</string>
|
||||
<string name="joystick_button_threshold_summary">Joystick/keypad button switch threshold in pts</string>
|
||||
<string name="joystick_button_threshold_summary">Joystick/keypad button switch threshold in pts (max: ⅓ screen height)</string>
|
||||
<string name="joystick_calibrate">Calibrate…</string>
|
||||
<string name="joystick_calibrate_summary">Configure and test current settings</string>
|
||||
<string name="joystick_configure">Configure joystick…</string>
|
||||
<string name="joystick_configure_summary">Axis touch, buttons, etc</string>
|
||||
<string name="joystick_axisleft">Joystick/keypad axis on left</string>
|
||||
<string name="joystick_axisleft_summary">Joystick/keypad axis on left (buttons on right)</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="joystick_visible">Joystick/keypad visibility</string>
|
||||
<string name="joystick_visible_summary">Show controls overlay when engaged</string>
|
||||
<string name="key_closed_apple">[ClosedApple]</string>
|
||||
@@ -84,12 +94,14 @@
|
||||
<string name="keyboard_click_enabled_summary">Enables key click sound if available</string>
|
||||
<string name="keyboard_configure">Configure keyboard…</string>
|
||||
<string name="keyboard_configure_summary">Transparency, lowercase, custom keys</string>
|
||||
<string name="keyboard_glyph_scale">Keyboard glyphs scaled 2x</string>
|
||||
<string name="keyboard_glyph_scale_summary">(Makes keyboard appear less pixelated on large screens)</string>
|
||||
<string name="keyboard_lowercase_enabled">Enable lowercase</string>
|
||||
<string name="keyboard_lowercase_enabled_summary">Enable lowercase keys</string>
|
||||
<string name="keyboard_visibility_active">Visibility when active</string>
|
||||
<string name="keyboard_visibility_active_summary">Keyboard visibility when active</string>
|
||||
<string name="keyboard_visibility_active_summary">Keyboard and touch menu visibility when active</string>
|
||||
<string name="keyboard_visibility_inactive">Visibility when inactive</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Keyboard visibility when inactive</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Keyboard and touch menu visibility when inactive</string>
|
||||
<string name="keypad">Keypad Joystick</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
@@ -119,8 +131,8 @@
|
||||
<string name="keypad_preset_left_right_space">←,→, tap spacebar</string>
|
||||
<string name="keypad_preset_wadx_space">W,A,D,X, tap spacebar</string>
|
||||
<string name="keypad_repeat_summary">Key repeat threshold in secs</string>
|
||||
<string name="menu_disks">Load disk image…</string>
|
||||
<string name="menu_disks_summary">Insert a Disk ][ image file</string>
|
||||
<string name="menu_disks">Load image or state file…</string>
|
||||
<string name="menu_disks_summary">Insert Disk ][ image or state file</string>
|
||||
<string name="menu_settings">Emulator settings…</string>
|
||||
<string name="menu_settings_summary">General settings, joystick, keyboard</string>
|
||||
<string name="mockingboard_disabled_title">Mockingboard disabled</string>
|
||||
@@ -129,21 +141,32 @@
|
||||
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (may require restart)</string>
|
||||
<string name="mockingboard_volume">Mockingboard volume</string>
|
||||
<string name="mockingboard_volume_summary">Set the Mockingboard volume</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
<string name="mode_landscape_summary">Enable landscape or portrait mode</string>
|
||||
<string name="no">No</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="portrait_calibrate">Calibrate portrait mode</string>
|
||||
<string name="portrait_calibrate_framebuffer">Display position</string>
|
||||
<string name="portrait_calibrate_keyboard_height">Keyboard height</string>
|
||||
<string name="portrait_calibrate_keyboard_position">Keyboard position</string>
|
||||
<string name="portrait_calibrate_summary">Adjust keyboard size, framebuffer position, etc</string>
|
||||
<string name="preferences_reset_title">Reset preferences</string>
|
||||
<string name="preferences_reset_summary">Reset preferences to defaults and quit emulator</string>
|
||||
<string name="preferences_reset_really">Really reset and quit?</string>
|
||||
<string name="preferences_reset_warning">You will lose your settings</string>
|
||||
<string name="quit">Quit</string>
|
||||
<string name="quit_reboot">Reboot or quit emulator…</string>
|
||||
<string name="quit_reboot_choice">Reboot or quit?</string>
|
||||
<string name="quit_reboot">Reset or quit emulator…</string>
|
||||
<string name="quit_reboot_choice">Reset/reboot or quit?</string>
|
||||
<string name="reboot">Reboot</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="restore">Quick restore</string>
|
||||
<string name="save">Quick save</string>
|
||||
<string name="saverestore">Save & restore…</string>
|
||||
<string name="saverestore_choice">Save current state or restore previous?</string>
|
||||
<string name="saverestore_summary">Quick save and restore</string>
|
||||
<string name="saverestore_summary">Save and restore emulator state</string>
|
||||
<string name="skip">Skip→</string>
|
||||
<string name="speaker_volume">Speaker volume</string>
|
||||
<string name="speaker_volume_summary">Set the speaker volume</string>
|
||||
@@ -152,11 +175,18 @@
|
||||
<string name="settings_advanced_summary">Warning: these settings may degrade performance</string>
|
||||
<string name="settings_advanced_joystick">Advanced joystick/keypad settings</string>
|
||||
<string name="settings_advanced_joystick_summary">Advanced settings and performance tuning</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="touch_menu_enable">Enable touch menus</string>
|
||||
<string name="touch_menu_enable_summary">Enables soft menu buttons in top screen corners</string>
|
||||
<string name="touch_menu_visibility">Touch menu visibility</string>
|
||||
<string name="touch_menu_visibility_summary">Touch menu visibility when inactive</string>
|
||||
<string name="video_configure">Configure video…</string>
|
||||
<string name="video_configure_summary">Color settings</string>
|
||||
<string name="video_configure_summary">Color landscape/portrait, color, etc</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
|
||||
</resources>
|
||||
|
||||
3
Android/app/src/main/res/xml/a2backupscheme.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
</full-backup-content>
|
||||
4
Android/app/src/main/res/xml/provider_paths.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="external_files" path="."/>
|
||||
</paths>
|
||||
@@ -5,7 +5,7 @@
|
||||
"_comment" : "hex code for special glyphs",
|
||||
"_AA" : "b5",
|
||||
"_ESC" : "bc",
|
||||
"_UP" : "8b",
|
||||
"_UP" : "8d",
|
||||
"_LT" : "88",
|
||||
"_RT" : "95",
|
||||
"_DN" : "8a",
|
||||
@@ -19,5 +19,5 @@
|
||||
[ "Y", "", "", "", "", "", "Z", "G", "", "_ESC"],
|
||||
[ "S", "", "", "", "", "", "C", "", "_UP", "" ],
|
||||
[ "", "", "", "", "", "", "", "_LT", "", "_RT"],
|
||||
[ "A", "", "T", "O", "J", "E", "_SP", "", "_DN", ""]
|
||||
[ "A", "", "T", "O", "F", "E", "_SP", "", "_DN", ""]
|
||||
]
|
||||
|
||||
23
Android/assets/keyboards/u5.kbd.json
Normal file
@@ -0,0 +1,23 @@
|
||||
[
|
||||
"Alt keyboard optimized for Ultima(tm) 5",
|
||||
|
||||
{
|
||||
"_comment" : "hex code for special glyphs",
|
||||
"_AA" : "b5",
|
||||
"_ESC" : "bc",
|
||||
"_UP" : "8d",
|
||||
"_LT" : "88",
|
||||
"_RT" : "95",
|
||||
"_DN" : "8a",
|
||||
"_SP" : "b1"
|
||||
},
|
||||
|
||||
[ "Q", "", "", "", "", "", "", "", "", "" ],
|
||||
[ "P", "", "", "", "", "", "", "", "", "" ],
|
||||
["_AA", "", "", "", "", "", "", "", "K", "X"],
|
||||
[ "N", "", "", "", "", "", "L", "B", "_SP", "V"],
|
||||
[ "Y", "", "", "", "", "", "Z", "G", "", "_ESC"],
|
||||
[ "S", "", "", "", "", "", "C", "", "_UP", "" ],
|
||||
[ "", "", "", "", "", "", "", "_LT", "", "_RT"],
|
||||
[ "A", "", "T", "O", "J", "F", "E", "", "_DN", ""]
|
||||
]
|
||||
1
Android/assets/shaders/SolidColor.fsh
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/video/SolidColor.fsh
|
||||
1
Android/assets/shaders/SolidColor.vsh
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/video/SolidColor.vsh
|
||||
@@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Wed Apr 10 15:27:10 PDT 2013
|
||||
#Mon Apr 17 16:37:13 HST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
|
||||
@@ -243,7 +243,7 @@ void android_keycode_to_emulator(int keyCode, int metaState, bool pressed) {
|
||||
}
|
||||
} while (0);
|
||||
|
||||
LOG("keyCode:%08x -> key:%02x ('%c') metaState:%08x", keyCode, key, key, metaState);
|
||||
//LOG("keyCode:%08x -> key:%02x ('%c') metaState:%08x", keyCode, key, key, metaState);
|
||||
|
||||
if (isASCII && _is_ctrl(metaState)) {
|
||||
key = c_keys_ascii_to_scancode(key);
|
||||
|
||||
@@ -28,13 +28,19 @@ LOCAL_SRC_FILES := jnicrash.c $(APPLE2_SRC_PATH)/breakpad.C
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) $(BREAKPAD_CFLAGS)
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),x86 x86_64))
|
||||
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
|
||||
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
|
||||
else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
ifeq ($(EMBEDDED_STACKWALKER),1)
|
||||
LOCAL_CPPFLAGS += -DEMBEDDED_STACKWALKER=1
|
||||
else
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
package_id="org.deadc0de.apple2ix.basic"
|
||||
apple2_src_path=apple2ix-src
|
||||
glue_srcs="$apple2_src_path/disk.c $apple2_src_path/misc.c $apple2_src_path/display.c $apple2_src_path/vm.c $apple2_src_path/cpu-supp.c $apple2_src_path/audio/speaker.c $apple2_src_path/audio/mockingboard.c"
|
||||
glue_srcs="$apple2_src_path/cpu-supp.c $apple2_src_path/disk.c $apple2_src_path/display.c $apple2_src_path/vm.c $apple2_src_path/audio/speaker.c $apple2_src_path/audio/mockingboard.c"
|
||||
|
||||
usage() {
|
||||
if test "$(basename $0)" = "clean" ; then
|
||||
@@ -12,7 +12,7 @@ usage() {
|
||||
echo "$0"
|
||||
echo " # uninstalls $package_id"
|
||||
else
|
||||
echo "$0 [build] [load|debug]"
|
||||
echo "$0 [build|release] [load|debug]"
|
||||
echo " # default builds $package_id and then load or debug"
|
||||
fi
|
||||
exit 0
|
||||
@@ -22,6 +22,14 @@ export EMBEDDED_STACKWALKER=1
|
||||
|
||||
while test "x$1" != "x"; do
|
||||
case "$1" in
|
||||
"build")
|
||||
do_build=1
|
||||
;;
|
||||
|
||||
"release")
|
||||
do_release=1
|
||||
;;
|
||||
|
||||
"debug")
|
||||
do_debug=1
|
||||
;;
|
||||
@@ -45,6 +53,11 @@ while test "x$1" != "x"; do
|
||||
shift
|
||||
done
|
||||
|
||||
if test "x$do_build" = "x1" -a "x$do_release" = "x1" ; then
|
||||
echo "Must specify either build or release"
|
||||
usage
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
if test "$(basename $0)" = "clean" ; then
|
||||
@@ -74,91 +87,115 @@ if test "$(basename $0)" = "uninstall" ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#CC=`which clang`
|
||||
CC=`which gcc`
|
||||
CFLAGS="-std=gnu11"
|
||||
|
||||
# ROMz
|
||||
$CC $CFLAGS -o $apple2_src_path/genrom $apple2_src_path/genrom.c && \
|
||||
$apple2_src_path/genrom $apple2_src_path/rom/apple_IIe.rom $apple2_src_path/rom/slot6.rom > $apple2_src_path/rom.c
|
||||
|
||||
# font
|
||||
$CC $CFLAGS -o $apple2_src_path/genfont $apple2_src_path/genfont.c && \
|
||||
$apple2_src_path/genfont < $apple2_src_path/font.txt > $apple2_src_path/font.c
|
||||
|
||||
# glue
|
||||
$apple2_src_path/x86/genglue $glue_srcs > $apple2_src_path/x86/glue.S
|
||||
$apple2_src_path/arm/genglue $glue_srcs > $apple2_src_path/arm/glue.S
|
||||
|
||||
if test "$(basename $0)" = "testcpu" ; then
|
||||
ln -s testcpu.mk Android.mk
|
||||
elif test "$(basename $0)" = "testvm" ; then
|
||||
ln -s testvm.mk Android.mk
|
||||
elif test "$(basename $0)" = "testdisplay" ; then
|
||||
ln -s testdisplay.mk Android.mk
|
||||
elif test "$(basename $0)" = "testdisk" ; then
|
||||
ln -s testdisk.mk Android.mk
|
||||
else
|
||||
elif test "$(basename $0)" = "testdisplay" ; then
|
||||
ln -s testdisplay.mk Android.mk
|
||||
elif test "$(basename $0)" = "testprefs" ; then
|
||||
ln -s testprefs.mk Android.mk
|
||||
elif test "$(basename $0)" = "testtrace" ; then
|
||||
ln -s testtrace.mk Android.mk
|
||||
elif test "$(basename $0)" = "testui" ; then
|
||||
ln -s testui.mk Android.mk
|
||||
elif test "$(basename $0)" = "testvm" ; then
|
||||
ln -s testvm.mk Android.mk
|
||||
elif test "$(basename $0)" = "apple2ix" ; then
|
||||
ln -s apple2ix.mk Android.mk
|
||||
else
|
||||
echo "OOPS, unsure of what to build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# build native sources
|
||||
ndk-build V=1 NDK_MODULE_PATH=. NDK_DEBUG=1 # NDK_TOOLCHAIN_VERSION=clang
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
exit $ret
|
||||
|
||||
if test "x$do_build" = "x1" -o "x$do_release" = "x1" ; then
|
||||
|
||||
#CC=`which clang`
|
||||
CC=`which gcc`
|
||||
CFLAGS="-std=gnu11"
|
||||
|
||||
# ROMz
|
||||
$CC $CFLAGS -o $apple2_src_path/genrom $apple2_src_path/genrom.c && \
|
||||
$apple2_src_path/genrom $apple2_src_path/rom/apple_IIe.rom $apple2_src_path/rom/slot6.rom > $apple2_src_path/rom.c
|
||||
|
||||
# font
|
||||
$CC $CFLAGS -o $apple2_src_path/genfont $apple2_src_path/genfont.c && \
|
||||
$apple2_src_path/genfont < $apple2_src_path/font.txt > $apple2_src_path/font.c
|
||||
|
||||
# trampoline generation
|
||||
TARGET_ARCH=x86 $apple2_src_path/genglue.sh $glue_srcs > $apple2_src_path/x86/glue.S
|
||||
TARGET_ARCH=arm $apple2_src_path/genglue.sh $glue_srcs > $apple2_src_path/arm/glue.S
|
||||
|
||||
if test "x$do_build" = "x1" ; then
|
||||
export BUILD_MODE=debug
|
||||
ndk-build V=1 NDK_MODULE_PATH=. NDK_DEBUG=1 NDK_TOOLCHAIN_VERSION=4.9
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
exit $ret
|
||||
fi
|
||||
else
|
||||
export BUILD_MODE=release
|
||||
ndk-build V=1 NDK_MODULE_PATH=. NDK_DEBUG=0 NDK_TOOLCHAIN_VERSION=4.9
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
exit $ret
|
||||
fi
|
||||
fi
|
||||
|
||||
# Symbolicate and move symbols file into location to be deployed on device
|
||||
|
||||
SYMFILE=libapple2ix.so.sym
|
||||
ARCHES_TO_SYMBOLICATE='armeabi armeabi-v7a x86'
|
||||
|
||||
for arch in $ARCHES_TO_SYMBOLICATE ; do
|
||||
SYMDIR=../assets/symbols/$arch/libapple2ix.so
|
||||
|
||||
# remove old symbols (if any)
|
||||
/bin/rm -rf $SYMDIR
|
||||
|
||||
# Run Breakpad's dump_syms
|
||||
host_arch=`uname -s`
|
||||
../../externals/bin/$host_arch/dump_syms ../obj/local/$arch/libapple2ix.so > $SYMFILE
|
||||
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
echo "OOPS, dump_syms failed for $arch"
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
# strip to the just the numeric id in the .sym header and verify it makes sense
|
||||
sym_id=$(head -1 $SYMFILE | cut -d ' ' -f 4)
|
||||
sym_id_check=$(echo $sym_id | wc -c | tr -d ' ' )
|
||||
if test "x$sym_id_check" != "x34" ; then
|
||||
echo "OOPS symbol header not expected size, meat-space intervention needed =P"
|
||||
exit 1
|
||||
fi
|
||||
sym_id_check=$(echo $sym_id | tr -d 'A-Fa-f0-9' | wc -c | tr -d ' ' )
|
||||
if test "x$sym_id_check" != "x1" ; then
|
||||
echo "OOPS unexpected characters in symbol header, meat-space intervention needed =P"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p $SYMDIR/$sym_id
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
echo "OOPS, could not create symbols directory for arch:$arch and sym_id:$sym_id"
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
/bin/mv $SYMFILE $SYMDIR/$sym_id/
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
echo "OOPS, could not move $SYMFILE to $SYMDIR/$sym_id/"
|
||||
exit $ret
|
||||
fi
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# Symbolicate and move symbols file into location to be deployed on device
|
||||
|
||||
SYMFILE=libapple2ix.so.sym
|
||||
ARCHES_TO_SYMBOLICATE='armeabi armeabi-v7a x86'
|
||||
|
||||
for arch in $ARCHES_TO_SYMBOLICATE ; do
|
||||
SYMDIR=../assets/symbols/$arch/libapple2ix.so
|
||||
|
||||
# remove old symbols (if any)
|
||||
/bin/rm -rf $SYMDIR
|
||||
|
||||
# Run Breakpad's dump_syms
|
||||
../../externals/bin/dump_syms ../obj/local/$arch/libapple2ix.so > $SYMFILE
|
||||
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
echo "OOPS, dump_syms failed for $arch"
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
# strip to the just the numeric id in the .sym header and verify it makes sense
|
||||
sym_id=$(head -1 $SYMFILE | cut -d ' ' -f 4)
|
||||
sym_id_check=$(echo $sym_id | wc -c)
|
||||
if test "x$sym_id_check" != "x34" ; then
|
||||
echo "OOPS symbol header not expected size, meat-space intervention needed =P"
|
||||
exit 1
|
||||
fi
|
||||
sym_id_check=$(echo $sym_id | tr -d 'A-Fa-f0-9' | wc -c)
|
||||
if test "x$sym_id_check" != "x1" ; then
|
||||
echo "OOPS unexpected characters in symbol header, meat-space intervention needed =P"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p $SYMDIR/$sym_id
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
echo "OOPS, could not create symbols directory for arch:$arch and sym_id:$sym_id"
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
/bin/mv $SYMFILE $SYMDIR/$sym_id/
|
||||
ret=$?
|
||||
if test "x$ret" != "x0" ; then
|
||||
echo "OOPS, could not move $SYMFILE to $SYMDIR/$sym_id/"
|
||||
exit $ret
|
||||
fi
|
||||
done
|
||||
|
||||
###############################################################################
|
||||
# usually we should build the Java stuff from within Android Studio
|
||||
if test "x$do_load" = "x1" ; then
|
||||
|
||||
@@ -17,6 +17,8 @@ enum {
|
||||
CRASH_NULL_DEREF,
|
||||
CRASH_STACKCALL_OVERFLOW,
|
||||
CRASH_STACKBUF_OVERFLOW,
|
||||
CRASH_SIGABRT,
|
||||
CRASH_SIGFPE,
|
||||
// MOAR!
|
||||
};
|
||||
|
||||
@@ -68,6 +70,21 @@ static volatile int __attribute__((noinline)) _crash_stackbuf_overflow(void) {
|
||||
return getpid();
|
||||
}
|
||||
|
||||
static void _crash_sigabrt(void) {
|
||||
kill(getpid(), SIGABRT);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void _crash_sigfpe(void) {
|
||||
static volatile int foo = 2;
|
||||
static volatile int bar = 0;
|
||||
while (foo >= 0) {
|
||||
--foo;
|
||||
bar = 2/foo;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativePerformCrash(JNIEnv *env, jclass cls, jint crashType) {
|
||||
#warning FIXME TODO ... we should turn off test codepaths in release build =D
|
||||
LOG("... performing crash of type : %d", crashType);
|
||||
@@ -85,6 +102,14 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativePerformCrash(JNIEnv *en
|
||||
_crash_stackbuf_overflow();
|
||||
break;
|
||||
|
||||
case CRASH_SIGABRT:
|
||||
_crash_sigabrt();
|
||||
break;
|
||||
|
||||
case CRASH_SIGFPE:
|
||||
_crash_sigfpe();
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown crasher, just abort ...
|
||||
abort();
|
||||
@@ -107,21 +132,21 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *en
|
||||
do {
|
||||
outputFILE = TEMP_FAILURE_RETRY_FOPEN(fopen(outputPath, "w"));
|
||||
if (!outputFILE) {
|
||||
ERRLOG("could not open %s", outputPath);
|
||||
LOG("could not open %s", outputPath);
|
||||
break;
|
||||
}
|
||||
|
||||
if (android_armArchV7A) {
|
||||
asprintf(&symbolsPath, "%s/symbols/armeabi-v7a", data_dir);
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/armeabi-v7a", data_dir);
|
||||
} else if (android_x86) {
|
||||
asprintf(&symbolsPath, "%s/symbols/x86", data_dir);
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/x86", data_dir);
|
||||
} else /*if (android_armArch)*/ {
|
||||
asprintf(&symbolsPath, "%s/symbols/armeabi", data_dir);
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/armeabi", data_dir);
|
||||
} /*else { moar archs ... } */
|
||||
|
||||
bool success = crashHandler->processCrash(crashPath, symbolsPath, outputFILE);
|
||||
if (!success) {
|
||||
RELEASE_LOG("CRASH REPORT PROCESSING FAILED ...");
|
||||
LOG("CRASH REPORT PROCESSING FAILED ...");
|
||||
}
|
||||
} while (0);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "androidkeys.h"
|
||||
#include "json_parse_private.h"
|
||||
|
||||
#include <cpu-features.h>
|
||||
#include <jni.h>
|
||||
@@ -47,8 +48,7 @@ typedef enum lifecycle_seq_t {
|
||||
static lifecycle_seq_t appState = APP_RUNNING;
|
||||
|
||||
#if TESTING
|
||||
static bool running_tests = false;
|
||||
static void _run_tests(void) {
|
||||
static void _start_tests(void) {
|
||||
char *local_argv[] = {
|
||||
"-f",
|
||||
NULL
|
||||
@@ -57,20 +57,41 @@ static void _run_tests(void) {
|
||||
for (char **p = &local_argv[0]; *p != NULL; p++) {
|
||||
++local_argc;
|
||||
}
|
||||
#if defined(TEST_CPU)
|
||||
|
||||
#if TEST_CPU
|
||||
// Currently this test is the only one that runs as a black screen
|
||||
extern int test_cpu(int, char *[]);
|
||||
test_cpu(local_argc, local_argv);
|
||||
tkill(getpid(), SIGKILL); // and we're done ...
|
||||
#elif defined(TEST_VM)
|
||||
extern int test_vm(int, char *[]);
|
||||
test_vm(local_argc, local_argv);
|
||||
#elif defined(TEST_DISPLAY)
|
||||
extern int test_display(int, char *[]);
|
||||
test_display(local_argc, local_argv);
|
||||
#elif defined(TEST_DISK)
|
||||
extern int test_disk(int, char *[]);
|
||||
kill(getpid(), SIGKILL); // and we're done ...
|
||||
#endif
|
||||
|
||||
cpu_pause();
|
||||
emulator_start();
|
||||
while (cpu_thread_id == 0) {
|
||||
sleep(1);
|
||||
}
|
||||
cpu_resume();
|
||||
|
||||
#if TEST_DISK
|
||||
extern void test_disk(int, char *[]);
|
||||
test_disk(local_argc, local_argv);
|
||||
#elif TEST_DISPLAY
|
||||
extern void test_display(int, char *[]);
|
||||
test_display(local_argc, local_argv);
|
||||
#elif TEST_PREFS
|
||||
extern void test_prefs(int, char *[]);
|
||||
test_prefs(local_argc, local_argv);
|
||||
#elif TEST_TRACE
|
||||
extern void test_trace(int, char *[]);
|
||||
test_trace(local_argc, local_argv);
|
||||
#elif TEST_UI
|
||||
extern void test_ui(int, char *[]);
|
||||
test_ui(local_argc, local_argv);
|
||||
#elif TEST_VM
|
||||
extern void test_vm(int, char *[]);
|
||||
test_vm(local_argc, local_argv);
|
||||
#elif TEST_CPU
|
||||
// handled above ...
|
||||
#else
|
||||
# error "OOPS, no tests specified"
|
||||
#endif
|
||||
@@ -159,10 +180,16 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jclas
|
||||
int pagesize = getpagesize();
|
||||
LOG("PAGESIZE IS : %d", pagesize);
|
||||
|
||||
data_dir = strdup(dataDir);
|
||||
data_dir = STRDUP(dataDir);
|
||||
if (crashHandler && crashHandler->init) {
|
||||
crashHandler->init(data_dir);
|
||||
}
|
||||
char *home = NULL;
|
||||
ASPRINTF(&home, "HOME=%s", data_dir);
|
||||
if (home) {
|
||||
putenv(home);
|
||||
LEAK(home);
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, j_dataDir, dataDir);
|
||||
LOG("data_dir : %s", data_dir);
|
||||
@@ -173,61 +200,61 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jclas
|
||||
|
||||
joydriver_setClampBeyondRadius(true);
|
||||
|
||||
#if !TESTING
|
||||
//#define DO_CPU65_TRACING 1
|
||||
#if DO_CPU65_TRACING
|
||||
# warning !!!!!!!!!! this will quickly eat up disk space !!!!!!!!!!
|
||||
char *trfile = NULL;
|
||||
ASPRINTF(&trfile, "%s/%s", data_dir, "cpu_trace.txt");
|
||||
cpu65_trace_begin(trfile);
|
||||
FREE(trfile);
|
||||
#endif
|
||||
|
||||
#if TESTING
|
||||
_start_tests();
|
||||
#else
|
||||
cpu_pause();
|
||||
emulator_start();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsChanged(JNIEnv *env, jclass cls, jint width, jint height) {
|
||||
// WARNING : this can happen on non-GL thread
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls) {
|
||||
LOG("...");
|
||||
video_backend->reshape(width, height);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls, jint width, jint height) {
|
||||
// WARNING : this needs to happen on the GL thread only
|
||||
LOG("width:%d height:%d", width, height);
|
||||
_video_setRenderThread(pthread_self()); // by definition, this method is called on the render thread ...
|
||||
video_shutdown();
|
||||
video_backend->reshape(width, height);
|
||||
video_backend->init((void *)0);
|
||||
video_init();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jclass cls) {
|
||||
#if TESTING
|
||||
// test driver thread is managing CPU
|
||||
if (!running_tests) {
|
||||
running_tests = true;
|
||||
assert(cpu_thread_id == 0 && "CPU thread must not be initialized yet...");
|
||||
_run_tests();
|
||||
}
|
||||
#else
|
||||
jboolean Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jclass cls) {
|
||||
if (!cpu_isPaused()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
LOG("...");
|
||||
cpu_resume();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jclass cls) {
|
||||
jboolean Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jclass cls) {
|
||||
if (appState != APP_RUNNING) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if DO_CPU65_TRACING
|
||||
cpu65_trace_checkpoint();
|
||||
#endif
|
||||
|
||||
disk6_flush(0);
|
||||
disk6_flush(1);
|
||||
|
||||
if (cpu_isPaused()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
LOG("...");
|
||||
|
||||
#if TESTING
|
||||
// test driver thread is managing CPU
|
||||
#else
|
||||
cpu_pause();
|
||||
#endif
|
||||
prefs_save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls) {
|
||||
@@ -241,6 +268,7 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls)
|
||||
return;
|
||||
}
|
||||
|
||||
//#define FPS_LOG 1
|
||||
#if FPS_LOG
|
||||
static uint32_t prevCount = 0;
|
||||
static uint32_t idleCount = 0;
|
||||
@@ -258,27 +286,34 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls)
|
||||
}
|
||||
#endif
|
||||
|
||||
video_backend->render();
|
||||
video_render();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass cls) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass cls, jint resetState) {
|
||||
LOG("...");
|
||||
cpu65_reboot();
|
||||
if (resetState) {
|
||||
// joystick button settings should be balanced by c_joystick_reset() triggered on CPU thread
|
||||
if (resetState == 1) {
|
||||
joy_button0 = 0xff;
|
||||
joy_button1 = 0x0;
|
||||
} else {
|
||||
joy_button0 = 0x0;
|
||||
joy_button1 = 0xff;
|
||||
}
|
||||
}
|
||||
cpu65_interrupt(ResetSig);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jclass cls) {
|
||||
#if TESTING
|
||||
// test driver thread is managing CPU
|
||||
#else
|
||||
appState = APP_REQUESTED_SHUTDOWN;
|
||||
|
||||
LOG("...");
|
||||
|
||||
disk6_eject(0);
|
||||
disk6_eject(1);
|
||||
#if DO_CPU65_TRACING
|
||||
cpu65_trace_end();
|
||||
#endif
|
||||
|
||||
cpu_resume();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyDown(JNIEnv *env, jclass cls, jint keyCode, jint metaState) {
|
||||
@@ -324,83 +359,259 @@ jlong Java_org_deadc0de_apple2ix_Apple2View_nativeOnTouch(JNIEnv *env, jclass cl
|
||||
return flags;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, jclass cls, jstring jPath, jboolean driveA, jboolean readOnly) {
|
||||
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
|
||||
int drive = driveA ? 0 : 1;
|
||||
int ro = readOnly ? 1 : 0;
|
||||
jstring Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeChooseDisk(JNIEnv *env, jclass cls, jstring jJsonString) {
|
||||
#if TESTING
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
assert(cpu_isPaused() && "considered dangerous to insert disk image when CPU thread is running");
|
||||
|
||||
LOG(": (%s, %s, %s)", path, driveA ? "drive A" : "drive B", readOnly ? "read only" : "read/write");
|
||||
if (disk6_insert(drive, path, ro)) {
|
||||
char *gzPath = NULL;
|
||||
asprintf(&gzPath, "%s.gz", path);
|
||||
if (disk6_insert(drive, gzPath, ro)) {
|
||||
char *diskImageUnreadable = "Disk Image Unreadable";
|
||||
unsigned int cols = strlen(diskImageUnreadable);
|
||||
video_backend->animation_showMessage(diskImageUnreadable, cols, 1);
|
||||
} else {
|
||||
video_backend->animation_showDiskChosen(drive);
|
||||
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
|
||||
|
||||
JSON_ref jsonData = NULL;
|
||||
bool ret = json_createFromString(jsonString, &jsonData);
|
||||
assert(ret > 0);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
|
||||
|
||||
char *path = NULL;
|
||||
json_mapCopyStringValue(jsonData, "disk", &path);
|
||||
json_unescapeSlashes(&path);
|
||||
|
||||
assert(path != NULL);
|
||||
assert(strlen(path) > 0);
|
||||
|
||||
bool readOnly = true;
|
||||
json_mapParseBoolValue(jsonData, "readOnly", &readOnly);
|
||||
|
||||
long fd = -1;
|
||||
if (!json_mapParseLongValue(jsonData, "fd", &fd, 10)) {
|
||||
TEMP_FAILURE_RETRY(fd = open(path, readOnly ? O_RDONLY : O_RDWR));
|
||||
if (fd == -1) {
|
||||
LOG("OOPS could not open disk path : %s", path);
|
||||
}
|
||||
FREE(gzPath);
|
||||
} else {
|
||||
video_backend->animation_showDiskChosen(drive);
|
||||
fd = dup(fd);
|
||||
if (fd == -1) {
|
||||
LOG("OOPS could not dup file descriptor!");
|
||||
}
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, jPath, path);
|
||||
|
||||
long drive = -1;
|
||||
json_mapParseLongValue(jsonData, "drive", &drive, 10);
|
||||
assert(drive == 0 || drive == 1);
|
||||
|
||||
bool inserted = true;
|
||||
const char *err = disk6_insert(fd, drive, path, readOnly);
|
||||
if (err) {
|
||||
char *diskImageUnreadable = "Disk Image Unreadable";
|
||||
unsigned int cols = strlen(diskImageUnreadable);
|
||||
video_getAnimationDriver()->animation_showMessage(diskImageUnreadable, cols, 1);
|
||||
inserted = false;
|
||||
} else {
|
||||
video_getAnimationDriver()->animation_showDiskChosen(drive);
|
||||
}
|
||||
|
||||
json_mapSetBoolValue(jsonData, "inserted", inserted);
|
||||
|
||||
if (fd >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
FREE(path);
|
||||
}
|
||||
|
||||
jsonString = ((JSON_s *)jsonData)->jsonString;
|
||||
jstring jstr = (*env)->NewStringUTF(env, jsonString);
|
||||
|
||||
json_destroy(&jsonData);
|
||||
|
||||
LOG(": (fd:%d, %s, %s, %s)", (int)fd, path, drive ? "drive A" : "drive B", readOnly ? "read only" : "read/write");
|
||||
|
||||
return jstr;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEjectDisk(JNIEnv *env, jclass cls, jboolean driveA) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeEjectDisk(JNIEnv *env, jclass cls, jboolean driveA) {
|
||||
#if TESTING
|
||||
return;
|
||||
#endif
|
||||
|
||||
LOG("...");
|
||||
disk6_eject(!driveA);
|
||||
disk6_eject(driveA ? 0 : 1);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jclass cls, jstring jPath) {
|
||||
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
|
||||
static int _openFdFromJson(OUTPARM int *fdOut, JSON_ref jsonData, const char * const fdKey, const char * const pathKey, int flags, int mode) {
|
||||
|
||||
long fd = -1;
|
||||
char *path = NULL;
|
||||
|
||||
do {
|
||||
if (!json_mapParseLongValue(jsonData, fdKey, &fd, 10)) {
|
||||
json_mapCopyStringValue(jsonData, pathKey, &path);
|
||||
assert(path != NULL);
|
||||
|
||||
json_unescapeSlashes(&path);
|
||||
if (strlen(path) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
TEMP_FAILURE_RETRY(fd = open(path, flags));
|
||||
} else {
|
||||
TEMP_FAILURE_RETRY(fd = open(path, flags, mode));
|
||||
}
|
||||
if (fd == -1) {
|
||||
LOG("OOPS could not open state file path %s", path);
|
||||
}
|
||||
} else {
|
||||
fd = dup(fd);
|
||||
if (fd == -1) {
|
||||
LOG("OOPS could not dup file descriptor!");
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
FREE(path);
|
||||
|
||||
*fdOut = (int)fd;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jclass cls, jstring jJsonString) {
|
||||
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
|
||||
|
||||
LOG(": (%s)", path);
|
||||
if (!emulator_saveState(path)) {
|
||||
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
|
||||
LOG(": (%s)", jsonString);
|
||||
|
||||
JSON_ref jsonData = NULL;
|
||||
bool ret = json_createFromString(jsonString, &jsonData);
|
||||
assert(ret > 0);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
|
||||
|
||||
int fdState = -1;
|
||||
_openFdFromJson(&fdState, jsonData, /*fdKey:*/"fdState", /*pathKey:*/"stateFile", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
|
||||
|
||||
if (!emulator_saveState(fdState)) {
|
||||
LOG("OOPS, could not save emulator state");
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jPath, path);
|
||||
}
|
||||
|
||||
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jclass cls, jstring jPath) {
|
||||
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
|
||||
|
||||
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
|
||||
|
||||
LOG(": (%s)", path);
|
||||
if (!emulator_loadState(path)) {
|
||||
LOG("OOPS, could not load emulator state");
|
||||
if (fdState >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdState));
|
||||
fdState = -1;
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jPath, path);
|
||||
json_destroy(&jsonData);
|
||||
}
|
||||
|
||||
// restoring state may cause a change in disk paths, so we need to notify the Java/Android menu system of the change
|
||||
// (normally we drive state from the Java/menu side...)
|
||||
char *disk1 = disk6.disk[0].file_name;
|
||||
bool readOnly1 = disk6.disk[0].is_protected;
|
||||
char *disk2 = disk6.disk[1].file_name;
|
||||
bool readOnly2 = disk6.disk[1].is_protected;
|
||||
char *str = NULL;
|
||||
jstring jstr = NULL;
|
||||
asprintf(&str, "{ disk1 = \"%s\"; readOnly1 = %s; disk2 = \"%s\"; readOnly2 = %s }", (disk1 ?: ""), readOnly1 ? "true" : "false", (disk2 ?: ""), readOnly2 ? "true" : "false");
|
||||
if (str) {
|
||||
jstr = (*env)->NewStringUTF(env, str);
|
||||
FREE(str);
|
||||
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jclass cls, jstring jJsonString) {
|
||||
assert(cpu_isPaused() && "considered dangerous to load state when CPU thread is running");
|
||||
|
||||
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
|
||||
LOG(": %s", jsonString);
|
||||
|
||||
JSON_ref jsonData = NULL;
|
||||
int ret = json_createFromString(jsonString, &jsonData);
|
||||
assert(ret > 0);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
|
||||
|
||||
int fdState = -1;
|
||||
_openFdFromJson(&fdState, jsonData, /*fdKey:*/"fdState", /*pathKey:*/"stateFile", O_RDONLY, 0);
|
||||
|
||||
int fdA = -1;
|
||||
{
|
||||
bool readOnlyA = true;
|
||||
json_mapParseBoolValue(jsonData, "readOnlyA", &readOnlyA);
|
||||
_openFdFromJson(&fdA, jsonData, /*fdKey:*/"fdA", /*pathKey:*/"diskA", readOnlyA ? O_RDONLY : O_RDWR, 0);
|
||||
}
|
||||
|
||||
int fdB = -1;
|
||||
{
|
||||
bool readOnlyB = true;
|
||||
json_mapParseBoolValue(jsonData, "readOnlyB", &readOnlyB);
|
||||
_openFdFromJson(&fdB, jsonData, /*fdKey:*/"fdB", /*pathKey:*/"diskB", readOnlyB ? O_RDONLY : O_RDWR, 0);
|
||||
}
|
||||
|
||||
bool loadStateSuccess = true;
|
||||
if (!emulator_loadState(fdState, (int)fdA, (int)fdB)) {
|
||||
loadStateSuccess = false;
|
||||
LOG("OOPS, could not load emulator state");
|
||||
// FIXME TODO : should show invalid state animation here ...
|
||||
}
|
||||
|
||||
if (fdState >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdState));
|
||||
fdState = -1;
|
||||
}
|
||||
if (fdA >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdA));
|
||||
fdA = -1;
|
||||
}
|
||||
if (fdB >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdB));
|
||||
fdB = -1;
|
||||
}
|
||||
|
||||
json_mapSetBoolValue(jsonData, "loadStateSuccess", loadStateSuccess);
|
||||
|
||||
jsonString = ((JSON_s *)jsonData)->jsonString;
|
||||
jstring jstr = (*env)->NewStringUTF(env, jsonString);
|
||||
|
||||
json_destroy(&jsonData);
|
||||
|
||||
return jstr;
|
||||
}
|
||||
|
||||
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeStateExtractDiskPaths(JNIEnv *env, jclass cls, jstring jJsonString) {
|
||||
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
|
||||
|
||||
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
|
||||
LOG(": (%s)", jsonString);
|
||||
|
||||
JSON_ref jsonData = NULL;
|
||||
bool ret = json_createFromString(jsonString, &jsonData);
|
||||
assert(ret > 0);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
|
||||
|
||||
int fdState = -1;
|
||||
_openFdFromJson(&fdState, jsonData, /*fdKey:*/"fdState", /*pathKey:*/"stateFile", O_RDONLY, 0);
|
||||
|
||||
if (!emulator_stateExtractDiskPaths(fdState, jsonData)) {
|
||||
LOG("OOPS, could not extract disk paths from emulator state file");
|
||||
}
|
||||
|
||||
jsonString = ((JSON_s *)jsonData)->jsonString;
|
||||
|
||||
jstring jstr = (*env)->NewStringUTF(env, jsonString);
|
||||
|
||||
json_destroy(&jsonData);
|
||||
|
||||
if (fdState >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdState));
|
||||
fdState = -1;
|
||||
}
|
||||
|
||||
return jstr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativePrefsSync(JNIEnv *env, jclass cls, jstring jDomain) {
|
||||
const char *domain = NULL;
|
||||
|
||||
__attribute__((constructor(CTOR_PRIORITY_LATE)))
|
||||
static void _init_jnihooks(void) {
|
||||
// ...
|
||||
if (jDomain) {
|
||||
domain = (*env)->GetStringUTFChars(env, jDomain, 0);
|
||||
}
|
||||
|
||||
#if !TEST_PREFS
|
||||
LOG("... domain: %s", domain);
|
||||
prefs_load();
|
||||
prefs_sync(domain);
|
||||
#endif
|
||||
|
||||
if (jDomain) {
|
||||
(*env)->ReleaseStringUTFChars(env, jDomain, domain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
typedef enum AndroidTouchJoystickButtonValues {
|
||||
//ANDROID_TOUCHJOY_NONE = 0,
|
||||
ANDROID_TOUCHJOY_BUTTON0 = 1,
|
||||
ANDROID_TOUCHJOY_BUTTON1,
|
||||
ANDROID_TOUCHJOY_BUTTON_BOTH,
|
||||
} AndroidTouchJoystickButtonValues;
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetColor(JNIEnv *env, jclass cls, jint color) {
|
||||
LOG("color : %d", color);
|
||||
#if TESTING
|
||||
color_mode = COLOR;
|
||||
#else
|
||||
if (color < COLOR_NONE || color > COLOR_INTERP) {
|
||||
return;
|
||||
}
|
||||
color_mode = color;
|
||||
|
||||
video_reset();
|
||||
video_setpage(!!(softswitches & SS_SCREEN));
|
||||
video_redraw();
|
||||
#endif
|
||||
}
|
||||
|
||||
jboolean Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetSpeakerEnabled(JNIEnv *env, jclass cls, jboolean enabled) {
|
||||
LOG("enabled : %d", true);
|
||||
// NO-OP ... speaker should always be enabled (but volume could be zero)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetSpeakerVolume(JNIEnv *env, jclass cls, jint goesToTen) {
|
||||
LOG("volume : %d", goesToTen);
|
||||
assert(goesToTen >= 0);
|
||||
sound_volume = goesToTen;
|
||||
#warning FIXME TODO refactor/remove sound_volume ?
|
||||
vm_reinitializeAudio();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetAudioLatency(JNIEnv *env, jclass cls, jfloat latencySecs) {
|
||||
#if !TESTING
|
||||
LOG("audio latency : %fsecs", latencySecs);
|
||||
assert(cpu_isPaused());
|
||||
audio_setLatency(latencySecs);
|
||||
timing_reinitializeAudio();
|
||||
#endif
|
||||
}
|
||||
|
||||
jboolean Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetMockingboardEnabled(JNIEnv *env, jclass cls, jboolean enabled) {
|
||||
#if !TESTING
|
||||
LOG("mockingboard enabled : %d", enabled);
|
||||
assert(cpu_isPaused());
|
||||
MB_SetEnabled(enabled);
|
||||
timing_reinitializeAudio();
|
||||
#endif
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetMockingboardVolume(JNIEnv *env, jclass cls, jint goesToTen) {
|
||||
LOG("mockingboard volume : %d", goesToTen);
|
||||
assert(goesToTen >= 0);
|
||||
MB_SetVolumeZeroToTen(goesToTen);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetCurrentTouchDevice(JNIEnv *env, jclass cls, jint touchDevice) {
|
||||
LOG("current touch device : %d", touchDevice);
|
||||
assert(touchDevice >= 0 && touchDevice < TOUCH_DEVICE_DEVICE_MAX);
|
||||
switch (touchDevice) {
|
||||
case TOUCH_DEVICE_JOYSTICK:
|
||||
keydriver_setTouchKeyboardOwnsScreen(false);
|
||||
joydriver_setTouchJoystickOwnsScreen(true);
|
||||
joydriver_setTouchVariant(EMULATED_JOYSTICK);
|
||||
video_backend->animation_showTouchJoystick();
|
||||
break;
|
||||
|
||||
case TOUCH_DEVICE_JOYSTICK_KEYPAD:
|
||||
keydriver_setTouchKeyboardOwnsScreen(false);
|
||||
joydriver_setTouchJoystickOwnsScreen(true);
|
||||
joydriver_setTouchVariant(EMULATED_KEYPAD);
|
||||
video_backend->animation_showTouchJoystick();
|
||||
break;
|
||||
|
||||
case TOUCH_DEVICE_KEYBOARD:
|
||||
keydriver_setTouchKeyboardOwnsScreen(true);
|
||||
joydriver_setTouchJoystickOwnsScreen(false);
|
||||
video_backend->animation_showTouchKeyboard();
|
||||
break;
|
||||
|
||||
case TOUCH_DEVICE_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickVisibility(JNIEnv *env, jclass cls, jboolean visibility) {
|
||||
LOG("visibility: %d", visibility);
|
||||
joydriver_setShowControls(visibility);
|
||||
}
|
||||
|
||||
jint Java_org_deadc0de_apple2ix_Apple2Preferences_nativeGetCurrentTouchDevice(JNIEnv *env, jclass cls) {
|
||||
LOG("%s", "");
|
||||
if (joydriver_ownsScreen()) {
|
||||
touchjoy_variant_t variant = joydriver_getTouchVariant();
|
||||
if (variant == EMULATED_JOYSTICK) {
|
||||
return TOUCH_DEVICE_JOYSTICK;
|
||||
} else if (variant == EMULATED_KEYPAD) {
|
||||
return TOUCH_DEVICE_JOYSTICK_KEYPAD;
|
||||
}
|
||||
} else if (keydriver_ownsScreen()) {
|
||||
return TOUCH_DEVICE_KEYBOARD;
|
||||
}
|
||||
return TOUCH_DEVICE_NONE;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchMenuEnabled(JNIEnv *env, jclass cls, jboolean enabled) {
|
||||
LOG("enabled : %d", enabled);
|
||||
interface_setTouchMenuEnabled(enabled);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetShowDiskOperationAnimation(JNIEnv *env, jclass cls, jboolean enabled) {
|
||||
LOG("enabled : %d", enabled);
|
||||
if (video_backend && video_backend->animation_setEnableShowTrackSector) {
|
||||
video_backend->animation_setEnableShowTrackSector(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchKeyboardLowercaseEnabled(JNIEnv *env, jclass cls, jboolean enabled) {
|
||||
LOG("enabled : %d", enabled);
|
||||
keydriver_setLowercaseEnabled(enabled);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchMenuVisibility(JNIEnv *env, jclass cls, jfloat alpha) {
|
||||
LOG("visibility : %f", alpha);
|
||||
interface_setTouchMenuVisibility(alpha);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchKeyboardVisibility(JNIEnv *env, jclass cls, jfloat inactiveAlpha, jfloat activeAlpha) {
|
||||
LOG("inactive:%f active:%f", inactiveAlpha, activeAlpha);
|
||||
keydriver_setVisibilityWhenOwnsScreen(inactiveAlpha, activeAlpha);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickButtonTypes(JNIEnv *env, jclass cls, jint touchDownButton, jint northButton, jint southButton) {
|
||||
LOG(": %d,%d,%d", touchDownButton, northButton, southButton);
|
||||
|
||||
touchDownButton -= 1;
|
||||
northButton -= 1;
|
||||
southButton -= 1;
|
||||
if (touchDownButton < TOUCH_NONE || touchDownButton > TOUCH_BOTH) {
|
||||
ERRLOG("OOPS, invalid parameter!");
|
||||
return;
|
||||
}
|
||||
if (northButton < TOUCH_NONE || northButton > TOUCH_BOTH) {
|
||||
ERRLOG("OOPS, invalid parameter!");
|
||||
return;
|
||||
}
|
||||
if (southButton < TOUCH_NONE || southButton > TOUCH_BOTH) {
|
||||
ERRLOG("OOPS, invalid parameter!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t rosetteChars[ROSETTE_COLS * ROSETTE_ROWS];
|
||||
int rosetteScancodes[ROSETTE_COLS * ROSETTE_ROWS];
|
||||
rosetteChars[ROSETTE_NORTHWEST] = ' '; rosetteScancodes[ROSETTE_NORTHWEST] = -1;
|
||||
rosetteChars[ROSETTE_NORTH] = (uint8_t)MOUSETEXT_UP; rosetteScancodes[ROSETTE_NORTH] = -1;
|
||||
rosetteChars[ROSETTE_NORTHEAST] = ' '; rosetteScancodes[ROSETTE_NORTHEAST] = -1;
|
||||
rosetteChars[ROSETTE_WEST] = (uint8_t)MOUSETEXT_LEFT; rosetteScancodes[ROSETTE_WEST] = -1;
|
||||
rosetteChars[ROSETTE_CENTER] = '+'; rosetteScancodes[ROSETTE_CENTER] = -1;
|
||||
rosetteChars[ROSETTE_EAST] = (uint8_t)MOUSETEXT_RIGHT; rosetteScancodes[ROSETTE_EAST] = -1;
|
||||
rosetteChars[ROSETTE_SOUTHWEST] = ' '; rosetteScancodes[ROSETTE_SOUTHWEST] = -1;
|
||||
rosetteChars[ROSETTE_SOUTH] = (uint8_t)MOUSETEXT_DOWN; rosetteScancodes[ROSETTE_SOUTH] = -1;
|
||||
rosetteChars[ROSETTE_SOUTHEAST] = ' '; rosetteScancodes[ROSETTE_SOUTHEAST] = -1;
|
||||
joydriver_setTouchAxisTypes(rosetteChars, rosetteScancodes);
|
||||
joydriver_setTouchButtonTypes((touchjoy_button_type_t)touchDownButton, -1, (touchjoy_button_type_t)northButton, -1, (touchjoy_button_type_t)southButton, -1);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickTapDelay(JNIEnv *env, jclass cls, jfloat secs) {
|
||||
LOG("tap delay : %f", secs);
|
||||
joydriver_setTapDelay(secs);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickAxisSensitivity(JNIEnv *env, jclass cls, jfloat multiplier) {
|
||||
LOG("axis sensitivity : %f", multiplier);
|
||||
joydriver_setTouchAxisSensitivity(multiplier);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickButtonSwitchThreshold(JNIEnv *env, jclass cls, jint delta) {
|
||||
LOG("delta : %d", delta);
|
||||
joydriver_setButtonSwitchThreshold(delta);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeTouchJoystickSetScreenDivision(JNIEnv *env, jclass cls, jfloat division) {
|
||||
LOG("division : %f", division);
|
||||
joydriver_setScreenDivision(division);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeTouchJoystickSetAxisOnLeft(JNIEnv *env, jclass cls, jboolean axisIsOnLeft) {
|
||||
LOG("axis on left : %d", axisIsOnLeft);
|
||||
joydriver_setAxisOnLeft(axisIsOnLeft);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeTouchJoystickSetKeypadTypes(JNIEnv *env, jclass cls,
|
||||
jintArray jRosetteChars, jintArray jRosetteScans, jintArray jButtonsChars, jintArray jButtonsScans)
|
||||
{
|
||||
jint *rosetteChars = (*env)->GetIntArrayElements(env, jRosetteChars, 0);
|
||||
jint *rosetteScans = (*env)->GetIntArrayElements(env, jRosetteScans, 0);
|
||||
jint *buttonsChars = (*env)->GetIntArrayElements(env, jButtonsChars, 0);
|
||||
jint *buttonsScans = (*env)->GetIntArrayElements(env, jButtonsScans, 0);
|
||||
|
||||
LOG("NW:%c/%d, N:%c/%d, NE:%c/%d, ... SWIPEUP:%c/%d",
|
||||
(char)rosetteChars[0], rosetteScans[0], (char)rosetteChars[1], rosetteScans[1], (char)rosetteChars[2], rosetteScans[2],
|
||||
(char)buttonsChars[1], buttonsScans[1]);
|
||||
LOG(" W:%c/%d, C:%c/%d, E:%c/%d, ... TAP:%c/%d",
|
||||
(char)rosetteChars[3], rosetteScans[3], (char)rosetteChars[4], rosetteScans[4], (char)rosetteChars[5], rosetteScans[5],
|
||||
(char)buttonsChars[0], buttonsScans[0]);
|
||||
LOG("SW:%c/%d, S:%c/%d, SE:%c/%d, ... SWIPEDN:%c/%d",
|
||||
(char)rosetteChars[6], rosetteScans[6], (char)rosetteChars[7], rosetteScans[7], (char)rosetteChars[8], rosetteScans[8],
|
||||
(char)buttonsChars[2], buttonsScans[2]);
|
||||
|
||||
// we could just pass these as jcharArray ... but this isn't a tight loop =P
|
||||
uint8_t actualChars[ROSETTE_ROWS * ROSETTE_COLS];
|
||||
for (unsigned int i=0; i<(ROSETTE_ROWS * ROSETTE_COLS); i++) {
|
||||
actualChars[i] = (uint8_t)rosetteChars[i];
|
||||
}
|
||||
joydriver_setTouchAxisTypes(actualChars, rosetteScans);
|
||||
joydriver_setTouchButtonTypes(
|
||||
(touchjoy_button_type_t)buttonsChars[0], buttonsScans[0],
|
||||
(touchjoy_button_type_t)buttonsChars[1], buttonsScans[1],
|
||||
(touchjoy_button_type_t)buttonsChars[2], buttonsScans[2]);
|
||||
|
||||
(*env)->ReleaseIntArrayElements(env, jRosetteChars, rosetteChars, 0);
|
||||
(*env)->ReleaseIntArrayElements(env, jRosetteScans, rosetteScans, 0);
|
||||
(*env)->ReleaseIntArrayElements(env, jButtonsChars, buttonsChars, 0);
|
||||
(*env)->ReleaseIntArrayElements(env, jButtonsScans, buttonsScans, 0);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeTouchDeviceBeginCalibrationMode(JNIEnv *env, jclass cls) {
|
||||
LOG("%s", "");
|
||||
if (joydriver_ownsScreen()) {
|
||||
joydriver_beginCalibration();
|
||||
} else if (keydriver_ownsScreen()) {
|
||||
keydriver_beginCalibration();
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeTouchDeviceEndCalibrationMode(JNIEnv *env, jclass cls) {
|
||||
LOG("%s", "");
|
||||
if (joydriver_ownsScreen()) {
|
||||
joydriver_endCalibration();
|
||||
} else if (keydriver_ownsScreen()) {
|
||||
keydriver_endCalibration();
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchDeviceKeyRepeatThreshold(JNIEnv *env, jclass cls, jfloat threshold) {
|
||||
LOG("threshold : %f", threshold);
|
||||
joydriver_setKeyRepeatThreshold(threshold);
|
||||
}
|
||||
|
||||
jint Java_org_deadc0de_apple2ix_Apple2Preferences_nativeGetCPUSpeed(JNIEnv *env, jclass cls) {
|
||||
LOG("%s", "");
|
||||
return (jint)round(cpu_scale_factor * 100.0);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetCPUSpeed(JNIEnv *env, jclass cls, jint percentSpeed) {
|
||||
LOG("percentSpeed : %d%%", percentSpeed);
|
||||
#if TESTING
|
||||
cpu_scale_factor = CPU_SCALE_FASTEST;
|
||||
cpu_altscale_factor = CPU_SCALE_FASTEST;
|
||||
timing_initialize();
|
||||
#else
|
||||
bool wasPaused = cpu_isPaused();
|
||||
|
||||
if (!wasPaused) {
|
||||
cpu_pause();
|
||||
}
|
||||
|
||||
cpu_scale_factor = percentSpeed/100.0;
|
||||
if (cpu_scale_factor > CPU_SCALE_FASTEST) {
|
||||
cpu_scale_factor = CPU_SCALE_FASTEST;
|
||||
}
|
||||
if (cpu_scale_factor < CPU_SCALE_SLOWEST) {
|
||||
cpu_scale_factor = CPU_SCALE_SLOWEST;
|
||||
}
|
||||
|
||||
if (video_backend->animation_showCPUSpeed) {
|
||||
video_backend->animation_showCPUSpeed();
|
||||
}
|
||||
|
||||
timing_initialize();
|
||||
|
||||
if (!wasPaused) {
|
||||
cpu_resume();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeLoadTouchKeyboardJSON(JNIEnv *env, jclass cls, jstring j_jsonPath) {
|
||||
const char *jsonPath = (*env)->GetStringUTFChars(env, j_jsonPath, 0);
|
||||
LOG("jsonPath: %s", jsonPath);
|
||||
keydriver_loadAltKbd(jsonPath);
|
||||
(*env)->ReleaseStringUTFChars(env, j_jsonPath, jsonPath);
|
||||
}
|
||||
|
||||
@@ -4,44 +4,67 @@
|
||||
APPLE2_SRC_PATH := apple2ix-src
|
||||
|
||||
APPLE2_X86_SRC := \
|
||||
$(APPLE2_SRC_PATH)/x86/glue.S $(APPLE2_SRC_PATH)/x86/cpu.S
|
||||
$(APPLE2_SRC_PATH)/x86/cpu.S \
|
||||
$(APPLE2_SRC_PATH)/x86/glue.S
|
||||
|
||||
APPLE2_ARM_SRC := \
|
||||
$(APPLE2_SRC_PATH)/arm/glue.S $(APPLE2_SRC_PATH)/arm/cpu.S
|
||||
$(APPLE2_SRC_PATH)/arm/cpu.S \
|
||||
$(APPLE2_SRC_PATH)/arm/glue.S
|
||||
|
||||
APPLE2_VIDEO_SRC = \
|
||||
$(APPLE2_SRC_PATH)/video/glvideo.c \
|
||||
$(APPLE2_SRC_PATH)/video/glnode.c \
|
||||
$(APPLE2_SRC_PATH)/video/glhudmodel.c \
|
||||
$(APPLE2_SRC_PATH)/video/glalert.c \
|
||||
$(APPLE2_SRC_PATH)/video/glhudmodel.c \
|
||||
$(APPLE2_SRC_PATH)/video/glnode.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy_joy.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy_kpad.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchkbd.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchmenu.c \
|
||||
$(APPLE2_SRC_PATH)/video/glvideo.c \
|
||||
$(APPLE2_SRC_PATH)/video/video.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/matrixUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/modelUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/sourceUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/vectorUtil.c
|
||||
|
||||
APPLE2_AUDIO_SRC = \
|
||||
$(APPLE2_SRC_PATH)/audio/soundcore.c $(APPLE2_SRC_PATH)/audio/soundcore-opensles.c $(APPLE2_SRC_PATH)/audio/speaker.c \
|
||||
$(APPLE2_SRC_PATH)/audio/mockingboard.c $(APPLE2_SRC_PATH)/audio/AY8910.c
|
||||
$(APPLE2_SRC_PATH)/audio/AY8910.c \
|
||||
$(APPLE2_SRC_PATH)/audio/mockingboard.c \
|
||||
$(APPLE2_SRC_PATH)/audio/soundcore.c \
|
||||
$(APPLE2_SRC_PATH)/audio/soundcore-opensles.c \
|
||||
$(APPLE2_SRC_PATH)/audio/speaker.c
|
||||
|
||||
APPLE2_META_SRC = \
|
||||
$(APPLE2_SRC_PATH)/meta/debug.c $(APPLE2_SRC_PATH)/meta/debugger.c $(APPLE2_SRC_PATH)/meta/opcodes.c \
|
||||
$(APPLE2_SRC_PATH)/meta/lintrace.c $(APPLE2_SRC_PATH)/test/sha1.c $(APPLE2_SRC_PATH)/json_parse.c \
|
||||
$(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c
|
||||
$(APPLE2_SRC_PATH)/meta/debug.c \
|
||||
$(APPLE2_SRC_PATH)/meta/debugger.c \
|
||||
$(APPLE2_SRC_PATH)/meta/lintrace.c \
|
||||
$(APPLE2_SRC_PATH)/meta/log.c \
|
||||
$(APPLE2_SRC_PATH)/meta/memmngt.c \
|
||||
$(APPLE2_SRC_PATH)/meta/opcodes.c \
|
||||
$(APPLE2_SRC_PATH)/test/sha1.c \
|
||||
|
||||
APPLE2_MAIN_SRC = \
|
||||
$(APPLE2_SRC_PATH)/font.c $(APPLE2_SRC_PATH)/rom.c $(APPLE2_SRC_PATH)/misc.c $(APPLE2_SRC_PATH)/display.c $(APPLE2_SRC_PATH)/vm.c \
|
||||
$(APPLE2_SRC_PATH)/timing.c $(APPLE2_SRC_PATH)/zlib-helpers.c $(APPLE2_SRC_PATH)/joystick.c $(APPLE2_SRC_PATH)/keys.c \
|
||||
$(APPLE2_SRC_PATH)/interface.c $(APPLE2_SRC_PATH)/disk.c $(APPLE2_SRC_PATH)/cpu-supp.c \
|
||||
jnihooks.c jniprefs.c androidkeys.c
|
||||
androidkeys.c \
|
||||
jnihooks.c \
|
||||
$(APPLE2_SRC_PATH)/cpu-supp.c \
|
||||
$(APPLE2_SRC_PATH)/disk.c \
|
||||
$(APPLE2_SRC_PATH)/display.c \
|
||||
$(APPLE2_SRC_PATH)/font.c \
|
||||
$(APPLE2_SRC_PATH)/interface.c \
|
||||
$(APPLE2_SRC_PATH)/joystick.c \
|
||||
$(APPLE2_SRC_PATH)/json_parse.c \
|
||||
$(APPLE2_SRC_PATH)/keys.c \
|
||||
$(APPLE2_SRC_PATH)/misc.c \
|
||||
$(APPLE2_SRC_PATH)/prefs.c \
|
||||
$(APPLE2_SRC_PATH)/rom.c \
|
||||
$(APPLE2_SRC_PATH)/timing.c \
|
||||
$(APPLE2_SRC_PATH)/vm.c \
|
||||
$(APPLE2_SRC_PATH)/zlib-helpers.c \
|
||||
$(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c
|
||||
|
||||
APPLE2_OPTIM_CFLAGS := -g -O2
|
||||
APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -DDEBUGGER=1 -DAUDIO_ENABLED=1 -std=gnu11 -DPREVENT_TEXTREL=1 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)
|
||||
APPLE2_BASE_LDLIBS := -llog -landroid -lGLESv2 -lz -lOpenSLES
|
||||
APPLE2_OPTIM_CFLAGS := -Os
|
||||
APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -std=gnu11 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)
|
||||
APPLE2_BASE_LDLIBS := -Wl,-z,text -Wl,-z,noexecstack -llog -landroid -lGLESv2 -lz -lOpenSLES -latomic
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += cpufeatures
|
||||
|
||||
|
||||
6
Android/jni/start_valgrind.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/system/bin/sh
|
||||
# WARNING : these $ variables need to be defined above and outside this bundled script
|
||||
set -x
|
||||
PACKAGE=org.deadc0de.apple2ix.basic
|
||||
export TMPDIR=/data/data/org.deadc0de.apple2ix.basic
|
||||
exec /data/local/Inst/bin/valgrind --gen-suppressions=all $GPU_VARIANT --num-callers=16 --error-limit=no -v --error-limit=no --default-suppressions=yes --suppressions=/data/local/Inst/lib/valgrind/default.supp --trace-children=yes --log-file=/sdcard/valgrind.log.%p --tool=memcheck --leak-check=full --show-reachable=yes $*
|
||||
@@ -12,7 +12,7 @@ include $(COMMON_SOURCES_MK)
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testcpu.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_CPU -DTESTING=1
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_CPU=1 -DTESTING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
@@ -23,6 +23,12 @@ else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
||||
@@ -12,7 +12,7 @@ include $(COMMON_SOURCES_MK)
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testdisk.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_DISK -DTESTING=1 -DDISK_TRACING=1
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_DISK=1 -DTESTING=1 -DDISK_TRACING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
@@ -23,6 +23,12 @@ else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
||||
@@ -12,7 +12,7 @@ include $(COMMON_SOURCES_MK)
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testdisplay.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_DISPLAY -DTESTING=1
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_DISPLAY=1 -DTESTING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
@@ -23,6 +23,12 @@ else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
||||
1
Android/jni/testprefs
Symbolic link
@@ -0,0 +1 @@
|
||||
build.sh
|
||||
40
Android/jni/testprefs.mk
Normal file
@@ -0,0 +1,40 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
PACKAGE_IDENTIFIER := "org.deadc0de.apple2ix"
|
||||
PACKAGE_NAME := "apple2ix"
|
||||
COMMON_SOURCES_MK := $(LOCAL_PATH)/sources.mk
|
||||
include $(COMMON_SOURCES_MK)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Android build config
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testprefs.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_PREFS=1 -DTESTING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
|
||||
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
|
||||
else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# --OR-- Build an executable so native can drive this show
|
||||
#include $(BUILD_EXECUTABLE)
|
||||
|
||||
$(call import-module, android/cpufeatures)
|
||||
1
Android/jni/testtrace
Symbolic link
@@ -0,0 +1 @@
|
||||
build.sh
|
||||
40
Android/jni/testtrace.mk
Normal file
@@ -0,0 +1,40 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
PACKAGE_IDENTIFIER := "org.deadc0de.apple2ix"
|
||||
PACKAGE_NAME := "apple2ix"
|
||||
COMMON_SOURCES_MK := $(LOCAL_PATH)/sources.mk
|
||||
include $(COMMON_SOURCES_MK)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Android build config
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testtrace.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_TRACE=1 -DTESTING=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DSPEAKER_TRACING=1 -DMB_TRACING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
|
||||
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
|
||||
else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# --OR-- Build an executable so native can drive this show
|
||||
#include $(BUILD_EXECUTABLE)
|
||||
|
||||
$(call import-module, android/cpufeatures)
|
||||
1
Android/jni/testui
Symbolic link
@@ -0,0 +1 @@
|
||||
build.sh
|
||||
40
Android/jni/testui.mk
Normal file
@@ -0,0 +1,40 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
PACKAGE_IDENTIFIER := "org.deadc0de.apple2ix"
|
||||
PACKAGE_NAME := "apple2ix"
|
||||
COMMON_SOURCES_MK := $(LOCAL_PATH)/sources.mk
|
||||
include $(COMMON_SOURCES_MK)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Android build config
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testui.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_UI=1 -DTESTING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
|
||||
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
|
||||
else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# --OR-- Build an executable so native can drive this show
|
||||
#include $(BUILD_EXECUTABLE)
|
||||
|
||||
$(call import-module, android/cpufeatures)
|
||||
@@ -12,7 +12,7 @@ include $(COMMON_SOURCES_MK)
|
||||
|
||||
LOCAL_MODULE := libapple2ix
|
||||
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testvm.c
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_VM -DTESTING=1
|
||||
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_VM=1 -DTESTING=1 -I$(APPLE2_SRC_PATH)/test
|
||||
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
|
||||
|
||||
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
|
||||
@@ -23,6 +23,12 @@ else
|
||||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
||||
@@ -56,26 +56,32 @@ static int _convert_crlf_to_lf(void) {
|
||||
|
||||
// convert CRLF -> LF
|
||||
|
||||
ssize_t outlen=0;
|
||||
ssize_t outmax=0;
|
||||
for (ssize_t i=0; i<inlen; i++) {
|
||||
char c = inbuf[i];
|
||||
|
||||
if (sawCR && (c != LF)) {
|
||||
outbuf[outlen++] = CR;
|
||||
outbuf[outmax++] = CR;
|
||||
}
|
||||
|
||||
sawCR = false;
|
||||
if (c == CR) {
|
||||
sawCR = true;
|
||||
} else {
|
||||
outbuf[outlen++] = c;
|
||||
outbuf[outmax++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, outbuf, outlen)) == -1) {
|
||||
errWrt = "error writing to stdout";
|
||||
break;
|
||||
}
|
||||
ssize_t outlen = 0;
|
||||
char *outb = &outbuf[0];
|
||||
do {
|
||||
if (TEMP_FAILURE_RETRY(outlen = write(STDOUT_FILENO, outb, outmax)) == -1) {
|
||||
errWrt = "error writing to stdout";
|
||||
break;
|
||||
}
|
||||
outb += outlen;
|
||||
outmax -= outlen;
|
||||
} while (outmax > 0);
|
||||
}
|
||||
|
||||
if (sawCR) {
|
||||
|
||||
304
Android/toolchain_edits/build/tools/dev-defaults.sh
Normal file
@@ -0,0 +1,304 @@
|
||||
# Default values used by several dev-scripts.
|
||||
#
|
||||
|
||||
# Current list of platform levels we support
|
||||
#
|
||||
# Note: levels 6 and 7 are omitted since they have the same native
|
||||
# APIs as level 5. Same for levels 10, 11 and 12
|
||||
#
|
||||
API_LEVELS="3 4 5 8 9 12 13 14 15 16 17 18 19 21"
|
||||
|
||||
FIRST_API64_LEVEL=21
|
||||
|
||||
# Default ABIs for the target prebuilt binaries.
|
||||
PREBUILT_ABIS="armeabi armeabi-v7a x86 mips armeabi-v7a-hard arm64-v8a x86_64 mips64"
|
||||
|
||||
# Location of the STLport sources, relative to the NDK root directory
|
||||
STLPORT_SUBDIR=sources/cxx-stl/stlport
|
||||
|
||||
# Location of the GAbi++ sources, relative to the NDK root directory
|
||||
GABIXX_SUBDIR=sources/cxx-stl/gabi++
|
||||
|
||||
# Location of the GNU libstdc++ headers and libraries, relative to the NDK
|
||||
# root directory.
|
||||
GNUSTL_SUBDIR=sources/cxx-stl/gnu-libstdc++
|
||||
|
||||
# Location of the LLVM libc++ headers and libraries, relative to the NDK
|
||||
# root directory.
|
||||
LIBCXX_SUBDIR=sources/cxx-stl/llvm-libc++
|
||||
|
||||
# Location of the LLVM libc++abi headers, relative to the NDK # root directory.
|
||||
LIBCXXABI_SUBDIR=sources/cxx-stl/llvm-libc++abi/libcxxabi
|
||||
|
||||
# Location of the libportable sources, relative to the NDK root directory
|
||||
LIBPORTABLE_SUBDIR=sources/android/libportable
|
||||
|
||||
# Location of the gccunwind sources, relative to the NDK root directory
|
||||
GCCUNWIND_SUBDIR=sources/android/gccunwind
|
||||
|
||||
# Location of the compiler-rt sources, relative to the NDK root directory
|
||||
COMPILER_RT_SUBDIR=sources/android/compiler-rt
|
||||
|
||||
# Location of the support sources for libc++, relative to the NDK root directory
|
||||
SUPPORT_SUBDIR=sources/android/support
|
||||
|
||||
# The date to use when downloading toolchain sources from AOSP servers
|
||||
# Leave it empty for tip of tree.
|
||||
TOOLCHAIN_GIT_DATE=now
|
||||
|
||||
# The space-separated list of all GCC versions we support in this NDK
|
||||
DEFAULT_GCC_VERSION_LIST="4.8 4.9"
|
||||
|
||||
DEFAULT_GCC32_VERSION=4.8
|
||||
DEFAULT_GCC64_VERSION=4.9
|
||||
FIRST_GCC32_VERSION=4.8
|
||||
FIRST_GCC64_VERSION=4.9
|
||||
DEFAULT_LLVM_GCC32_VERSION=4.8
|
||||
DEFAULT_LLVM_GCC64_VERSION=4.9
|
||||
|
||||
DEFAULT_BINUTILS_VERSION=2.25
|
||||
DEFAULT_GDB_VERSION=7.7
|
||||
DEFAULT_MPFR_VERSION=3.1.1
|
||||
DEFAULT_GMP_VERSION=5.0.5
|
||||
DEFAULT_MPC_VERSION=1.0.1
|
||||
DEFAULT_CLOOG_VERSION=0.18.0
|
||||
DEFAULT_ISL_VERSION=0.11.1
|
||||
DEFAULT_PPL_VERSION=1.0
|
||||
DEFAULT_PYTHON_VERSION=2.7.5
|
||||
DEFAULT_PERL_VERSION=5.16.2
|
||||
|
||||
RECENT_BINUTILS_VERSION=2.25
|
||||
|
||||
# Default platform to build target binaries against.
|
||||
DEFAULT_PLATFORM=android-9
|
||||
|
||||
# The list of default CPU architectures we support
|
||||
DEFAULT_ARCHS="arm x86 mips arm64 x86_64 mips64"
|
||||
|
||||
# Default toolchain names and prefix
|
||||
#
|
||||
# This is used by get_default_toolchain_name_for_arch and get_default_toolchain_prefix_for_arch
|
||||
# defined below
|
||||
DEFAULT_ARCH_TOOLCHAIN_NAME_arm=arm-linux-androideabi
|
||||
DEFAULT_ARCH_TOOLCHAIN_PREFIX_arm=arm-linux-androideabi
|
||||
|
||||
DEFAULT_ARCH_TOOLCHAIN_NAME_arm64=aarch64-linux-android
|
||||
DEFAULT_ARCH_TOOLCHAIN_PREFIX_arm64=aarch64-linux-android
|
||||
|
||||
DEFAULT_ARCH_TOOLCHAIN_NAME_x86=x86
|
||||
DEFAULT_ARCH_TOOLCHAIN_PREFIX_x86=i686-linux-android
|
||||
|
||||
DEFAULT_ARCH_TOOLCHAIN_NAME_x86_64=x86_64
|
||||
DEFAULT_ARCH_TOOLCHAIN_PREFIX_x86_64=x86_64-linux-android
|
||||
|
||||
DEFAULT_ARCH_TOOLCHAIN_NAME_mips=mipsel-linux-android
|
||||
DEFAULT_ARCH_TOOLCHAIN_PREFIX_mips=mipsel-linux-android
|
||||
|
||||
DEFAULT_ARCH_TOOLCHAIN_NAME_mips64=mips64el-linux-android
|
||||
DEFAULT_ARCH_TOOLCHAIN_PREFIX_mips64=mips64el-linux-android
|
||||
|
||||
# The space-separated list of all LLVM versions we support in NDK
|
||||
DEFAULT_LLVM_VERSION_LIST="3.6 3.5"
|
||||
|
||||
# The default LLVM version (first item in the list)
|
||||
DEFAULT_LLVM_VERSION=$(echo "$DEFAULT_LLVM_VERSION_LIST" | tr ' ' '\n' | head -n 1)
|
||||
|
||||
# The default URL to download the LLVM tar archive
|
||||
DEFAULT_LLVM_URL="http://llvm.org/releases"
|
||||
|
||||
# The list of default host NDK systems we support
|
||||
DEFAULT_SYSTEMS="linux-x86 windows darwin-x86"
|
||||
|
||||
# The default issue tracker URL
|
||||
DEFAULT_ISSUE_TRACKER_URL="http://source.android.com/source/report-bugs.html"
|
||||
|
||||
# Return the default gcc version for a given architecture
|
||||
# $1: Architecture name (e.g. 'arm')
|
||||
# Out: default arch-specific gcc version
|
||||
get_default_gcc_version_for_arch ()
|
||||
{
|
||||
case $1 in
|
||||
*64) echo $DEFAULT_GCC64_VERSION ;;
|
||||
*) echo $DEFAULT_GCC32_VERSION ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Return the first gcc version for a given architecture
|
||||
# $1: Architecture name (e.g. 'arm')
|
||||
# Out: default arch-specific gcc version
|
||||
get_first_gcc_version_for_arch ()
|
||||
{
|
||||
case $1 in
|
||||
*64) echo $FIRST_GCC64_VERSION ;;
|
||||
*) echo $FIRST_GCC32_VERSION ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Return default NDK ABI for a given architecture name
|
||||
# $1: Architecture name
|
||||
# Out: ABI name
|
||||
get_default_abi_for_arch ()
|
||||
{
|
||||
local RET
|
||||
case $1 in
|
||||
arm)
|
||||
RET="armeabi"
|
||||
;;
|
||||
arm64)
|
||||
RET="arm64-v8a"
|
||||
;;
|
||||
x86|x86_64|mips|mips64)
|
||||
RET="$1"
|
||||
;;
|
||||
mips32r6)
|
||||
RET="mips"
|
||||
;;
|
||||
*)
|
||||
2> echo "ERROR: Unsupported architecture name: $1, use one of: arm arm64 x86 x86_64 mips mips64"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
echo "$RET"
|
||||
}
|
||||
|
||||
|
||||
# Retrieve the list of default ABIs supported by a given architecture
|
||||
# $1: Architecture name
|
||||
# Out: space-separated list of ABI names
|
||||
get_default_abis_for_arch ()
|
||||
{
|
||||
local RET
|
||||
case $1 in
|
||||
arm)
|
||||
RET="armeabi armeabi-v7a armeabi-v7a-hard"
|
||||
;;
|
||||
arm64)
|
||||
RET="arm64-v8a"
|
||||
;;
|
||||
x86|x86_64|mips|mips32r6|mips64)
|
||||
RET="$1"
|
||||
;;
|
||||
*)
|
||||
2> echo "ERROR: Unsupported architecture name: $1, use one of: arm arm64 x86 x86_64 mips mips64"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
echo "$RET"
|
||||
}
|
||||
|
||||
# Return toolchain name for given architecture and GCC version
|
||||
# $1: Architecture name (e.g. 'arm')
|
||||
# $2: optional, GCC version (e.g. '4.8')
|
||||
# Out: default arch-specific toolchain name (e.g. 'arm-linux-androideabi-$GCC_VERSION')
|
||||
# Return empty for unknown arch
|
||||
get_toolchain_name_for_arch ()
|
||||
{
|
||||
if [ ! -z "$2" ] ; then
|
||||
eval echo \"\${DEFAULT_ARCH_TOOLCHAIN_NAME_$1}-$2\"
|
||||
else
|
||||
eval echo \"\${DEFAULT_ARCH_TOOLCHAIN_NAME_$1}\"
|
||||
fi
|
||||
}
|
||||
|
||||
# Return the default toolchain name for a given architecture
|
||||
# $1: Architecture name (e.g. 'arm')
|
||||
# Out: default arch-specific toolchain name (e.g. 'arm-linux-androideabi-$GCCVER')
|
||||
# Return empty for unknown arch
|
||||
get_default_toolchain_name_for_arch ()
|
||||
{
|
||||
local GCCVER=$(get_default_gcc_version_for_arch $1)
|
||||
eval echo \"\${DEFAULT_ARCH_TOOLCHAIN_NAME_$1}-$GCCVER\"
|
||||
}
|
||||
|
||||
# Return the default toolchain program prefix for a given architecture
|
||||
# $1: Architecture name
|
||||
# Out: default arch-specific toolchain prefix (e.g. arm-linux-androideabi)
|
||||
# Return empty for unknown arch
|
||||
get_default_toolchain_prefix_for_arch ()
|
||||
{
|
||||
eval echo "\$DEFAULT_ARCH_TOOLCHAIN_PREFIX_$1"
|
||||
}
|
||||
|
||||
# Get the list of all toolchain names for a given architecture
|
||||
# $1: architecture (e.g. 'arm')
|
||||
# $2: comma separated versions (optional)
|
||||
# Out: list of toolchain names for this arch (e.g. arm-linux-androideabi-4.8 arm-linux-androideabi-4.9)
|
||||
# Return empty for unknown arch
|
||||
get_toolchain_name_list_for_arch ()
|
||||
{
|
||||
local PREFIX VERSION RET ADD FIRST_GCC_VERSION VERSIONS
|
||||
PREFIX=$(eval echo \"\$DEFAULT_ARCH_TOOLCHAIN_NAME_$1\")
|
||||
if [ -z "$PREFIX" ]; then
|
||||
return 0
|
||||
fi
|
||||
RET=""
|
||||
FIRST_GCC_VERSION=$(get_first_gcc_version_for_arch $1)
|
||||
ADD=""
|
||||
VERSIONS=$(commas_to_spaces $2)
|
||||
if [ -z "$VERSIONS" ]; then
|
||||
VERSIONS=$DEFAULT_GCC_VERSION_LIST
|
||||
else
|
||||
ADD="yes" # include everything we passed explicitly
|
||||
fi
|
||||
for VERSION in $VERSIONS; do
|
||||
if [ -z "$ADD" -a "$VERSION" = "$FIRST_GCC_VERSION" ]; then
|
||||
ADD="yes"
|
||||
fi
|
||||
if [ -z "$ADD" ]; then
|
||||
continue
|
||||
fi
|
||||
RET=$RET" $PREFIX-$VERSION"
|
||||
done
|
||||
RET=${RET## }
|
||||
echo "$RET"
|
||||
}
|
||||
|
||||
# Return the binutils version to be used by default when
|
||||
# building a given version of GCC. This is needed to ensure
|
||||
# we use binutils-2.19 when building gcc-4.4.3 for ARM and x86,
|
||||
# and later binutils in other cases (mips, or gcc-4.6+).
|
||||
#
|
||||
# Note that technically, we could use latest binutils for all versions of
|
||||
# GCC, however, in NDK r7, we did build GCC 4.4.3 with binutils-2.20.1
|
||||
# and this resulted in weird C++ debugging bugs. For NDK r7b and higher,
|
||||
# binutils was reverted to 2.19, to ensure at least
|
||||
# feature/bug compatibility.
|
||||
#
|
||||
# $1: toolchain with version numer (e.g. 'arm-linux-androideabi-4.8')
|
||||
#
|
||||
get_default_binutils_version_for_gcc ()
|
||||
{
|
||||
echo "$DEFAULT_BINUTILS_VERSION"
|
||||
}
|
||||
|
||||
# Return the binutils version to be used by default when
|
||||
# building a given version of llvm. For llvm-3.4 or later,
|
||||
# we use binutils-2.23+ to ensure the LLVMgold.so could be
|
||||
# built properly. For llvm-3.3, we use binutils-2.21 as default.
|
||||
#
|
||||
# $1: toolchain with version numer (e.g. 'llvm-3.3')
|
||||
#
|
||||
get_default_binutils_version_for_llvm ()
|
||||
{
|
||||
echo "$DEFAULT_BINUTILS_VERSION"
|
||||
}
|
||||
|
||||
# Return the gdb version to be used by default when building a given
|
||||
# version of GCC.
|
||||
#
|
||||
# $1: toolchain with version numer (e.g. 'arm-linux-androideabi-4.8')
|
||||
#
|
||||
get_default_gdb_version_for_gcc ()
|
||||
{
|
||||
echo "$DEFAULT_GDB_VERSION"
|
||||
}
|
||||
|
||||
# Return the gdbserver version to be used by default when building a given
|
||||
# version of GCC.
|
||||
#
|
||||
# $1: toolchain with version numer (e.g. 'arm-linux-androideabi-4.8')
|
||||
#
|
||||
get_default_gdbserver_version_for_gcc ()
|
||||
{
|
||||
echo "$DEFAULT_GDB_VERSION"
|
||||
}
|
||||
980
Android/toolchain_edits/build/tools/ndk-common.sh
Normal file
@@ -0,0 +1,980 @@
|
||||
# Copyright (C) 2009 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# A collection of shell function definitions used by various build scripts
|
||||
# in the Android NDK (Native Development Kit)
|
||||
#
|
||||
|
||||
# Get current script name into PROGNAME
|
||||
PROGNAME=`basename $0`
|
||||
|
||||
# Find the Android NDK root, assuming we are invoked from a script
|
||||
# within its directory structure.
|
||||
#
|
||||
# $1: Variable name that will receive the path
|
||||
# $2: Path of invoking script
|
||||
find_ndk_root ()
|
||||
{
|
||||
# Try to auto-detect the NDK root by walking up the directory
|
||||
# path to the current script.
|
||||
local PROGDIR="`dirname \"$2\"`"
|
||||
while [ -n "1" ] ; do
|
||||
if [ -d "$PROGDIR/build/core" ] ; then
|
||||
break
|
||||
fi
|
||||
if [ -z "$PROGDIR" -o "$PROGDIR" = '/' ] ; then
|
||||
return 1
|
||||
fi
|
||||
PROGDIR="`cd \"$PROGDIR/..\" && pwd`"
|
||||
done
|
||||
eval $1="$PROGDIR"
|
||||
}
|
||||
|
||||
# Put location of Android NDK into ANDROID_NDK_ROOT and
|
||||
# perform a tiny amount of sanity check
|
||||
#
|
||||
if [ -z "$ANDROID_NDK_ROOT" ] ; then
|
||||
find_ndk_root ANDROID_NDK_ROOT "$0"
|
||||
if [ $? != 0 ]; then
|
||||
echo "Please define ANDROID_NDK_ROOT to point to the root of your"
|
||||
echo "Android NDK installation."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$ANDROID_NDK_ROOT" | grep -q -e " "
|
||||
if [ $? = 0 ] ; then
|
||||
echo "ERROR: The Android NDK installation path contains a space !"
|
||||
echo "Please install to a different location."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d $ANDROID_NDK_ROOT ] ; then
|
||||
echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f $ANDROID_NDK_ROOT/build/tools/ndk-common.sh ] ; then
|
||||
echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Use DRYRUN to find out top-level commands.
|
||||
DRYRUN=${DRYRUN-no}
|
||||
|
||||
## Logging support
|
||||
##
|
||||
VERBOSE=${VERBOSE-yes}
|
||||
VERBOSE2=${VERBOSE2-no}
|
||||
|
||||
|
||||
# If NDK_LOGFILE is defined in the environment, use this as the log file
|
||||
TMPLOG=
|
||||
if [ -n "$NDK_LOGFILE" ] ; then
|
||||
mkdir -p `dirname "$NDK_LOGFILE"` && touch "$NDK_LOGFILE"
|
||||
TMPLOG="$NDK_LOGFILE"
|
||||
fi
|
||||
|
||||
# Setup a log file where all log() and log2() output will be sent
|
||||
#
|
||||
# $1: log file path (optional)
|
||||
#
|
||||
setup_default_log_file ()
|
||||
{
|
||||
if [ -n "$NDK_LOGFILE" ] ; then
|
||||
return
|
||||
fi
|
||||
if [ -n "$1" ] ; then
|
||||
NDK_LOGFILE="$1"
|
||||
else
|
||||
NDK_LOGFILE=/tmp/ndk-log-$$.txt
|
||||
fi
|
||||
export NDK_LOGFILE
|
||||
TMPLOG="$NDK_LOGFILE"
|
||||
rm -rf "$TMPLOG" && mkdir -p `dirname "$TMPLOG"` && touch "$TMPLOG"
|
||||
echo "To follow build in another terminal, please use: tail -F $TMPLOG"
|
||||
}
|
||||
|
||||
dump ()
|
||||
{
|
||||
if [ -n "$TMPLOG" ] ; then
|
||||
echo "$@" >> $TMPLOG
|
||||
fi
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
dump_n ()
|
||||
{
|
||||
if [ -n "$TMPLOG" ] ; then
|
||||
printf %s "$@" >> $TMPLOG
|
||||
fi
|
||||
printf %s "$@"
|
||||
}
|
||||
|
||||
log ()
|
||||
{
|
||||
if [ "$VERBOSE" = "yes" ] ; then
|
||||
echo "$@"
|
||||
else
|
||||
if [ -n "$TMPLOG" ] ; then
|
||||
echo "$@" >> $TMPLOG
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
log_n ()
|
||||
{
|
||||
if [ "$VERBOSE" = "yes" ] ; then
|
||||
printf %s "$@"
|
||||
else
|
||||
if [ -n "$TMPLOG" ] ; then
|
||||
printf %s "$@" >> $TMPLOG
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
log2 ()
|
||||
{
|
||||
if [ "$VERBOSE2" = "yes" ] ; then
|
||||
echo "$@"
|
||||
else
|
||||
if [ -n "$TMPLOG" ] ; then
|
||||
echo "$@" >> $TMPLOG
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
run ()
|
||||
{
|
||||
if [ "$DRYRUN" = "yes" ] ; then
|
||||
echo "## SKIP COMMAND: $@"
|
||||
elif [ "$VERBOSE" = "yes" ] ; then
|
||||
echo "## COMMAND: $@"
|
||||
"$@" 2>&1
|
||||
else
|
||||
if [ -n "$TMPLOG" ] ; then
|
||||
echo "## COMMAND: $@" >> $TMPLOG
|
||||
"$@" >>$TMPLOG 2>&1
|
||||
else
|
||||
"$@" > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
run2 ()
|
||||
{
|
||||
if [ "$DRYRUN" = "yes" ] ; then
|
||||
echo "## SKIP COMMAND: $@"
|
||||
elif [ "$VERBOSE2" = "yes" ] ; then
|
||||
echo "## COMMAND: $@"
|
||||
"$@" 2>&1
|
||||
elif [ "$VERBOSE" = "yes" ]; then
|
||||
echo "## COMMAND: $@"
|
||||
if [ -n "$TMPLOG" ]; then
|
||||
echo "## COMMAND: $@" >> $TMPLOG
|
||||
"$@" >>$TMPLOG 2>&1
|
||||
else
|
||||
"$@" > /dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
if [ -n "$TMPLOG" ]; then
|
||||
"$@" >>$TMPLOG 2>&1
|
||||
else
|
||||
"$@" > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
panic ()
|
||||
{
|
||||
dump "ERROR: $@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
fail_panic ()
|
||||
{
|
||||
if [ $? != 0 ] ; then
|
||||
dump "ERROR: $@"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fail_warning ()
|
||||
{
|
||||
if [ $? != 0 ] ; then
|
||||
dump "WARNING: $@"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
## Utilities
|
||||
##
|
||||
|
||||
# Return the value of a given named variable
|
||||
# $1: variable name
|
||||
#
|
||||
# example:
|
||||
# FOO=BAR
|
||||
# BAR=ZOO
|
||||
# echo `var_value $FOO`
|
||||
# will print 'ZOO'
|
||||
#
|
||||
var_value ()
|
||||
{
|
||||
# find a better way to do that ?
|
||||
eval echo "$`echo $1`"
|
||||
}
|
||||
|
||||
# convert to uppercase
|
||||
# assumes tr is installed on the platform ?
|
||||
#
|
||||
to_uppercase ()
|
||||
{
|
||||
echo $1 | tr "[:lower:]" "[:upper:]"
|
||||
}
|
||||
|
||||
## First, we need to detect the HOST CPU, because proper HOST_ARCH detection
|
||||
## requires platform-specific tricks.
|
||||
##
|
||||
HOST_EXE=""
|
||||
HOST_OS=`uname -s`
|
||||
case "$HOST_OS" in
|
||||
Darwin)
|
||||
HOST_OS=darwin
|
||||
;;
|
||||
Linux)
|
||||
# note that building 32-bit binaries on x86_64 is handled later
|
||||
HOST_OS=linux
|
||||
;;
|
||||
FreeBsd) # note: this is not tested
|
||||
HOST_OS=freebsd
|
||||
;;
|
||||
CYGWIN*|*_NT-*)
|
||||
HOST_OS=windows
|
||||
HOST_EXE=.exe
|
||||
if [ "x$OSTYPE" = xcygwin ] ; then
|
||||
HOST_OS=cygwin
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
log2 "HOST_OS=$HOST_OS"
|
||||
log2 "HOST_EXE=$HOST_EXE"
|
||||
|
||||
## Now find the host architecture. This must correspond to the bitness of
|
||||
## the binaries we're going to run with this NDK. Certain platforms allow
|
||||
## you to use a 64-bit kernel with a 32-bit userland, and unfortunately
|
||||
## commands like 'uname -m' only report the kernel bitness.
|
||||
##
|
||||
HOST_ARCH=`uname -m`
|
||||
case "$HOST_ARCH" in
|
||||
i?86) HOST_ARCH=x86
|
||||
# "uname -m" reports i386 on Snow Leopard even though its architecture is
|
||||
# 64-bit. In order to use it to build 64-bit toolchains we need to fix the
|
||||
# reporting anomoly here.
|
||||
if [ "$HOST_OS" = darwin ] ; then
|
||||
if ! echo __LP64__ | (CCOPTS= gcc -E - 2>/dev/null) | grep -q __LP64__ ; then
|
||||
# or if gcc -dM -E - < /dev/null | grep -q __LP64__; then
|
||||
HOST_ARCH=x86_64
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
amd64) HOST_ARCH=x86_64
|
||||
;;
|
||||
powerpc) HOST_ARCH=ppc
|
||||
;;
|
||||
esac
|
||||
|
||||
HOST_FILE_PROGRAM="file"
|
||||
case "$HOST_OS-$HOST_ARCH" in
|
||||
linux-x86_64|darwin-x86_64)
|
||||
## On Linux or Darwin, a 64-bit kernel doesn't mean that the user-land
|
||||
## is always 32-bit, so use "file" to determine the bitness of the shell
|
||||
## that invoked us. The -L option is used to de-reference symlinks.
|
||||
##
|
||||
## Note that on Darwin, a single executable can contain both x86 and
|
||||
## x86_64 machine code, so just look for x86_64 (darwin) or x86-64 (Linux)
|
||||
## in the output.
|
||||
##
|
||||
## Also note that some versions of 'file' in MacPort may report erroneous
|
||||
## result. See http://b.android.com/53769. Use /usr/bin/file if exists.
|
||||
if [ "$HOST_OS" = "darwin" ]; then
|
||||
SYSTEM_FILE_PROGRAM="/usr/bin/file"
|
||||
test -x "$SYSTEM_FILE_PROGRAM" && HOST_FILE_PROGRAM="$SYSTEM_FILE_PROGRAM"
|
||||
fi
|
||||
"$HOST_FILE_PROGRAM" -L "$SHELL" | grep -q "x86[_-]64"
|
||||
if [ $? != 0 ]; then
|
||||
# $SHELL is not a 64-bit executable, so assume our userland is too.
|
||||
log2 "Detected 32-bit userland on 64-bit kernel system!"
|
||||
HOST_ARCH=x86
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
log2 "HOST_ARCH=$HOST_ARCH"
|
||||
|
||||
# at this point, the supported values for HOST_ARCH are:
|
||||
# x86
|
||||
# x86_64
|
||||
# ppc
|
||||
#
|
||||
# other values may be possible but haven't been tested
|
||||
#
|
||||
# at this point, the value of HOST_OS should be one of the following:
|
||||
# linux
|
||||
# darwin
|
||||
# windows (MSys)
|
||||
# cygwin
|
||||
#
|
||||
# Note that cygwin is treated as a special case because it behaves very differently
|
||||
# for a few things. Other values may be possible but have not been tested
|
||||
#
|
||||
|
||||
# define HOST_TAG as a unique tag used to identify both the host OS and CPU
|
||||
# supported values are:
|
||||
#
|
||||
# linux-x86
|
||||
# linux-x86_64
|
||||
# darwin-x86
|
||||
# darwin-x86_64
|
||||
# darwin-ppc
|
||||
# windows
|
||||
# windows-x86_64
|
||||
#
|
||||
# other values are possible but were not tested.
|
||||
#
|
||||
compute_host_tag ()
|
||||
{
|
||||
HOST_TAG=${HOST_OS}-${HOST_ARCH}
|
||||
# Special case for windows-x86 => windows
|
||||
case $HOST_TAG in
|
||||
windows-x86|cygwin-x86)
|
||||
HOST_TAG="windows"
|
||||
;;
|
||||
esac
|
||||
log2 "HOST_TAG=$HOST_TAG"
|
||||
}
|
||||
|
||||
compute_host_tag
|
||||
|
||||
# Compute the number of host CPU cores an HOST_NUM_CPUS
|
||||
#
|
||||
case "$HOST_OS" in
|
||||
linux)
|
||||
HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l`
|
||||
;;
|
||||
darwin|freebsd)
|
||||
HOST_NUM_CPUS=`sysctl -n hw.ncpu`
|
||||
;;
|
||||
windows|cygwin)
|
||||
HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS
|
||||
;;
|
||||
*) # let's play safe here
|
||||
HOST_NUM_CPUS=1
|
||||
esac
|
||||
|
||||
log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS"
|
||||
|
||||
# If BUILD_NUM_CPUS is not already defined in your environment,
|
||||
# define it as the double of HOST_NUM_CPUS. This is used to
|
||||
# run Make commands in parralles, as in 'make -j$BUILD_NUM_CPUS'
|
||||
#
|
||||
if [ -z "$BUILD_NUM_CPUS" ] ; then
|
||||
BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2`
|
||||
fi
|
||||
|
||||
log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS"
|
||||
|
||||
|
||||
## HOST TOOLCHAIN SUPPORT
|
||||
##
|
||||
|
||||
# force the generation of 32-bit binaries on 64-bit systems
|
||||
#
|
||||
FORCE_32BIT=no
|
||||
force_32bit_binaries ()
|
||||
{
|
||||
if [ "$HOST_ARCH" = x86_64 ] ; then
|
||||
log2 "Forcing generation of 32-bit host binaries on $HOST_ARCH"
|
||||
FORCE_32BIT=yes
|
||||
HOST_ARCH=x86
|
||||
log2 "HOST_ARCH=$HOST_ARCH"
|
||||
compute_host_tag
|
||||
fi
|
||||
}
|
||||
|
||||
# On Windows, cygwin binaries will be generated by default, but
|
||||
# you can force mingw ones that do not link to cygwin.dll if you
|
||||
# call this function.
|
||||
#
|
||||
disable_cygwin ()
|
||||
{
|
||||
if [ $HOST_OS = cygwin ] ; then
|
||||
log2 "Disabling cygwin binaries generation"
|
||||
CFLAGS="$CFLAGS -mno-cygwin"
|
||||
LDFLAGS="$LDFLAGS -mno-cygwin"
|
||||
HOST_OS=windows
|
||||
compute_host_tag
|
||||
fi
|
||||
}
|
||||
|
||||
# Various probes are going to need to run a small C program
|
||||
mkdir -p /tmp/ndk-$USER/tmp/tests
|
||||
|
||||
TMPC=/tmp/ndk-$USER/tmp/tests/test-$$.c
|
||||
TMPO=/tmp/ndk-$USER/tmp/tests/test-$$.o
|
||||
TMPE=/tmp/ndk-$USER/tmp/tests/test-$$$EXE
|
||||
TMPL=/tmp/ndk-$USER/tmp/tests/test-$$.log
|
||||
|
||||
# cleanup temporary files
|
||||
clean_temp ()
|
||||
{
|
||||
rm -f $TMPC $TMPO $TMPL $TMPE
|
||||
}
|
||||
|
||||
# cleanup temp files then exit with an error
|
||||
clean_exit ()
|
||||
{
|
||||
clean_temp
|
||||
exit 1
|
||||
}
|
||||
|
||||
# this function will setup the compiler and linker and check that they work as advertised
|
||||
# note that you should call 'force_32bit_binaries' before this one if you want it to
|
||||
# generate 32-bit binaries on 64-bit systems (that support it).
|
||||
#
|
||||
setup_toolchain ()
|
||||
{
|
||||
if [ -z "$CC" ] ; then
|
||||
CC=gcc
|
||||
fi
|
||||
if [ -z "$CXX" ] ; then
|
||||
CXX=g++
|
||||
fi
|
||||
if [ -z "$CXXFLAGS" ] ; then
|
||||
CXXFLAGS="$CFLAGS"
|
||||
fi
|
||||
if [ -z "$LD" ] ; then
|
||||
LD="$CC"
|
||||
fi
|
||||
|
||||
log2 "Using '$CC' as the C compiler"
|
||||
|
||||
# check that we can compile a trivial C program with this compiler
|
||||
mkdir -p $(dirname "$TMPC")
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {}
|
||||
EOF
|
||||
|
||||
if [ "$FORCE_32BIT" = yes ] ; then
|
||||
CC="$CC -m32"
|
||||
CXX="$CXX -m32"
|
||||
LD="$LD -m32"
|
||||
compile
|
||||
if [ $? != 0 ] ; then
|
||||
# sometimes, we need to also tell the assembler to generate 32-bit binaries
|
||||
# this is highly dependent on your GCC installation (and no, we can't set
|
||||
# this flag all the time)
|
||||
CFLAGS="$CFLAGS -Wa,--32"
|
||||
compile
|
||||
fi
|
||||
fi
|
||||
|
||||
compile
|
||||
if [ $? != 0 ] ; then
|
||||
echo "your C compiler doesn't seem to work:"
|
||||
cat $TMPL
|
||||
clean_exit
|
||||
fi
|
||||
log "CC : compiler check ok ($CC)"
|
||||
|
||||
# check that we can link the trivial program into an executable
|
||||
link
|
||||
if [ $? != 0 ] ; then
|
||||
OLD_LD="$LD"
|
||||
LD="$CC"
|
||||
compile
|
||||
link
|
||||
if [ $? != 0 ] ; then
|
||||
LD="$OLD_LD"
|
||||
echo "your linker doesn't seem to work:"
|
||||
cat $TMPL
|
||||
clean_exit
|
||||
fi
|
||||
fi
|
||||
log2 "Using '$LD' as the linker"
|
||||
log "LD : linker check ok ($LD)"
|
||||
|
||||
# check the C++ compiler
|
||||
log2 "Using '$CXX' as the C++ compiler"
|
||||
|
||||
cat > $TMPC <<EOF
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
int main()
|
||||
{
|
||||
cout << "Hello World!" << endl;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
compile_cpp
|
||||
if [ $? != 0 ] ; then
|
||||
echo "your C++ compiler doesn't seem to work"
|
||||
cat $TMPL
|
||||
clean_exit
|
||||
fi
|
||||
|
||||
log "CXX : C++ compiler check ok ($CXX)"
|
||||
|
||||
# XXX: TODO perform AR checks
|
||||
AR=ar
|
||||
ARFLAGS=
|
||||
}
|
||||
|
||||
# try to compile the current source file in $TMPC into an object
|
||||
# stores the error log into $TMPL
|
||||
#
|
||||
compile ()
|
||||
{
|
||||
log2 "Object : $CC -o $TMPO -c $CFLAGS $TMPC"
|
||||
$CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL
|
||||
}
|
||||
|
||||
compile_cpp ()
|
||||
{
|
||||
log2 "Object : $CXX -o $TMPO -c $CXXFLAGS $TMPC"
|
||||
$CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL
|
||||
}
|
||||
|
||||
# try to link the recently built file into an executable. error log in $TMPL
|
||||
#
|
||||
link()
|
||||
{
|
||||
log2 "Link : $LD -o $TMPE $TMPO $LDFLAGS"
|
||||
$LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL
|
||||
}
|
||||
|
||||
# run a command
|
||||
#
|
||||
execute()
|
||||
{
|
||||
log2 "Running: $*"
|
||||
$*
|
||||
}
|
||||
|
||||
# perform a simple compile / link / run of the source file in $TMPC
|
||||
compile_exec_run()
|
||||
{
|
||||
log2 "RunExec : $CC -o $TMPE $CFLAGS $TMPC"
|
||||
compile
|
||||
if [ $? != 0 ] ; then
|
||||
echo "Failure to compile test program"
|
||||
cat $TMPC
|
||||
cat $TMPL
|
||||
clean_exit
|
||||
fi
|
||||
link
|
||||
if [ $? != 0 ] ; then
|
||||
echo "Failure to link test program"
|
||||
cat $TMPC
|
||||
echo "------"
|
||||
cat $TMPL
|
||||
clean_exit
|
||||
fi
|
||||
$TMPE
|
||||
}
|
||||
|
||||
pattern_match ()
|
||||
{
|
||||
echo "$2" | grep -q -E -e "$1"
|
||||
}
|
||||
|
||||
# Let's check that we have a working md5sum here
|
||||
check_md5sum ()
|
||||
{
|
||||
A_MD5=`echo "A" | md5sum | cut -d' ' -f1`
|
||||
if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then
|
||||
echo "Please install md5sum on this machine"
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
# Find if a given shell program is available.
|
||||
# We need to take care of the fact that the 'which <foo>' command
|
||||
# may return either an empty string (Linux) or something like
|
||||
# "no <foo> in ..." (Darwin). Also, we need to redirect stderr
|
||||
# to /dev/null for Cygwin
|
||||
#
|
||||
# $1: variable name
|
||||
# $2: program name
|
||||
#
|
||||
# Result: set $1 to the full path of the corresponding command
|
||||
# or to the empty/undefined string if not available
|
||||
#
|
||||
find_program ()
|
||||
{
|
||||
local PROG RET
|
||||
PROG=`which $2 2>/dev/null`
|
||||
RET=$?
|
||||
if [ $RET != 0 ]; then
|
||||
PROG=
|
||||
fi
|
||||
eval $1=\"$PROG\"
|
||||
return $RET
|
||||
}
|
||||
|
||||
prepare_download ()
|
||||
{
|
||||
find_program CMD_WGET wget
|
||||
find_program CMD_CURL curl
|
||||
find_program CMD_SCRP scp
|
||||
}
|
||||
|
||||
find_pbzip2 ()
|
||||
{
|
||||
if [ -z "$_PBZIP2_initialized" ] ; then
|
||||
find_program PBZIP2 pbzip2
|
||||
_PBZIP2_initialized="yes"
|
||||
fi
|
||||
}
|
||||
|
||||
# Download a file with either 'curl', 'wget' or 'scp'
|
||||
#
|
||||
# $1: source URL (e.g. http://foo.com, ssh://blah, /some/path)
|
||||
# $2: target file
|
||||
download_file ()
|
||||
{
|
||||
# Is this HTTP, HTTPS or FTP ?
|
||||
if pattern_match "^(http|https|ftp):.*" "$1"; then
|
||||
if [ -n "$CMD_WGET" ] ; then
|
||||
run $CMD_WGET -O $2 $1
|
||||
elif [ -n "$CMD_CURL" ] ; then
|
||||
run $CMD_CURL -o $2 $1
|
||||
else
|
||||
echo "Please install wget or curl on this machine"
|
||||
exit 1
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
# Is this SSH ?
|
||||
# Accept both ssh://<path> or <machine>:<path>
|
||||
#
|
||||
if pattern_match "^(ssh|[^:]+):.*" "$1"; then
|
||||
if [ -n "$CMD_SCP" ] ; then
|
||||
scp_src=`echo $1 | sed -e s%ssh://%%g`
|
||||
run $CMD_SCP $scp_src $2
|
||||
else
|
||||
echo "Please install scp on this machine"
|
||||
exit 1
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
# Is this a file copy ?
|
||||
# Accept both file://<path> or /<path>
|
||||
#
|
||||
if pattern_match "^(file://|/).*" "$1"; then
|
||||
cp_src=`echo $1 | sed -e s%^file://%%g`
|
||||
run cp -f $cp_src $2
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
# Form the relative path between from one abs path to another
|
||||
#
|
||||
# $1 : start path
|
||||
# $2 : end path
|
||||
#
|
||||
# From:
|
||||
# http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory
|
||||
relpath ()
|
||||
{
|
||||
[ $# -ge 1 ] && [ $# -le 2 ] || return 1
|
||||
current="${2:+"$1"}"
|
||||
target="${2:-"$1"}"
|
||||
[ "$target" != . ] || target=/
|
||||
target="/${target##/}"
|
||||
[ "$current" != . ] || current=/
|
||||
current="${current:="/"}"
|
||||
current="/${current##/}"
|
||||
appendix="${target##/}"
|
||||
relative=''
|
||||
while appendix="${target#"$current"/}"
|
||||
[ "$current" != '/' ] && [ "$appendix" = "$target" ]; do
|
||||
if [ "$current" = "$appendix" ]; then
|
||||
relative="${relative:-.}"
|
||||
echo "${relative#/}"
|
||||
return 0
|
||||
fi
|
||||
current="${current%/*}"
|
||||
relative="$relative${relative:+/}.."
|
||||
done
|
||||
relative="$relative${relative:+${appendix:+/}}${appendix#/}"
|
||||
echo "$relative"
|
||||
}
|
||||
|
||||
# Unpack a given archive
|
||||
#
|
||||
# $1: archive file path
|
||||
# $2: optional target directory (current one if omitted)
|
||||
#
|
||||
unpack_archive ()
|
||||
{
|
||||
local ARCHIVE="$1"
|
||||
local DIR=${2-.}
|
||||
local RESULT TARFLAGS ZIPFLAGS
|
||||
mkdir -p "$DIR"
|
||||
if [ "$VERBOSE2" = "yes" ] ; then
|
||||
TARFLAGS="vxpf"
|
||||
ZIPFLAGS=""
|
||||
else
|
||||
TARFLAGS="xpf"
|
||||
ZIPFLAGS="q"
|
||||
fi
|
||||
case "$ARCHIVE" in
|
||||
*.zip)
|
||||
(cd $DIR && run unzip $ZIPFLAGS "$ARCHIVE")
|
||||
;;
|
||||
*.tar)
|
||||
run tar $TARFLAGS "$ARCHIVE" -C $DIR
|
||||
;;
|
||||
*.tar.gz)
|
||||
run tar z$TARFLAGS "$ARCHIVE" -C $DIR
|
||||
;;
|
||||
*.tar.bz2)
|
||||
find_pbzip2
|
||||
if [ -n "$PBZIP2" ] ; then
|
||||
run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" -C $DIR
|
||||
else
|
||||
run tar j$TARFLAGS "$ARCHIVE" -C $DIR
|
||||
fi
|
||||
# remove ._* files by MacOSX to preserve resource forks we don't need
|
||||
find $DIR -name "\._*" -exec rm {} \;
|
||||
;;
|
||||
*)
|
||||
panic "Cannot unpack archive with unknown extension: $ARCHIVE"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Pack a given archive
|
||||
#
|
||||
# $1: archive file path (including extension)
|
||||
# $2: source directory for archive content
|
||||
# $3+: list of files (including patterns), all if empty
|
||||
pack_archive ()
|
||||
{
|
||||
local ARCHIVE="$1"
|
||||
local SRCDIR="$2"
|
||||
local SRCFILES
|
||||
local TARFLAGS ZIPFLAGS
|
||||
shift; shift;
|
||||
if [ -z "$1" ] ; then
|
||||
SRCFILES="*"
|
||||
else
|
||||
SRCFILES="$@"
|
||||
fi
|
||||
if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then
|
||||
ARCHIVE="`pwd`/$ARCHIVE"
|
||||
fi
|
||||
mkdir -p `dirname $ARCHIVE`
|
||||
if [ "$VERBOSE2" = "yes" ] ; then
|
||||
TARFLAGS="vcf"
|
||||
ZIPFLAGS="-9r"
|
||||
else
|
||||
TARFLAGS="cf"
|
||||
ZIPFLAGS="-9qr"
|
||||
fi
|
||||
# Ensure symlinks are stored as is in zip files. for toolchains
|
||||
# this can save up to 7 MB in the size of the final archive
|
||||
#ZIPFLAGS="$ZIPFLAGS --symlinks"
|
||||
case "$ARCHIVE" in
|
||||
*.zip)
|
||||
(cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES)
|
||||
;;
|
||||
*.tar)
|
||||
(cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES)
|
||||
;;
|
||||
*.tar.gz)
|
||||
(cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES)
|
||||
;;
|
||||
*.tar.bz2)
|
||||
find_pbzip2
|
||||
if [ -n "$PBZIP2" ] ; then
|
||||
(cd $SRCDIR && run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" $SRCFILES)
|
||||
else
|
||||
(cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES)
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
panic "Unsupported archive format: $ARCHIVE"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Copy a directory, create target location if needed
|
||||
#
|
||||
# $1: source directory
|
||||
# $2: target directory location
|
||||
#
|
||||
copy_directory ()
|
||||
{
|
||||
local SRCDIR="$1"
|
||||
local DSTDIR="$2"
|
||||
if [ ! -d "$SRCDIR" ] ; then
|
||||
panic "Can't copy from non-directory: $SRCDIR"
|
||||
fi
|
||||
log "Copying directory: "
|
||||
log " from $SRCDIR"
|
||||
log " to $DSTDIR"
|
||||
mkdir -p "$DSTDIR" && (cd "$SRCDIR" && 2>/dev/null tar cf - *) | (tar xf - -C "$DSTDIR")
|
||||
fail_panic "Cannot copy to directory: $DSTDIR"
|
||||
}
|
||||
|
||||
# Move a directory, create target location if needed
|
||||
#
|
||||
# $1: source directory
|
||||
# $2: target directory location
|
||||
#
|
||||
move_directory ()
|
||||
{
|
||||
local SRCDIR="$1"
|
||||
local DSTDIR="$2"
|
||||
if [ ! -d "$SRCDIR" ] ; then
|
||||
panic "Can't move from non-directory: $SRCDIR"
|
||||
fi
|
||||
log "Move directory: "
|
||||
log " from $SRCDIR"
|
||||
log " to $DSTDIR"
|
||||
mkdir -p "$DSTDIR" && (mv "$SRCDIR"/* "$DSTDIR")
|
||||
fail_panic "Cannot move to directory: $DSTDIR"
|
||||
}
|
||||
|
||||
# This is the same than copy_directory(), but symlinks will be replaced
|
||||
# by the file they actually point to instead.
|
||||
copy_directory_nolinks ()
|
||||
{
|
||||
local SRCDIR="$1"
|
||||
local DSTDIR="$2"
|
||||
if [ ! -d "$SRCDIR" ] ; then
|
||||
panic "Can't copy from non-directory: $SRCDIR"
|
||||
fi
|
||||
log "Copying directory (without symlinks): "
|
||||
log " from $SRCDIR"
|
||||
log " to $DSTDIR"
|
||||
mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar chf - *) | (tar xf - -C "$DSTDIR")
|
||||
fail_panic "Cannot copy to directory: $DSTDIR"
|
||||
}
|
||||
|
||||
# Copy certain files from one directory to another one
|
||||
# $1: source directory
|
||||
# $2: target directory
|
||||
# $3+: file list (including patterns)
|
||||
copy_file_list ()
|
||||
{
|
||||
local SRCDIR="$1"
|
||||
local DSTDIR="$2"
|
||||
shift; shift;
|
||||
if [ ! -d "$SRCDIR" ] ; then
|
||||
panic "Cant' copy from non-directory: $SRCDIR"
|
||||
fi
|
||||
log "Copying file: $@"
|
||||
log " from $SRCDIR"
|
||||
log " to $DSTDIR"
|
||||
mkdir -p "$DSTDIR" && (cd "$SRCDIR" && (echo $@ | tr ' ' '\n' | tar cf - -T -)) | (tar xf - -C "$DSTDIR")
|
||||
fail_panic "Cannot copy files to directory: $DSTDIR"
|
||||
}
|
||||
|
||||
# Rotate a log file
|
||||
# If the given log file exist, add a -1 to the end of the file.
|
||||
# If older log files exist, rename them to -<n+1>
|
||||
# $1: log file
|
||||
# $2: maximum version to retain [optional]
|
||||
rotate_log ()
|
||||
{
|
||||
# Default Maximum versions to retain
|
||||
local MAXVER="5"
|
||||
local LOGFILE="$1"
|
||||
shift;
|
||||
if [ ! -z "$1" ] ; then
|
||||
local tmpmax="$1"
|
||||
shift;
|
||||
tmpmax=`expr $tmpmax + 0`
|
||||
if [ $tmpmax -lt 1 ] ; then
|
||||
panic "Invalid maximum log file versions '$tmpmax' invalid; defaulting to $MAXVER"
|
||||
else
|
||||
MAXVER=$tmpmax;
|
||||
fi
|
||||
fi
|
||||
|
||||
# Do Nothing if the log file does not exist
|
||||
if [ ! -f "${LOGFILE}" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Rename existing older versions
|
||||
ver=$MAXVER
|
||||
while [ $ver -ge 1 ]
|
||||
do
|
||||
local prev=$(( $ver - 1 ))
|
||||
local old="-$prev"
|
||||
|
||||
# Instead of old version 0; use the original filename
|
||||
if [ $ver -eq 1 ] ; then
|
||||
old=""
|
||||
fi
|
||||
|
||||
if [ -f "${LOGFILE}${old}" ] ; then
|
||||
mv -f "${LOGFILE}${old}" "${LOGFILE}-${ver}"
|
||||
fi
|
||||
|
||||
ver=$prev
|
||||
done
|
||||
}
|
||||
|
||||
# Dereference symlink
|
||||
# $1+: directories
|
||||
dereference_symlink ()
|
||||
{
|
||||
local DIRECTORY SYMLINKS DIR FILE LINK
|
||||
for DIRECTORY in "$@"; do
|
||||
if [ -d "$DIRECTORY" ]; then
|
||||
while true; do
|
||||
# Find all symlinks in this directory.
|
||||
SYMLINKS=`find $DIRECTORY -type l`
|
||||
if [ -z "$SYMLINKS" ]; then
|
||||
break;
|
||||
fi
|
||||
# Iterate symlinks
|
||||
for SYMLINK in $SYMLINKS; do
|
||||
if [ -L "$SYMLINK" ]; then
|
||||
DIR=`dirname "$SYMLINK"`
|
||||
FILE=`basename "$SYMLINK"`
|
||||
# Note that if `readlink $FILE` is also a link, we want to deal
|
||||
# with it in the next iteration. There is potential infinite-loop
|
||||
# situation for cicular link doesn't exist in our case, though.
|
||||
(cd "$DIR" && \
|
||||
LINK=`readlink "$FILE"` && \
|
||||
test ! -L "$LINK" && \
|
||||
rm -f "$FILE" && \
|
||||
cp -a "$LINK" "$FILE")
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
1675
Android/toolchain_edits/build/tools/prebuilt-common.sh
Normal file
@@ -677,7 +677,7 @@ log "Found data directory: '$DATA_DIR'"
|
||||
# is not there, push 'gdbserver' found in prebuilt.
|
||||
#
|
||||
DEVICE_GDBSERVER=$DATA_DIR/lib/gdbserver
|
||||
adb_var_shell2 GDBSERVER_RESULT ls $DEVICE_GDBSERVER
|
||||
adb_var_shell2 GDBSERVER_RESULT run-as $PACKAGE_NAME ls $DEVICE_GDBSERVER
|
||||
if [ $? != 0 ]; then
|
||||
|
||||
# Figure out what's the target-arch and find gdbserver in prebuilt.
|
||||
|
||||
249
Android/toolchain_edits/valgrind-android.supp
Normal file
@@ -0,0 +1,249 @@
|
||||
|
||||
##----------------------------------------------------------------------##
|
||||
|
||||
# Format of this file is:
|
||||
# {
|
||||
# name_of_suppression
|
||||
# tool_name:supp_kind
|
||||
# (optional extra info for some suppression types)
|
||||
# caller0 name, or /name/of/so/file.so
|
||||
# caller1 name, or ditto
|
||||
# (optionally: caller2 name)
|
||||
# (optionally: caller3 name)
|
||||
# }
|
||||
#
|
||||
# For Memcheck, the supp_kinds are:
|
||||
#
|
||||
# Param Value1 Value2 Value4 Value8 Value16 Jump
|
||||
# Free Addr1 Addr2 Addr4 Addr8 Addr16
|
||||
# Cond (previously known as Value0)
|
||||
#
|
||||
# and the optional extra info is:
|
||||
# if Param: name of system call param
|
||||
|
||||
##----------------------------------------------------------------------##
|
||||
|
||||
|
||||
# zlib-1.2.x uses uninitialised memory in some tricky way which
|
||||
# apparently is harmless (it must amount to a vectorised while-loop,
|
||||
# nothing else makes sense). Fools Memcheck though. See the mentioned
|
||||
# URL for details.
|
||||
{
|
||||
zlib-1.2.x trickyness (1a): See http://www.zlib.net/zlib_faq.html#faq36
|
||||
Memcheck:Cond
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
...
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
fun:deflate
|
||||
}
|
||||
|
||||
{
|
||||
zlib-1.2.x trickyness (1b): See http://www.zlib.net/zlib_faq.html#faq36
|
||||
Memcheck:Cond
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
fun:deflate
|
||||
}
|
||||
|
||||
{
|
||||
zlib-1.2.x trickyness (2a): See http://www.zlib.net/zlib_faq.html#faq36
|
||||
Memcheck:Value8
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
...
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
fun:deflate
|
||||
}
|
||||
|
||||
{
|
||||
zlib-1.2.x trickyness (2b): See http://www.zlib.net/zlib_faq.html#faq36
|
||||
Memcheck:Value8
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
fun:deflate
|
||||
}
|
||||
|
||||
{
|
||||
zlib-1.2.x trickyness (3a): See http://www.zlib.net/zlib_faq.html#faq36
|
||||
Memcheck:Value4
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
...
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
fun:deflate
|
||||
}
|
||||
|
||||
{
|
||||
zlib-1.2.x trickyness (3b): See http://www.zlib.net/zlib_faq.html#faq36
|
||||
Memcheck:Value4
|
||||
obj:/*lib*/libz.so.1.2.*
|
||||
fun:deflate
|
||||
}
|
||||
|
||||
##----------------------------------------------------------------------##
|
||||
|
||||
# Suppressions for Android's libc (bionic) and probably other
|
||||
# stuff too.
|
||||
|
||||
# this is a real bug in the Android stack -- this routine really does read and write below sp.
|
||||
{
|
||||
sha1_block_data_order-reads-below-sp
|
||||
Memcheck:Addr4
|
||||
fun:sha1_block_data_order
|
||||
}
|
||||
|
||||
# This is a false error, and it's reported in the wrong place. Memcheck misinterprets
|
||||
# a restore path in dvmPlatformInvoke: "ldmdb r4, {r4, r5, r6, r7, r8, r9, sp, pc}"
|
||||
# because it breaks this up into non-atomic IR. This non atomic IR restores PC
|
||||
# first, then SP, and then r4-r9; the latter of which happen after (from Memcheck's
|
||||
# point of view) the assignment to SP, hence constitute a read below SP (depends
|
||||
# which way SP moved, I guess). Worse, because these happen after the restore to SP,
|
||||
# the errors are reported in the callers of this function, not here :-(
|
||||
# General bogusness all round, but I don't see how to handle it any better. Hence
|
||||
# hide all the callers; fortunately there appear to be not many.
|
||||
#
|
||||
{
|
||||
dvmPlatformInvoke-misinterpretation-1
|
||||
Memcheck:Addr4
|
||||
fun:dvmCallJNIMethod_virtualNoRef
|
||||
}
|
||||
|
||||
{
|
||||
dvmPlatformInvoke-misinterpretation-2
|
||||
Memcheck:Addr4
|
||||
fun:dvmCallJNIMethod_staticNoRef
|
||||
}
|
||||
|
||||
{
|
||||
dvmPlatformInvoke-misinterpretation-3
|
||||
Memcheck:Addr4
|
||||
fun:dvmCallJNIMethod_general
|
||||
}
|
||||
|
||||
##----------------------------------------------------------------------##
|
||||
# ASC ADDED ...
|
||||
|
||||
{
|
||||
Linker-1
|
||||
Memcheck:Cond
|
||||
obj:/system/bin/linker
|
||||
}
|
||||
|
||||
{
|
||||
Linker-2
|
||||
Memcheck:Value4
|
||||
obj:/system/bin/linker
|
||||
}
|
||||
|
||||
{
|
||||
Linker-3
|
||||
Memcheck:Free
|
||||
obj:/system/bin/linker
|
||||
}
|
||||
|
||||
{
|
||||
Linker-4
|
||||
Memcheck:Leak
|
||||
obj:/system/bin/linker
|
||||
}
|
||||
|
||||
# ...
|
||||
|
||||
{
|
||||
BootOAT-1
|
||||
Memcheck:Cond
|
||||
obj:/data/dalvik-cache/arm/system@framework@boot.oat
|
||||
}
|
||||
|
||||
{
|
||||
BootOAT-2
|
||||
Memcheck:Addr4
|
||||
obj:/data/dalvik-cache/arm/system@framework@boot.oat
|
||||
}
|
||||
|
||||
{
|
||||
BootOAT-3
|
||||
Memcheck:Free
|
||||
obj:/data/dalvik-cache/arm/system@framework@boot.oat
|
||||
}
|
||||
|
||||
{
|
||||
BootOAT-4
|
||||
Memcheck:Leak
|
||||
obj:/data/dalvik-cache/arm/system@framework@boot.oat
|
||||
}
|
||||
|
||||
# ...
|
||||
|
||||
{
|
||||
LibJavaCore-1
|
||||
Memcheck:Cond
|
||||
obj:/system/lib/libjavacore.so
|
||||
}
|
||||
|
||||
{
|
||||
LibJavaCore-2
|
||||
Memcheck:Addr4
|
||||
obj:/system/lib/libjavacore.so
|
||||
}
|
||||
|
||||
{
|
||||
LibJavaCore-3
|
||||
Memcheck:Free
|
||||
obj:/system/lib/libjavacore.so
|
||||
}
|
||||
|
||||
{
|
||||
LibJavaCore-4
|
||||
Memcheck:Leak
|
||||
obj:/system/lib/libjavacore.so
|
||||
}
|
||||
|
||||
# ...
|
||||
|
||||
{
|
||||
APP2-SPECIFIC-1
|
||||
Memcheck:Cond
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic-2@base.apk@classes.dex
|
||||
}
|
||||
|
||||
{
|
||||
APP2-SPECIFIC-2
|
||||
Memcheck:Addr4
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic-2@base.apk@classes.dex
|
||||
}
|
||||
|
||||
{
|
||||
APP2-SPECIFIC-3
|
||||
Memcheck:Free
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic-2@base.apk@classes.dex
|
||||
}
|
||||
|
||||
{
|
||||
APP2-SPECIFIC-4
|
||||
Memcheck:Leak
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic-2@base.apk@classes.dex
|
||||
}
|
||||
|
||||
# ...
|
||||
|
||||
{
|
||||
APP-SPECIFIC-1
|
||||
Memcheck:Cond
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic@base.apk@classes.dex
|
||||
}
|
||||
|
||||
{
|
||||
APP-SPECIFIC-2
|
||||
Memcheck:Addr4
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic@base.apk@classes.dex
|
||||
}
|
||||
|
||||
{
|
||||
APP-SPECIFIC-3
|
||||
Memcheck:Free
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic@base.apk@classes.dex
|
||||
}
|
||||
|
||||
{
|
||||
APP-SPECIFIC-4
|
||||
Memcheck:Leak
|
||||
obj:/data/dalvik-cache/arm/data@app@org.deadc0de.apple2ix.basic@base.apk@classes.dex
|
||||
}
|
||||
|
||||
17
Apple2Mac/Apple2Mac-Prefix.pch
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Prefix header
|
||||
//
|
||||
// The contents of this file are implicitly included at the beginning of every source file.
|
||||
//
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
# ifdef __OBJC__
|
||||
# import <UIKit/UIKit.h>
|
||||
# endif
|
||||
#else
|
||||
# ifdef __OBJC__
|
||||
# import <Cocoa/Cocoa.h>
|
||||
# endif
|
||||
#endif
|
||||
@@ -6,10 +6,14 @@
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleHelpBookFolder</key>
|
||||
<string>Apple2Mac.help</string>
|
||||
<key>CFBundleHelpBookName</key>
|
||||
<string>org.deadc0de.Apple2Mac.help</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.deadc0de.Apple2Mac</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@@ -17,15 +21,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.1</string>
|
||||
<string>0.9.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CFBundleHelpBookFolder</key>
|
||||
<string>Apple2Mac.help</string>
|
||||
<key>CFBundleHelpBookName</key>
|
||||
<string>org.deadc0de.Apple2Mac.help</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.education</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
23
Apple2Mac/Apple2Mac/AppleViewController.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// AppleViewController.h
|
||||
// Apple2Mac
|
||||
//
|
||||
// Created by Jerome Vernet on 24/12/2015.
|
||||
// Copyright © 2015 deadc0de.org. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "iosPrefControllerViewController.h"
|
||||
|
||||
@interface AppleViewController : UIViewController
|
||||
@property (nonatomic, assign) BOOL paused;
|
||||
@property (assign) IBOutlet UIToolbar *mainToolBar;
|
||||
@property (assign) IBOutlet iosPrefControllerViewController *viewPrefs;
|
||||
|
||||
-(IBAction)rebootItemSelected:(id)sender;
|
||||
-(IBAction)prefsItemSelected:(id)sender;
|
||||
-(IBAction)toggleCPUSpeedItemSelected:(id)sender;
|
||||
-(IBAction)togglePauseItemSelected:(id)sender;
|
||||
-(IBAction)diskInsert:(id)sender;
|
||||
|
||||
@end
|
||||
124
Apple2Mac/Apple2Mac/AppleViewController.m
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// AppleViewController.m
|
||||
// Apple2Mac
|
||||
//
|
||||
// Created by Jerome Vernet on 24/12/2015.
|
||||
// Copyright © 2015 deadc0de.org. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppleViewController.h"
|
||||
#import "common.h"
|
||||
#import "modelUtil.h"
|
||||
|
||||
@interface AppleViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppleViewController
|
||||
|
||||
@synthesize paused = _paused;
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// [self mainToolBar ];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
cpu_pause();
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)unwindForSegue:(UIStoryboardSegue*)sender
|
||||
{
|
||||
cpu_resume();
|
||||
}
|
||||
- (IBAction)upSwipe:(id)sender
|
||||
{
|
||||
self.mainToolBar.hidden=NO;
|
||||
}
|
||||
|
||||
- (IBAction)diskInsert:(id)sender
|
||||
{
|
||||
NSLog(@"LISTING ALL FILES FOUND");
|
||||
|
||||
int Count;
|
||||
NSString *path;
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Disks"];
|
||||
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
|
||||
for (Count = 0; Count < (int)[directoryContent count]; Count++)
|
||||
{
|
||||
NSLog(@"File %d: %@", (Count + 1), [directoryContent objectAtIndex:Count]);
|
||||
}
|
||||
}
|
||||
|
||||
-(IBAction)rebootItemSelected:(id)sender{
|
||||
cpu65_reboot();
|
||||
}
|
||||
|
||||
-(IBAction)prefsItemSelected:(id)sender{
|
||||
cpu_pause();
|
||||
//[self.viewPrefs ];
|
||||
//pause
|
||||
//show pref windows
|
||||
cpu_resume();
|
||||
}
|
||||
|
||||
- (IBAction)toggleCPUSpeedItemSelected:(id)sender
|
||||
{
|
||||
cpu_pause();
|
||||
timing_toggleCPUSpeed();
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if (anim && anim->animation_showCPUSpeed)
|
||||
{
|
||||
anim->animation_showCPUSpeed();
|
||||
}
|
||||
cpu_resume();
|
||||
}
|
||||
|
||||
- (IBAction)togglePauseItemSelected:(id)sender
|
||||
{
|
||||
NSAssert(pthread_main_np(), @"Pause emulation called from non-main thread");
|
||||
self.paused = !_paused;
|
||||
}
|
||||
|
||||
- (void)setPaused:(BOOL)paused
|
||||
{
|
||||
if (_paused == paused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_paused = paused;
|
||||
if (paused)
|
||||
{
|
||||
cpu_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_resume();
|
||||
}
|
||||
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if (anim && anim->animation_showPaused)
|
||||
{
|
||||
anim->animation_showPaused();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1060" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6245"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="3zY-RA-n0f" id="Tyx-8E-lAx"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="3zY-RA-n0f" userLabel="App Delegate" customClass="CPUTestAppDelegate">
|
||||
<connections>
|
||||
<outlet property="window" destination="HyN-la-Rec" id="PzJ-8q-2Yu"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<menu title="AMainMenu" systemMenu="main" id="29">
|
||||
<items>
|
||||
<menuItem title="Apple2Mac" id="56">
|
||||
<menu key="submenu" title="Apple2Mac" systemMenu="apple" id="57">
|
||||
<items>
|
||||
<menuItem title="About Apple2Mac" id="58">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="236">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="129"/>
|
||||
<menuItem isSeparatorItem="YES" id="143">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Services" id="131">
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="130"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="144">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Apple2Mac" keyEquivalent="h" id="134">
|
||||
<connections>
|
||||
<action selector="hide:" target="-1" id="367"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="145">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="-1" id="368"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="150">
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="-1" id="370"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="149">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Quit Apple2Mac" keyEquivalent="q" id="136">
|
||||
<connections>
|
||||
<action selector="terminate:" target="-3" id="449"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="490">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="491">
|
||||
<items>
|
||||
<menuItem title="Apple2Mac Help" keyEquivalent="?" id="492" userLabel="Menu Item - Apple2Mac Help">
|
||||
<connections>
|
||||
<action selector="showHelp:" target="-1" id="493"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="HyN-la-Rec">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<view key="contentView" id="6V4-fW-Bkm">
|
||||
<rect key="frame" x="7" y="11" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1060" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8191"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@@ -23,27 +23,6 @@
|
||||
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Reboot Emulator" id="FjO-UG-hG2" userLabel="Menu Item - Reboot">
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
CA
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="reboot:" target="M8b-ga-iOS" id="AbH-Xq-1VZ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Disks" id="IU3-Bt-BuK" userLabel="Menu Item - Disks">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Disks" systemMenu="help" id="Wh3-tN-xkr">
|
||||
<items>
|
||||
<menuItem title="Insert..." keyEquivalent="D" id="Oj8-qO-A80" userLabel="Menu Item - Insert">
|
||||
<connections>
|
||||
<action selector="showDisksWindow:" target="M8b-ga-iOS" id="GVw-D1-gi0"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="236">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
@@ -52,21 +31,6 @@ CA
|
||||
<action selector="showPreferences:" target="M8b-ga-iOS" id="oDD-g4-QEJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle Full Screen" keyEquivalent="F" id="rP9-cs-9dM">
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="M8b-ga-iOS" id="Xan-eQ-CRM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle CPU Speed" keyEquivalent="S" id="b9q-zr-oNh">
|
||||
<connections>
|
||||
<action selector="toggleCPUSpeed:" target="M8b-ga-iOS" id="fA3-dJ-wtg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Pause Emulation" keyEquivalent="X" id="r9g-Ro-UwW">
|
||||
<connections>
|
||||
<action selector="togglePause:" target="M8b-ga-iOS" id="c65-mm-bIj"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="143">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
@@ -103,6 +67,299 @@ CA
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="4dZ-4f-42V">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="File" id="ma8-CB-dnr">
|
||||
<items>
|
||||
<menuItem title="Reboot Emulator" id="Xr5-Y9-tRL" userLabel="Menu Item - Reboot">
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
CA
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="reboot:" target="M8b-ga-iOS" id="XtR-At-SSS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle CPU Speed" keyEquivalent="S" id="pJl-yR-ULm">
|
||||
<connections>
|
||||
<action selector="toggleCPUSpeed:" target="M8b-ga-iOS" id="JUd-Uf-yyX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Pause Emulation" keyEquivalent="X" id="OKW-bt-a58">
|
||||
<connections>
|
||||
<action selector="togglePause:" target="M8b-ga-iOS" id="KLo-hL-5zu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Bp7-3g-GDj"/>
|
||||
<menuItem title="Disks" id="rp2-u6-d0B" userLabel="Menu Item - Disks">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Disks" systemMenu="help" id="8XK-7x-7hh">
|
||||
<items>
|
||||
<menuItem title="Insert..." keyEquivalent="D" id="JhN-ZL-f2O" userLabel="Menu Item - Insert">
|
||||
<connections>
|
||||
<action selector="showDisksWindow:" target="M8b-ga-iOS" id="EEd-WE-b9g"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Mec-fL-Gcp"/>
|
||||
<menuItem title="Page Setup…" enabled="NO" keyEquivalent="P" id="0HU-OV-39A">
|
||||
<connections>
|
||||
<action selector="runPageLayout:" target="-1" id="GVI-mL-WRX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Print…" enabled="NO" keyEquivalent="p" id="dXC-8t-bQ7">
|
||||
<connections>
|
||||
<action selector="print:" target="-1" id="MkR-UN-gGO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="ZKa-Nk-KCW">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Edit" id="WCv-04-9tQ">
|
||||
<items>
|
||||
<menuItem title="Undo" enabled="NO" keyEquivalent="z" id="7ji-O5-1oP">
|
||||
<connections>
|
||||
<action selector="undo:" target="-1" id="nTg-8e-qqX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" enabled="NO" keyEquivalent="Z" id="jYN-aO-Gse">
|
||||
<connections>
|
||||
<action selector="redo:" target="-1" id="3cC-fV-e1H"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="cRv-NN-CM3"/>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="B9f-O6-lco">
|
||||
<connections>
|
||||
<action selector="cut:" target="-1" id="cEF-Mr-gEI"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="BRV-TN-Pzv">
|
||||
<connections>
|
||||
<action selector="copy:" target="-1" id="xcu-og-fVt"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="geM-qO-aZ2">
|
||||
<connections>
|
||||
<action selector="paste:" target="-1" id="uDP-lX-2QO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste and Match Style" enabled="NO" keyEquivalent="V" id="gUM-x3-iEs">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteAsPlainText:" target="-1" id="62M-Kk-7W0"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="i2b-GO-OI0">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="-1" id="Ofc-Df-mrY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="l6c-o9-Lcb">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="-1" id="hfq-sH-Hrd"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gPI-YZ-Ej7"/>
|
||||
<menuItem title="Find" id="wpu-4I-0bh">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Find" id="Hm4-5s-n7i">
|
||||
<items>
|
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="xx4-kU-rZA">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="QjO-TQ-NTO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="Mzr-n7-gii">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="uJq-AO-zpb"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="EcB-rH-6Fn">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="7oO-Bh-siN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="cYe-Hg-XZ2">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="NLQ-EP-xeT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="VRT-xH-o4f">
|
||||
<connections>
|
||||
<action selector="centerSelectionInVisibleArea:" target="-1" id="hvL-8z-0XQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Spelling and Grammar" id="lBL-48-NL8">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Spelling" id="7rr-yF-apD">
|
||||
<items>
|
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="TxR-Iv-fxN">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="-1" id="Fi5-eF-xtd"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="1NC-db-BRz">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="-1" id="4Cb-VT-uRv"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="1VO-3p-hKr"/>
|
||||
<menuItem title="Check Spelling While Typing" id="R7T-Py-IUl">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="-1" id="fRX-Xn-i0s"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="A2e-bf-a76">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="-1" id="PYu-Cs-Nvn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Correct Spelling Automatically" id="Z8h-ou-V7a">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="keB-gX-m3T"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="jb7-2B-6xa">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Substitutions" id="iMe-LJ-g9B">
|
||||
<items>
|
||||
<menuItem title="Show Substitutions" id="Fa7-uJ-Naj">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="PoI-1s-Hjv"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="lQF-eK-0p9"/>
|
||||
<menuItem title="Smart Copy/Paste" id="KS0-Pe-biv">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="-1" id="Rrf-F9-auF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" id="uXJ-Bm-7aA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="pZw-O8-1Q6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Dashes" id="8KL-lT-U1f">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="EHC-04-hyV"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" id="hq9-VC-W6c">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="-1" id="3BN-Bo-i7K"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Data Detectors" id="qeO-vj-7ge">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDataDetection:" target="-1" id="fAF-LU-W4B"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Text Replacement" id="vGB-cx-gYU">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticTextReplacement:" target="-1" id="sQF-gF-l9g"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Transformations" id="898-0g-Oio">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Transformations" id="7Zl-6t-TqO">
|
||||
<items>
|
||||
<menuItem title="Make Upper Case" id="6C2-i8-KVq">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="uppercaseWord:" target="-1" id="pjO-OZ-Lwk"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Make Lower Case" id="ZZP-5z-YrA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowercaseWord:" target="-1" id="4ZN-4K-BgR"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Capitalize" id="MIg-Ae-S5l">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="capitalizeWord:" target="-1" id="wNF-kk-YaV"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="phA-NA-yWC">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Speech" id="voe-xv-aqn">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="zfA-gc-OcH">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="-1" id="kdt-Em-BHj"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="FHw-p7-luT">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="-1" id="cAo-hP-Ubn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="TP0-Ag-yPc">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="v0D-uE-mdE">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="m" id="dq0-ap-hiO">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="-1" id="wuW-Cq-NVB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="Kw3-wb-a0i">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="performZoom:" target="-1" id="Rab-bb-j9C"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle Full Screen" keyEquivalent="F" id="Lem-uE-El9">
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="M8b-ga-iOS" id="0fX-bE-3MN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="yFd-C5-chc"/>
|
||||
<menuItem title="Bring All to Front" id="Kwp-da-LVP">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="-1" id="iee-gu-gae"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="490">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="491">
|
||||
@@ -118,21 +375,50 @@ CA
|
||||
</items>
|
||||
</menu>
|
||||
<window title="Apple2Mac" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371" userLabel="Window - Apple2Mac" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" unifiedTitleAndToolbar="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="200" y="200" width="568" height="384"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<view key="contentView" id="372" customClass="EmulatorGLView">
|
||||
<rect key="frame" x="0.0" y="-1" width="568" height="384"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-315" y="-1328"/>
|
||||
<toolbar key="toolbar" implicitIdentifier="8323D01A-4ECF-4973-8DC6-3BB0A67F10FD" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="small" id="gXM-1s-f0F">
|
||||
<allowedToolbarItems>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarShowColorsItem" id="oed-am-Cfb"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" id="sk6-41-C3g"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="AoN-cv-QQ2"/>
|
||||
<toolbarItem implicitItemIdentifier="CBD2C3ED-B0AA-40F1-818F-B61B04F93E7F" label="Preferences" paletteLabel="Preferences" tag="-1" image="Prefs" id="85b-WO-tks"/>
|
||||
<toolbarItem implicitItemIdentifier="1AF00BE2-1806-4F36-AA9B-EDCD8587D441" label="Reboot" paletteLabel="Reboot" tag="-1" image="Reboot" id="hOg-ec-Okz"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="372-hX-Xt1"/>
|
||||
<toolbarItem implicitItemIdentifier="ED8F052E-C9AE-42F6-BA6D-2A675E8390E5" label="Disks" paletteLabel="Disks" tag="-1" image="Disks" id="jHk-qj-bmw"/>
|
||||
<toolbarItem implicitItemIdentifier="0E674D24-EE72-4444-A2D2-256161A8EEC6" label="CPU" paletteLabel="CPU" tag="-1" image="CPU" id="xjq-6u-Yc9" userLabel="CPU">
|
||||
<connections>
|
||||
<action selector="toggleCPUSpeed:" target="M8b-ga-iOS" id="FVD-QZ-joo"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="B1B89899-E7C4-4A6A-9B19-B29D3C7FB7CC" label="Pause" paletteLabel="Pause" tag="-1" image="Stop" id="hkP-Yj-QZG"/>
|
||||
<toolbarItem implicitItemIdentifier="3358D7A0-4F67-4503-ADD8-6E900BB291CC" label="Toolbar Item" paletteLabel="Toolbar Item" tag="-1" image="NSUser" id="JbN-Qp-xsc"/>
|
||||
<toolbarItem implicitItemIdentifier="E796EDE5-7BB6-4CBB-AC6B-17DA3FC696C9" label="FullScreen" paletteLabel="FullScreen" tag="-1" image="Fullscreen" id="Ahr-ZD-7wt"/>
|
||||
</allowedToolbarItems>
|
||||
<defaultToolbarItems>
|
||||
<toolbarItem reference="hOg-ec-Okz"/>
|
||||
<toolbarItem reference="hkP-Yj-QZG"/>
|
||||
<toolbarItem reference="Ahr-ZD-7wt"/>
|
||||
<toolbarItem reference="AoN-cv-QQ2"/>
|
||||
<toolbarItem reference="AoN-cv-QQ2"/>
|
||||
<toolbarItem reference="jHk-qj-bmw"/>
|
||||
<toolbarItem reference="372-hX-Xt1"/>
|
||||
<toolbarItem reference="sk6-41-C3g"/>
|
||||
<toolbarItem reference="85b-WO-tks"/>
|
||||
</defaultToolbarItems>
|
||||
</toolbar>
|
||||
<point key="canvasLocation" x="-201" y="-1220"/>
|
||||
</window>
|
||||
<customObject id="494" userLabel="EmulatorGLView" customClass="EmulatorGLView"/>
|
||||
<customObject id="M8b-ga-iOS" customClass="EmulatorWindowController" colorLabel="IBBuiltInLabel-Blue">
|
||||
<connections>
|
||||
<outlet property="disksWindow" destination="RAk-at-ZT4" id="64k-qW-zF5"/>
|
||||
<outlet property="pauseMenuItem" destination="r9g-Ro-UwW" id="4YW-pt-lai"/>
|
||||
<outlet property="prefsWindow" destination="Mzv-VG-jce" id="dQt-pf-qdi"/>
|
||||
<outlet property="view" destination="372" id="pRG-Kn-92X"/>
|
||||
<outlet property="window" destination="371" id="z3B-S9-PsV"/>
|
||||
@@ -238,7 +524,7 @@ CA
|
||||
<rect key="frame" x="20" y="153" width="212" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="cellSize" width="89" height="18"/>
|
||||
<size key="cellSize" width="88" height="18"/>
|
||||
<size key="intercellSpacing" width="4" height="2"/>
|
||||
<buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" inset="2" id="800-L1-WxW">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@@ -266,7 +552,7 @@ CA
|
||||
<rect key="frame" x="271" y="153" width="212" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="cellSize" width="89" height="18"/>
|
||||
<size key="cellSize" width="88" height="18"/>
|
||||
<size key="intercellSpacing" width="4" height="2"/>
|
||||
<buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" inset="2" id="uEc-fa-XXZ">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@@ -365,7 +651,7 @@ DQ
|
||||
<rect key="contentRect" x="109" y="132" width="580" height="360"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="778"/>
|
||||
<view key="contentView" id="bfK-7M-z1X">
|
||||
<rect key="frame" x="0.0" y="1" width="580" height="360"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="580" height="360"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<tabView id="xvZ-VK-VbM">
|
||||
@@ -729,5 +1015,15 @@ DQ
|
||||
<outlet property="window" destination="Mzv-VG-jce" id="86q-Ys-9Mt"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<toolbarItem implicitItemIdentifier="ED8F052E-C9AE-42F6-BA6D-2A675E8390E5" label="Disks" paletteLabel="Disks" tag="-1" image="Disks" id="iyV-hM-okT"/>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="CPU" width="32" height="32"/>
|
||||
<image name="Disks" width="32" height="32"/>
|
||||
<image name="Fullscreen" width="32" height="32"/>
|
||||
<image name="NSUser" width="32" height="32"/>
|
||||
<image name="Prefs" width="32" height="32"/>
|
||||
<image name="Reboot" width="32" height="32"/>
|
||||
<image name="Stop" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
23
Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cpu32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cpu64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cpu128.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu128.png
vendored
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu32.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu64.png
vendored
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
6
Apple2Mac/Apple2Mac/Images.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
23
Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy128.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy128.png
vendored
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy32.png
vendored
Normal file
|
After Width: | Height: | Size: 907 B |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy64.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
23
Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "fullscreen32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "fullscreen64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "fullscreen128.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen128.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen32.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen64.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
23
Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "pref32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "pref64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "pref128.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref128.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref32.png
vendored
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref64.png
vendored
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
21
Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "reboot32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||