Skip to content

Commit 07cc39e

Browse files
committed
feat(TouchController): add IME padding support
1 parent 0699175 commit 07cc39e

4 files changed

Lines changed: 203 additions & 68 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: 115 additions & 8 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;
@@ -35,13 +36,19 @@
3536
import android.view.WindowManager;
3637
import android.widget.AdapterView;
3738
import android.widget.ArrayAdapter;
39+
import android.widget.FrameLayout;
3840
import android.widget.ListView;
3941
import android.widget.Toast;
4042

4143
import androidx.annotation.Keep;
4244
import androidx.annotation.NonNull;
45+
import androidx.annotation.Nullable;
4346
import androidx.annotation.RequiresApi;
4447
import 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;
4552
import androidx.drawerlayout.widget.DrawerLayout;
4653

4754
import com.kdt.LoggerView;
@@ -76,9 +83,10 @@
7683

7784
import java.io.File;
7885
import java.io.IOException;
86+
import java.util.List;
7987
import 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

Comments
 (0)