First cut at audio settings menu

This commit is contained in:
Aaron Culliney 2015-07-24 22:39:46 -07:00
parent c2fdebd040
commit 37a8985f79
6 changed files with 387 additions and 6 deletions

View File

@ -0,0 +1,307 @@
/*
* Apple // emulator for *nix
*
* This software package is subject to the GNU General Public License
* version 2 or later (your choice) as published by the Free Software
* Foundation.
*
* THERE ARE NO WARRANTIES WHATSOEVER.
*
*/
package org.deadc0de.apple2ix;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
public class Apple2AudioSettingsMenu {
private final static String TAG = "Apple2AudioSettingsMenu";
private Apple2Activity mActivity = null;
private View mSettingsView = null;
public Apple2AudioSettingsMenu(Apple2Activity activity) {
mActivity = activity;
setup();
}
enum SETTINGS {
SPEAKER_ENABLED {
@Override public String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.speaker_enable);
}
@Override public String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.speaker_enable_summary);
}
@Override public View getView(final Apple2Activity activity, View convertView) {
convertView = _basicView(activity, this, convertView);
CheckBox cb = _addCheckbox(activity, this, convertView, true);
cb.setEnabled(false);
return convertView;
}
},
SPEAKER_VOLUME {
@Override public String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.speaker_volume);
}
@Override public String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.speaker_volume_summary);
}
@Override public View getView(final Apple2Activity activity, View convertView) {
LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.a2preference_slider, null, false);
TextView tv = (TextView)convertView.findViewById(R.id.a2preference_slider_summary);
tv.setText(getSummary(activity));
final TextView seekBarValue = (TextView)convertView.findViewById(R.id.a2preference_slider_seekBarValue);
SeekBar sb = (SeekBar)convertView.findViewById(R.id.a2preference_slider_seekBar);
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser) {
return;
}
seekBarValue.setText("" + progress);
Apple2Preferences.SPEAKER_VOLUME.saveVolume(activity, Apple2Preferences.Volume.values()[progress]);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
sb.setMax(0); // http://stackoverflow.com/questions/10278467/seekbar-not-setting-actual-progress-setprogress-not-working-on-early-android
sb.setMax(Apple2Preferences.Volume.MAX.ordinal() - 1);
int vol = Apple2Preferences.SPEAKER_VOLUME.intValue(activity);
sb.setProgress(vol);
seekBarValue.setText("" + vol);
return convertView;
}
},
MOCKINGBOARD_ENABLED {
@Override
public String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.mockingboard_enable);
}
@Override
public String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.mockingboard_enable_summary);
}
@Override
public View getView(final Apple2Activity activity, View convertView) {
convertView = _basicView(activity, this, convertView);
CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.MOCKINGBOARD_ENABLED.booleanValue(activity));
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.MOCKINGBOARD_ENABLED.saveBoolean(activity, isChecked);
}
});
return convertView;
}
},
MOCKINGBOARD_VOLUME {
@Override public String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.mockingboard_volume);
}
@Override public String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.mockingboard_volume_summary);
}
@Override public View getView(final Apple2Activity activity, View convertView) {
LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.a2preference_slider, null, false);
TextView tv = (TextView)convertView.findViewById(R.id.a2preference_slider_summary);
tv.setText(getSummary(activity));
final TextView seekBarValue = (TextView)convertView.findViewById(R.id.a2preference_slider_seekBarValue);
SeekBar sb = (SeekBar)convertView.findViewById(R.id.a2preference_slider_seekBar);
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser) {
return;
}
seekBarValue.setText("" + progress);
Apple2Preferences.MOCKINGBOARD_VOLUME.saveVolume(activity, Apple2Preferences.Volume.values()[progress]);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
sb.setMax(0); // http://stackoverflow.com/questions/10278467/seekbar-not-setting-actual-progress-setprogress-not-working-on-early-android
sb.setMax(Apple2Preferences.Volume.MAX.ordinal() - 1);
int vol = Apple2Preferences.MOCKINGBOARD_VOLUME.intValue(activity);
sb.setProgress(vol);
seekBarValue.setText("" + vol);
return convertView;
}
};
private static View _basicView(Apple2Activity activity, SETTINGS setting, View convertView) {
TextView tv = (TextView)convertView.findViewById(R.id.a2preference_title);
tv.setText(setting.getTitle(activity));
tv = (TextView)convertView.findViewById(R.id.a2preference_summary);
tv.setText(setting.getSummary(activity));
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.a2preference_widget_frame);
if (layout.getChildCount() > 0) {
// layout cells appear to be reused when scrolling into view ... make sure we start with clear hierarchy
layout.removeAllViews();
}
return convertView;
}
private static ImageView _addPopupIcon(Apple2Activity activity, SETTINGS setting, View convertView) {
ImageView imageView = new ImageView(activity);
Drawable drawable = activity.getResources().getDrawable(android.R.drawable.ic_menu_edit);
imageView.setImageDrawable(drawable);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.a2preference_widget_frame);
layout.addView(imageView);
return imageView;
}
private static CheckBox _addCheckbox(Apple2Activity activity, SETTINGS setting, View convertView, boolean isChecked) {
CheckBox checkBox = new CheckBox(activity);
checkBox.setChecked(isChecked);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.a2preference_widget_frame);
layout.addView(checkBox);
return checkBox;
}
public static final int size = SETTINGS.values().length;
public abstract String getTitle(Apple2Activity activity);
public abstract String getSummary(Apple2Activity activity);
public void handleSelection(Apple2AudioSettingsMenu settingsMenu, boolean isChecked) {
/* ... */
}
public View getView(Apple2Activity activity, View convertView) {
return _basicView(activity, this, convertView);
}
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;
}
}
private void setup() {
LayoutInflater inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mSettingsView = inflater.inflate(R.layout.activity_settings, null, false);
TextView title = (TextView)mSettingsView.findViewById(R.id.header_settings);
title.setText(R.string.settings_audio);
ListView settingsList = (ListView)mSettingsView.findViewById(R.id.listView_settings);
settingsList.setEnabled(true);
// This is a bit of a hack ... we're not using the ArrayAdapter as intended here, simply piggy-backing off its call to getView() to supply a completely custom view. The arguably better way would be to create a custom Apple2SettingsAdapter or something akin to that...
ArrayAdapter<?> adapter = new ArrayAdapter<String>(mActivity, R.layout.a2preference, R.id.a2preference_title, SETTINGS.titles(mActivity)) {
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
if (position < 0 || position >= SETTINGS.size) {
throw new ArrayIndexOutOfBoundsException();
}
return position == SETTINGS.MOCKINGBOARD_ENABLED.ordinal();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//View view = super.getView(position, convertView, parent);
// ^^^ WHOA ... this is catching an NPE deep in AOSP code on the second time loading the audio menu, WTF?
// Methinks it is related to the hack of loading a completely different R.layout.something for certain views...
View view = convertView != null ? convertView : super.getView(position, null, parent);
SETTINGS setting = SETTINGS.values()[position];
return setting.getView(mActivity, view);
}
};
settingsList.setAdapter(adapter);
settingsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SETTINGS setting = SETTINGS.values()[position];
LinearLayout layout = (LinearLayout) view.findViewById(R.id.a2preference_widget_frame);
if (layout == null) {
return;
}
View childView = layout.getChildAt(0);
boolean selected = false;
if (childView != null && childView instanceof CheckBox) {
CheckBox checkBox = (CheckBox) childView;
checkBox.setChecked(!checkBox.isChecked());
selected = checkBox.isChecked();
}
setting.handleSelection(Apple2AudioSettingsMenu.this, selected);
}
});
}
public void show() {
if (isShowing()) {
return;
}
mActivity.nativeOnPause();
mActivity.addContentView(mSettingsView, new FrameLayout.LayoutParams(mActivity.getWidth(), mActivity.getHeight()));
}
public void dismiss() {
if (isShowing()) {
dismissWithoutResume();
//mActivity.nativeOnResume(/*isSystemResume:*/false);
}
}
public void dismissWithoutResume() {
if (isShowing()) {
((ViewGroup)mSettingsView.getParent()).removeView(mSettingsView);
}
}
public boolean isShowing() {
return mSettingsView.isShown();
}
}

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/preference_margin_left"
android:layout_marginStart="@dimen/preference_margin_left"
android:layout_marginRight="@dimen/preference_margin_right"
android:layout_marginEnd="@dimen/preference_margin_right"
android:layout_marginTop="@dimen/preference_margin_top"
android:layout_marginBottom="@dimen/preference_margin_bottom"
android:layout_weight="1">
<TextView android:id="@+id/a2preference_slider_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Lorem ipsum dolor sit amet"
android:maxLines="4" />
<LinearLayout android:id="@+id/a2preference_slider_widgets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/a2preference_slider_summary"
android:layout_alignLeft="@id/a2preference_slider_summary"
android:layout_alignStart="@id/a2preference_slider_summary"
android:gravity="center_vertical"
android:orientation="horizontal"
android:descendantFocusability="blocksDescendants">
<SeekBar
android:id="@+id/a2preference_slider_seekBar"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/a2preference_slider_seekBarValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/preference_margin"
android:layout_marginStart="@dimen/preference_margin"
android:gravity="center"
android:text="0" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -28,7 +28,7 @@
<RadioButton
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/diskB"
android:id="@+id/radioButton_diskB" />

