I'm integrating Unity as a subview in a native Android app.
I'd need to prepare Unity when the app starts, but without showing it, because I need to change between scenes when the user taps a button, without showing the Unity screen presentation.
The flow is:
User chooses a scene in Activity A -> Display scene in PlayGameActivity with UnityPlayer.UnitySendMessage, without Unity splash/loading screen
In iOS I did it like this:
class AppDelegate: UIResponder, UIApplicationDelegate {
var currentUnityController: UnityAppController!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.currentUnityController = UnityAppController()
self.currentUnityController.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
But I don't find something similar in Android.
This is how I'm showing the UnityPlayer in a subview:
public class PlayGameActivity extends UnityPlayerActivity {
private static final String TAG = "PlayGameActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_game);
// Create the UnityPlayer
mUnityPlayer = new UnityPlayer(this);
int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
boolean trueColor8888 = false;
mUnityPlayer.init(glesMode, trueColor8888);
// Add the Unity view
RelativeLayout layout = (RelativeLayout) findViewById(R.id.container_unity_play_game_activity);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) layout.getLayoutParams();
layout.addView(mUnityPlayer.getView(), 0, lp);
String unityScene = "some_scene";
Log.d(TAG, "calling scene " + unityScene);
UnityPlayer.UnitySendMessage("AController", "AMethodToChangeScene", unityScene);
}
}
I tried changing scene in an Activity with the player and the buttons below, and it works, because I wait for the player to be ready. Unity does receive the message of changing scene and does so after loading itself.
So is there a way to init Unity without showing it like in iOS? Or a way to know when the UnityPlayer is ready/isn't showing the splash screen?
I tested an approach that I think may work for you.
First I made a two View variables so that the views can be manipulated throughout the class.
public class PlayGameActivity extends UnityPlayerActivity {
private static final String TAG = "PlayGameActivity";
private View playerView;
private RelativeLayout layout;
RelativeLayout.LayoutParams lp
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_game);
// Create the UnityPlayer
mUnityPlayer = new UnityPlayer(this);
int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
boolean trueColor8888 = false;
mUnityPlayer.init(glesMode, trueColor8888);
//MODIFIED VERSION OF YOUR CODE
playerView = mUnityPlayer.getView();
// Add the Unity view SLIGHTY MODIFIED
layout = (RelativeLayout) findViewById(R.id.container_unity_play_game_activity);
lp = (RelativeLayout.LayoutParams) layout.getLayoutParams();
String unityScene = "some_scene";
Log.d(TAG, "calling scene " + unityScene);
UnityPlayer.UnitySendMessage("AController", "AMethodToChangeScene", unityScene);
}
}
Then in my test, I had two buttons with listeners set up. The first button let me send a message to Unity,
Button theButton = (Button)findViewById(R.id.button);
theButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mUnityPlayer.UnitySendMessage("CallThis", "MessageFromAndroid", "HI!");
}
});
Then the second button did the following,
Button good = (Button)findViewById(R.id.button2);
good.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
layout.addView(playerView);
mUnityPlayer.requestFocus();
}
});
So the basic idea is don't add mUnityPlayer using layout.addView() to the view until you are ready. You could have your program call UnitySendMessage, and then from within Unity make a call into Android that runs the second line from the button I made. That is, just replace that button I used with a function that Unity can call. You're probably familiar with it already but I'll link to the Android Scripting API anyway.
EDIT: I ran another test and it is not necessary to put mUnityPlayer.requestFocus() in the method that adds the UnityPlayer to your view.
Related
I'm new at androidstudio and want to compare a imageView by the following:
I have 2 imageView, both are using a drawable i named "blank" at the start of the app, using if/else I want to chance those images to another drawable i have, i tried the following:
private ImageView equipament1;
private ImageView equipament2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_analise)
equipament1 = findViewById(R.id.equipamento1);
equipament2 = findViewById(R.id.equipamento2);
public void sentImg() {
if (equipament1.equals(R.drawable.blank)){
equipament1.setImageResource(R.drawable.reactor);
}
else if (equipament2.equals(R.drawable.blank)){
equipament2.setImageResource(R.drawable.reactor);
} else {finish();}
but it doesn't work, the app just replaces the first image and if i click on the button again, nothing happens (this if/else is inside a button).
I want to check if the first image is blank, if it is, the app should replace the blank image with the image "reactor" or, if is not blank, the app should move to the second blank image, and replace it and this go on for more 2 blank spaces.
I'm doing this because I'm building an program similar to LucidChart where you put your equipments in the app.
The problem is that the second time you have already changed the value of the comparator.
If the objective is just to change the images you don't need the if/else.
private ImageView equipament1;
private ImageView equipament2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_analise)
equipament1 = findViewById(R.id.equipamento1);
equipament2 = findViewById(R.id.equipamento2);
public void sentImg() {
equipament1.setImageResource(R.drawable.reactor);
equipament2.setImageResource(R.drawable.reactor);
}
When the user clicks your button, you want to do 2 things. You want to show some images, or you want to call finish().
I would suggest using a boolean as a flag the the state and compare that instead of comparing the ImageView itself. This'll be easier, and make your code easier to read.
I created a flag called firstClick that is set to true by default. When the user clicks your button (button1 in this example), we check against that and show the images. Then we set it to false,
so the next click will call finish().
private ImageView equipament1;
private ImageView equipament2;
// The current state of the Activity
private boolean firstClick = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_analise)
equipament1 = findViewById(R.id.equipamento1);
equipament2 = findViewById(R.id.equipamento2);
// Setting your OnClickListener
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if( firstClick ) {
firstClick = false;
sentImg();
} else {
finish();
}
}
});
}
public void sentImg() {
equipament1.setImageResource(R.drawable.reactor);
equipament2.setImageResource(R.drawable.reactor);
}
I'm trying to TDD/test the text colour of a textView for android. However all of the properties seem to return either 0 or null, does anyone know why?
The code creating the text view:
public void setupTextView() {
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
TextView textView = new TextView(this);
textView.setText(job.getName());
if (job.getLastBuild().getBuildStatus().equals("SUCCESS")) {
textView.setTextColor(Color.parseColor("#007000"));
} else {
textView.setTextColor(Color.parseColor("#FF0000"));
}
layout.addView(textView);
}
I've ran the application and the code above works.
The properties I've tried accessing in the test code:
#Test
public void firstTextViewShouldReflectPassingJobStatus() throws Exception {
LinearLayout layout = layout = (LinearLayout) activity.findViewById(R.id.layout);
TextView gomoTextView = (TextView) layout.getChildAt(0);
System.out.println(gomoTextView.getCurrentTextColor()); //Returns 0
System.out.println(gomoTextView.getTextColors()); //Returns null
System.out.println(gomoTextView.getSolidColor()); //Returns 0
System.out.println(gomoTextView.getCurrentHintTextColor()); //Returns 0
//I also tried using `Robolectric.shadowOf()`:
ShadowTextView shadowGomoTextView = Robolectric.shadowOf(gomoTextView);
System.out.println(shadowGomoTextView.getTextColorHexValue()); //Returns 0
System.out.println(shadowGomoTextView.getHintColorHexValue()); //Returns null
}
Update to answer comments
I have a before in the unit test class which calls onCreate():
private LinearLayout layout;
private HomeActivity activity;
#Before
public void setUp() throws Exception {
activity = spy(new HomeActivity());
Jenkins mockJenkins = TestUtilities.getTestJenkins();
when(activity.getJenkins()).thenReturn(mockJenkins);
activity.onCreate(null);
layout = (LinearLayout) activity.findViewById(R.id.layout);
}
And the the onCreate method in the HomeActivity class:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Jenkins jenkins = getJenkins();
displayJenkins(jenkins);
}
And then display jenkins calls a load of other methods which include setupTextView()
Looking to the sources it's not implemented yet. I would suggest you to implement your own shadow as described here.
Robolectric 2.0 has been promoted to the alpha state. I think you issue should be fixed during release since they are going to use as much as possible real Android source code.
I have a class which uses other classes to build up a FrameLayout. One is for Navigation through a building, the other for displaying schematics with sensors of it, and the other one to display sensordata. I build up the whole frame one time, and want to make the sensordata visible in the sensorview part of the frame. Lets say I have 5 sensors, and when I click on one the sensorview shows up the sensordata. I could just make 5 sensorviewframes on top of each other, initiating them invisible, and just make the one visible which was selected via a click on a sensor.
I wanted to ask, is it possible to change the LinearLayout containing the TextViews in a different class with an update method?
I already tried it, but with my code it doesn't work at the moment.
public static SensorBar Create_SensorBar_Layout(Context myContext, ObjectStructure objStruct, ObjectView objView, List<SensorDevice> listofCurrentSensordevices)
{
// Init
LinearLayout SensorBarLinearLayout = new LinearLayout(myContext);
LinearLayout.LayoutParams layoutParamsSensorBar = new LinearLayout.LayoutParams(
200, 653);
layoutParamsSensorBar.setMargins(5, 5, 5, 5);
SensorBarLinearLayout.setOrientation(LinearLayout.VERTICAL);
SensorBarLinearLayout.setLayoutParams(layoutParamsSensorBar);
SensorBarLinearLayout.setBackgroundResource(R.drawable.window_frame);
SensorBarLinearLayout.setPadding(4,4,4,4);
LinearLayout SensorBarData = new LinearLayout(myContext);
LinearLayout.LayoutParams layoutParamsSensorBarData = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
SensorBarData.setOrientation(LinearLayout.VERTICAL);
SensorBarData.setLayoutParams(layoutParamsSensorBarData);
//--- Button Headline ---
Button buttonNavBarHeadline = new Button(myContext);
buttonNavBarHeadline.setText("Sensordata");
buttonNavBarHeadline.setTextColor(Color.BLACK);
buttonNavBarHeadline.setBackgroundResource(R.layout.mainview_window_headline);
buttonNavBarHeadline.setTextAppearance(myContext, R.style.headline3);
//Layout buildup
SensorBarLinearLayout.addView(buttonNavBarHeadline);
SensorBarLinearLayout.addView(SensorBarData);
return new SensorBar(SensorBarLinearLayout, SensorBarData);
}
This is the Sensorbar, and I want to have the LinearLayout SensorBarData to be dynamically swapped out by clicking on the sensorbuttons.
public void updateSensorBar(Context myContext, ObjectStructure objStruct, List<SensorDevice> listofCurrentSensordevices, int activeSensor)
{
LinearLayout linearlayoutSensorvalueTextviews = new LinearLayout(myContext);
... (additional Textviews for Sensordata, which get added with addview())
setSensorBarData(linearlayoutSensorvalueTextviews);
}
This is used by an OnClick event.
public void setSensorBarData(LinearLayout SensorBarData) { this.dataSensorBar = SensorBarData; }
This is used by the updateSensorBar to update the LinearLayout.
I would be glad for any help.
Define an interface and use a callback to let the activity know that a sensor has been updated.
public Interface SensorUpdatedListener {
void onSensorUpdated();
}
In your SensorBar class.
ArrayList<SensorUpdatedListener > listeners = new ArrayList<SensorUpdatedListener >();
...
public void setSensorUpdatedListener(SensorUpdatedListener listener){
listeners.add(listener);
}
In your sensor bar update method:
for (SensorUpdatedListener listener:listeners){
listener.onSensorUpdated();
}
In your Activity:
public class Test extends Activity implements SensorUpdatedListener {
...
#Override
public void onCreate(Bundle savedInstanceState)
{
...
sensorBar.setSensorUpdatedListener(this);
...
}
public void onSensorUpdated(){
// do whatever you need to do
}
You could improve the SensorBar class by adding removeSensorUpdatedListener and checking that you do not add the same listener twice in setSensorUpdatedListener.
Why is this:
public class HelpTab extends Activity
{
LinearLayout helpLayout; //was changed to LinearLayout helpLayout = new LinearLayout(this);
TextView helpText = new TextView(this);
Button tips = new Button(this);
Button walkThrough = new Button(this);
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
buttonCreator();
setContentView(helpLayout);
}
public void buttonCreator()
{
//Button featuress defined in here (setText("") and adding them to the layout, addView();)
}
Causing my program to crash?
I have looked at the code extensively and I can't put my finger on it, and the debugger also says source not found when it opens the new page tab thing to tell me what is happening.
Try calling setContentView(helpLayout); first and then buttonCreator();
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(helpLayout);
buttonCreator();
}
Assuming that you are trying to initialize your button inside buttonCreater() with respect to a button you have declared in your helplayout, you might run into Null Pointer Exception.
I'm still sort of new with Android, so forgive me if it's an obvious mistake. In this activity I'm using ViewPager to horizontally scroll through three layouts containing an ImageButton that has an animated background depending on its current state. When the button is pressed, it starts a new activity. However, when I hit the back button to go back to the activity containing the animation from the new activity, sometimes the animation freezes or plays back faster than it should. I wrote a method for starting up the animation that I use in onWindowFocusChanged(), and onRestart(). I'm working in Android 2.1 (API 7).
This is my code:
public class CopyOfWorld extends Activity{
MediaPlayer muzak;
Boolean mSwitch = false;
ImageButton holmes;
AnimationDrawable holmesAnimation;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.world);
Preferencer pp = (Preferencer)getApplicationContext();
ViewPagerAdapter adapter = new ViewPagerAdapter();
ViewPager myPager = (ViewPager) findViewById(R.id.viewpager);
myPager.setAdapter(adapter);
myPager.setCurrentItem(1);
if(pp.getMuzak()){
mSwitch = true;
muzak = MediaPlayer.create(CopyOfWorld.this, R.raw.level1);
muzak.setLooping(true);
muzak.start();
}
}
public void clicker(View v){
Intent myIntent = new Intent(CopyOfWorld.this , Subworld.class);
startActivityForResult(myIntent, 0);
}
#Override
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
beginRender();
}
#Override
protected void onPause(){
super.onPause();
if(mSwitch){
muzak.release();
}
}
#Override
protected void onRestart(){
super.onRestart();
Preferencer pp = (Preferencer)getApplicationContext();
if(pp.getMuzak()){
muzak = MediaPlayer.create(CopyOfWorld.this, R.raw.level1);
muzak.setLooping(true);
muzak.start();
}
beginRender();
}
public void beginRender(){
ImageButton holmes = (ImageButton) findViewById(R.id.subworlder);
StateListDrawable background = (StateListDrawable) holmes.getBackground();
Drawable current = background.getCurrent();
if(current instanceof AnimationDrawable){
holmesAnimation = (AnimationDrawable) current;
holmesAnimation.start();
}
}
}
I've tried calling the method beginRender() under ()onResume, but then the app simply crashes.
Could anyone point me in the right direction?
EDIT:
I've been tweaking the code here and there, unfortunately to no avail. But I did notice a pattern in the behavior of the animation. When I press down on the ImageButton or hold it so that it goes from its default animation to its pressed or focused animation then move my finger away from the button so that it doesn't start up the new activity, it sometimes behaves very much as I described at the beginning of this post (i.e. it's supposed to return to its default animation, but instead plays back at twice the rate, chokes up, or doesn't play at all.)
Currently the xml that contains these ImageButtons defines their backgrounds as the animations and have no source (src). But when I change the background to transparent and the src to the animations, the app crashes.
Any clues?