How can I configure Launcher activity programmatically in android? - android

I am working on an app with two activities : LoginActivity and MainActivity. When the user first opens the app he will login and his credentials (username and token) are saved in Preferences.
Now, if the user opens the app again then MainActivity should start. I tried to switch between these activities in Application class and removed intent-filter for LAUNCHER_ACTIVITY from manifest, but it doesn't work.
Is there any way of switching between Launcher Activities programmatically on basis of saved preferences?

Is there any way of switching between Launcher Activities programmatically on basis of saved preferences ?
You can try this:
Step #1: Have LoginActivity have the LAUNCHER <intent-filter> as normal, and have MainActivity have no <intent-filter>.
Step #2: Have an <activity-alias> element in the manifest pointing to MainActivity that has the LAUNCHER <intent-filter>.
Step #3: Put android:enabled="false" on the <activity-alias>, so it is disabled by default, so when the app is first installed, the only launcher icon is for LoginActivity.
Step #4: When the user logs in, and you want to change so MainActivity is the launcher activity, use PackageManager and setComponentEnabledSetting() to make the <activity-alias> enabled and to disable the LoginActivity.
Not all home screens will detect this change on the fly, and for those, the device would need to reboot in all likelihood to pick up the change. For this reason, it would be better to stick with a single launcher activity. If you want, that launcher activity could have Theme.NoDisplay and simply route to the correct "real" activity in onCreate(), per Fahim's answer.

Long story short, you cannot change the Activity that is launched by default. Update: There is an alternative as described by CommonsWare in another answer.
However, there are reasonable work arounds. In your MainActivity you can check whether the user is logged in and immediately redirect them to the LoginActivity. That has the added benefit of automatically returning to the MainActivity after you have logged in.
Alternatively, you can always go first to the LoginActivity, and if the user is already logged in, send them to the MainActivity (rewrite the Intent history to remove the return to LoginActivity or set the noHistory flag in the manifest).

The easiest way is to make MainActivity launcher activity, as usual.
Then check in MainActivity#onCreate(Bundle) via SharedPreferences if the user already logged in and, if not, start LoginActivity immediately. When user logs in, save the boolean flag indicating that user logged in in SharedPreferences and finish MainActivity.

An activity doesn't necessarily require a UI, so you can use the launcher activity in the manifest to lauch any activity you desire.

As far as I know changing launcher programmatically is not possible, but it also doesn't make sense.
On your LoginActivity's onCreate check if a username and token is already saved, if it is try to login with that automatically, is succeed redirect to your MainAcivity. Depending on the way your app works you can have a variable that checks if a user is logged in or not, if he is the LoginActivity would redirect him to MainActivity without trying to log in again.
//LoginActivity
onCreate(Bundle bundle)
{
/* ... */
//Or whatever you use to login (it could also go inside a thread or an AsyncTask
if (login())
{
//Intent
Intent intent = new Intent(this, MainActivity.class);
//Start Activity
startActivity(intent);
//Finish this activity, so when user pressed back the login activity will not come forth and the app will exit
//this looks like when a user has logged in once, the login screen will not be visible to him (unless you want to)
finish();
}
}
You can also configure it to save username and token only if a login is successful which means the above code can be modified like this:
if (getUsername() != null)
{
/* Start Main Activity */
}
This won't attempt to log in, but it knows the credential are right since it has logged in at least once with them.
If your app behaves a different way that these methods do not work, feel free to say so, I may be able to provide more info

You can jsut add Intent after OnCreate to the XML you want to show in the beginning of your APP.
public class LoginActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//add some code to detect if user is logged in
if (user != null){
Intent in = new Intent(LoginActivity.this, YourDesiredActivity.class);
startActivity(in);
}
..........
...........

Related

Is there a way to detect which Activity will be resumed upon hitting the back button?

