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 ;
3435import android .view .View ;
3536import android .widget .AdapterView ;
3637import android .widget .ArrayAdapter ;
38+ import android .widget .FrameLayout ;
3739import android .widget .ListView ;
3840import android .widget .Toast ;
3941
4042import androidx .annotation .Keep ;
4143import androidx .annotation .NonNull ;
44+ import androidx .annotation .Nullable ;
4245import androidx .annotation .RequiresApi ;
4346import androidx .core .content .ContextCompat ;
47+ import androidx .core .view .ViewCompat ;
48+ import androidx .core .view .WindowCompat ;
49+ import androidx .core .view .WindowInsetsAnimationCompat ;
50+ import androidx .core .view .WindowInsetsCompat ;
4451import androidx .drawerlayout .widget .DrawerLayout ;
4552
4653import com .kdt .LoggerView ;
7582
7683import java .io .File ;
7784import java .io .IOException ;
85+ import java .util .List ;
7886import java .util .Objects ;
7987
80- public class MainActivity extends BaseActivity implements ControlButtonMenuListener , EditorExitable , ServiceConnection {
88+ public class MainActivity extends BaseActivity implements ControlButtonMenuListener , EditorExitable , ServiceConnection , TouchControllerInputView . InputAreaRectListener {
8189 public static volatile ClipboardManager GLOBAL_CLIPBOARD ;
8290 public static final String TAG = "MainActivity" ;
8391 public static final String INTENT_MINECRAFT_VERSION = "intent_version" ;
@@ -96,6 +104,14 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
96104 private GyroControl mGyroControl = null ;
97105 private ControlLayout mControlLayout ;
98106 private HotbarView mHotbarView ;
107+ private FrameLayout contentFrame ;
108+
109+ @ Nullable
110+ private RectF inputAreaRect ;
111+ @ Nullable
112+ private WindowInsetsAnimationCompat imeAnimation ;
113+ private int fullImeHeight ;
114+ private int targetImeHeight ;
99115
100116 MinecraftProfile minecraftProfile ;
101117
@@ -110,6 +126,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
110126 @ Override
111127 public void onCreate (Bundle savedInstanceState ) {
112128 super .onCreate (savedInstanceState );
129+ WindowCompat .setDecorFitsSystemWindows (getWindow (), false );
113130 if (LauncherPreferences .PREF_GAMEPAD_SDL_PASSTHRU ) {
114131 // TODO: Use lower level HID capture that needs a dialogue box from the user for the
115132 // app to fully take focus of the input devices. Might cause issues with older android
@@ -185,6 +202,57 @@ public void onCreate(Bundle savedInstanceState) {
185202 MCOptionUtils .addMCOptionListener (optionListener );
186203 mControlLayout .setModifiable (false );
187204
205+ // Listen to IME offsets
206+ ViewCompat .setWindowInsetsAnimationCallback (contentFrame , new WindowInsetsAnimationCompat .Callback (WindowInsetsAnimationCompat .Callback .DISPATCH_MODE_STOP ) {
207+ @ Override
208+ public void onPrepare (@ NonNull WindowInsetsAnimationCompat animation ) {
209+ if ((animation .getTypeMask () & WindowInsetsCompat .Type .ime ()) != 0 ) {
210+ imeAnimation = animation ;
211+ }
212+ }
213+
214+ @ NonNull
215+ @ Override
216+ public WindowInsetsAnimationCompat .BoundsCompat onStart (@ NonNull WindowInsetsAnimationCompat animation , @ NonNull WindowInsetsAnimationCompat .BoundsCompat bounds ) {
217+ if ((animation .getTypeMask () & WindowInsetsCompat .Type .ime ()) != 0 ) {
218+ refreshImeTranslation ();
219+ }
220+ return bounds ;
221+ }
222+
223+ @ NonNull
224+ @ Override
225+ public WindowInsetsCompat onProgress (@ NonNull WindowInsetsCompat insets , @ NonNull List <WindowInsetsAnimationCompat > runningAnimations ) {
226+ // Find an IME animation
227+ for (WindowInsetsAnimationCompat animation : runningAnimations ) {
228+ if ((animation .getTypeMask () & WindowInsetsCompat .Type .ime ()) != 0 ) {
229+ imeAnimation = animation ;
230+ break ;
231+ }
232+ }
233+ refreshImeTranslation ();
234+ return insets ;
235+ }
236+
237+ @ Override
238+ public void onEnd (@ NonNull WindowInsetsAnimationCompat animation ) {
239+ imeAnimation = null ;
240+ refreshImeTranslation ();
241+ }
242+ });
243+ ViewCompat .setOnApplyWindowInsetsListener (contentFrame , (v , insets ) -> {
244+ boolean imeVisible = insets .isVisible (WindowInsetsCompat .Type .ime ());
245+ if (imeVisible ) {
246+ int height = insets .getInsets (WindowInsetsCompat .Type .ime ()).bottom ;
247+ fullImeHeight = height ;
248+ targetImeHeight = height ;
249+ } else {
250+ // Retain last value of fullImeHeight
251+ targetImeHeight = 0 ;
252+ }
253+ return insets ;
254+ });
255+
188256 // Set the activity for the executor. Must do this here, or else Tools.showErrorRemote() may not
189257 // execute the correct method
190258 ContextExecutor .setActivity (this );
@@ -209,7 +277,7 @@ protected void initLayout(int resId) {
209277 GLOBAL_CLIPBOARD = (ClipboardManager ) getSystemService (CLIPBOARD_SERVICE );
210278 touchCharInput .setCharacterSender (new LwjglCharSender ());
211279
212- touchControllerInputView .setSize ( minecraftGLView . getWidth (), minecraftGLView . getHeight () );
280+ touchControllerInputView .setInputAreaRectListener ( this );
213281
214282 if (minecraftProfile .pojavRendererName != null ) {
215283 Log .i ("RdrDebug" ,"__P_renderer=" +minecraftProfile .pojavRendererName );
@@ -260,6 +328,9 @@ protected void initLayout(int resId) {
260328 touchpad .post (() -> touchpad .switchState ());
261329 }
262330
331+ // At this time, correct size is known
332+ touchControllerInputView .setSize (minecraftGLView .getWidth (), minecraftGLView .getHeight ());
333+
263334 runCraft (finalVersion , mVersionInfo );
264335 }catch (Throwable e ){
265336 Tools .showErrorRemote (e );
@@ -314,6 +385,7 @@ private void bindValues(){
314385 touchControllerInputView = findViewById (R .id .touch_controller_input );
315386 mDrawerPullButton = findViewById (R .id .drawer_button );
316387 mHotbarView = findViewById (R .id .hotbar_view );
388+ contentFrame = findViewById (R .id .content_frame );
317389 }
318390
319391 @ Override
@@ -701,4 +773,35 @@ public void onTrimMemory(int level) {
701773 public void onBackPressed () {
702774 super .onBackPressed ();
703775 }
776+
777+ @ Override
778+ public void updateInputAreaRect (@ Nullable RectF rect ) {
779+ inputAreaRect = rect ;
780+ refreshImeTranslation ();
781+ }
782+
783+ private void refreshImeTranslation () {
784+ if (inputAreaRect == null || fullImeHeight == 0 ) {
785+ contentFrame .setTranslationY (0 );
786+ return ;
787+ }
788+
789+ int inputAreaBottom = (int ) inputAreaRect .bottom ;
790+ int animationImeHeight ;
791+ if (imeAnimation != null ) {
792+ if (targetImeHeight == 0 ) {
793+ // Collapsing
794+ animationImeHeight = (int ) (fullImeHeight * (1 - imeAnimation .getInterpolatedFraction ()));
795+ } else {
796+ // Expanding
797+ animationImeHeight = (int ) (targetImeHeight * imeAnimation .getInterpolatedFraction ());
798+ }
799+ } else {
800+ animationImeHeight = targetImeHeight ;
801+ }
802+ int bottomDistance = contentFrame .getHeight () - inputAreaBottom ;
803+ int bottomPadding = Math .max (animationImeHeight - bottomDistance , 0 );
804+
805+ contentFrame .setTranslationY (-bottomPadding );
806+ }
704807}
0 commit comments