Can Activity classes be made launchable only during development/debug? - android

A common situation I face is that I wish to test a custom View visibly on screen while it is being developed as part of a large application. I realise that unit testing exists, particularly using ActivityUnitTestCase, but as far as I understand these frameworks don't actually attach the components visibly on screen.
At present, the way I tend to do this is to just place the component wherever it will actually be used within the application. This often means needing to wait some time for the application to start or to navigate through parts of the application before it is visible, which can become cumbersome.
The better way I've found is to create an Activity within the application that exists purely for test purposes (e.g. to simply display a custom View I'm developing), which is launched to display the custom View (or whatever) that I am working on. To do this, the only intent filter I've assigned to that Activity in the manifest is android.intent.action.MAIN, and not android.intent.category.LAUNCHER. Then, I can simply create a Run/Debug Configuration in Android Studio to launch that Activity directly. This, as far as I believe, effectively allows me to have Activity classes which may only be launched by me from the IDE.
My questions are:
Does omitting android.intent.category.LAUNCHER guarantee that users of the application won't be able to launch that Activity by any means nor be aware of its existence? Is this a safe to have Activity classes for development only?
Is there a workflow or test framework of any kind I could use to improve on how I am doing this?

I realise that unit testing exists, particularly using ActivityUnitTestCase, but as far as I understand these frameworks don't actually attach the components visibly on screen.
Well, ActivityInstrumentationTestCase2 does, as does the new ActivityTestRule. I don't recall playing with ActivityUnitTestCase.
Does omitting android.intent.category.LAUNCHER guarantee that users of the application won't be able to launch that Activity by any means nor be aware of its existence?
No. It won't be easy for them to start it, but it is exported and has an <intent-filter>, so somebody could find a way.
Is this a safe to have Activity classes for development only?
I would put them in your debug sourceset, assuming that you are using Android Studio. Here is a sample project that has a production launcher activity in main and a diagnostic activity in debug. In a release build, the diagnostic activity does not even ship.

Why don't declared some value like
public static boolean IS_DEBUG = true;
then in any part you want to show it, just put in condition like
if (IS_DEBUG) {
your_develop_view.setVisibility(View.VISIBLE);
//...
}
else {
your_develop_view.setVisibility(View.GONE);
}
after you finish develop. before you publish, just change
IS_DEBUG = false;

Instead of defining your own IS_DEBUG, just use BuildConfig.DEBUG

Related

Android : Get Activity/Fragment/Classes of different Apps with same user_id

