Skip to content

Commit 239681f

Browse files
committed
feat(TouchController): add IME padding support
1 parent 2f48e67 commit 239681f

4 files changed

Lines changed: 193 additions & 62 deletions

File tree

app_pojavlauncher/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|keyboard|navigation|uiMode"
111111
android:launchMode="singleTop"
112112
android:process=":game"
113+
android:windowSoftInputMode="adjustResize"
113114
android:screenOrientation="sensorLandscape" />
114115

115116
<provider

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MainActivity.java

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.content.ServiceConnection;
2323
import android.content.res.Configuration;
2424
import android.graphics.Color;
25+
import android.graphics.RectF;
2526
import android.graphics.drawable.ColorDrawable;
2627
import android.net.Uri;
2728
import android.os.Build;
@@ -34,13 +35,19 @@
3435
import android.view.View;
3536
import android.widget.AdapterView;
3637
import android.widget.ArrayAdapter;
38+
import android.widget.FrameLayout;
3739
import android.widget.ListView;
3840
import android.widget.Toast;
3941

4042
import androidx.annotation.Keep;
4143
import androidx.annotation.NonNull;
44+
import androidx.annotation.Nullable;
4245
import androidx.annotation.RequiresApi;
4346
import 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;
4451
import androidx.drawerlayout.widget.DrawerLayout;
4552

4653
import com.kdt.LoggerView;
@@ -75,9 +82,10 @@
7582

7683
import java.io.File;
7784
import java.io.IOException;
85+
import java.util.List;
7886
import 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

Comments
 (0)