2222import android .content .ServiceConnection ;
2323import android .content .res .Configuration ;
2424import android .graphics .Color ;
25+ import android .graphics .RectF ;
2526import android .graphics .drawable .ColorDrawable ;
2627import android .net .Uri ;
2728import android .os .Build ;
3536import android .view .WindowManager ;
3637import android .widget .AdapterView ;
3738import android .widget .ArrayAdapter ;
39+ import android .widget .FrameLayout ;
3840import android .widget .ListView ;
3941import android .widget .Toast ;
4042
4143import androidx .annotation .Keep ;
4244import androidx .annotation .NonNull ;
45+ import androidx .annotation .Nullable ;
4346import androidx .annotation .RequiresApi ;
4447import androidx .core .content .ContextCompat ;
48+ import androidx .core .view .ViewCompat ;
49+ import androidx .core .view .WindowCompat ;
50+ import androidx .core .view .WindowInsetsAnimationCompat ;
51+ import androidx .core .view .WindowInsetsCompat ;
4552import androidx .drawerlayout .widget .DrawerLayout ;
4653
4754import com .kdt .LoggerView ;
7683
7784import java .io .File ;
7885import java .io .IOException ;
86+ import java .util .List ;
7987import java .util .Objects ;
8088
81- public class MainActivity extends BaseActivity implements ControlButtonMenuListener , EditorExitable , ServiceConnection {
89+ public class MainActivity extends BaseActivity implements ControlButtonMenuListener , EditorExitable , ServiceConnection , TouchControllerInputView . InputAreaRectListener {
8290 public static volatile ClipboardManager GLOBAL_CLIPBOARD ;
8391 public static final String TAG = "MainActivity" ;
8492 public static final String INTENT_MINECRAFT_VERSION = "intent_version" ;
@@ -97,6 +105,14 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
97105 private GyroControl mGyroControl = null ;
98106 private ControlLayout mControlLayout ;
99107 private HotbarView mHotbarView ;
108+ private FrameLayout contentFrame ;
109+
110+ @ Nullable
111+ private RectF inputAreaRect ;
112+ @ Nullable
113+ private WindowInsetsAnimationCompat imeAnimation ;
114+ private int fullImeHeight ;
115+ private int targetImeHeight ;
100116
101117 MinecraftProfile minecraftProfile ;
102118
@@ -111,12 +127,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
111127 @ Override
112128 public void onCreate (Bundle savedInstanceState ) {
113129 super .onCreate (savedInstanceState );
114-
115- if (LauncherPreferences .PREF_KEYBOARD_PANNING ) {
116- getWindow ().setSoftInputMode (WindowManager .LayoutParams .SOFT_INPUT_ADJUST_PAN );
117- } else {
118- getWindow ().setSoftInputMode (WindowManager .LayoutParams .SOFT_INPUT_ADJUST_NOTHING );
119- }
130+ WindowCompat .setDecorFitsSystemWindows (getWindow (), false );
120131
121132 if (LauncherPreferences .PREF_GAMEPAD_SDL_PASSTHRU ) {
122133 // TODO: Use lower level HID capture that needs a dialogue box from the user for the
@@ -193,6 +204,57 @@ public void onCreate(Bundle savedInstanceState) {
193204 MCOptionUtils .addMCOptionListener (optionListener );
194205 mControlLayout .setModifiable (false );
195206
207+ // Listen to IME offsets
208+ ViewCompat .setWindowInsetsAnimationCallback (contentFrame , new WindowInsetsAnimationCompat .Callback (WindowInsetsAnimationCompat .Callback .DISPATCH_MODE_STOP ) {
209+ @ Override
210+ public void onPrepare (@ NonNull WindowInsetsAnimationCompat animation ) {
211+ if ((animation .getTypeMask () & WindowInsetsCompat .Type .ime ()) != 0 ) {
212+ imeAnimation = animation ;
213+ }
214+ }
215+
216+ @ NonNull
217+ @ Override
218+ public WindowInsetsAnimationCompat .BoundsCompat onStart (@ NonNull WindowInsetsAnimationCompat animation , @ NonNull WindowInsetsAnimationCompat .BoundsCompat bounds ) {
219+ if ((animation .getTypeMask () & WindowInsetsCompat .Type .ime ()) != 0 ) {
220+ refreshImeTranslation ();
221+ }
222+ return bounds ;
223+ }
224+
225+ @ NonNull
226+ @ Override
227+ public WindowInsetsCompat onProgress (@ NonNull WindowInsetsCompat insets , @ NonNull List <WindowInsetsAnimationCompat > runningAnimations ) {
228+ // Find an IME animation
229+ for (WindowInsetsAnimationCompat animation : runningAnimations ) {
230+ if ((animation .getTypeMask () & WindowInsetsCompat .Type .ime ()) != 0 ) {
231+ imeAnimation = animation ;
232+ break ;
233+ }
234+ }
235+ refreshImeTranslation ();
236+ return insets ;
237+ }
238+
239+ @ Override
240+ public void onEnd (@ NonNull WindowInsetsAnimationCompat animation ) {
241+ imeAnimation = null ;
242+ refreshImeTranslation ();
243+ }
244+ });
245+ ViewCompat .setOnApplyWindowInsetsListener (contentFrame , (v , insets ) -> {
246+ boolean imeVisible = insets .isVisible (WindowInsetsCompat .Type .ime ());
247+ if (imeVisible ) {
248+ int height = insets .getInsets (WindowInsetsCompat .Type .ime ()).bottom ;
249+ fullImeHeight = height ;
250+ targetImeHeight = height ;
251+ } else {
252+ // Retain last value of fullImeHeight
253+ targetImeHeight = 0 ;
254+ }
255+ return insets ;
256+ });
257+
196258 // Set the activity for the executor. Must do this here, or else Tools.showErrorRemote() may not
197259 // execute the correct method
198260 ContextExecutor .setActivity (this );
@@ -217,7 +279,7 @@ protected void initLayout(int resId) {
217279 GLOBAL_CLIPBOARD = (ClipboardManager ) getSystemService (CLIPBOARD_SERVICE );
218280 touchCharInput .setCharacterSender (new LwjglCharSender ());
219281
220- touchControllerInputView .setSize ( minecraftGLView . getWidth (), minecraftGLView . getHeight () );
282+ touchControllerInputView .setInputAreaRectListener ( this );
221283
222284 if (minecraftProfile .pojavRendererName != null ) {
223285 Log .i ("RdrDebug" ,"__P_renderer=" +minecraftProfile .pojavRendererName );
@@ -268,6 +330,9 @@ protected void initLayout(int resId) {
268330 touchpad .post (() -> touchpad .switchState ());
269331 }
270332
333+ // At this time, correct size is known
334+ touchControllerInputView .setSize (minecraftGLView .getWidth (), minecraftGLView .getHeight ());
335+
271336 runCraft (finalVersion , mVersionInfo );
272337 }catch (Throwable e ){
273338 Tools .showErrorRemote (e );
@@ -322,6 +387,7 @@ private void bindValues(){
322387 touchControllerInputView = findViewById (R .id .touch_controller_input );
323388 mDrawerPullButton = findViewById (R .id .drawer_button );
324389 mHotbarView = findViewById (R .id .hotbar_view );
390+ contentFrame = findViewById (R .id .content_frame );
325391 }
326392
327393 @ Override
@@ -718,4 +784,45 @@ public void onTrimMemory(int level) {
718784 public void onBackPressed () {
719785 super .onBackPressed ();
720786 }
787+
788+ @ Override
789+ public void updateInputAreaRect (@ Nullable RectF rect ) {
790+ inputAreaRect = rect ;
791+ refreshImeTranslation ();
792+ }
793+
794+ private void refreshImeTranslation () {
795+ if (fullImeHeight == 0 ) {
796+ // Early exit
797+ contentFrame .setTranslationY (0 );
798+ return ;
799+ }
800+
801+ int inputAreaBottom ;
802+ if (inputAreaRect != null ) {
803+ inputAreaBottom = (int ) inputAreaRect .bottom ;
804+ } else if (LauncherPreferences .PREF_KEYBOARD_PANNING ) {
805+ inputAreaBottom = contentFrame .getHeight ();
806+ } else {
807+ contentFrame .setTranslationY (0 );
808+ return ;
809+ }
810+
811+ int animationImeHeight ;
812+ if (imeAnimation != null ) {
813+ if (targetImeHeight == 0 ) {
814+ // Collapsing
815+ animationImeHeight = (int ) (fullImeHeight * (1 - imeAnimation .getInterpolatedFraction ()));
816+ } else {
817+ // Expanding
818+ animationImeHeight = (int ) (targetImeHeight * imeAnimation .getInterpolatedFraction ());
819+ }
820+ } else {
821+ animationImeHeight = targetImeHeight ;
822+ }
823+ int bottomDistance = contentFrame .getHeight () - inputAreaBottom ;
824+ int bottomPadding = Math .max (animationImeHeight - bottomDistance , 0 );
825+
826+ contentFrame .setTranslationY (-bottomPadding );
827+ }
721828}
0 commit comments