mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 21:39:52 +00:00
Merge pull request #12881 from unknownbrackets/android-size
Refactor Android resize management and improve restart
This commit is contained in:
commit
6edf4ddc57
@ -636,6 +636,25 @@ void TouchTestScreen::CreateViews() {
|
||||
root_ = new LinearLayout(ORIENT_VERTICAL);
|
||||
LinearLayout *theTwo = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f));
|
||||
root_->Add(theTwo);
|
||||
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" };
|
||||
PopupMultiChoice *renderingBackendChoice = root_->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager()));
|
||||
renderingBackendChoice->OnChoice.Handle(this, &TouchTestScreen::OnRenderingBackend);
|
||||
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL))
|
||||
renderingBackendChoice->HideChoice((int)GPUBackend::OPENGL);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9))
|
||||
renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D9);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11))
|
||||
renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN))
|
||||
renderingBackendChoice->HideChoice((int)GPUBackend::VULKAN);
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
root_->Add(new Choice(gr->T("Recreate Activity")))->OnClick.Handle(this, &TouchTestScreen::OnRecreateActivity);
|
||||
#endif
|
||||
root_->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &TouchTestScreen::OnImmersiveModeChange);
|
||||
root_->Add(new Button(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
}
|
||||
@ -687,7 +706,7 @@ void TouchTestScreen::render() {
|
||||
g_dpi_scale_x, g_dpi_scale_y,
|
||||
g_dpi_scale_real_x, g_dpi_scale_real_y);
|
||||
|
||||
ui_context->DrawTextShadow(buffer, bounds.x + 20.0f, dp_yres / 2.0f, 0xFFFFFFFF, ALIGN_VCENTER | FLAG_DYNAMIC_ASCII);
|
||||
ui_context->DrawTextShadow(buffer, bounds.x + 20.0f, bounds.y + 20.0f, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
||||
ui_context->Flush();
|
||||
}
|
||||
|
||||
@ -700,3 +719,14 @@ UI::EventReturn TouchTestScreen::OnImmersiveModeChange(UI::EventParams &e) {
|
||||
}
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn TouchTestScreen::OnRenderingBackend(UI::EventParams &e) {
|
||||
g_Config.Save("GameSettingsScreen::RenderingBackend");
|
||||
System_SendMessage("graphics_restart", "--touchscreentest");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn TouchTestScreen::OnRecreateActivity(UI::EventParams &e) {
|
||||
RecreateActivity();
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
@ -132,6 +132,9 @@ protected:
|
||||
};
|
||||
TrackedTouch touches_[MAX_TOUCH_POINTS]{};
|
||||
|
||||
virtual void CreateViews() override;
|
||||
void CreateViews() override;
|
||||
|
||||
UI::EventReturn OnImmersiveModeChange(UI::EventParams &e);
|
||||
UI::EventReturn OnRenderingBackend(UI::EventParams &e);
|
||||
UI::EventReturn OnRecreateActivity(UI::EventParams &e);
|
||||
};
|
||||
|
@ -1195,14 +1195,25 @@ void GameSettingsScreen::CallbackMemstickFolder(bool yes) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void GameSettingsScreen::TriggerRestart(const char *why) {
|
||||
// Extra save here to make sure the choice really gets saved even if there are shutdown bugs in
|
||||
// the GPU backend code.
|
||||
g_Config.Save(why);
|
||||
std::string param = "--gamesettings";
|
||||
if (editThenRestore_) {
|
||||
// We won't pass the gameID, so don't resume back into settings.
|
||||
param = "";
|
||||
} else if (!gamePath_.empty()) {
|
||||
param += " \"" + ReplaceAll(ReplaceAll(gamePath_, "\\", "\\\\"), "\"", "\\\"") + "\"";
|
||||
}
|
||||
System_SendMessage("graphics_restart", param.c_str());
|
||||
}
|
||||
|
||||
void GameSettingsScreen::CallbackRenderingBackend(bool yes) {
|
||||
// If the user ends up deciding not to restart, set the config back to the current backend
|
||||
// so it doesn't get switched by accident.
|
||||
if (yes) {
|
||||
// Extra save here to make sure the choice really gets saved even if there are shutdown bugs in
|
||||
// the GPU backend code.
|
||||
g_Config.Save("GameSettingsScreen::RenderingBackendYes");
|
||||
System_SendMessage("graphics_restart", "");
|
||||
TriggerRestart("GameSettingsScreen::RenderingBackendYes");
|
||||
} else {
|
||||
g_Config.iGPUBackend = (int)GetGPUBackend();
|
||||
}
|
||||
@ -1212,10 +1223,7 @@ void GameSettingsScreen::CallbackRenderingDevice(bool yes) {
|
||||
// If the user ends up deciding not to restart, set the config back to the current backend
|
||||
// so it doesn't get switched by accident.
|
||||
if (yes) {
|
||||
// Extra save here to make sure the choice really gets saved even if there are shutdown bugs in
|
||||
// the GPU backend code.
|
||||
g_Config.Save("GameSettingsScreen::RenderingDeviceYes");
|
||||
System_SendMessage("graphics_restart", "");
|
||||
TriggerRestart("GameSettingsScreen::RenderingDeviceYes");
|
||||
} else {
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting)
|
||||
@ -1227,8 +1235,7 @@ void GameSettingsScreen::CallbackRenderingDevice(bool yes) {
|
||||
|
||||
void GameSettingsScreen::CallbackInflightFrames(bool yes) {
|
||||
if (yes) {
|
||||
g_Config.Save("GameSettingsScreen::InflightFramesYes");
|
||||
System_SendMessage("graphics_restart", "");
|
||||
TriggerRestart("GameSettingsScreen::InflightFramesYes");
|
||||
} else {
|
||||
g_Config.iInflightFrames = prevInflightFrames_;
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ protected:
|
||||
bool UseVerticalLayout() const;
|
||||
|
||||
private:
|
||||
void TriggerRestart(const char *why);
|
||||
|
||||
std::string gameID_;
|
||||
bool lastVertical_;
|
||||
UI::CheckBox *enableReportsCheckbox_;
|
||||
|
@ -420,7 +420,14 @@ void NewLanguageScreen::OnCompleted(DialogResult result) {
|
||||
void LogoScreen::Next() {
|
||||
if (!switched_) {
|
||||
switched_ = true;
|
||||
if (boot_filename.size()) {
|
||||
if (gotoGameSettings_) {
|
||||
if (boot_filename.size()) {
|
||||
screenManager()->switchScreen(new EmuScreen(boot_filename));
|
||||
} else {
|
||||
screenManager()->switchScreen(new MainScreen());
|
||||
}
|
||||
screenManager()->push(new GameSettingsScreen(boot_filename));
|
||||
} else if (boot_filename.size()) {
|
||||
screenManager()->switchScreen(new EmuScreen(boot_filename));
|
||||
} else {
|
||||
screenManager()->switchScreen(new MainScreen());
|
||||
|
@ -114,8 +114,8 @@ private:
|
||||
|
||||
class LogoScreen : public UIScreen {
|
||||
public:
|
||||
LogoScreen()
|
||||
: frames_(0), switched_(false) {}
|
||||
LogoScreen(bool gotoGameSettings = false)
|
||||
: gotoGameSettings_(gotoGameSettings) {}
|
||||
bool key(const KeyInput &key) override;
|
||||
bool touch(const TouchInput &touch) override;
|
||||
void update() override;
|
||||
@ -125,8 +125,9 @@ public:
|
||||
|
||||
private:
|
||||
void Next();
|
||||
int frames_;
|
||||
bool switched_;
|
||||
int frames_ = 0;
|
||||
bool switched_ = false;
|
||||
bool gotoGameSettings_ = false;
|
||||
};
|
||||
|
||||
class CreditsScreen : public UIDialogScreenWithBackground {
|
||||
|
@ -92,17 +92,18 @@
|
||||
#include "Core/WebServer.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
|
||||
#include "UI/BackgroundAudio.h"
|
||||
#include "UI/ControlMappingScreen.h"
|
||||
#include "UI/DiscordIntegration.h"
|
||||
#include "UI/EmuScreen.h"
|
||||
#include "UI/GameInfoCache.h"
|
||||
#include "UI/GPUDriverTestScreen.h"
|
||||
#include "UI/HostTypes.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
#include "UI/RemoteISOScreen.h"
|
||||
#include "UI/TiltEventProcessor.h"
|
||||
#include "UI/BackgroundAudio.h"
|
||||
#include "UI/TextureUtil.h"
|
||||
#include "UI/DiscordIntegration.h"
|
||||
#include "UI/GPUDriverTestScreen.h"
|
||||
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
#include "Common/KeyMap.h"
|
||||
@ -551,6 +552,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
const char *stateToLoad = 0;
|
||||
|
||||
bool gotBootFilename = false;
|
||||
bool gotoGameSettings = false;
|
||||
bool gotoTouchScreenTest = false;
|
||||
boot_filename = "";
|
||||
|
||||
// Parse command line
|
||||
@ -593,6 +596,10 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
g_Config.bPauseMenuExitsEmulator = true;
|
||||
if (!strcmp(argv[i], "--fullscreen"))
|
||||
g_Config.bFullScreen = true;
|
||||
if (!strcmp(argv[i], "--touchscreentest"))
|
||||
gotoTouchScreenTest = true;
|
||||
if (!strcmp(argv[i], "--gamesettings"))
|
||||
gotoGameSettings = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -628,7 +635,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
std::unique_ptr<FileLoader> fileLoader(ConstructFileLoader(boot_filename));
|
||||
if (!fileLoader->Exists()) {
|
||||
fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__ANDROID__)
|
||||
// Ignore and proceed.
|
||||
#else
|
||||
// Bail.
|
||||
@ -638,7 +645,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Can only boot one file");
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__ANDROID__)
|
||||
// Ignore and proceed.
|
||||
#else
|
||||
// Bail.
|
||||
@ -711,7 +718,12 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
}
|
||||
|
||||
screenManager = new ScreenManager();
|
||||
if (skipLogo) {
|
||||
if (gotoGameSettings) {
|
||||
screenManager->switchScreen(new LogoScreen(true));
|
||||
} else if (gotoTouchScreenTest) {
|
||||
screenManager->switchScreen(new MainScreen());
|
||||
screenManager->push(new TouchTestScreen());
|
||||
} else if (skipLogo) {
|
||||
screenManager->switchScreen(new EmuScreen(boot_filename));
|
||||
} else {
|
||||
screenManager->switchScreen(new LogoScreen());
|
||||
|
@ -290,6 +290,9 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
|
||||
// Unfortunately, glew will generate an invalid enum error, ignore.
|
||||
glGetError();
|
||||
|
||||
// Reset in case we're in a backend switch.
|
||||
ResetGLExtensions();
|
||||
|
||||
int contextFlags = g_Config.bGfxDebugOutput ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
|
||||
|
||||
HGLRC m_hrc = nullptr;
|
||||
|
@ -153,13 +153,20 @@ namespace W32Util
|
||||
moduleFilename.resize(sz);
|
||||
}
|
||||
|
||||
void ExitAndRestart() {
|
||||
void ExitAndRestart(bool overrideArgs, const std::string &args) {
|
||||
// This preserves arguments (for example, config file) and working directory.
|
||||
std::wstring workingDirectory;
|
||||
std::wstring moduleFilename;
|
||||
GetSelfExecuteParams(workingDirectory, moduleFilename);
|
||||
|
||||
const wchar_t *cmdline = RemoveExecutableFromCommandLine(GetCommandLineW());
|
||||
const wchar_t *cmdline;
|
||||
std::wstring wargs;
|
||||
if (overrideArgs) {
|
||||
wargs = ConvertUTF8ToWString(args);
|
||||
cmdline = wargs.c_str();
|
||||
} else {
|
||||
cmdline = RemoveExecutableFromCommandLine(GetCommandLineW());
|
||||
}
|
||||
ShellExecute(nullptr, nullptr, moduleFilename.c_str(), cmdline, workingDirectory.c_str(), SW_SHOW);
|
||||
|
||||
ExitProcess(0);
|
||||
|
@ -11,7 +11,7 @@ namespace W32Util
|
||||
BOOL CopyTextToClipboard(HWND hwnd, const char *text);
|
||||
BOOL CopyTextToClipboard(HWND hwnd, const std::wstring &wtext);
|
||||
void MakeTopMost(HWND hwnd, bool topMost);
|
||||
void ExitAndRestart();
|
||||
void ExitAndRestart(bool overrideArgs = false, const std::string &args = "");
|
||||
void GetSelfExecuteParams(std::wstring &workingDirectory, std::wstring &moduleFilename);
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,8 @@ static std::string langRegion;
|
||||
static std::string osName;
|
||||
static std::string gpuDriverVersion;
|
||||
|
||||
static std::string restartArgs;
|
||||
|
||||
HMENU g_hPopupMenus;
|
||||
int g_activeWindow = 0;
|
||||
|
||||
@ -283,6 +285,7 @@ void System_SendMessage(const char *command, const char *parameter) {
|
||||
PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0);
|
||||
}
|
||||
} else if (!strcmp(command, "graphics_restart")) {
|
||||
restartArgs = parameter == nullptr ? "" : parameter;
|
||||
if (IsDebuggerPresent()) {
|
||||
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_RESTART_EMUTHREAD, 0, 0);
|
||||
} else {
|
||||
@ -415,7 +418,14 @@ static bool DetectVulkanInExternalProcess() {
|
||||
std::vector<std::wstring> GetWideCmdLine() {
|
||||
wchar_t **wargv;
|
||||
int wargc = -1;
|
||||
wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
|
||||
// This is used for the WM_USER_RESTART_EMUTHREAD path.
|
||||
if (!restartArgs.empty()) {
|
||||
std::wstring wargs = ConvertUTF8ToWString("PPSSPP " + restartArgs);
|
||||
wargv = CommandLineToArgvW(wargs.c_str(), &wargc);
|
||||
restartArgs.clear();
|
||||
} else {
|
||||
wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
|
||||
}
|
||||
|
||||
std::vector<std::wstring> wideArgs(wargv, wargv + wargc);
|
||||
LocalFree(wargv);
|
||||
@ -447,12 +457,12 @@ static void WinMainInit() {
|
||||
}
|
||||
|
||||
static void WinMainCleanup() {
|
||||
if (g_Config.bRestartRequired) {
|
||||
W32Util::ExitAndRestart();
|
||||
}
|
||||
|
||||
net::Shutdown();
|
||||
CoUninitialize();
|
||||
|
||||
if (g_Config.bRestartRequired) {
|
||||
W32Util::ExitAndRestart(!restartArgs.empty(), restartArgs);
|
||||
}
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
|
||||
|
@ -399,6 +399,60 @@ extern "C" jstring Java_org_ppsspp_ppsspp_NativeApp_queryConfig
|
||||
return jresult;
|
||||
}
|
||||
|
||||
static void parse_args(std::vector<std::string> &args, const std::string value) {
|
||||
// Simple argument parser so we can take args from extra params.
|
||||
const char *p = value.c_str();
|
||||
|
||||
while (*p != '\0') {
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
if (*p == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
bool quote = false;
|
||||
std::string arg;
|
||||
|
||||
while (!done) {
|
||||
size_t sz = strcspn(p, "\"\\ \r\n\t");
|
||||
arg += std::string(p, sz);
|
||||
p += sz;
|
||||
|
||||
switch (*p) {
|
||||
case '"':
|
||||
quote = !quote;
|
||||
p++;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
p++;
|
||||
arg += std::string(p, 1);
|
||||
p++;
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// If it's not the above, it's whitespace.
|
||||
if (!quote) {
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
args.push_back(arg);
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
|
||||
(JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
|
||||
jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jcacheDir, jstring jshortcutParam,
|
||||
@ -455,18 +509,22 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
|
||||
|
||||
NativeGetAppInfo(&app_name, &app_nice_name, &landscape, &version);
|
||||
|
||||
// If shortcut_param is not empty, pass it as additional varargs argument to NativeInit() method.
|
||||
// If shortcut_param is not empty, pass it as additional arguments to the NativeInit() method.
|
||||
// NativeInit() is expected to treat extra argument as boot_filename, which in turn will start game immediately.
|
||||
// NOTE: Will only work if ppsspp started from Activity.onCreate(). Won't work if ppsspp app start from onResume().
|
||||
|
||||
if (shortcut_param.empty()) {
|
||||
const char *argv[2] = {app_name.c_str(), 0};
|
||||
NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
|
||||
} else {
|
||||
const char *argv[3] = {app_name.c_str(), shortcut_param.c_str(), 0};
|
||||
NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
|
||||
std::vector<const char *> args;
|
||||
std::vector<std::string> temp;
|
||||
args.push_back(app_name.c_str());
|
||||
if (!shortcut_param.empty()) {
|
||||
parse_args(temp, shortcut_param);
|
||||
for (const auto &arg : temp) {
|
||||
args.push_back(arg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
NativeInit((int)args.size(), &args[0], user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
|
||||
|
||||
retry:
|
||||
// Now that we've loaded config, set javaGL.
|
||||
javaGL = NativeQueryConfig("androidJavaGL") == "true";
|
||||
@ -968,14 +1026,21 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) {
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) {
|
||||
ILOG("NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate);
|
||||
display_xres = xres;
|
||||
display_yres = yres;
|
||||
display_dpi_x = dpi;
|
||||
display_dpi_y = dpi;
|
||||
display_hz = refreshRate;
|
||||
bool changed = false;
|
||||
changed = changed || display_xres != xres || display_yres != yres;
|
||||
changed = changed || display_dpi_x != dpi || display_dpi_y != dpi;
|
||||
changed = changed || display_hz != refreshRate;
|
||||
|
||||
recalculateDpi();
|
||||
NativeResized();
|
||||
if (changed) {
|
||||
display_xres = xres;
|
||||
display_yres = yres;
|
||||
display_dpi_x = dpi;
|
||||
display_dpi_y = dpi;
|
||||
display_hz = refreshRate;
|
||||
|
||||
recalculateDpi();
|
||||
NativeResized();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_computeDesiredBackbufferDimensions() {
|
||||
|
@ -28,25 +28,17 @@ import android.os.PowerManager;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.InputType;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.Gravity;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnSystemUiVisibilityChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
@ -59,7 +51,7 @@ import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
public abstract class NativeActivity extends Activity {
|
||||
// Remember to loadLibrary your JNI .so in a static {} block
|
||||
|
||||
// Adjust these as necessary
|
||||
@ -81,6 +73,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
protected NativeRenderer nativeRenderer;
|
||||
|
||||
private String shortcutParam = "";
|
||||
private static String overrideShortcutParam = null;
|
||||
|
||||
public static String runCommand;
|
||||
public static String commandParameter;
|
||||
@ -91,7 +84,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
|
||||
private boolean sustainedPerfSupported;
|
||||
|
||||
private boolean navigationHidden;
|
||||
private View navigationCallbackView = null;
|
||||
|
||||
// audioFocusChangeListener to listen to changes in audio state
|
||||
@ -116,20 +108,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
private String inputPlayerADesc;
|
||||
|
||||
private PowerSaveModeReceiver mPowerSaveModeReceiver = null;
|
||||
|
||||
private SizeManager sizeManager = null;
|
||||
private static LocationHelper mLocationHelper;
|
||||
private static CameraHelper mCameraHelper;
|
||||
|
||||
private float densityDpi;
|
||||
private float refreshRate;
|
||||
private int pixelWidth;
|
||||
private int pixelHeight;
|
||||
|
||||
private int safeInsetLeft = 0;
|
||||
private int safeInsetRight = 0;
|
||||
private int safeInsetTop = 0;
|
||||
private int safeInsetBottom = 0;
|
||||
|
||||
private static final String[] permissionsForStorage = {
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
};
|
||||
@ -319,9 +301,11 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
|
||||
String model = Build.MANUFACTURER + ":" + Build.MODEL;
|
||||
String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
|
||||
String shortcut = overrideShortcutParam == null ? shortcutParam : overrideShortcutParam;
|
||||
overrideShortcutParam = null;
|
||||
|
||||
NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate);
|
||||
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, cacheDir, shortcutParam, Build.VERSION.SDK_INT, Build.BOARD);
|
||||
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, cacheDir, shortcut, Build.VERSION.SDK_INT, Build.BOARD);
|
||||
|
||||
// Allow C++ to tell us to use JavaGL or not.
|
||||
javaGL = "true".equalsIgnoreCase(NativeApp.queryConfig("androidJavaGL"));
|
||||
@ -437,7 +421,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
} else {
|
||||
Log.e(TAG, "updateSystemUiVisibility: decor view not yet created, ignoring for now");
|
||||
}
|
||||
updateDisplayMeasurements();
|
||||
sizeManager.checkDisplayMeasurements();
|
||||
}
|
||||
|
||||
// Need API 11 to check for existence of a vibrator? Zany.
|
||||
@ -467,48 +451,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
// Tells the render loop thread to exit, so we can restart it.
|
||||
public native void exitEGLRenderLoop();
|
||||
|
||||
public void getDesiredBackbufferSize(Point sz) {
|
||||
NativeApp.computeDesiredBackbufferDimensions();
|
||||
sz.x = NativeApp.getDesiredBackbufferWidth();
|
||||
sz.y = NativeApp.getDesiredBackbufferHeight();
|
||||
}
|
||||
|
||||
private SurfaceView getSurfaceView() {
|
||||
if (mGLSurfaceView != null) {
|
||||
return mGLSurfaceView;
|
||||
} else {
|
||||
return mSurfaceView;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
public void updateDisplayMeasurements() {
|
||||
Display display = 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 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
display.getRealMetrics(metrics);
|
||||
} else {
|
||||
display.getMetrics(metrics);
|
||||
}
|
||||
|
||||
// Later on, we have the exact pixel size so let's just use it.
|
||||
SurfaceView view = getSurfaceView();
|
||||
if (view != null) {
|
||||
metrics.widthPixels = view.getWidth();
|
||||
metrics.heightPixels = view.getHeight();
|
||||
}
|
||||
densityDpi = metrics.densityDpi;
|
||||
refreshRate = display.getRefreshRate();
|
||||
|
||||
NativeApp.setDisplayParameters(metrics.widthPixels, metrics.heightPixels, (int) densityDpi, refreshRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
sizeManager = new SizeManager(this);
|
||||
TextRenderer.init(this);
|
||||
shuttingDown = false;
|
||||
registerCallbacks();
|
||||
@ -516,7 +462,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
// 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.
|
||||
updateDisplayMeasurements();
|
||||
sizeManager.updateDisplayMeasurements();
|
||||
|
||||
if (!initialized) {
|
||||
Initialize();
|
||||
@ -540,7 +486,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
mGLSurfaceView = new NativeGLView(this);
|
||||
nativeRenderer = new NativeRenderer(this);
|
||||
mGLSurfaceView.setEGLContextClientVersion(2);
|
||||
mGLSurfaceView.getHolder().addCallback(NativeActivity.this);
|
||||
sizeManager.setSurfaceView(mGLSurfaceView);
|
||||
|
||||
// Setup the GLSurface and ask android for the correct
|
||||
// Number of bits for r, g, b, a, depth and stencil components
|
||||
@ -572,93 +518,28 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
}
|
||||
mGLSurfaceView.setRenderer(nativeRenderer);
|
||||
setContentView(mGLSurfaceView);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
mGLSurfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
|
||||
checkInsets(windowInsets);
|
||||
return windowInsets;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
|
||||
mSurfaceView = new NativeSurfaceView(NativeActivity.this);
|
||||
mSurfaceView.getHolder().addCallback(NativeActivity.this);
|
||||
sizeManager.setSurfaceView(mSurfaceView);
|
||||
Log.i(TAG, "setcontentview before");
|
||||
setContentView(mSurfaceView);
|
||||
Log.i(TAG, "setcontentview after");
|
||||
ensureRenderLoop();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
mSurfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
|
||||
checkInsets(windowInsets);
|
||||
return windowInsets;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Point desiredSize = new Point();
|
||||
private int badOrientationCount = 0;
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
pixelWidth = holder.getSurfaceFrame().width();
|
||||
pixelHeight = holder.getSurfaceFrame().height();
|
||||
|
||||
// Workaround for terrible bug when locking and unlocking the screen in landscape mode on Nexus 5X.
|
||||
int requestedOr = getRequestedOrientation();
|
||||
boolean requestedPortrait = requestedOr == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOr == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
||||
boolean detectedPortrait = pixelHeight > pixelWidth;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && badOrientationCount < 3 && requestedPortrait != detectedPortrait && requestedOr != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
|
||||
Log.e(TAG, "Bad orientation detected (w=" + pixelWidth + " h=" + pixelHeight + "! Recreating activity.");
|
||||
badOrientationCount++;
|
||||
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" + (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? " (sdk version)" : ""));
|
||||
}
|
||||
|
||||
Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr);
|
||||
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.
|
||||
Log.d(TAG, "Setting fixed size " + desiredSize.x + " x " + desiredSize.y);
|
||||
holder.setFixedSize(desiredSize.x, desiredSize.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
updateSustainedPerformanceMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
Log.v(TAG, "surfaceChanged: isCreating:" + holder.isCreating() + " holder: " + holder.toString());
|
||||
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.w(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();
|
||||
mSurface = holder.getSurface();
|
||||
public void notifySurface(Surface surface) {
|
||||
mSurface = surface;
|
||||
if (!javaGL) {
|
||||
// If we got a surface, this starts the thread. If not, it doesn't.
|
||||
if (mSurface == null) {
|
||||
@ -670,17 +551,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
updateSustainedPerformanceMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mSurface = null;
|
||||
Log.w(TAG, "Surface destroyed.");
|
||||
if (!javaGL) {
|
||||
joinRenderLoopThread();
|
||||
}
|
||||
// Autosize the next created surface.
|
||||
holder.setSizeFromLayout();
|
||||
}
|
||||
|
||||
// Invariants: After this, mRenderLoopThread will be set, and the thread will be running.
|
||||
protected synchronized void ensureRenderLoop() {
|
||||
if (javaGL) {
|
||||
@ -728,20 +598,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
return;
|
||||
}
|
||||
|
||||
decorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
|
||||
@Override
|
||||
public void onSystemUiVisibilityChange(int 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);
|
||||
Log.i(TAG, "decorView: " + decorView.getWidth() + "x" + decorView.getHeight());
|
||||
updateDisplayMeasurements();
|
||||
}
|
||||
});
|
||||
sizeManager.setupSystemUiCallback(decorView);
|
||||
navigationCallbackView = decorView;
|
||||
}
|
||||
|
||||
@ -776,6 +633,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
mSurfaceView.onDestroy();
|
||||
mSurfaceView = null;
|
||||
}
|
||||
sizeManager.setSurfaceView(null);
|
||||
if (mPowerSaveModeReceiver != null) {
|
||||
mPowerSaveModeReceiver.destroy(this);
|
||||
mPowerSaveModeReceiver = null;
|
||||
@ -864,29 +722,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
}
|
||||
}
|
||||
|
||||
private void checkInsets(WindowInsets insets) {
|
||||
if (insets == null) {
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
DisplayCutout cutout = insets.getDisplayCutout();
|
||||
if (cutout != null) {
|
||||
safeInsetLeft = cutout.getSafeInsetLeft();
|
||||
safeInsetRight = cutout.getSafeInsetRight();
|
||||
safeInsetTop = cutout.getSafeInsetTop();
|
||||
safeInsetBottom = cutout.getSafeInsetBottom();
|
||||
Log.i(TAG, "Safe insets: left: " + safeInsetLeft + " right: " + safeInsetRight + " top: " + safeInsetTop + " bottom: " + safeInsetBottom);
|
||||
} else {
|
||||
Log.i(TAG, "Cutout was null");
|
||||
safeInsetLeft = 0;
|
||||
safeInsetRight = 0;
|
||||
safeInsetTop = 0;
|
||||
safeInsetBottom = 0;
|
||||
}
|
||||
NativeApp.sendMessage("safe_insets", safeInsetLeft + ":" + safeInsetRight + ":" + safeInsetTop + ":" + safeInsetBottom);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
Log.i(TAG, "onAttachedToWindow");
|
||||
@ -905,7 +740,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
densityDpi = (float)newConfig.densityDpi;
|
||||
sizeManager.updateDpi((float)newConfig.densityDpi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -914,7 +749,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
// onConfigurationChanged not called on multi-window change
|
||||
Log.i(TAG, "onMultiWindowModeChanged: isInMultiWindowMode = " + isInMultiWindowMode);
|
||||
super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
|
||||
updateDisplayMeasurements();
|
||||
sizeManager.checkDisplayMeasurements();
|
||||
}
|
||||
|
||||
// keep this static so we can call this even if we don't
|
||||
@ -1420,6 +1255,9 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
recreate();
|
||||
} else if (command.equals("graphics_restart")) {
|
||||
Log.i(TAG, "graphics_restart");
|
||||
if (params != null && !params.equals("")) {
|
||||
overrideShortcutParam = params;
|
||||
}
|
||||
shuttingDown = true;
|
||||
recreate();
|
||||
} else if (command.equals("ask_permission") && params.equals("storage")) {
|
||||
@ -1456,6 +1294,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
if (params.equals("ingame")) {
|
||||
// Keep the screen bright - very annoying if it goes dark when tilting away
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
updateSustainedPerformanceMode();
|
||||
} else {
|
||||
// Only keep the screen bright ingame.
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
@ -12,6 +12,8 @@ public class PpssppActivity extends NativeActivity {
|
||||
private static final String TAG = "PpssppActivity";
|
||||
// Key used by shortcut.
|
||||
public static final String SHORTCUT_EXTRA_KEY = "org.ppsspp.ppsspp.Shortcuts";
|
||||
// Key used for debugging.
|
||||
public static final String ARGS_EXTRA_KEY = "org.ppsspp.ppsspp.Args";
|
||||
|
||||
private static boolean m_hasUnsupportedABI = false;
|
||||
private static boolean m_hasNoNativeBinary = false;
|
||||
@ -78,14 +80,18 @@ public class PpssppActivity extends NativeActivity {
|
||||
if (data != null) {
|
||||
String path = intent.getData().getPath();
|
||||
Log.i(TAG, "Found Shortcut Parameter in data: " + path);
|
||||
super.setShortcutParam(path);
|
||||
super.setShortcutParam("\"" + path.replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
|
||||
// Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
String param = getIntent().getStringExtra(SHORTCUT_EXTRA_KEY);
|
||||
String args = getIntent().getStringExtra(ARGS_EXTRA_KEY);
|
||||
Log.e(TAG, "Got ACTION_VIEW without a valid uri, trying param");
|
||||
if (param != null) {
|
||||
Log.i(TAG, "Found Shortcut Parameter in extra-data: " + param);
|
||||
super.setShortcutParam(getIntent().getStringExtra(SHORTCUT_EXTRA_KEY));
|
||||
super.setShortcutParam("\"" + param.replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
|
||||
} else if (args != null) {
|
||||
Log.i(TAG, "Found args parameter in extra-data: " + args);
|
||||
super.setShortcutParam(args);
|
||||
} else {
|
||||
Log.e(TAG, "Shortcut missing parameter!");
|
||||
super.setShortcutParam("");
|
||||
|
214
android/src/org/ppsspp/ppsspp/SizeManager.java
Normal file
214
android/src/org/ppsspp/ppsspp/SizeManager.java
Normal file
@ -0,0 +1,214 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import java.lang.Runnable;
|
||||
|
||||
public class SizeManager implements SurfaceHolder.Callback {
|
||||
private static String TAG = "PPSSPPSizeManager";
|
||||
|
||||
final NativeActivity activity;
|
||||
SurfaceView surfaceView = null;
|
||||
|
||||
private int safeInsetLeft = 0;
|
||||
private int safeInsetRight = 0;
|
||||
private int safeInsetTop = 0;
|
||||
private int safeInsetBottom = 0;
|
||||
|
||||
private float densityDpi;
|
||||
private float refreshRate;
|
||||
private int pixelWidth;
|
||||
private int pixelHeight;
|
||||
|
||||
private boolean navigationHidden = false;
|
||||
private boolean displayUpdatePending = false;
|
||||
|
||||
private Point desiredSize = new Point();
|
||||
private int badOrientationCount = 0;
|
||||
|
||||
public SizeManager(final NativeActivity a) {
|
||||
activity = a;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public void setSurfaceView(SurfaceView view) {
|
||||
surfaceView = view;
|
||||
if (surfaceView == null)
|
||||
return;
|
||||
|
||||
surfaceView.getHolder().addCallback(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
surfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
|
||||
updateInsets(windowInsets);
|
||||
return windowInsets;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
pixelWidth = holder.getSurfaceFrame().width();
|
||||
pixelHeight = holder.getSurfaceFrame().height();
|
||||
|
||||
// Workaround for terrible bug when locking and unlocking the screen in landscape mode on Nexus 5X.
|
||||
int requestedOr = activity.getRequestedOrientation();
|
||||
boolean requestedPortrait = requestedOr == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOr == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
||||
boolean detectedPortrait = pixelHeight > pixelWidth;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && badOrientationCount < 3 && requestedPortrait != detectedPortrait && requestedOr != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
|
||||
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" + (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? " (sdk version)" : ""));
|
||||
}
|
||||
|
||||
Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr);
|
||||
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.
|
||||
Log.d(TAG, "Setting fixed 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.toString());
|
||||
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.w(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();
|
||||
|
||||
activity.notifySurface(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
activity.notifySurface(null);
|
||||
|
||||
// Autosize the next created surface.
|
||||
holder.setSizeFromLayout();
|
||||
}
|
||||
|
||||
public void checkDisplayMeasurements() {
|
||||
if (displayUpdatePending) {
|
||||
return;
|
||||
}
|
||||
displayUpdatePending = true;
|
||||
|
||||
final Runnable updater = new Runnable() {
|
||||
public void run() {
|
||||
Log.d(TAG, "checkDisplayMeasurements: checking now");
|
||||
updateDisplayMeasurements();
|
||||
}
|
||||
};
|
||||
|
||||
final Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.postDelayed(updater, 10);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
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 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
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);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public void setupSystemUiCallback(final View view) {
|
||||
view.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
|
||||
@Override
|
||||
public void onSystemUiVisibilityChange(int 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);
|
||||
Log.i(TAG, "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();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
private void updateInsets(WindowInsets insets) {
|
||||
if (insets == null) {
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
DisplayCutout cutout = insets.getDisplayCutout();
|
||||
if (cutout != null) {
|
||||
safeInsetLeft = cutout.getSafeInsetLeft();
|
||||
safeInsetRight = cutout.getSafeInsetRight();
|
||||
safeInsetTop = cutout.getSafeInsetTop();
|
||||
safeInsetBottom = cutout.getSafeInsetBottom();
|
||||
Log.i(TAG, "Safe insets: left: " + safeInsetLeft + " right: " + safeInsetRight + " top: " + safeInsetTop + " bottom: " + safeInsetBottom);
|
||||
} else {
|
||||
Log.i(TAG, "Safe insets: Cutout was null");
|
||||
safeInsetLeft = 0;
|
||||
safeInsetRight = 0;
|
||||
safeInsetTop = 0;
|
||||
safeInsetBottom = 0;
|
||||
}
|
||||
NativeApp.sendMessage("safe_insets", safeInsetLeft + ":" + safeInsetRight + ":" + safeInsetTop + ":" + safeInsetBottom);
|
||||
}
|
||||
}
|
||||
}
|
@ -38,9 +38,9 @@ PFNGLISVERTEXARRAYOESPROC glIsVertexArrayOES;
|
||||
|
||||
GLExtensions gl_extensions;
|
||||
std::string g_all_gl_extensions;
|
||||
std::set<std::string> g_set_gl_extensions;
|
||||
static std::set<std::string> g_set_gl_extensions;
|
||||
std::string g_all_egl_extensions;
|
||||
std::set<std::string> g_set_egl_extensions;
|
||||
static std::set<std::string> g_set_egl_extensions;
|
||||
|
||||
static bool extensionsDone = false;
|
||||
static bool useCoreContext = false;
|
||||
@ -564,6 +564,15 @@ void SetGLCoreContext(bool flag) {
|
||||
gl_extensions.IsCoreContext = useCoreContext;
|
||||
}
|
||||
|
||||
void ResetGLExtensions() {
|
||||
extensionsDone = false;
|
||||
|
||||
gl_extensions = {};
|
||||
gl_extensions.IsCoreContext = useCoreContext;
|
||||
g_all_gl_extensions.clear();
|
||||
g_all_egl_extensions.clear();
|
||||
}
|
||||
|
||||
static const char *glsl_fragment_prelude =
|
||||
"#ifdef GL_ES\n"
|
||||
"precision mediump float;\n"
|
||||
|
@ -120,5 +120,6 @@ extern std::string g_all_egl_extensions;
|
||||
|
||||
void CheckGLExtensions();
|
||||
void SetGLCoreContext(bool flag);
|
||||
void ResetGLExtensions();
|
||||
|
||||
std::string ApplyGLSLPrelude(const std::string &source, uint32_t stage);
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "ui/view.h"
|
||||
|
||||
ScreenManager::ScreenManager() {
|
||||
nextScreen_ = 0;
|
||||
uiContext_ = 0;
|
||||
dialogFinished_ = 0;
|
||||
}
|
||||
@ -18,7 +17,7 @@ ScreenManager::~ScreenManager() {
|
||||
}
|
||||
|
||||
void ScreenManager::switchScreen(Screen *screen) {
|
||||
if (screen == nextScreen_) {
|
||||
if (!nextStack_.empty() && screen == nextStack_.front().screen) {
|
||||
ELOG("Already switching to this screen");
|
||||
return;
|
||||
}
|
||||
@ -26,23 +25,23 @@ void ScreenManager::switchScreen(Screen *screen) {
|
||||
// will only become apparent if the dialog is closed. The previous screen will stick around
|
||||
// until that switch.
|
||||
// TODO: is this still true?
|
||||
if (nextScreen_ != 0) {
|
||||
ELOG("Already had a nextScreen_! Asynchronous open while doing something? Deleting the new screen.");
|
||||
if (!nextStack_.empty()) {
|
||||
ELOG("Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen.");
|
||||
delete screen;
|
||||
return;
|
||||
}
|
||||
if (screen == 0) {
|
||||
if (screen == nullptr) {
|
||||
WLOG("Swiching to a zero screen, this can't be good");
|
||||
}
|
||||
if (stack_.empty() || screen != stack_.back().screen) {
|
||||
nextScreen_ = screen;
|
||||
nextScreen_->setScreenManager(this);
|
||||
screen->setScreenManager(this);
|
||||
nextStack_.push_back({ screen, 0 });
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenManager::update() {
|
||||
std::lock_guard<std::recursive_mutex> guard(inputLock_);
|
||||
if (nextScreen_) {
|
||||
if (!nextStack_.empty()) {
|
||||
switchToNext();
|
||||
}
|
||||
|
||||
@ -53,22 +52,25 @@ void ScreenManager::update() {
|
||||
|
||||
void ScreenManager::switchToNext() {
|
||||
std::lock_guard<std::recursive_mutex> guard(inputLock_);
|
||||
if (!nextScreen_) {
|
||||
ELOG("switchToNext: No nextScreen_!");
|
||||
if (nextStack_.empty()) {
|
||||
ELOG("switchToNext: No nextStack_!");
|
||||
}
|
||||
|
||||
Layer temp = {0, 0};
|
||||
Layer temp = {nullptr, 0};
|
||||
if (!stack_.empty()) {
|
||||
temp = stack_.back();
|
||||
stack_.pop_back();
|
||||
}
|
||||
Layer newLayer = {nextScreen_, 0};
|
||||
stack_.push_back(newLayer);
|
||||
stack_.push_back(nextStack_.front());
|
||||
if (temp.screen) {
|
||||
delete temp.screen;
|
||||
}
|
||||
nextScreen_ = 0;
|
||||
UI::SetFocusedView(0);
|
||||
UI::SetFocusedView(nullptr);
|
||||
|
||||
for (size_t i = 1; i < nextStack_.size(); ++i) {
|
||||
stack_.push_back(nextStack_[i]);
|
||||
}
|
||||
nextStack_.clear();
|
||||
}
|
||||
|
||||
bool ScreenManager::touch(const TouchInput &touch) {
|
||||
@ -197,19 +199,16 @@ Screen *ScreenManager::topScreen() const {
|
||||
|
||||
void ScreenManager::shutdown() {
|
||||
std::lock_guard<std::recursive_mutex> guard(inputLock_);
|
||||
for (auto x = stack_.begin(); x != stack_.end(); x++)
|
||||
delete x->screen;
|
||||
for (auto layer : stack_)
|
||||
delete layer.screen;
|
||||
stack_.clear();
|
||||
delete nextScreen_;
|
||||
nextScreen_ = nullptr;
|
||||
for (auto layer : nextStack_)
|
||||
delete layer.screen;
|
||||
nextStack_.clear();
|
||||
}
|
||||
|
||||
void ScreenManager::push(Screen *screen, int layerFlags) {
|
||||
std::lock_guard<std::recursive_mutex> guard(inputLock_);
|
||||
if (nextScreen_ && stack_.empty()) {
|
||||
// we're during init, this is OK
|
||||
switchToNext();
|
||||
}
|
||||
screen->setScreenManager(this);
|
||||
if (screen->isTransparent()) {
|
||||
layerFlags |= LAYER_TRANSPARENT;
|
||||
@ -224,7 +223,10 @@ void ScreenManager::push(Screen *screen, int layerFlags) {
|
||||
touch(input);
|
||||
|
||||
Layer layer = {screen, layerFlags};
|
||||
stack_.push_back(layer);
|
||||
if (nextStack_.empty())
|
||||
stack_.push_back(layer);
|
||||
else
|
||||
nextStack_.push_back(layer);
|
||||
}
|
||||
|
||||
void ScreenManager::pop() {
|
||||
|
@ -147,7 +147,6 @@ private:
|
||||
void switchToNext();
|
||||
void processFinishDialog();
|
||||
|
||||
Screen *nextScreen_;
|
||||
UIContext *uiContext_;
|
||||
Draw::DrawContext *thin3DContext_;
|
||||
|
||||
@ -166,4 +165,5 @@ private:
|
||||
// Dialog stack. These are shown "on top" of base screens and the Android back button works as expected.
|
||||
// Used for options, in-game menus and other things you expect to be able to back out from onto something.
|
||||
std::vector<Layer> stack_;
|
||||
std::vector<Layer> nextStack_;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user