mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-15 23:40:29 +02:00
Merge pull request #22460 from hrydgard/android-config-changes
Android: Handle more activity config changes manually
This commit is contained in:
7 files changed
+201
-237
No files matched your search
+3
-1
@@ -1345,7 +1345,9 @@ void NativeFrame(GraphicsContext *graphicsContext) {
|
||||
g_screenManager->resized();
|
||||
|
||||
// TODO: Move this to the GraphicsContext objects for each backend.
|
||||
#if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID)
|
||||
// (Android used to be left out here, since every size change there was a full graphics restart,
|
||||
// and DeviceRestore covers it. Rotation and window resizing are in-place now.)
|
||||
#if !PPSSPP_PLATFORM(WINDOWS)
|
||||
PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
|
||||
PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
|
||||
System_PostUIMessage(UIMessage::GPU_DISPLAY_RESIZED);
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<meta-data android:name="android.max_aspect" android:value="2.4" />
|
||||
<activity
|
||||
android:name=".PpssppActivity"
|
||||
android:configChanges="locale|keyboard|keyboardHidden|navigation|uiMode"
|
||||
android:configChanges="locale|keyboard|keyboardHidden|navigation|uiMode|orientation|screenSize|screenLayout|smallestScreenSize|density"
|
||||
android:theme="@style/ppsspp_style"
|
||||
android:launchMode="singleInstance"
|
||||
android:resizeableActivity="true"
|
||||
|
||||
@@ -940,11 +940,19 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
|
||||
INFO_LOG(Log::System, "NativeApp.shutdown() -- end");
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint pixel_xres, jint pixel_yres, jint format) {
|
||||
INFO_LOG(Log::System, "NativeApp.backbufferResize(%d x %d)", pixel_xres, pixel_yres);
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint pixel_xres, jint pixel_yres, jint format, jint rotation) {
|
||||
INFO_LOG(Log::System, "NativeApp.backbufferResize(%d x %d, rotation %d)", pixel_xres, pixel_yres, rotation);
|
||||
|
||||
// The display's Surface.ROTATION_*. A 180 degree flip changes this but not the size, and the swapchain
|
||||
// still needs recreating, for the pre-rotation.
|
||||
static int lastRotation = -1;
|
||||
const bool rotated = lastRotation != -1 && rotation != lastRotation;
|
||||
lastRotation = rotation;
|
||||
|
||||
int old_w = g_display.pixel_xres;
|
||||
int old_h = g_display.pixel_yres;
|
||||
int old_dp_w = g_display.dp_xres;
|
||||
int old_dp_h = g_display.dp_yres;
|
||||
|
||||
// pixel_*res is the backbuffer resolution.
|
||||
backbuffer_format = format;
|
||||
@@ -966,8 +974,10 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv
|
||||
INFO_LOG(Log::G3D, "RecalcDPI: g_dpi=%d scaled_dpi_x=%f scaled_dpi_y=%f display_scale_x=%f display_scale_y=%f g_dpi_scale_x=%f g_dpi_scale_y=%f dp_xres=%d dp_yres=%d",
|
||||
display_dpi, dpi_x, dpi_y, display_scale_x, display_scale_y, g_display.dpi_scale_x, g_display.dpi_scale_y, g_display.dp_xres, g_display.dp_yres);
|
||||
|
||||
if (new_size) {
|
||||
INFO_LOG(Log::G3D, "Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h);
|
||||
if (new_size || rotated) {
|
||||
// Note that a density change moves the dp size while the pixel size stays put.
|
||||
INFO_LOG(Log::G3D, "%s detected (previously %dx%d px, %dx%d dp) - calling NativeResized()",
|
||||
new_size ? "Size change" : "Rotation change", old_w, old_h, old_dp_w, old_dp_h);
|
||||
NativeResized();
|
||||
} else {
|
||||
INFO_LOG(Log::G3D, "NativeApp::backbufferResize: Size didn't change.");
|
||||
@@ -1321,6 +1331,9 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNI
|
||||
System_PostUIMessage(UIMessage::PERMISSION_GRANTED, prm);
|
||||
} else if (msg == "sustained_perf_supported") {
|
||||
sustainedPerfSupported = true;
|
||||
} else if (msg == "smallestScreenWidthDp") {
|
||||
// Changes on fold/unfold. Decides SYSPROP_CAN_RESTRICT_ORIENTATION.
|
||||
smallestScreenWidthDp = (int)parseLong(prm);
|
||||
} else if (msg == "safe_insets") {
|
||||
// INFO_LOG(Log::System, "Got insets: %s", prm.c_str());
|
||||
// We don't bother with supporting exact rectangular regions. Safe insets are good enough.
|
||||
|
||||
@@ -41,7 +41,9 @@ public class NativeApp {
|
||||
public static native int getDesiredBackbufferHeight();
|
||||
|
||||
public static native void setDisplayParameters(int display_xres, int display_yres, int dpi, float refreshRate);
|
||||
public static native void backbufferResize(int bufferWidth, int bufferHeight, int format);
|
||||
// rotation is the Surface.ROTATION_* of the display. A change in it alone (a 180 degree flip) keeps the size
|
||||
// but the swapchain still has to be recreated, for the pre-rotation.
|
||||
public static native void backbufferResize(int bufferWidth, int bufferHeight, int format, int rotation);
|
||||
|
||||
public static native boolean isLandscape();
|
||||
public static native boolean isAtTopLevel();
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
// Keeps the native side informed of the display and surface size, and applies the hardware
|
||||
// scaling (fixed surface size) setting.
|
||||
public class NativeSurfaceManager implements SurfaceHolder.Callback {
|
||||
private static final String TAG = "PPSSPPSurfaceManager";
|
||||
|
||||
final PpssppActivity activity;
|
||||
SurfaceView surfaceView = null;
|
||||
|
||||
private float densityDpi;
|
||||
|
||||
// The fixed surface size we last asked for, or 0,0 for "size from layout".
|
||||
private final Point desiredSize = new Point();
|
||||
|
||||
// What we last told the native side about the surface, and the density we told it with.
|
||||
// A density change has to re-report it, see densityChanged().
|
||||
private int reportedWidth;
|
||||
private int reportedHeight;
|
||||
private int reportedFormat;
|
||||
private float reportedDensityDpi;
|
||||
|
||||
public NativeSurfaceManager(final PpssppActivity a) {
|
||||
activity = a;
|
||||
}
|
||||
|
||||
public void setSurfaceView(SurfaceView view) {
|
||||
surfaceView = view;
|
||||
if (surfaceView == null)
|
||||
return;
|
||||
|
||||
surfaceView.getHolder().addCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
int pixelWidth = holder.getSurfaceFrame().width();
|
||||
int pixelHeight = holder.getSurfaceFrame().height();
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
|
||||
Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder + " " + display.getRefreshRate() + "Hz");
|
||||
NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int)densityDpi, display.getRefreshRate());
|
||||
getDesiredBackbufferSize(desiredSize);
|
||||
|
||||
// Note that desiredSize might be 0,0 here - but that's fine when calling setFixedSize! It means auto.
|
||||
if (desiredSize.x == 0) {
|
||||
Log.d(TAG, "Setting auto surface size (not fixed)");
|
||||
} else {
|
||||
Log.d(TAG, "Setting fixed surface size " + desiredSize.x + " x " + desiredSize.y);
|
||||
}
|
||||
holder.setFixedSize(desiredSize.x, desiredSize.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
Log.v(TAG, "surfaceChanged: isCreating:" + holder.isCreating() + " holder: " + holder);
|
||||
if (holder.isCreating() && desiredSize.x > 0 && desiredSize.y > 0) {
|
||||
// We have called setFixedSize which will trigger another surfaceChanged after the initial
|
||||
// one. This one is the original one, and we don't care about it.
|
||||
Log.w(TAG, "holder.isCreating = true, ignoring. width=" + width + " height=" + height + " desWidth=" + desiredSize.x + " desHeight=" + desiredSize.y);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
|
||||
// The window size might have changed (rotation, immersive mode, multi-window)
|
||||
updateDisplayMeasurements();
|
||||
|
||||
// A rotation or a window resize doesn't recreate the activity, so a fixed-size (hardware scaled)
|
||||
// surface has to be re-fixed here for the new display size and aspect. The fixed size is what the
|
||||
// surface will report, so only do it when it doesn't already match, or this would loop.
|
||||
if (!holder.isCreating()) {
|
||||
Point newDesired = new Point();
|
||||
getDesiredBackbufferSize(newDesired);
|
||||
boolean fixed = desiredSize.x > 0 && desiredSize.y > 0;
|
||||
boolean wantFixed = newDesired.x > 0 && newDesired.y > 0;
|
||||
if (wantFixed && (newDesired.x != width || newDesired.y != height)) {
|
||||
Log.i(TAG, "Display changed, re-fixing surface size to " + newDesired.x + " x " + newDesired.y);
|
||||
desiredSize.set(newDesired.x, newDesired.y);
|
||||
holder.setFixedSize(newDesired.x, newDesired.y);
|
||||
return; // Another surfaceChanged is coming, with the new size.
|
||||
} else if (!wantFixed && fixed) {
|
||||
Log.i(TAG, "Display changed, surface no longer needs a fixed size");
|
||||
desiredSize.set(0, 0);
|
||||
holder.setSizeFromLayout();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reportSurfaceSize(width, height, format);
|
||||
activity.notifySurface(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
activity.notifySurface(null);
|
||||
reportedWidth = 0;
|
||||
reportedHeight = 0;
|
||||
|
||||
// Autosize the next created surface.
|
||||
holder.setSizeFromLayout();
|
||||
}
|
||||
|
||||
private void reportSurfaceSize(int width, int height, int format) {
|
||||
reportedWidth = width;
|
||||
reportedHeight = height;
|
||||
reportedFormat = format;
|
||||
reportedDensityDpi = densityDpi;
|
||||
NativeApp.backbufferResize(width, height, format, activity.getWindowManager().getDefaultDisplay().getRotation());
|
||||
}
|
||||
|
||||
// A density change rescales the UI but leaves the surface size alone, so no surfaceChanged
|
||||
// follows it to carry the new density to the native side - the DPI is only recalculated in
|
||||
// backbufferResize. Re-report the surface we already have, or the UI keeps the old scale
|
||||
// until the next real resize. Call after updateDisplayMeasurements has picked up the change.
|
||||
public void densityChanged() {
|
||||
if (reportedWidth <= 0 || densityDpi == reportedDensityDpi) {
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Density is now " + densityDpi + ", re-reporting surface " + reportedWidth + "x" + reportedHeight);
|
||||
reportSurfaceSize(reportedWidth, reportedHeight, reportedFormat);
|
||||
}
|
||||
|
||||
public void updateDisplayMeasurements() {
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
display.getRealMetrics(metrics);
|
||||
|
||||
// Early in startup, we don't have a view to query, and the display size is the best we have.
|
||||
// It's only used for config default heuristics then. Later on, we have the exact size.
|
||||
if (surfaceView != null && surfaceView.getWidth() > 0) {
|
||||
metrics.widthPixels = surfaceView.getWidth();
|
||||
metrics.heightPixels = surfaceView.getHeight();
|
||||
}
|
||||
densityDpi = metrics.densityDpi;
|
||||
|
||||
NativeApp.setDisplayParameters(metrics.widthPixels, metrics.heightPixels, (int)densityDpi, display.getRefreshRate());
|
||||
}
|
||||
|
||||
private void getDesiredBackbufferSize(Point sz) {
|
||||
NativeApp.computeDesiredBackbufferDimensions();
|
||||
sz.x = NativeApp.getDesiredBackbufferWidth();
|
||||
sz.y = NativeApp.getDesiredBackbufferHeight();
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,6 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
@@ -100,8 +99,6 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
|
||||
private boolean sustainedPerfSupported;
|
||||
|
||||
private View navigationCallbackView = null;
|
||||
|
||||
// audioFocusChangeListener to listen to changes in audio state
|
||||
private AudioFocusChangeListener audioFocusChangeListener;
|
||||
private AudioManager audioManager;
|
||||
@@ -111,12 +108,15 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// switched-away from or rotated etc.
|
||||
private boolean shuttingDown;
|
||||
|
||||
// surfaceChanged now also fires for rotations and resizes, where the thread just keeps going.
|
||||
private boolean renderLoopRunning = false;
|
||||
|
||||
// Allow for multiple connected gamepads but just consider them the same for now.
|
||||
// Actually this is not entirely true, see the code.
|
||||
private final ArrayList<InputDeviceState> inputPlayers = new ArrayList<>();
|
||||
|
||||
private PowerSaveModeReceiver mPowerSaveModeReceiver = null;
|
||||
private SizeManager sizeManager = null;
|
||||
private NativeSurfaceManager surfaceManager = null;
|
||||
private static LocationHelper mLocationHelper;
|
||||
private static InfraredHelper mInfraredHelper;
|
||||
private static CameraHelper mCameraHelper;
|
||||
@@ -555,7 +555,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
return;
|
||||
}
|
||||
|
||||
// WARNING: when adding new modes here, check SizeManager's workaround in surfaceCreated.j
|
||||
// WARNING: when adding new modes here, check NativeSurfaceManager.surfaceCreated.
|
||||
|
||||
int nativeRotation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
switch (rot) {
|
||||
@@ -632,7 +632,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
}
|
||||
}
|
||||
|
||||
sizeManager.checkDisplayMeasurements();
|
||||
surfaceManager.updateDisplayMeasurements();
|
||||
}
|
||||
|
||||
// Starts the native render loop thread, which owns the graphics context and its surface.
|
||||
@@ -680,7 +680,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
mSensorManager = (SensorManager)getSystemService(Activity.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
sizeManager = new SizeManager(this);
|
||||
surfaceManager = new NativeSurfaceManager(this);
|
||||
TextRenderer.init(this);
|
||||
shuttingDown = false;
|
||||
registerCallbacks();
|
||||
@@ -688,7 +688,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// This calls NativeApp.setDisplayParameters. Make sure that's done early in order
|
||||
// to be able to set defaults when loading config for the first time. Like figuring out
|
||||
// whether to start at 1x or 2x.
|
||||
sizeManager.updateDisplayMeasurements();
|
||||
surfaceManager.updateDisplayMeasurements();
|
||||
|
||||
// On the first run, the shortcut parameter is passed to NativeApp.init in here.
|
||||
final boolean firstRun = !initialized;
|
||||
@@ -713,7 +713,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
updateSystemUiVisibility();
|
||||
|
||||
mSurfaceView = new NativeSurfaceView(this);
|
||||
sizeManager.setSurfaceView(mSurfaceView);
|
||||
surfaceManager.setSurfaceView(mSurfaceView);
|
||||
setInsetsListener(mSurfaceView);
|
||||
setContentView(mSurfaceView);
|
||||
|
||||
@@ -898,10 +898,15 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderLoopRunning) {
|
||||
Log.i(TAG, "startRenderLoopThread: already running, surface changed in place");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.w(TAG, "startRenderLoopThread: Starting thread");
|
||||
|
||||
applyFrameRate(mSurface, 60.0f);
|
||||
runRenderLoop(mSurface);
|
||||
renderLoopRunning = runRenderLoop(mSurface);
|
||||
}
|
||||
|
||||
private synchronized void joinRenderLoopThread() {
|
||||
@@ -915,16 +920,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// This will wait until the thread has exited.
|
||||
Log.i(TAG, "requestExitRenderLoop");
|
||||
requestExitRenderLoop();
|
||||
}
|
||||
|
||||
void setupSystemUiCallback() {
|
||||
final View decorView = getWindow().peekDecorView();
|
||||
if (decorView == null || decorView == navigationCallbackView) {
|
||||
return;
|
||||
}
|
||||
|
||||
sizeManager.setupSystemUiCallback(decorView);
|
||||
navigationCallbackView = decorView;
|
||||
renderLoopRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -945,7 +941,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
audioFocusChangeListener = null;
|
||||
audioManager = null;
|
||||
|
||||
sizeManager.setSurfaceView(null);
|
||||
surfaceManager.setSurfaceView(null);
|
||||
if (mPowerSaveModeReceiver != null) {
|
||||
mPowerSaveModeReceiver.destroy(this);
|
||||
mPowerSaveModeReceiver = null;
|
||||
@@ -971,8 +967,6 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
Log.i(TAG, "in onDestroy, but not shutting down.");
|
||||
}
|
||||
}
|
||||
navigationCallbackView = null;
|
||||
|
||||
// Really ugly workaround for VR issues when PPSSPP restarts
|
||||
if (isVRDevice()) {
|
||||
System.exit(0);
|
||||
@@ -1011,7 +1005,6 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
mSensorManager.unregisterListener(this);
|
||||
|
||||
loseAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
sizeManager.onPause();
|
||||
Log.i(TAG, "Calling NativeApp.pause...");
|
||||
NativeApp.pause();
|
||||
if (mCameraHelper != null) {
|
||||
@@ -1033,7 +1026,6 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
Log.i(TAG, "onResume begin");
|
||||
|
||||
updateSustainedPerformanceMode();
|
||||
sizeManager.onResume();
|
||||
updateSystemUiVisibility();
|
||||
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
@@ -1072,25 +1064,21 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
NativeApp.accelerometer(event.values[0], event.values[1], event.values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
Log.i(TAG, "onAttachedToWindow");
|
||||
super.onAttachedToWindow();
|
||||
if (m_hasNoNativeBinary) {
|
||||
return;
|
||||
}
|
||||
setupSystemUiCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
Log.i(TAG, "onConfigurationChanged");
|
||||
Log.i(TAG, "onConfigurationChanged: orientation=" + newConfig.orientation + " density=" + newConfig.densityDpi
|
||||
+ " screen=" + newConfig.screenWidthDp + "x" + newConfig.screenHeightDp + "dp");
|
||||
if (m_hasNoNativeBinary) {
|
||||
return;
|
||||
}
|
||||
// The surface size change that comes with it is what actually updates the native side, except
|
||||
// for this, which the native side was told once at init. Changes on fold/unfold.
|
||||
NativeApp.sendMessageFromJava("smallestScreenWidthDp", String.valueOf(newConfig.smallestScreenWidthDp));
|
||||
// This re-measures the display, so the density check below sees the new value.
|
||||
updateSystemUiVisibility();
|
||||
sizeManager.updateDpi((float)newConfig.densityDpi);
|
||||
// A density change doesn't resize the surface, so it needs separate handling.
|
||||
surfaceManager.densityChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1101,7 +1089,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
if (m_hasNoNativeBinary) {
|
||||
return;
|
||||
}
|
||||
sizeManager.checkDisplayMeasurements();
|
||||
surfaceManager.updateDisplayMeasurements();
|
||||
}
|
||||
|
||||
// keep this static so we can call this even if we don't
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Point;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
|
||||
public class SizeManager implements SurfaceHolder.Callback {
|
||||
private static final String TAG = "PPSSPPSizeManager";
|
||||
|
||||
final PpssppActivity activity;
|
||||
SurfaceView surfaceView = null;
|
||||
|
||||
private float densityDpi;
|
||||
private float refreshRate;
|
||||
|
||||
private boolean navigationHidden = false;
|
||||
private boolean displayUpdatePending = false;
|
||||
|
||||
private final Point desiredSize = new Point();
|
||||
private int badOrientationCount = 0;
|
||||
|
||||
// Used to fix a race condition on some Android versions.
|
||||
private Surface earlySurface = null;
|
||||
|
||||
private boolean paused = false;
|
||||
|
||||
public SizeManager(final PpssppActivity a) {
|
||||
activity = a;
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
if (earlySurface != null) {
|
||||
Log.i(TAG, "Applying deferred surface");
|
||||
activity.notifySurface(earlySurface);
|
||||
earlySurface = null;
|
||||
}
|
||||
paused = false;
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
paused = true;
|
||||
// Make sure.
|
||||
earlySurface = null;
|
||||
}
|
||||
|
||||
public void setSurfaceView(SurfaceView view) {
|
||||
surfaceView = view;
|
||||
if (surfaceView == null)
|
||||
return;
|
||||
|
||||
surfaceView.getHolder().addCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
int pixelWidth = holder.getSurfaceFrame().width();
|
||||
int pixelHeight = holder.getSurfaceFrame().height();
|
||||
|
||||
// Workaround for terrible bug when locking and unlocking the screen in landscape mode on Nexus 5X.
|
||||
// TODO: Look into removing this.
|
||||
int requestedOr = activity.getRequestedOrientation();
|
||||
boolean requestedPortrait = requestedOr == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOr == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
||||
boolean detectedPortrait = pixelHeight > pixelWidth;
|
||||
if (badOrientationCount < 3 && requestedPortrait != detectedPortrait && requestedOr != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED && requestedOr != ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE && requestedOr != ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
|
||||
Log.e(TAG, "Bad orientation detected (w=" + pixelWidth + " h=" + pixelHeight + "! Recreating activity.");
|
||||
badOrientationCount++;
|
||||
activity.recreate();
|
||||
return;
|
||||
} else if (requestedPortrait == detectedPortrait) {
|
||||
Log.i(TAG, "Correct orientation detected, resetting orientation counter.");
|
||||
badOrientationCount = 0;
|
||||
} else {
|
||||
Log.i(TAG, "Bad orientation detected but ignored");
|
||||
}
|
||||
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
|
||||
refreshRate = display.getRefreshRate();
|
||||
|
||||
Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder + " or: " + requestedOr + " " + refreshRate + "Hz");
|
||||
NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int)densityDpi, refreshRate);
|
||||
getDesiredBackbufferSize(desiredSize);
|
||||
|
||||
// Note that desiredSize might be 0,0 here - but that's fine when calling setFixedSize! It means auto.
|
||||
if (desiredSize.x == 0) {
|
||||
Log.d(TAG, "Setting auto surface size (not fixed)");
|
||||
} else {
|
||||
Log.d(TAG, "Setting fixed surface size " + desiredSize.x + " x " + desiredSize.y);
|
||||
}
|
||||
holder.setFixedSize(desiredSize.x, desiredSize.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
Log.v(TAG, "surfaceChanged: isCreating:" + holder.isCreating() + " holder: " + holder);
|
||||
if (holder.isCreating() && desiredSize.x > 0 && desiredSize.y > 0) {
|
||||
// We have called setFixedSize which will trigger another surfaceChanged after the initial
|
||||
// one. This one is the original one, and we don't care about it.
|
||||
Log.w(TAG, "holder.isCreating = true, ignoring. width=" + width + " height=" + height + " desWidth=" + desiredSize.x + " desHeight=" + desiredSize.y);
|
||||
|
||||
// TODO: Should we still set earlySurface here, to be sure?
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
|
||||
// The window size might have changed (immersive mode, native fullscreen on some devices)
|
||||
NativeApp.backbufferResize(width, height, format);
|
||||
updateDisplayMeasurements();
|
||||
|
||||
if (!paused) {
|
||||
activity.notifySurface(holder.getSurface());
|
||||
} else {
|
||||
earlySurface = holder.getSurface();
|
||||
Log.i(TAG, "Skipping notifySurface while paused - deferring to resume");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
// Don't hand a dead surface over on resume.
|
||||
earlySurface = null;
|
||||
activity.notifySurface(null);
|
||||
|
||||
// Autosize the next created surface.
|
||||
holder.setSizeFromLayout();
|
||||
}
|
||||
|
||||
public void checkDisplayMeasurements() {
|
||||
if (displayUpdatePending) {
|
||||
return;
|
||||
}
|
||||
displayUpdatePending = true;
|
||||
|
||||
activity.runOnUiThread(() -> {
|
||||
Log.d(TAG, "checkDisplayMeasurements: checking now");
|
||||
updateDisplayMeasurements();
|
||||
});
|
||||
}
|
||||
|
||||
public void updateDisplayMeasurements() {
|
||||
displayUpdatePending = false;
|
||||
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
// Early in startup, we don't have a view to query. Do our best to get some kind of size
|
||||
// that can be used by config default heuristics, and so on.
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
if (navigationHidden) {
|
||||
display.getRealMetrics(metrics);
|
||||
} else {
|
||||
display.getMetrics(metrics);
|
||||
}
|
||||
|
||||
// Later on, we have the exact pixel size so let's just use it.
|
||||
if (surfaceView != null) {
|
||||
metrics.widthPixels = surfaceView.getWidth();
|
||||
metrics.heightPixels = surfaceView.getHeight();
|
||||
}
|
||||
densityDpi = metrics.densityDpi;
|
||||
refreshRate = display.getRefreshRate();
|
||||
|
||||
NativeApp.setDisplayParameters(metrics.widthPixels, metrics.heightPixels, (int)densityDpi, refreshRate);
|
||||
}
|
||||
|
||||
public void setupSystemUiCallback(final View view) {
|
||||
view.setOnSystemUiVisibilityChangeListener(visibility -> {
|
||||
// Called when the system UI's visibility changes, regardless of
|
||||
// whether it's because of our or system actions.
|
||||
// We will try to force it to follow our preference but will not stupidly
|
||||
// act as if it's visible if it's not.
|
||||
navigationHidden = ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0);
|
||||
// TODO: Check here if it's the state we want.
|
||||
Log.i(TAG, "SystemUiVisibilityChange! visibility=" + visibility + " navigationHidden: " + navigationHidden + " decorView: " + view.getWidth() + "x" + view.getHeight());
|
||||
checkDisplayMeasurements();
|
||||
});
|
||||
}
|
||||
|
||||
public void updateDpi(float dpi) {
|
||||
densityDpi = dpi;
|
||||
}
|
||||
|
||||
private void getDesiredBackbufferSize(Point sz) {
|
||||
NativeApp.computeDesiredBackbufferDimensions();
|
||||
sz.x = NativeApp.getDesiredBackbufferWidth();
|
||||
sz.y = NativeApp.getDesiredBackbufferHeight();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user