Skip to content

Commit c90d0d2

Browse files
committed
[VrKeyboardActivity] Add a hacky in-app keyboard that won't crash
1 parent 5fec9c3 commit c90d0d2

File tree

12 files changed

+865
-162
lines changed

12 files changed

+865
-162
lines changed

src/android/app/src/main/AndroidManifest.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,22 @@
126126
</activity>
127127

128128

129+
<activity
130+
android:name="org.citra.citra_emu.vr.VrKeyboardActivity"
131+
android:exported="true"
132+
android:process=":vr_process"
133+
android:windowSoftInputMode="stateVisible|adjustResize"
134+
android:resizeableActivity="false"
135+
android:screenOrientation="landscape">
136+
137+
<!-- This intentfilter marks this Activity as the one that gets launched from Home screen. -->
138+
<intent-filter>
139+
<action android:name="android.intent.action.MAIN" />
140+
<category android:name="com.oculus.intent.category.2D" />
141+
</intent-filter>
142+
</activity>
143+
144+
129145
<service android:name="org.citra.citra_emu.utils.ForegroundService" />
130146

131147
<activity

src/android/app/src/main/java/org/citra/citra_emu/applets/SoftwareKeyboard.java

Lines changed: 105 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,34 @@
77
import android.app.Activity;
88
import android.app.Dialog;
99
import android.content.DialogInterface;
10+
import android.content.Intent;
1011
import android.os.Bundle;
1112
import android.text.InputFilter;
1213
import android.text.Spanned;
1314
import android.view.ViewGroup;
1415
import android.widget.EditText;
1516
import android.widget.FrameLayout;
16-
1717
import androidx.annotation.NonNull;
1818
import androidx.annotation.Nullable;
1919
import androidx.appcompat.app.AlertDialog;
2020
import androidx.fragment.app.DialogFragment;
21-
2221
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
23-
22+
import java.util.Objects;
2423
import org.citra.citra_emu.CitraApplication;
2524
import org.citra.citra_emu.NativeLibrary;
2625
import org.citra.citra_emu.R;
2726
import org.citra.citra_emu.activities.EmulationActivity;
2827
import org.citra.citra_emu.utils.Log;
28+
import org.citra.citra_emu.vr.VrActivity;
29+
import org.citra.citra_emu.vr.VrKeyboardActivity;
2930

30-
import java.util.Objects;
3131