My app begins with Activity A (log in screen) which I always want on the bottom of the Activity stack.
Based on some logic after login, I launch some other Activity B-Z. There is a menu in the app which allows you to switch around between any Activity B-Z.
If the user hits the back button enough times, I don't want them returned to the login screen. I want the user to be sent to the Android Home screen if the back button is pressed on the Activity which has Activity A as the next Activity on the stack. This Activity is not guaranteed to be the Activity which was launched by Activity A because my Activities use singleTop.
Ideas?
The only other option I can think of is to remove singleTop and whatever Activity is launched by Activity A could remember that (my Activities all derive from a base class, which I would use to do that).
Another possibility may be to do something like the following in the onBackPressed handler:
if (getParent().getClass().getName().equals(ActivityA.class.getName())) {}
Although not a direct answer to your question, but if the problem is that
I don't want them returned to the login screen
then the classic solution is to finish() the login Activity when the user has logged in successfully. This way you'll make sure the user will never return to that Activity.
To do this, Why don't you get the User Login information, and store it in your apps private shared preferences. Then when the User launches your application, you can read the Shared preferences from activity A, and automagically log them in to activity b .
something like this:
SharedPreferences myPrefs = getBaseContext().getSharedPreferences("MyPrefs", SharedPreferences.MODE_PRIVATE);
if((myPrefs.getString("username",null) != null) && (myPrefs.getString("password",null) !=null)){
// Make sure your user is a member of your application
// auto log in to the home page
Intent bIntent = new Intent(getBaseContext(), BIntent.class);
startActivity(bIntent);
}
For more reference on how to use Shared Preferences
http://developer.android.com/reference/android/content/SharedPreferences.html
Then if you want to be really slick, Store the Class name when the onDestroy() method is called in each Activity, overwriting each class as the last open Activity. So whichever activity the user was last on before the application was closed is stored in preferences and you can read that in the login activity, then from there launch b-z
This will make it so that the login activity is always in memory, since it is first launched to check your users credentials.

Avoiding login activity on startup if password is cached

I have a typical Android app where the user has to log in before displaying the main Activity of the application. However, if we've already got a cached username / password, I want to skip the login page.
I could, in my Login onCreate, detect if I've got a user/pass and push a new Activity, but I'm worried that this will make my app startup slower (since I have to load an activity then immediately throw it away), and it also perhaps breaks the back button (i.e. you can hit back and end up back at the login screen).
Is there any way to avoid this and only load the full Login Activity if there is no cached password?
You can make a separate helper activity which launches either your login activity or your main activity. In its onCreate, you'd use startActivity and immediately call finish to remove the helper activity from the back stack.
Intent intent;
if ( /* already logged in */ ) {
intent = new Intent(this, MainActivity.class);
} else {
intent = new Intent(this, LoginActivity.class);
}
startActivity(intent);
finish();
Then, LoginActivity should re-launch MainActivity as normal. This way, the user will never be able to navigate back to the helper activity as it does not appear in the back stack. Do note however that the user can still login, go to the MainActivity, pause that activity, remove his account (through the Android settings) and resume the activity (from the recent apps). If you want to prevent this, you're probably better off placing the login redirect in MainActivity instead (perhaps even in onResume).
You could create a Splash Activity.
On the AndroidManifest.xml's Splash Activity tag, add the android:noHistory="true".
On the Splash Activity, check whatever you need (maybe with an AsyncTask if it may take a long time, to avoid freezing the Activity) and, depending on the result, you start the Login Activity or any other Activity.
Another approach is to transform login screen from Activity to Dialog. That should be easy. And then make your main activity check if there is cached username/password or not. In the second case show LoginDialog to user.
I also have a typical Android app with the same requirement, and I solve it as follows.
First I configure the initial launch activity to be MainActivity, and then inside onCreate(), check if the user has saved credentials (this is all done through AccountManager and authenticator service).
If the check fails and user needs to authenticate, then I start the LoginActivity. If logging in fails or the user presses back, the MainActivity calls finish() on itself to close the whole app. Otherwise, after logging in, the MainActivity is resumed and is presented to the user properly.
The advantage of doing it in this order is that (in my case anyway) the user is more likely to be logged in than out, and so this will avoid any start/stopping of unneeded activities as you say.
A second advantage is that, if the MainActivity (or another activity) is resumed at a later time and the user's session has expired, you can simply start the LoginActivity again to reauthenticate them.
Hope that all makes sense :)

How to Skip the first activity under a condition

