Im writing a program that offers a quick reply dialog upon receipt of an SMS.
However, I am getting an unexpected result. When I receieve an SMS, the appropriate dialog activity comes up displaying the correct phone number and message, however there is a second activity behind it that is the 'default' activity in my program (it is what opens when i launch my application)
I do not want this second activity to come up. The quick reply activity should come up by itself over top of whatever the user was doing before.
The 'floating' activity:
public class quickReply extends Activity {
String mNumber, mMessage;
TextView mMainText;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mMainText = (TextView)findViewById(R.id.mainText);
try{
Intent i = getIntent();
Bundle extras = i.getExtras();
mNumber = extras.getString("theNumber");
mMessage = extras.getString("theMessage");
this.setTitle("Message From:" + mNumber);
mMainText.setText(mMessage);
} catch(Exception e) {
mMainText.setText(e.getMessage());
}
}
}
The call to the activity inside an onReceive()
Intent i = new Intent(context, quickReply.class);
i.putExtra("theNumber", mNumber);
i.putExtra("theMessage", mMessage);
i.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
The Manifest:
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".quickReply"
android:label="#string/app_name"
android:theme="#android:style/Theme.Dialog"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".SmsReceiver">
<intent-filter>
<action android:name=
"android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
the only way I have found that works, in your activity definition in manifest:
android:launchMode="singleInstance"
but then you have to relaunch your main/default activity once the dialog is dismissed. NOTE: you will lose all state from the previous launch, so this is a less than ideal solution.
UPDATE:
you can also do this by:
Intent.FLAG_ACTIVITY_CLEAR_TASK
so here's what I did:
open the original/main activity
from a service, launch the dialog style activity using the above (main goes bye-bye).
when the user dismisses the dialog, start main again with an extra intent (IS_BACK) that is processed in onCreate() and calls:
moveTaskToBack(true);
this will keep the task under the dialog on top and your main in the back of the stack.
You should set the task affinity of the activity to something different than your main activity. This will separate it from the main activity and it will track as a separate task:
<activity android:name=".quickReply"
android:label="#string/app_name"
android:theme="#android:style/Theme.Dialog"
android:launchMode="singleTask"
android:taskAffinity="quickReply"
>
Related
I have StartActivity and MainActivity, in manifest scheme is already set.
<activity
android:name=".StartActivity"
android:label="#string/app_name"
android:theme="#style/AppThemeNoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="myApp" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:parentActivityName=".StartActivity" />
StartActivity:
public class StartActivity extends InstrumentedActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_start);
if (isLogin) {
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
}
}
The original design is after user pressed the url in browser, it open StartActivity and then go to MainActivity when user logined.
This works correctly in the first time (App is killed and user pressed the url).
But while the app is in the background (in MainActivity), after user press the url, it didn't go through StartActivity but only onResume of MainActivity.
Anyone know the reason? and how to make sure it go to StartActivity? Thanks.
when you open your Activity first time from URL ,that time Activity created so onCreate() method called .But if your Activity is in Background then
onNewIntent() will be called so Override this method And put you code here .
Add below method : IN MainActivity
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// add your code here
}
In Manifest :
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
/>
Start Activity :
Intent intent = new Intent(context, MainActivity.class);
startActivity(intent);
if you want pass any input value then you may pass in Intent through Bundle ,that is received into onNewIntent(Intent intent) ,and you can get just like we get data from Intent send from one Activity to next activity.
In my application I have several "intents" that I use to transition between different activities in my application. I have noticed a strange behavior that occurs on Samsung devices - but not on Nexus devices - whenever a new intent is created the application launches a second "task" for this new activity! When the user goes to the multi-tasking menu they can see multiple copies of the application! This is not the desired behavior. Any and all advice would be greatly appreciated!
Manifest:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:launchMode="singleInstance">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
android:launchMode="singleInstance">
</activity>
<activity
android:name=".Settings_area"
android:screenOrientation="portrait" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyDieXTCaFoIL0kJ_IM4UMBSQL3sNn92AWM" />
<activity
android:name=".MapsActivity"
android:label="#string/title_activity_maps" />
<activity android:name=".Splash"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".aboutPageActivity" />
<activity android:name=".turnOffFromNotification"
android:noHistory="true"></activity>
</application>
I have already attempted removing the launch modes as well as changing the application launch mode to singleTop and standard.
Intent that creates a second instance:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
/* Create an Intent that will start the Menu-Activity. */
Intent mainIntent = new Intent(Splash.this,MainActivity.class);
Splash.this.startActivity(mainIntent);
Splash.this.finish();
}
}, splashDisplayLength);
return;
}
Intent that creates a third instance:
public void goToAboutPage()
{
Intent goToAboutPage = new Intent(this, aboutPageActivity.class); //create the intent to go to the map screen
startActivity(goToAboutPage); //actually go to the map screen
}
A third instance can also be created from launching a settings intent:
public void changeToSettingsScreen() //changes the screen to the setting screen
{
readyToSendPackets = false;
sendSwitch.setChecked(false);
// textView.setText("NOT sending"); //set the textview to advise users packets are not being sent
Intent goToSettings = new Intent(this, Settings_area.class);
startActivity(goToSettings);
}
I also over rode the onNewIntent Method:
protected void onNewIntent(Intent intent) {
// super.onNewIntent(intent); //REMOVED THIS TO AVOID DOUBLE INSTANTIATION ON TOUCHWIZ IF ANYTHING BREAKS LOOK HERE FIRST
setIntent(intent); //this allows us to recieve the extras bundled with the intent
// System.out.println("Here is the bindle: " + getIntent().getExtras());
if (getIntent().getExtras() != null) //check to see if there are any extras, there wont be on apps first start
{
Bundle extras = getIntent().getExtras(); //get the extras
String methodName = extras.getString("methodName"); //assign the extras to local variables
if(methodName != null && methodName.equals("turn_send_switch_off"))
{
sendSwitch.setChecked(false);
}
//else if(**other actions that may need to be performed can go here**)
}
Thank you very much for any help!!!
Usually if you have to force a single instance of the app, you should avoid putting android:launchMode="singleInstance" on each activity seeing as it would try to launch an instance for each activity.
Removing the launchMode from everything except the application should ensure that only the application runs in a single instance, although what #Shaishav said is true, most of the time you can let android deal with the lifecycle of an application by not setting the launchMode, unless you have a real need to ensure only one instance is running at a time.
The idea is to manage what activity will be launched depending on already set up properties?
Now I'm using Activity A1 which decides Activity A2 or Activity A3 will be launched.
A1 extends Activity{
...
onCreate(...) {
Intent intent = new Intent();
if (launchA2){
intent = new Intent(this,A2.class);
} else {
intent = new Intent(this,A3.class);
}
startActivity(intent);
finish();
}
...
}
Is there any solution to move this logic into Application class or somewhere without A1 class?
Futhermore, there is another problem about AndroidManifest.xml file.
<activity
android:name="A1"
android:launchMode="singleTop"
android:label="#string/app_alias">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Is it possible to change this Activity programmatically?
For now, the InitialActivity is set as the main activity in the AndroidManifest.xml file.
<activity
android:name=".ui.SplashActivity"
android:noHistory="true" >
</activity>
<activity
android:name=".ui.InitialActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.LoginActivity"
android:noHistory="true" >
</activity>
<activity
android:name=".ui.RegisterActivity"
android:noHistory="true" >
</activity>
<activity
android:name=".ui.MainScreenActivity"
android:launchMode="singleTop">
</activity>
After finishing the registration process in the RegisterActivity, quit the application and re-start the app, I want the app to directly go to MainScreenActivity automatically logged in. So here's the part of the InitialActivity class that checks if I am logged in and goes to the MainScreenActivity if I am.
session = new SessionManager(getApplicationContext());
// check if user is already logged in.
if(session.isLoggedIn()) {
// User is already logged in. Take him to MainScreenActivity.
Intent intent = new Intent(InitialActivity.this, MainScreenActivity.class);
startActivity(intent);
finish();
} else {
startActivity(new Intent(this, SplashActivity.class));
}
So far, I managed to go directly into the MainScreenActivity with the code above, but in this case I miss the splash. How can I modify the code so that I can still see the SplashActivity even after being automatically logged in?
FYI here's the SplashActivity class code.
public class SplashActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Handler hd = new Handler();
hd.postDelayed(new Runnable() {
#Override
public void run() {
finish();
}
}, 1500);
}
}
I will use the splashActivity as the launcher activity (it will be launch every time) and I will check in this activity if user is logged or not, depending on the response launch the RegisterActivity or the mainActivity
I have separated activity which is launched from service and is used for collecting results after some event.
Problem is that separated activity is launched and after the selectiong of the result by user is closed using
public void closeApp() {
Toast.makeText(getApplicationContext(), "Saved",Toast.LENGTH_LONG).show();
this.finish();
}
Separated activity is closed but "under" this activity is already started main activity of the app and this is not what i want.
I just want to do following:
Display separated activity,
Select result,
Close separated activity
Without starting the main app activity (if user want to see collected result must tap on the app icon).
Here is what i tried:
Manifest:
Main activity:
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="#string/app_name" android:launchMode="singleTop" android:name="CallPlanner" android:theme="#android:style/Theme.Black.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Separated activity:
<activity android:name="com.result.plugin.ReceiverActivity" android:theme="#android:style/Theme.Translucent.NoTitleBar" />
Separetd activity is stared from the service using these tags:
intentOne.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentOne.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
How can i solve it and what is best way how to do it?
Many Thanks for any help.
EDIT: ADDED ACTIVITY CALLING FROM RECEIVER
/*
* CALL RESULT ACTIVITY IN CASE THAT OUTGOING CALL IS ENDED, NUMBER IS AVAILABLE AND APP IS ACTIVE
*/
if (DataHolder.getAction().equals("OUTGOING_CALL")
&& !DataHolder.getPhoneNumber().isEmpty()
&& extraState.equals(TelephonyManager.EXTRA_STATE_IDLE)
&& isAppActive == 1) {
Log.i("Catched", "Catched");
Toast.makeText(context, "Catched",Toast.LENGTH_LONG).show();
// START ACTIVITY AND PASS PARAMS
intentOne = new Intent(context.getApplicationContext(),
ReceiverActivity.class);
// intentOne = new Intent(context.getApplicationContext(),
// CordovaReceiverActivity.class);
if(intentOne == null) {
throw new NullPointerException(
" :: intentOne 'param' was null inside method 'onReceive'.");
}
intentOne.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentOne.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
//intentOne.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//intentOne.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//intentOne.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
/*
intentOne.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intentOne.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intentOne.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intentOne.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intentOne.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
*/
// PASS PARAM TO CALLED ACTIVITY
Bundle b = new Bundle();
b.putString("phone_number", DataHolder.getPhoneNumber());
// Put your id to your next Intent
intentOne.putExtras(b);
// START ACTIVITY
context.startActivity(intentOne);
};