32+
// Warning (amwatson): I had to tear through this pretty quickly because I didn't realize
33+
// there was a system keyboard. This is a pretty hack solution that will not
34+
// merge well.
3235
public final class SoftwareKeyboard {
3336
/// Corresponds to Frontend::ButtonConfig
34-
private interface ButtonConfig {
37+
public interface ButtonConfig {
3538
int Single = 0; /// Ok button
3639
int Dual = 1; /// Cancel | Ok buttons
3740
int Triple = 2; /// Cancel | I Forgot | Ok buttons
@@ -62,8 +65,7 @@ public static class KeyboardConfig implements java.io.Serializable {
6265
public int max_text_length;
6366
public boolean multiline_mode; /// True if the keyboard accepts multiple lines of input
6467
public String hint_text; /// Displayed in the field as a hint before
65-
@Nullable
66-
public String[] button_text; /// Contains the button text that the caller provides
68+
@Nullable public String[] button_text; /// Contains the button text that the caller provides
6769
}
6870

6971
/// Corresponds to Frontend::KeyboardData
@@ -77,13 +79,13 @@ private KeyboardData(int button, String text) {
7779
}
7880
}
7981

80-
private static class Filter implements InputFilter {
82+
public static class Filter implements InputFilter {
8183
@Override
8284
public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
8385
int dstart, int dend) {
8486
String text = new StringBuilder(dest)
85-
.replace(dstart, dend, source.subSequence(start, end).toString())
86-
.toString();
87+
.replace(dstart, dend, source.subSequence(start, end).toString())
88+
.toString();
8789
if (ValidateFilters(text) == ValidationError.None) {
8890
return null; // Accept replacement
8991
}
@@ -107,52 +109,52 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
107109
assert emulationActivity != null;
108110

109111
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
110-
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
112+
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
111113
params.leftMargin = params.rightMargin =
112-
CitraApplication.getAppContext().getResources().getDimensionPixelSize(
113-
R.dimen.dialog_margin);
114+
CitraApplication.getAppContext().getResources().getDimensionPixelSize(
115+
R.dimen.dialog_margin);
114116

115117
KeyboardConfig config = Objects.requireNonNull(
116-
(KeyboardConfig) Objects.requireNonNull(getArguments()).getSerializable("config"));
118+
(KeyboardConfig)Objects.requireNonNull(getArguments()).getSerializable("config"));
117119

118120
// Set up the input
119121
EditText editText = new EditText(CitraApplication.getAppContext());
120122
editText.setHint(config.hint_text);
121123
editText.setSingleLine(!config.multiline_mode);
122124
editText.setLayoutParams(params);
123-
editText.setFilters(new InputFilter[]{
124-
new Filter(), new InputFilter.LengthFilter(config.max_text_length)});
125+
editText.setFilters(new InputFilter[] {
126+
new Filter(), new InputFilter.LengthFilter(config.max_text_length)});
125127

126128
FrameLayout container = new FrameLayout(emulationActivity);
127129
container.addView(editText);
128130

129131
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
130-
.setTitle(R.string.software_keyboard)
131-
.setView(container);
132+
.setTitle(R.string.software_keyboard)
133+
.setView(container);
132134
setCancelable(false);
133135

134136
switch (config.button_config) {
135-
case ButtonConfig.Triple: {
136-
final String text = config.button_text[1].isEmpty()
137-
? emulationActivity.getString(R.string.i_forgot)
138-
: config.button_text[1];
139-
builder.setNeutralButton(text, null);
140-
}
141-
// fallthrough
142-
case ButtonConfig.Dual: {
143-
final String text = config.button_text[0].isEmpty()
144-
? emulationActivity.getString(android.R.string.cancel)
145-
: config.button_text[0];
146-
builder.setNegativeButton(text, null);
147-
}
148-
// fallthrough
149-
case ButtonConfig.Single: {
150-
final String text = config.button_text[2].isEmpty()
151-
? emulationActivity.getString(android.R.string.ok)
152-
: config.button_text[2];
153-
builder.setPositiveButton(text, null);
154-
break;
155-
}
137+
case ButtonConfig.Triple: {
138+
final String text = config.button_text[1].isEmpty()
139+
? emulationActivity.getString(R.string.i_forgot)
140+
: config.button_text[1];
141+
builder.setNeutralButton(text, null);
142+
}
143+
// fallthrough
144+
case ButtonConfig.Dual: {
145+
final String text = config.button_text[0].isEmpty()
146+
? emulationActivity.getString(android.R.string.cancel)
147+
: config.button_text[0];
148+
builder.setNegativeButton(text, null);
149+
}
150+
// fallthrough
151+
case ButtonConfig.Single: {
152+
final String text = config.button_text[2].isEmpty()
153+
? emulationActivity.getString(android.R.string.ok)
154+
: config.button_text[2];
155+
builder.setPositiveButton(text, null);
156+
break;
157+
}
156158
}
157159

158160
final AlertDialog dialog = builder.create();
@@ -209,31 +211,65 @@ private static void ExecuteImpl(KeyboardConfig config) {
209211
fragment.show(emulationActivity.getSupportFragmentManager(), "keyboard");
210212
}
211213

212-
private static void HandleValidationError(KeyboardConfig config, ValidationError error) {
214+
public static void HandleValidationError(KeyboardConfig config, ValidationError error) {
213215
final EmulationActivity emulationActivity = NativeLibrary.sEmulationActivity.get();
214216
String message = "";
215217
switch (error) {
216-
case FixedLengthRequired:
217-
message =
218-
emulationActivity.getString(R.string.fixed_length_required, config.max_text_length);
219-
break;
220-
case MaxLengthExceeded:
221-
message =
222-
emulationActivity.getString(R.string.max_length_exceeded, config.max_text_length);
223-
break;
224-
case BlankInputNotAllowed:
225-
message = emulationActivity.getString(R.string.blank_input_not_allowed);
226-
break;
227-
case EmptyInputNotAllowed:
228-
message = emulationActivity.getString(R.string.empty_input_not_allowed);
229-
break;
218+
case FixedLengthRequired:
219+
message =
220+
emulationActivity.getString(R.string.fixed_length_required, config.max_text_length);
221+
break;
222+
case MaxLengthExceeded:
223+
message =
224+
emulationActivity.getString(R.string.max_length_exceeded, config.max_text_length);
225+
break;
226+
case BlankInputNotAllowed:
227+
message = emulationActivity.getString(R.string.blank_input_not_allowed);
228+
break;
229+
case EmptyInputNotAllowed:
230+
message = emulationActivity.getString(R.string.empty_input_not_allowed);
231+
break;
230232
}
231233

232-
new MaterialAlertDialogBuilder(emulationActivity)
233-
.setTitle(R.string.software_keyboard)
234-
.setMessage(message)
235-
.setPositiveButton(android.R.string.ok, null)
236-
.show();
234+
// TODO show error dialog
235+
Log.warning("Keyboard error: " + message);
236+
/* new MaterialAlertDialogBuilder(emulationActivity)
237+
.setTitle(R.string.software_keyboard)
238+
.setMessage(message)
239+
.setPositiveButton(android.R.string.ok, null)
240+
.show();*/
241+
}
242+
243+
public static void onFinishVrKeyboardPositive(final String text, final KeyboardConfig config) {
244+
data = new KeyboardData(0, "");
245+
data.button = config.button_config;
246+
data.text = text;
247+
final ValidationError error = ValidateInput(data.text);
248+
if (error != ValidationError.None) {
249+
HandleValidationError(config, error);
250+
final EmulationActivity emulationActivity = NativeLibrary.sEmulationActivity.get();
251+
onFinishVrKeyboardNegative();
252+
return;
253+
}
254+
synchronized (finishLock) {
255+
finishLock.notifyAll();
256+
}
257+
}
258+
259+
public static void onFinishVrKeyboardNeutral() {
260+
data = new KeyboardData(0, "");
261+
data.button = 1;
262+
synchronized (finishLock) {
263+
finishLock.notifyAll();
264+
}
265+
}
266+
267+
public static void onFinishVrKeyboardNegative() {
268+
data = new KeyboardData(0, "");
269+
data.button = 0;
270+
synchronized (finishLock) {
271+
finishLock.notifyAll();
272+
}
237273
}
238274

239275
public static KeyboardData Execute(KeyboardConfig config) {
@@ -242,7 +278,12 @@ public static KeyboardData Execute(KeyboardConfig config) {
242278
return new KeyboardData(0, "");
243279
}
244280

245-
NativeLibrary.sEmulationActivity.get().runOnUiThread(() -> ExecuteImpl(config));
281+
final EmulationActivity emulationActivity = NativeLibrary.sEmulationActivity.get();
282+
if (emulationActivity instanceof VrActivity) {
283+
((VrActivity)emulationActivity).mVrKeyboardLauncher.launch(config);
284+
} else {
285+
NativeLibrary.sEmulationActivity.get().runOnUiThread(() -> ExecuteImpl(config));
286+
}
246287

247288
synchronized (finishLock) {
248289
try {
@@ -256,11 +297,11 @@ public static KeyboardData Execute(KeyboardConfig config) {
256297

257298
public static void ShowError(String error) {
258299
NativeLibrary.displayAlertMsg(
259-
CitraApplication.getAppContext().getResources().getString(R.string.software_keyboard),
260-
error, false);
300+
CitraApplication.getAppContext().getResources().getString(R.string.software_keyboard),
301+
error, false);
261302
}
262303

263-
private static native ValidationError ValidateFilters(String text);
304+
public static native ValidationError ValidateFilters(String text);
264305

265-
private static native ValidationError ValidateInput(String text);
306+
public static native ValidationError ValidateInput(String text);
266307
}

src/android/app/src/main/java/org/citra/citra_emu/vr/ErrorMessageLayer.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
package org.citra.citra_emu.vr;
22

3-
public class ErrorMessageLayer
4-
{
3+
public class ErrorMessageLayer {
54

65
public static ErrorMessageLayer instance = null;
76

8-
public static void showErrorWindow(final String titleStr,
9-
final String mainMessageStr)
10-
{
11-
}
7+
public static void showErrorWindow(final String titleStr, final String mainMessageStr) {}
128

13-
public void _showErrorWindow(final String titleStr,
14-
final String mainMessageStr)
15-
{
16-
}
9+
public void _showErrorWindow(final String titleStr, final String mainMessageStr) {}
1710

1811
public void hideErrorWindow() {}
1912

src/android/app/src/main/java/org/citra/citra_emu/vr/GameSurfaceLayer.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@
1414
* Note: this is set up to require the min number of changes possible to
1515
*existing Citra code, in case an upstream merge is desired.
1616
**/
17-
public class GameSurfaceLayer
18-
{
19-
public static void setSurface(VrActivity activity, Surface surface)
20-
{
17+
public class GameSurfaceLayer {
18+
public static void setSurface(VrActivity activity, Surface surface) {
2119
assert activity != null;
22-
((EmulationFragment)activity.getSupportFragmentManager()
23-
.findFragmentById(R.id.frame_emulation_fragment))
20+
((EmulationFragment)activity.getSupportFragmentManager().findFragmentById(
21+
R.id.frame_emulation_fragment))
2422
.surfaceCreated(surface);
2523
}
2624
}

0 commit comments

Comments
 (0)