First time asking on stackoverflow here !
Okay so here's the context. I'm doing an android application, and I'm trying to implement something like a plug-in framework.
My main app's MainActivity's purpose is to manage and launch/show Fragments.
Each of my plug-in will contain (at least) a Fragment and it's layout.
Thus, the idea is to fetch the fragment and put it inside my main app's MainActivity, from it.
So I decided to put my Fragments/Plug-ins into different apps and give all my plug-ins and main app the same user_id. This way all of them are in the same process, and even if they appear in the phone's Application Manager, only the main app is launchable and visible in the Application Browser (which is great).
But here's my problem... How do I get access to my plug-ins Fragments ?
I thought I could fetch some class through the PackageManager and use relfexion to use my fragment, but apparently you can't (or I didn't find how).
I considered binding Services together on each end (Application - Plug-in) but I have no guarantee that the services will bind together. Especially since each app have the same copy of the service, aka not the same Service.
Maybe by using a common .jar to make sure the Services are the same, and thus pass an instance of my Fragment to the main app (yes an instance would suffice).
Or make a CustomClassLoader (but then I might need advice on how to load classes from my other app, because I don't know how to do that...)
I've been running in circles in my head and on the net to find a solution...
To make things clear:
How do i fetch the classe (CustomClassLoader) or an instance (via binding or maybe sharedPreference or wiriting my instance in a file and read it in the main ?) of another app, considering they share the same user_id and thus are in the same process ?
Just because apps share the same user_id this does not imply they are running in the same process. They may and propably have been started by the same process. Sharing resources amongst processes is commonly known as IPC.
AIDL , the android Interface Definition language is a way for implementing IPC. Still this will not allow you retrieve objects from a different application directly but the possibility to invoke methods on remote objects.
But your problem description to me seems more like accessing objects of an jar at runtime in an application. This could be done via classloading.
So your app could retrieve a jar from a Server and load your fragments from it. The definitions of the fragments than would be runtime updateable if you define your fragments completely by code.

Robolectric & testing startActivityForResult

I have troubles with my Robolectric unit test.
I can assert without problem that a click started a new activity when the listener uses the method startActivity( Intent )
But it seems Robolectric has trouble when a new activity is started with the method startActivityForResult(Intent, int) : putting some breaks in the code made me figure out that the activity wasn't started ( and just changing for method startActivity( Intent ) made the assert pass).
Is that normal ? It's a pity since the first activity of my app uses startActivityForResult(Intent, int).
Did someone manage to make tests with this way of launching activities ?
Thanks for your help ..
The short Answer to your question is that, due to the way Robolectric converts Android classes to code that executes in the JVM, a lot of their functionality doesn't behave as you'd expect. Many system callbacks won't execute, and you'll have to rely on what Robolectric provides in their Shadow implementation of classes. (See the link provided by #Steven_BDawg).
The long answer: It may be possible to implement this whole flow in one big test, but it's not what the framework is designed for.
Robolectric and Unit Testing in general aren't meant to be used in the way that you describe. The Unit Testing page on wikipedia states that one can view a unit as the smallest testable part of an application. A unit testing suite should contain many lightweight tests, where each test isolates a bit of functionality in your app and ensure it's working properly.
Consider a basic Application that contains two Activities, A and B. Activity A displays some information about a topic, and Activity B allows the user to select which topic to show in A. When the user moves from Activity A to Activity B, B gets called with startActivityForResult() and should return to A with the selected topic.
Now say we want to Unit Test this flow of A getting the result from B and displaying the data. We can break this up into two tests:
Activity Under Test - Activity A. In our test, we'll create a new instance of Activity A. In the Robolectric Test, we create the Intent that we expect B to return to A, and call the shadow method receiveResult() for A, filling out the arguments with a result code of OK and this Intent. After receiveResult(), run your assertions. You now know that Activity A handles the result properly!
Activity Under Test - Activity B. In our test, we'll create a new instance of Activity B, setting it up as if it were started for result from Activity A. In the Robolectric Test, we'll perform all actions needed to select the data, create the intent we'll send back, then run assertions on the intent to ensure it was created correctly.
This is a very simple example. These two steps could probably be broken out into many more tests, as, again, each unit test should only be testing the smallest unit of functionality that your app can be broken into. The example is mainly to help you start thinking in a unit testing kind of way. I've found that as my understand of unit testing deepens, the way I write code has changed. I try to avoid writing methods and classes in such a way that they do too much work and cannot be properly unit tested. As a rule of thumb, code that's easy to unit test performs very specific operations which are readily apparent when reading the code for the first time.
Finally, if you want to take this a step further, mocking frameworks can greatly aid your ability to Unit Test. Mockito is a mocking framework I've had success with in the past. The purpose of a mocking framework is to create stub Objects whose behavior you tightly control. Mockito (or any other Mocking Framework), will allow you to define an object that extends from any type you need and only implement the methods you need. You'll be able to directly control the response to any of these method invocations. This aids Unit Testing because the only real object that you'll need is the Object Under Test; by Mocking all other objects, you'll have a better sense of whether or not the Object Under Test is behaving properly because all other behavior is explicitly defined by you, the tester. (And yes, this does lead to lots of extra code, but such is the life of a good unit tester. However, as previously stated, as you get more comfortable with unit testing, you may find yourself writing methods that require less mocking and are more conducive to writing tests. Some coders will even write their unit tests BEFORE they code, in order to keep their code tight and focused on a single purpose)
Hope this helps!
I did some Google'ing for you. I don't know if this will definitely help you or not, but I think it is a good start!
Roboelectric: Testing startActivityForResult() and onActivityResult()

How to write a Android test case that spans over 2 applications

According to the Robotium doc we can not write test case spans two applications, it says "the test project is locked to the targetPackage. Going outside of that target package is not allowed by the Android platform. Therefore you will need 2 test projects, one for each application."
Currently what I want to do is like monkey tool. I want to randomly fire actions on the screen to exhaustively trigger application's function. During the traversing process, the program flow sometimes will go out of the application and then JUnit or Robotium lose control of the program. I want to know is there any way that I can direct the program flow back to the application? Or is there any way that I can take control of multiple applications at the same time?
Thanks!
One Easy thing to do with write a simple Application which access the Activity Manager and reads every 2 seconds what is active as an external service within your app or another application altogether.
http://developer.android.com/reference/android/app/ActivityManager.html
Basically, check that the ActivityManager.RecentTaskInfo() and check that the Activity Component it was started from is one which you are OK with. Then, so that it does not affect your normal user, .isUserAMonkey() return a boolean of true.
If the Activity is not what you want, write:
else
startService(new Intent(this, TheService.class));
or
else
startActivity(new Intent(this, TheActivity.class));
If you're willing to test only on Android 4.1 and above, you can use the new UI Automator framework, which supports testing across multiple packages.
Some info:
https://plus.google.com/103712615773524578393/posts/dzqtF7BYyG4

How can Android source code not have a main method and still run?

I've seen this in a few tutorials now... but how in the world can Android source code not have a main method and still run.
For example (from http://developer.android.com/guide/tutorials/hello-world.html):
public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
That runs but there is no main!!!
I've also thought that using things like onCreate (or formLoad, etc.) was bad becuase a constructor should do that work and such built-in methods can be smelly sometimes. But onCreate is an entry point? Even without a main?
What if there is more than one activity... is there a hierarchy to these built in event handlers? OnCreate trumps everything else? Otherwise, how would the app know what to run or where to enter the program?
Thanks!
Each application will be having it's own Virtual Machine. To run an app, within it's space (VM), must have a main method.
Activities are not the actual classes to be invoked for start of application. There is a class called Application, which will be the root class for an application to be launched.
If there is no main method, how can a VM recognize how to start an app?
Framework has classes called Process, VMRuntime which are responsible for starting an application. Which indeed deal with main method.
For better understanding, study the Zygote service of Android. deals with Applicationmanager Service, ActivityStack Activity Threadds etc.
That runs but there is no main!!!
Of course. Many things that you might think of as a Java "application" do not have their own main() method. For example, IIRC, servlets, WARs, and the like do not have main() methods -- the main() method, if there is one, is in the container.
But onCreate is an entry point?
onCreate() is a method.
What if there is more than one activity... is there a hierarchy to these built in event handlers?
Not really.
OnCreate trumps everything else?
Not really.
Otherwise, how would the app know what to run or where to enter the program?
An app does not "know what to run or where to enter the program".
An Android application is a basket of components. Some components may be tied to icons in a home screen launcher. Some components may be tied to scheduled timers, like cron jobs or Windows scheduled tasks. Some components may be tied to system events, such as when the device is placed into or removed from a car dock. Those components will be automatically created and used when appropriate (e.g., when a user taps the icon in the home screen launcher). Yet other components are only created and used when your code specifically asks for them.
Thinking of an Android application as if it were a monolithic console-mode Java program will cause you no end of trouble.
You tell it which one to run on startup in the manifest file. There isn't a main() because there doesn't have to be, main may be a convention used for "regular" java apps, but it isn't for things like browser applets. The system creates the activity object and calls methods within it, which may or may not be called main. In this case, it's not.
onCreate is different from a main, and from a constructor, in that it can be called twice on a single activity, such as if the process is killed and the user navigates back to the activity. See http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
Actually, this type of pattern is not peculiar of Android, but happens whenever you have some framework in the middle. Some basic examples are java Applets and Servlets. Some of the answers already provide give the correct response, but I will try to elaborate a bit.
When you launch a Java app, you start a JVM and then you need to load something into it: so you need a static method (the main) because there are no objects (yet) living in the JVM that you can refer to.
If you have some sort of framework in the middle, it is the framework that will start the JVM and will start populating it with its own service objects: writing your code then means writing your own objects (which will be subclasses of given "template"). Your objects can then be injected (loaded) by the framework. The framework service objects manage the lifecycle of the injected objects by calling the lifecycle methods defined in the "template" superclass.
So for instance when you provide an applet to a browser, you do not launch a static main method: you rather only provide a subclass of java.applet.Applet that implements some instance methods which act as callback to manage the lifecycle (init, paint, stop...). It is the browser that will launch the JVM, instantiate what's needed for the launching an applet, load your applet and call it.
Similarly, with servlets you subclass the javax.servlet.http.HttpServlet class and implement some instance (non static) methods (doGet, doPost...). The Web container (e.g. Tomcat) will be in charge to launch the JVM, instantiate what's needed for launching a servlet, load your servlet and call it.
The pattern in Android is pretty much the same: what do you do is to create a subclass of android.app.Activity. When you launch an app, the system looks in the manifest to find out which activity should be started, then the "framework" loads it and calls its instance methods (onCreate, onPause, onResume...).
In Java programs we need a main() method, because while executing the byte code the JVM will search for the main() method in the class and start executing there.
In Android, the Dalvik Virtual Machine is designed to find a class which is a subclass of Activity and which is set to start the execution of the application from its onCreate() method, so there is no need of a main() method.
The order in which Dalvik Virtual Machine calls methods is based on order of priorities called android life cycle for more information on android life cycle check the link below
Android Life Cycle: https://developer.android.com/guide/components/activities/activity-lifecycle.html
While there is no specific main entry point, intent filters describe which activity is started when the application is launched.
They are controlled in AndroidManifest.xml as described here:
http://developer.android.com/guide/topics/intents/intents-filters.html
where a note pad application example is described:
This filter declares the main entry point into the Note Pad application. The standard MAIN action is an entry point that does not require any other information in the Intent (no data specification, for example), and the LAUNCHER category says that this entry point should be listed in the application launcher.
An android programmer should learn this like the back of their hands it simply explains everything and would help in the future when creating activities.
http://developer.android.com/reference/android/app/Activity.html
There is a main of sorts, it just happens to be out of your hands. After all, there's nothing special about a main function in any language. It's just the entry point where your code starts executing. The Android operating system expects applications to have a certain structure and it calls your code based on the conventions you follow.
I found this particularly useful...
http://developer.android.com/guide/topics/fundamentals.html#appcomp
Applets don't have main() methods either. It just depends on how your code is packaged.
The Android UI frame encapsulate some Java common details, you can study the source code of the android UI framework
I think that Jonathon's answer is going in the right direction. He says the OS expects a certain structure. There's a name for that structure which is a "state machine". In this case Android calls it the "activity lifecycle". Rob gives a link to the documentation which contains an important diagram of that state machine though the text is a bit dry. A quick search also found me the following link that explains it fairly clearly: http://www.android-app-market.com/android-activity-lifecycle.html
In Java, there is a main even if it isn't listed as main(). The page you get after the icon click, whatever its name, is the main().

Android Application class being called twice

In my Android application, I overload the Application class, and I updated the tag in my manifest. This application also creates an Android Service.
I have put some logs in the onCreate of my Application class, and I see it being called twice.
The first time is when my application gets launched (this is expected) and then, it's usually right after the Service is being created.
the log also shows that a second instance of the Application is being created.
(I print the "this" value and they are different).
I thought the Application would be created as a singleton.
Is that happening because I create a Service?
Yes, if you used android:process then you have it running in a separate process, so when the service starts a new process is started for it and thus a new Application object for that process needs to be created.
But there is a more fundamental problem - it is just not right for an Application object to start one of its services. It is important that you don't confuse Application with how you may think of an "application" in another OS. The Application object does not drive the app. It is just a global of state for the app in that process. In fact, the Application object is completely superfluous -- you never need one to write an Android application. Generally I actually recommend that people don't use it. It is more likely to cause trouble than anything else.
Another way to put this: what really defines an application is its collection of activity, service, receiver, and provider tags. Those are what are "launched." All an Application is, is something that is created as part of initializing an application's process. It has no lifecycle of its own, it is just there to serve the other real components in the app.
So just ignore Application when designing your app; it will reduce confusion. (In its place, I prefer to use global singletons for such state.)
Also as a general rule, I recommend not using android:process. There are certainly some uses for it, but the vast majority of the time it is not needed and just makes an application use more RAM, less efficient, and harder to write (since you can't take advantage of globals in a single process). It should be obvious to you if you reach a place where there is actually a good reason to use android:process.
A Service should not really be thought of as an Activity, and you're bound to have problems later on if you think this way. Services and Activities can belong to the same application, if you defined them that way in your AndroidManifest.xml, but they behave differently and have different lifecycles. If you want your Service in a different process, then you set android:process="string" in the <service> section to give it a name different from your application name. You won't have access to global variables when it's in a separate process, and you should communicate to your service through Intents. If your service is more complex, you might want to look at making it remotely callable through AIDL. If you want a singleton activity, then set that Activity's launchMode to either singleInstance or singleTask. singleInstance means it will be the first and only instance of this Activity in it's task stack and no new instances will be created for any new Intents. Since it's the only instance of this Activity, it will always be at the top of the task stack, and always in a position to handle new Intents directed at this Activity. If the Activity is declared as singleTask it will also be a singleton but may have other Activities in the same task stack, and may even have Activities at the top of the task stack above it. This is an important distinction to note. Remember this: singleton Activities that are NOT at the top of the task stack cannot handle new Intents, and the Intent will be dropped. If you want your Activity to always be able to handle all new Intents destined for it, then you most likely want to use singleInstance
The problem is that a Service is a component too, with its own lifecycle, just it hasn't got an user interface.
You should check the developer application fundamentals for the alternatives.
I just had this issue and after reading all this, nothing helped. Here is what helped me.
Add the attribute MainLauncher = true to your MainActivity.cs class.

Categories

Resources