Skip to content

Commit

Permalink
05/16/24 UPDATE (#2)
Browse files Browse the repository at this point in the history
* Fix[msa]: Avoid the issue of accounts 404-ing when attempting to log in

* Feat[layout_vert]: center screen scrollability

* Feat[mouse]: always grab the mouse and use the touchpad as the cursor.

* Code[mouse]: change internal function names and use `default` in AbstractTouchpad

* Feat[mouse]: scale touchpad mouse speed by 1dp

* Fix[mouse]: TOOL_TYPE_MOUSE events handled in both generic motion and touch event handlers

* Fix[input]: implement scrolling gestures for touchpads

* Fix[msa_fragment]: fix inability to track log-ins in fragment after partial state restoration

* Fix[fragment]: only initialize the ROOT transaction if the back stack is empty.

* Feat[download]: don't always redowload files with missing hashes

* Fix[dialog]: clipboard copies are no longer empty text

* Fix[lang]: remove the mention of "email"

* Fix: QoL stuff (PojavLauncherTeam#5443)

* Tweak: align ram selection to multiples of height

* tweak: ignore the notch for portrait devices while in the launcher

* tweak(colors): make colors consistent across screens

* fix(ui): make click animation consistent

* fix(modpack-ui): handle long titles overlapping the source icon

* fix:(modrinth-api): offset call is being ignored

* fix(modpack-ui): remove keyboard after search

* fix(profile-editor): properly consume file selection for custom controls

Based from the work of @HopiHopy

* Merge conflict fix

---------

Co-authored-by: artdeell <[email protected]>
Co-authored-by: Mathias Boulay <[email protected]>
  • Loading branch information
3 people authored May 16, 2024
1 parent ab5a962 commit a8424c9
Show file tree
Hide file tree
Showing 26 changed files with 391 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ protected void onResume() {
protected void onPostResume() {
super.onPostResume();
Tools.setFullscreen(this, setFullscreen());
Tools.ignoreNotch(PREF_IGNORE_NOTCH,this);
Tools.ignoreNotch(shouldIgnoreNotch(),this);
}

/** @return Whether or not the notch should be ignored */
protected boolean shouldIgnoreNotch(){
return PREF_IGNORE_NOTCH;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package net.kdt.pojavlaunch;

import android.content.*;
import android.os.*;
import androidx.appcompat.app.*;
import android.util.*;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class FatalErrorActivity extends AppCompatActivity {

Expand All @@ -13,8 +16,13 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Bundle extras = getIntent().getExtras();
boolean storageAllow = extras.getBoolean("storageAllow");
final String stackTrace = Log.getStackTraceString((Throwable) extras.getSerializable("throwable"));
if(extras == null) {
finish();
return;
}
boolean storageAllow = extras.getBoolean("storageAllow", false);
Throwable throwable = (Throwable) extras.getSerializable("throwable");
final String stackTrace = throwable != null ? Tools.printToString(throwable) : "<null>";
String strSavePath = extras.getString("savePath");
String errHeader = storageAllow ?
"Crash stack trace saved to " + strSavePath + "." :
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.kdt.pojavlaunch;

import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import android.Manifest;
import android.app.NotificationManager;
import android.content.Context;
Expand All @@ -23,14 +24,15 @@
import com.kdt.mcgui.ProgressLayout;
import com.kdt.mcgui.mcAccountSpinner;

import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.contracts.OpenDocumentWithExtension;
import net.kdt.pojavlaunch.extra.ExtraConstants;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.fragments.MainMenuFragment;
import net.kdt.pojavlaunch.fragments.MicrosoftLoginFragment;
import net.kdt.pojavlaunch.fragments.SelectAuthFragment;
import net.kdt.pojavlaunch.lifecycle.ContextAwareDoneListener;
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker;
import net.kdt.pojavlaunch.modloaders.modpacks.imagecache.IconCacheJanitor;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
Expand All @@ -40,7 +42,6 @@
import net.kdt.pojavlaunch.services.ProgressServiceKeeper;
import net.kdt.pojavlaunch.tasks.AsyncMinecraftDownloader;
import net.kdt.pojavlaunch.tasks.AsyncVersionList;
import net.kdt.pojavlaunch.lifecycle.ContextAwareDoneListener;
import net.kdt.pojavlaunch.tasks.MinecraftDownloader;
import net.kdt.pojavlaunch.utils.NotificationUtils;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
Expand Down Expand Up @@ -153,17 +154,27 @@ public void onFragmentResumed(@NonNull FragmentManager fm, @NonNull Fragment f)
private ActivityResultLauncher<String> mRequestNotificationPermissionLauncher;
private WeakReference<Runnable> mRequestNotificationPermissionRunnable;

@Override
protected boolean shouldIgnoreNotch() {
return getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT || super.shouldIgnoreNotch();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pojav_launcher);
FragmentManager fragmentManager = getSupportFragmentManager();
// If we don't have a back stack root yet...
if(fragmentManager.getBackStackEntryCount() < 1) {
// Manually add the first fragment to the backstack to get easily back to it
// There must be a better way to handle the root though...
// (artDev: No, there is not. I've spent days researching this for another unrelated project.)
fragmentManager.beginTransaction()
.setReorderingAllowed(true)
.addToBackStack("ROOT")
.add(R.id.container_fragment, MainMenuFragment.class, null, "ROOT").commit();
}

// Manually add the first fragment to the backstack to get easily back to it
// There must be a better way to handle the root though...
this.getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.addToBackStack("ROOT")
.add(R.id.container_fragment, MainMenuFragment.class, null, "ROOT").commit();

IconCacheJanitor.runJanitor();
mRequestNotificationPermissionLauncher = registerForActivityResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.app.Activity;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
Expand All @@ -28,6 +29,7 @@
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
import net.kdt.pojavlaunch.customcontrols.mouse.AbstractTouchpad;
import net.kdt.pojavlaunch.customcontrols.mouse.AndroidPointerCapture;
import net.kdt.pojavlaunch.customcontrols.mouse.InGUIEventProcessor;
import net.kdt.pojavlaunch.customcontrols.mouse.InGameEventProcessor;
import net.kdt.pojavlaunch.customcontrols.mouse.TouchEventProcessor;
Expand Down Expand Up @@ -76,6 +78,7 @@ public class MinecraftGLSurface extends View implements GrabListener {
private final InGameEventProcessor mIngameProcessor = new InGameEventProcessor(mSensitivityFactor);
private final InGUIEventProcessor mInGUIProcessor = new InGUIEventProcessor(mScaleFactor);
private TouchEventProcessor mCurrentTouchProcessor = mInGUIProcessor;
private AndroidPointerCapture mPointerCapture;
private boolean mLastGrabState = false;

public MinecraftGLSurface(Context context) {
Expand All @@ -87,13 +90,20 @@ public MinecraftGLSurface(Context context, AttributeSet attributeSet) {
setFocusable(true);
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void setUpPointerCapture(AbstractTouchpad touchpad) {
if(mPointerCapture != null) mPointerCapture.detach();
mPointerCapture = new AndroidPointerCapture(touchpad, this, mScaleFactor);
}

/** Initialize the view and all its settings
* @param isAlreadyRunning set to true to tell the view that the game is already running
* (only updates the window without calling the start listener)
* @param touchpad the optional cursor-emulating touchpad, used for touch event processing
* when the cursor is not grabbed
*/
public void start(boolean isAlreadyRunning, AbstractTouchpad touchpad){
if(MainActivity.isAndroid8OrHigher()) setUpPointerCapture(touchpad);
mInGUIProcessor.setAbstractTouchpad(touchpad);
if(LauncherPreferences.PREF_USE_ALTERNATE_SURFACE){
SurfaceView surfaceView = new SurfaceView(getContext());
Expand Down Expand Up @@ -162,7 +172,6 @@ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {}

}


/**
* The touch event for both grabbed an non-grabbed mouse state on the touch screen
* Does not cover the virtual mouse touchpad
Expand All @@ -175,7 +184,14 @@ public boolean onTouchEvent(MotionEvent e) {

// Looking for a mouse to handle, won't have an effect if no mouse exists.
for (int i = 0; i < e.getPointerCount(); i++) {
if(e.getToolType(i) != MotionEvent.TOOL_TYPE_MOUSE && e.getToolType(i) != MotionEvent.TOOL_TYPE_STYLUS ) continue;
int toolType = e.getToolType(i);
if(toolType == MotionEvent.TOOL_TYPE_MOUSE) {
if(MainActivity.isAndroid8OrHigher() &&
mPointerCapture != null) {
mPointerCapture.handleAutomaticCapture();
return true;
}
}else if(toolType != MotionEvent.TOOL_TYPE_STYLUS) continue;

// Mouse found
if(CallbackBridge.isGrabbing()) return false;
Expand Down Expand Up @@ -232,32 +248,6 @@ public boolean dispatchGenericMotionEvent(MotionEvent event) {
}
}

//TODO MOVE THIS SOMEWHERE ELSE
/** The input event for mouse with a captured pointer */
@RequiresApi(26)
@Override
public boolean dispatchCapturedPointerEvent(MotionEvent e) {
CallbackBridge.mouseX += (e.getX()* mScaleFactor);
CallbackBridge.mouseY += (e.getY()* mScaleFactor);

// Position is updated by many events, hence it is send regardless of the event value
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);

switch (e.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_BUTTON_PRESS:
return sendMouseButtonUnconverted(e.getActionButton(), true);
case MotionEvent.ACTION_BUTTON_RELEASE:
return sendMouseButtonUnconverted(e.getActionButton(), false);
case MotionEvent.ACTION_SCROLL:
CallbackBridge.sendScroll(e.getAxisValue(MotionEvent.AXIS_HSCROLL), e.getAxisValue(MotionEvent.AXIS_VSCROLL));
return true;
default:
return false;
}
}

/** The event for keyboard/ gamepad button inputs */
public boolean processKeyEvent(KeyEvent event) {
//Log.i("KeyEvent", event.toString());
Expand Down Expand Up @@ -404,29 +394,6 @@ private void updateGrabState(boolean isGrabbing) {
mCurrentTouchProcessor = pickEventProcessor(isGrabbing);
mLastGrabState = isGrabbing;
}
if(!MainActivity.isAndroid8OrHigher()) return;

boolean hasPointerCapture = hasPointerCapture();
if(isGrabbing){
if(!hasPointerCapture) {
requestFocus();
if(hasWindowFocus()) requestPointerCapture();
// Otherwise, onWindowFocusChanged() would get called.
}
return;
}

if(hasPointerCapture) {
releasePointerCapture();
clearFocus();
}
}

@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if(hasWindowFocus && CallbackBridge.isGrabbing() &&
MainActivity.isAndroid8OrHigher()) requestPointerCapture();
}

/** A small interface called when the listener is ready for the first time */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ private static void showError(final Context ctx, final int titleId, final String
.setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, (p1, p2) -> showError(ctx, titleId, rolledMessage, e, exitIfOk, !showMore))
.setNeutralButton(android.R.string.copy, (p1, p2) -> {
ClipboardManager mgr = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
mgr.setPrimaryClip(ClipData.newPlainText("error", Log.getStackTraceString(e)));
mgr.setPrimaryClip(ClipData.newPlainText("error", printToString(e)));
if(exitIfOk) {
if (ctx instanceof MainActivity) {
MainActivity.fullyExit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class MicrosoftBackgroundLogin {
private static final String xstsAuthUrl = "https://xsts.auth.xboxlive.com/xsts/authorize";
private static final String mcLoginUrl = "https://api.minecraftservices.com/authentication/login_with_xbox";
private static final String mcProfileUrl = "https://api.minecraftservices.com/minecraft/profile";
private static final String mcStoreUrl = "https://api.minecraftservices.com/entitlements/mcstore";

private final boolean mIsRefresh;
private final String mAuthCode;
Expand Down Expand Up @@ -81,6 +82,7 @@ public void performLogin(@Nullable final ProgressListener progressListener,
notifyProgress(progressListener, 4);
String mcToken = acquireMinecraftToken(xsts[0], xsts[1]);
notifyProgress(progressListener, 5);
fetchOwnedItems(mcToken);
checkMcProfile(mcToken);

MinecraftAccount acc = MinecraftAccount.load(mcName);
Expand Down Expand Up @@ -255,6 +257,21 @@ private String acquireMinecraftToken(String xblUhs, String xblXsts) throws IOExc
}
}

private void fetchOwnedItems(String mcAccessToken) throws IOException {
URL url = new URL(mcStoreUrl);

HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestProperty("Authorization", "Bearer " + mcAccessToken);
conn.setUseCaches(false);
conn.connect();
if(conn.getResponseCode() < 200 || conn.getResponseCode() >= 300) {
throw getResponseThrowable(conn);
}
// We don't need any data from this request, it just needs to happen in order for
// the MS servers to work properly. The data from this is practically useless
// as it does not indicate whether the user owns the game through Game Pass.
}

private void checkMcProfile(String mcAccessToken) throws IOException, JSONException {
URL url = new URL(mcProfileUrl);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
package net.kdt.pojavlaunch.customcontrols.mouse;

public interface AbstractTouchpad {
/**
* Get the supposed display state of the mouse (whether it should be shown when the user is in a GUI)
* Note that this does *not* reflect the actual visibility state of the mouse
* @return current supposed enabled state
*/
boolean getDisplayState();
void applyMotionVector(float[] vector);

/**
* Apply a motion vector to the mouse in form of a two-entry float array. This will move the mouse
* on the screen and send the new cursor position to the game.
* @param vector the array that contains the vector
*/
default void applyMotionVector(float[] vector) {
applyMotionVector(vector[0], vector[1]);
}

/**
* Apply a motion vector to the mouse in form of the separate X/Y coordinates. This will move the mouse
* on the screen and send the new cursor position to the game.
* @param x the relative X coordinate of the vector
* @param y the relative Y coordinate for the vector
*/
void applyMotionVector(float x, float y);

/**
* Sets the state of the touchpad to "enabled"
* @param supposed if set to true, this will set the supposed display state to enabled but may not
* affect the touchpad until internal conditions are met
* if set to false it will turn the touchpad on regardless of internal conditions
*/
void enable(boolean supposed);
/**
* Sets the state of the touchpad to "disabled".
*/
void disable();
}
Loading

0 comments on commit a8424c9

Please sign in to comment.