A game framework written with osu! in mind.
at master 4.3 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using Android.Content; 6using Android.Runtime; 7using Android.Text; 8using Android.Util; 9using Android.Views; 10using Android.Views.InputMethods; 11using osu.Framework.Android.Input; 12using osuTK.Graphics; 13 14namespace osu.Framework.Android 15{ 16 public class AndroidGameView : osuTK.Android.AndroidGameView 17 { 18 public AndroidGameHost Host { get; private set; } 19 20 private readonly Game game; 21 22 public new event Action<Keycode, KeyEvent> KeyDown; 23 public new event Action<Keycode, KeyEvent> KeyUp; 24 public event Action<Keycode, KeyEvent> KeyLongPress; 25 public event Action<string> CommitText; 26 public event Action<AndroidGameHost> HostStarted; 27 28 public AndroidGameView(Context context, Game game) 29 : base(context) 30 { 31 this.game = game; 32 33 init(); 34 } 35 36 public AndroidGameView(Context context, IAttributeSet attrs) 37 : base(context, attrs) 38 { 39 init(); 40 } 41 42 public AndroidGameView(IntPtr handle, JniHandleOwnership transfer) 43 : base(handle, transfer) 44 { 45 init(); 46 } 47 48 private void init() 49 { 50 AutoSetContextOnRenderFrame = true; 51 ContextRenderingApi = GLVersion.ES3; 52 53 // enable soft and hardware keyboard 54 // this needs to happen in the constructor 55 Focusable = true; 56 FocusableInTouchMode = true; 57 } 58 59 protected override void CreateFrameBuffer() 60 { 61 try 62 { 63 base.CreateFrameBuffer(); 64 Log.Verbose("AndroidGameView", "Successfully created the framebuffer"); 65 } 66 catch (Exception e) 67 { 68 Log.Verbose("AndroidGameView", "{0}", e); 69 throw new InvalidOperationException("Can't load egl, aborting", e); 70 } 71 } 72 73 public bool OnCommitText(string text) 74 { 75 CommitText?.Invoke(text); 76 return false; 77 } 78 79 public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e) 80 { 81 switch (keyCode) 82 { 83 // Do not consume Volume keys, so the system can handle them 84 case Keycode.VolumeDown: 85 case Keycode.VolumeUp: 86 case Keycode.VolumeMute: 87 return false; 88 89 default: 90 KeyDown?.Invoke(keyCode, e); 91 return true; 92 } 93 } 94 95 public override bool OnKeyLongPress([GeneratedEnum] Keycode keyCode, KeyEvent e) 96 { 97 KeyLongPress?.Invoke(keyCode, e); 98 return true; 99 } 100 101 public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e) 102 { 103 KeyUp?.Invoke(keyCode, e); 104 return true; 105 } 106 107 protected override void OnLoad(EventArgs e) 108 { 109 base.OnLoad(e); 110 111 RenderGame(); 112 } 113 114 [STAThread] 115 public void RenderGame() 116 { 117 Host = new AndroidGameHost(this); 118 Host.ExceptionThrown += handleException; 119 Host.Run(game); 120 HostStarted.Invoke(Host); 121 } 122 123 private bool handleException(Exception ex) 124 { 125 // suppress exceptions related to MobileAuthenticatedStream disposal 126 // (see: https://github.com/ppy/osu/issues/6264 and linked related mono/xamarin issues) 127 // to be removed when upstream fixes come in 128 return ex is AggregateException ae 129 && ae.InnerException is ObjectDisposedException ode 130 && ode.ObjectName == "MobileAuthenticatedStream"; 131 } 132 133 public override bool OnCheckIsTextEditor() => true; 134 135 public override IInputConnection OnCreateInputConnection(EditorInfo outAttrs) 136 { 137 outAttrs.ImeOptions = ImeFlags.NoExtractUi; 138 outAttrs.InputType = InputTypes.Null; 139 return new AndroidInputConnection(this, true); 140 } 141 } 142}