I have multiple classes that implement Screen.
I want to, say, have the Main Menu screen portrait, then the Play Screen landscape. Is there anyway of changing the orientation dynamically?
I thought I could just start another Activity and have the Play Screen extend Game. And the new Activity would intialize the Play Screen. But it appears that you can't call startActivity or the like, obviously, as LibGDX is platform independent.
I use Gdx.graphics.getWidth() and Gdx.graphics.getHeight() to align Sprites and Actors, so it looks "right" on different devices.
I've also tried swapping the Gdx.graphics.getWidth() and Gdx.graphics.getHeight(), respectively, but can't seem to get the position of sprites and actors correct.
Also, in my manifest I have orientation="landscape".
Here are some images that should make more sense.
So this is my Main Menu in landscape:
And this is my Main Menu in portrait:
The position and size of Actors and Sprites are all based on Gdx.graphics.getWidth() and Gdx.graphics.getHeight(). The only thing that changes between the two images is orientation="landscape" and orientation="portrait" in my manifest.
Now I want my Main Menu in portrait but the Play Screen, where the game is on, should be in landscape.
I initially started working on the Play Screen and the sizes and positions where set based on orientation="landscape", and now that I am working on the Main Menu it is based on orientation="portrait". Hence why I want to change the orientation dynamically.
This is a good question :) I develop noone's answer (which is correct)
How to set lanscape screen with Android sdk specific classes ?
And how to import android classes in a libgdx project ?
First of all note that Android classes can only be imported in the android project and not in the core. So there we save the Activity in a platform dependant object. Here is my AndroidLauncher:
import android.os.Bundle;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.mygdx.game.MyGdxGame;
import com.mygdx.game.util.Platform;
public class AndroidLauncher extends AndroidApplication {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
PlatformAndroid platform = new PlatformAndroid();
platform.setActivity(this);
initialize(new MyGdxGame((Platform) platform ), cfg);
}
}
PlatformAndroid implements Platform. These two classes are made to access platform specific objects. Let's look at them :
public interface Platform {
public void SetOrientation(String string);
}
and
package com.mygdx.game.android;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.mygdx.game.util.Platform;
public class PlatformAndroid extends AndroidApplication implements Platform {
private Activity activity;
#Override
public void SetOrientation(String string) {
if (string == "landscape"){
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
public void setActivity(Activity activity){ this.activity = activity; }
}
You can also create a PLatformDesktop called by the desktop launcher. Anyway, keep the platform variable in your classes and when you want to set the screen to landscape just call:
platform.SetOrientation("landscape");
You should not have multiple Activities. To learn how to switch the orientation programmatically you can have a look at this link.
As you said, LibGDX is platform-independent. That's why you cannot access your Android-Activity from your "core" code. To learn how to workaround that, have a look at Interfacing with platform specific code.
When you call your interface to change the orientation from your game when doing a Screen transition, LibGDX will automatically call resize(width, height) with the new values and you can align your Stage and so on according to the new values.
I had the same problem and this solved it:
#Override
public void resize(int width, int height) {
stage.getViewport().setScreenSize(width, height);
}
For some reason, even though the screen resolution changed, the stage didn't know that. So I've told it to the stage.
Just create a interface in core project and and declare a method with any name than implement that interface in your AndroidLauncher class. Give definition of your method.
For me GameOrien.java is interface having method declaration
public interface GameOrien {
public static final int PORTRAIT=1;
public static final int LANDSCAPE=2;
void setOrientation(int orientation);
}
In AndroidLauncher.java class which is in Android project.
public class AndroidLauncher extends AndroidApplication implements GameOrien {
**...**
#Override
public void setOrientation(int orientation) {
if(orientation==PORTRAIT)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
else if(orientation==LANDSCAPE)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
When you want to change orientation for GamePlay just call setOrientaion() method of interface. Your orientation changed.
Related
I am learning Android's new SplashScreen API introduced with Android 12. I have so far gotten it to work on my Emulator and Google Pixel 4A, but I want to increase its duration. In my Splash Screen I do not want a fancy animation, I just want a static drawable.
I know, I know (sigh) some of you might be thinking, that I should not increase the duration and I know there are several good arguments in favor of not doing so. However, for me the duration of a splash screen with a non animated drawable is so brief (less than a second), I think it raises an accessibility concern, especially so since it cannot be disabled (ironically). Simply, the organization behind the product or its brand/product identity cannot be properly absorbed or recognized by a new user at that size and in that time, rendering the new splash screen redundant.
I see the property windowSplashScreenAnimationDuration in the theme for the splash screen (shown below), but this has no effect on the duration presumably because I am not animating.
<style name="Theme.App.starting" parent="Theme.SplashScreen">
<!--Set the splash screen background, animated icon, and animation duration.-->
<item name="windowSplashScreenBackground">#color/gold</item>
<!-- Use windowSplashScreenAnimatedIcon to add either a drawable or an
animated drawable. One of these is required-->
<item name="windowSplashScreenAnimatedIcon">#drawable/accessibility_today</item>
<item name="windowSplashScreenAnimationDuration">300</item> <!--# Required for-->
<!--# animated icons-->
<!--Set the theme of the activity that directly follows your splash screen-->
<item name="postSplashScreenTheme">#style/Theme.MyActivity</item>
<item name="android:windowSplashScreenBrandingImage">#drawable/wculogo</item>
</style>
Is there a straightforward way to extend the duration of a non animated splash screen?
As I was writing this question and almost ready to post it, I stumbled on the method setKeepOnScreenCondition (below) that belongs to the splashScreen that we must install on the onCreate of our main activity. I thought it seemed wasteful not to post this, given there are no other posts on this topic and no such similar answers to other related questions (as of Jan 2022).
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
plashScreen.setKeepOnScreenCondition(....);
Upon inspecting it I found this method receives an instance of the splashScreen.KeepOnScreenCondition() interface for which the implementation must supply the following method signature implementation:
public boolean shouldKeepOnScreen()
It seems this method will be called by the splash screen and retain the splash screen visibly until it returns false. This is where the light bulb moment I so love about programming occurred.
What if I use a boolean initialized as true, and set it to false after a delay? That hunch turned out to work. Here is my solution. It seems to work and I thought it would be useful to others. Presumably instead of using a Handler for a delay, one could also use this to set the boolean after some process had completed.
package com.example.mystuff.myactivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.splashscreen.SplashScreen;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private boolean keep = true;
private final int DELAY = 1250;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Handle the splash screen transition.
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
//Keep returning false to Should Keep On Screen until ready to begin.
splashScreen.setKeepOnScreenCondition(new SplashScreen.KeepOnScreenCondition() {
#Override
public boolean shouldKeepOnScreen() {
return keep;
}
});
Handler handler = new Handler();
handler.postDelayed(runner, DELAY);
}
/**Will cause a second process to run on the main thread**/
private final Runnable runner = new Runnable() {
#Override
public void run() {
keep = false;
}
};
}
If you are into Java Lambdas an even nicer and more compact solution is as follows:
package com.example.mystuff.myactivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.splashscreen.SplashScreen;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private boolean keep = true;
private final int DELAY = 1250;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Handle the splash screen transition.
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Keep returning false to Should Keep On Screen until ready to begin.
splashScreen.setKeepOnScreenCondition(() -> keep);
Handler handler = new Handler();
handler.postDelayed(() -> keep = false, DELAY);;
}
}
If you have comments or feedback (besides telling me I should not increase the duration of the splash screen), or a better way please do comment or respond with additional answers.
in Kotlin:
var keepSplashOnScreen = true
val delay = 2000L
installSplashScreen().setKeepOnScreenCondition { keepSplashOnScreen }
Handler(Looper.getMainLooper()).postDelayed({ keepSplashOnScreen = false }, delay)
you can put this into onCreate fun before super.onCreate calling (in activity with LAUNCHER intent filter in Manifest)
One proxy way could be to use
runBlocking { delay(1200) } in onCreate method, to keep on main thread for some specific time.
I would create an app for get the double tap also if the app is in background.
I create this code:
public class MainActivity extends Activity implements
GestureDetector.OnGestureListener,
GestureDetector.OnDoubleTapListener
{
private static final String DEBUG_TAG = "Gestures";
private GestureDetectorCompat mDetector;
private int counter = 0;
// Called when the activity is first created.
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDetector = new GestureDetectorCompat(this,this);
mDetector.setOnDoubleTapListener(this);
}
#Override
public boolean onDoubleTap(MotionEvent event)
{
counter++;
Log.d(DEBUG_TAG, String.valueOf(counter));
return true;
}
//..........................
}
if the app is open in the log i see the number of count of double tap increase, if the app work in background the number is blocked.
There is a way for fix it? or i have to create a services? i need a grafic app and service, there is a way for create just one with both things?
Thanks
There isn't an easy answer to this. Normally it is NOT possibile because an App cannot interact with other pieces of Android interface that is OUTSIDE the App itselfs. But if the device has Root Permissions it's possibile to directly read the Touchscreen and intercept all touch events.
An alternative method that not requires Root exists but I discurage to use it: place a fullscreen View that acts as a transparent layer and that intercepts all the events. However this method has few disadvantages: slows down graphic performance of WHOLE device (expecially while running games), could interfere with user experience while touching interactive areas (buttons, checkboxes, etc...) and however could not work well by loosing some touching events.
I make a game with Java and LibGdx
It's a game of skill with a time limit, and the problem is the player can push home button to pause app, and go to task manager, and can see preview of app to seek what he has to find without counting time
So, I would like to hide the preview of the app when the player push home button to pause
What I tried to do
I override pause and resume handler
#Override
public void pause() {
Gdx.app.log("LibGDX", "pause");
state = State.PAUSE;
Gdx.graphics.setContinuousRendering(false);
Gdx.graphics.requestRendering();
}
#Override
public void resume() {
Gdx.app.log("LibGDX", "resume");
state = State.RUN;
Gdx.graphics.setContinuousRendering(true);
}
and main part of my public void render(float) function
switch (state)
{
case RUN:
// game
break;
case PAUSE:
// a black rectangle on screen
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(Color.BLACK);
shapeRenderer.rect(0, 0, GameScreen.WIDTH, GameScreen.HEIGHT);
shapeRenderer.end();
break;
default:
break;
}
log tell me that pause and resume are indeed invoked
but in task manager, I still see the game and not the black rectangle
Update 1
to Ridcully answer :
I tried what you suggested
package com.mygdx.game;
import android.os.Bundle;
import android.view.WindowManager;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
public class AndroidLauncher extends AndroidApplication {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
// --
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
// --
initialize(new MyGame(), config);
}
}
But same thing, I still see the screenshot
I'm with Android Studio 2.1
My smartphone: Oneplus One
and Android 6.0.1
Do you have an idea ? thanks
There is a flag for that. You can use this little method, e.g. in onCreate() to prevent Android from creating a 'screenshot' for the 'recent activities' list. You can activate/deactivate as you want, e.g. only activate it when the actual game board is visible etc.
/**
* Sets/clears FLAG_SECURE which prevents system from creating screenshots for 'recent activities' list.
* Flag should be set while user is in vault.
*
* #param set
*/
protected void setWindowFlagSecure(boolean set) {
if (set) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
EDIT
I just found this SO answer, regarding Libgdx applications: Seems you have to set the flag AFTER invoking the initialize() method.
You can do that using
public class SampleActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.main);
}
}
Make sure you do that before you call setContentView.
I'm creating an app where I really need to know the correct screen dimensions. Actually I know how to do that... but a problem appeared, because even if you dorequestWindowFeature(Window.FEATURE_NO_TITLE);, this:
still stays on the screen and it seems, it's also counted as a part of the screen so the "screenWidth" is actually bigger, than the usable part.
Isn't there any method how to get the size of the usable part and not whole screen? Or at least get the sizes of the 'scrolling thing'(but there would be a problem, that there are devices that don't show them)?
I had the same question a while back and here is the answer that i found. Shows the activity dimensions.
import android.app.*;
import android.os.*;
import android.view.*;
import android.widget.*;
import android.graphics.Point;
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main)
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
//Set two textViews to display the width and height
//ex: txtWidth.setText("X: " + width);
}
}
I know this question is really old, but I have fought with this so many times until I found this stupidly simple solution:
public final void updateUsableScreenSize() {
final View vContent = findViewById(android.R.id.content);
vContent.post(new Runnable() {
#Override
public void run() {
nMaxScreenWidth = vContent.getWidth();
nMaxScreenHeight = vContent.getHeight();
}
});
}
Run this code after setContentView() in your Activity's onCreate(), and delay any code that depends on those values until onCreate() is finished, for example by using post() again after this one.
Explanation: This code obtains your activity's root view, which can always be accessed by generic resource id android.R.id.content, and asks the UI handler to run that code as the next message after initial layout is done. Your root view will be of the exact size you have available. You cannot run this directly on the onCreate() callback because layout did not happen yet.
you can use also the full screen
developer.android
I've been trying to get the Robotium tester to work for the Android project in libGDX, but got some problems.
First I want to test my games buttons (that are imageButtons), but for that I need the imageButton index in Android.
How can I get that?
My button is in the main project:
ImageButtonStyle style = new ImageButtonStyle();
style.imageUp = buttonsImagesUp;
style.imageDown = buttonsImagesDown;
ImageButton newgameButton = new ImageButton(style);
newgameButton.setPosition(425,330);
This is the button I would like to test in JUnit.
My JUnit code:
public class ButtonTest extends ActivityInstrumentationTestCase2<MainActivity> {
private Solo solo;
#SuppressWarnings("deprecation")
public ButtonTest() {
super("com.me.myGame", MainActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
}
public void testMenu(){
solo.assertCurrentActivity("First menu selected", MainActivity.class);
solo.clickOnImageButton(index); //need index
}
}
My game is set up like this:
First there is the main Game class that handles the resources and sets the first screen to the main Menu:
#Override
public void create() {
playSound = userPref.getBoolean("playSounds");
setScreen(mainMenuScreen);
}
And after this it goes to the MainMenuScreen.js and thats were the buttons are that I want to test with JUnit
Robotium's idea of an ImageButton is very, very different from Libgdx. Robotium is expecting an image button that is defined as part of the standard Android UI infrastructure (see Android ImageButton). The Libgdx ImageButton is a Java object with an OpenGL texture reference (see Libgdx ImageButton). From the Android UI infrastructure point of view, a Libgdx app is just a full-screen OpenGL view, and has very little meta-data for Robotium to use.
You may be able to use the raw "clickOnScreen" infrastructure, but you will have to manually compute and track the location of your buttons on the screen. Additionally, I would be surprised if Robotium did not contain other dependencies on the Android UI infrastructure that are not there in a Libgdx app.