View File

@ -2,4 +2,9 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="preference_margin">6dp</dimen>
<dimen name="preference_margin_left">15dp</dimen>
<dimen name="preference_margin_right">6dp</dimen>
<dimen name="preference_margin_top">6dp</dimen>
<dimen name="preference_margin_bottom">6dp</dimen>
</resources>

View File

@ -4,15 +4,16 @@
<color name="black">#000000</color>
<color name="white">#ffffff</color>
<string name="action_settings">Settings</string>
<string name="app_name">Apple2ix</string>
<string name="audio_enabled">Enable audio</string>
<string name="audio_enabled_summary">(Unimplemented … but hopefully coming soon!)</string>
<string name="audio_configure">Configure audio…</string>
<string name="audio_configure_summary">Volume, mockingboard, etc</string>
<string name="cancel">Cancel</string>
<string name="color_bw">Black/white</string>
<string name="color_color">Color</string>
<string name="color_interpolated">Interpolated color</string>
<string name="configure_joystick">Configure emulated joysticks…</string>
<string name="configure_joystick_summary">TouchJoy axis and buttons, hitboxes, etc</string>
<string name="configure_joystick_summary">Touch/tilt, axis and buttons, etc</string>
<string name="configure_video">Configure video…</string>
<string name="configure_video_summary">Color settings</string>
<string name="diskA">Drive 1</string>
@ -35,26 +36,35 @@
<string name="menu_settings_summary">General, CPU, Joystick</string>
<string name="mockingboard_disabled_title">Mockingboard disabled</string>
<string name="mockingboard_disabled_mesg">Mockingboard could not be enabled</string>
<string name="mockingboard_enable">Enable Mockingboard</string>
<string name="mockingboard_enable_summary">Revision C in Slot 4/5</string>
<string name="mockingboard_volume">Mockingboard volume</string>
<string name="mockingboard_volume_summary">Set the Mockingboard(s) volume</string>
<string name="no">No</string>
<string name="ok">OK</string>
<string name="quit">Quit emulator…</string>
<string name="quit_summary"></string>
<string name="quit_really">Quit emulator?</string>
<string name="quit_warning">You will lose unsaved progress</string>
<string name="reboot">Reboot emulator…</string>
<string name="reboot_really">Reboot emulator?</string>
<string name="reboot_warning">You will lose unsaved progress</string>
<string name="reboot_summary"></string>
<string name="reboot_warning">You will lose unsaved progress</string>
<string name="spacer"></string>
<string name="speaker_disabled_title">Speaker disabled</string>
<string name="speaker_disabled_mesg">Speaker could not be enabled</string>
<string name="speaker_enable">Enable Speaker</string>
<string name="speaker_enable_summary">(Speaker cannot be disabled)</string>
<string name="speaker_volume">Speaker volume</string>
<string name="speaker_volume_summary">Set the speaker volume</string>
<string name="speed_alt">Alternate CPU Speed</string>
<string name="speed_cpu">CPU Speed</string>
<string name="speed_swipe">Swipe changes emulation speed</string>
<string name="speed_swipe_summary">Left/right swiping decreases/increases emulation speed</string>
<string name="settings">Apple2ix emulator settings</string>
<string name="settings_audio">Apple2ix audio settings</string>
<string name="tab_general">General</string>
<string name="tab_joystick">Joystick</string>
<string name="title_activity_second">SecondActivity</string>
<string name="action_settings">Settings</string>
</resources>

View File

@ -41,6 +41,8 @@ jboolean Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetSpeakerEnabled(JN
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetSpeakerVolume(JNIEnv *env, jclass cls, jint goesToTen) {
LOG("native set speaker volume : %d", goesToTen);
assert(goesToTen >= 0);
sound_volume = goesToTen;
#warning FIXME TODO refactor/remove sound_volume ?
speaker_setVolumeZeroToTen(goesToTen);
}
@ -52,6 +54,7 @@ jboolean Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetMockingboardEnabl
if (enabled) {
MB_Initialize();
}
return MB_ISEnabled();
}
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetMockingboardVolume(JNIEnv *env, jclass cls, jint goesToTen) {