I'm building a group of apps as a package similar to MS Office. Here each app has its own launcher as well as it can be launched from inside the home app. Each app has a login page. I need to display the login page when the app is launched from android launcher and not showing login page while launch from home app, How can i achieve this?
My scenario:
From Launcher----->(App)Login page--->(App)Home screen
From Home app----->(App)Home screen
You can do that by launching an empty activity (with no UI) and in its OnCreate method depending on some variable information (You can use SharedPreferences perhaps for that purpose) you can decide which Activity to start (Login or Home Screen app).
PS:
Btw if the login always leads to the same activity (Home Screen and is not used to login somewhere else) you don't even need the empty activity, you can check this in the Oncreate method of the login activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (logged_in_check_is_true)
{
Intent intent = new Intent(this, HomeScreenActivity.class);
this.startActivity (intent);
this.finishActivity (0);
}
...
You should always start LoginPageActivity. But if you start it from your "home app" just pass special extra to activtiy:
public class LoginPageActivity extends Activity {
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean needLogin = getIntent().getBooleanExtra("need login extra", true);
if (!needLogin)
{
// start your home screen
}
//setup login page
}
}
In home app just pass "need login extra" as false.
Basically similar to what tozka said yet you can also launch the activity you expect to be more often required and onCreate you check if you are in the right activity. If not call startActivity with the other activity without inflating any views etc before. So if your expectation is right then in more than 50% of the cases you are already in the right activity saving your app from two activities being called when it is launched

android launchMode singleTask with startActivityForResult

We have a requirement to force the user to set up a password the first time he/she starts the app. So we have our main activity with launchMode=singleTask which start a password setting activity using startActivityForResult.
We also want the user to go back to their home if he/she taps back from the password setting page so we put the code to finish the main activity in its onActivityResult if it receives RESULT_CANCELLED. However, if the user taps home and re-enter our app, we want to show the password setting page again. But in this case, it will be destroyed (because main activity's launchMode is singleTask) and also returns RESULT_CANCELLED to our main activity causing it to be finished.
So the problem is from main activity, we cannot distinguish between tapping back and tapping home then re-enter the app.
Is there anyway to fulfill this requirement while still keeping the launchMode as singleTask ?
onBackPressed() for tapping back
Called when the activity has detected the user's press of the back
key. The default implementation simply finishes the current activity,
but you can override this to do whatever you want.
http://developer.android.com/reference/android/app/Activity.html#onBackPressed%28%29
&&
onPause() for home screen
(though it can be due to other things also like your next activity or switching to another application)
http://developer.android.com/reference/android/app/Activity.html#onPause%28%29
Update :
Why Don't you use Sharedpreferences and check if the app is run for the first time and password/rest fields are set rather than using the approach you are using right now .
I had a very similar issue recently.
What I would suggest is that you don't actually finish the app when you get the RESULT_CANCELLED.
Instead do something like:
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED) {
if (/*TEST IF A USER IS SIGNED IN*/) {
//IF SIGNED IN PROCEED TO MAIN ACTIVITY
}
// OTHERWISE FORCE THEM TO SIGNIN/REGISTER/WHATEVER AGAIN
// WITH ANOTHER CALL TO startActivityForResult
...
This is a back of an envelope approach to your problem, but this pattern has worked for me.
For me, my Authentication/Registration is all done in an Abstarct Class that extends Activity. Each of my activities then extends this class. I Place the Auth/Reg method calls in the onResume() of this Abstarct Class.
When a startActivityForResult is launched in the onResume() method and fails I don't finish() the activity but just let the app proceed and let the class handle which Reg/Auth form to present. Which it will do by checking various flags to determine what action it is meant to be performing.
The added benefit of this approach is that each and every Activity that might extend this abstract class gets the added benefit of a security check each time it is used.

Start root activity if no other activity live for this android app when press back key

I have a message notification, when user select the notificaton, a message display activity will show.
When user read the message and press back key to close the activity, I want to check if the previous activity is the same app's, if so, just go ahead, if not, I want to start the home activity for this app.
How can I do that?
How about this: Have the notification launch the Home Activity in a state that immediately has the Home Activity launch the MessageDisplayActivity. That is: (1) The intent that the notification sends should target the HomeActivity and include an extra flag identifying the Intent as being from the notification. (2) The HomeActivity, in onCreate(), upon finding that flag then simply launches the MesssageDisplayActivity.
Thus the HomeActivity will exist for a brief moment of time, but probably not long enough to be visible. It will then remain upon the back stack so that the back key will bring you there.
You should consider changing the launch mode of your Activity, so that you never have this problem - using singleTask or singleInstance should make this Activity always be the only one open for your app.
Have Intents within your app that call the message display activity (MDA) pass a boolean value of "true" that's extracted and stored in a field in the MDA. Have the field set by default to "false." Thus, if the MDA is called from an activity within your app, the field will have a boolean value of "true," if it's called from anywhere else (such as a notification), it will be set to false.
Override public void onBackPressed() in the MDA as follows:
public void onBackPressed() {
if (wasCalledFromYourApp == true) {
super.onBackPressed();
} else {
//[code that launches your app's home activity here]
}
}
(This is assuming the notification will only be created by one app).

Categories

Resources