I have a very strange problem regarding Android intent-filter from URL.
In short: I have activity A as MAIN & LAUNCHER and activity B that has intent-filter that allows it to be opened via href="intent://...". Activity B has activity A listed as parent.
If I open the app via clicking the href, it opened directly to B (as expected). But then, if I press back (so I am in activity A) and try to open the app from href again, it opened to activity A instead of B! This is is really strange as activity A does not have any intent filter other than MAIN and LAUNCHER.
What I have right now:
Manifest containing activity A and activity B:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.my.app">
<activity
android:name=".AActivity"
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=".BActivity"
android:label="#string/app_name"
android:launchMode="singleTop"
android:parentActivityName=".AActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".AActivity" />
<intent-filter>
<data
android:host="m.something.com"
android:path="/somepath"
android:scheme="https" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
The href I used:
href="intent://m.something.com/somepath#Intent;scheme=https;package=com.my.app;S.extra_string=name#domain.com;end"
Activity B code:
At first, I didn't override the onOptionsItemSelected. I thought if I have specified the parent activity in the manifest, then Android (by default) will open Activity A, but when I opened activity B from URL and press up, it closed the app. Therefore, I need to do the following code.
#Override
public void onCreate(Bundle savedInstanceState) {
setSupportActionBar(...);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (isTaskRoot()) {
Intent upIntent = NavUtils.getParentActivityIntent(this);
startActivity(upIntent);
}
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
Fragment Z code inside activity B:
//Code omitted, basically I get the extra_string from the intent
//(from the a href) and processed it here.
Now, these steps work:
Open app from launcher (hence, activity A is shown).
Tap device's recent app button, open chrome, navigate to web that contains that a href and click it.
App opened activity B, fragment Z can obtain the extra_string
Tap device's recent app button, go to chrome, and click a href again.
App opened activity B, fragment Z can obtain the extra_string.
BUT, these are the steps that lead to the problem:
Swipe app from recent app (this is important).
Open chrome, navigate to web that contains the a href and click it.
The app opened directly to activity B, the fragment Z can obtain the extra_string successfully.
Press up, the app "goes back" to activity A successfully.
Press device's recent app button, open chrome (back to the web that contains a href) and press the a href again.
Expectation:
The app opened directly to activity B.
Reality:
The app opened to activity A.
I really have no idea what's going on here. I have tried to search for similar problem in SO to no avail. Anybody experienced the same problem?
Related
I have an app that acts as a Launcher. This app has 3 activities:
SplashActivity: shows a splash screen while loading, then launches LauncherActivity and finishes. This is the Activity marked as launcher in the manifest.
startActivity(Intent(this, LauncherActivity::class.java))
finish()
<activity
android:name=".SplashActivity"
android:label="#string/app_name"
android:screenOrientation="landscape"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
LauncherActivity: main activity for Launcher. Has a menu button that launches DashboardActivity.
startActivity(Intent(this#LauncherActivity, DashboardActivity::class.java))
<activity
android:name=".LauncherActivity"
android:launchMode="singleTask"
android:screenOrientation="landscape" />
DashboardActivity: shows a list of apps and launches them through their launch intent.
private val DEFAULT_FLAGS_APP_LAUNCH = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(packageManager.getLaunchIntentForPackage(packageInfo.packageName).apply {
flags = DEFAULT_FLAGS_APP_LAUNCH
})
<activity
android:label="#string/apps"
android:theme="#style/TNA"
android:name=".DashboardActivity"
android:launchMode="singleTask"
android:screenOrientation="landscape" />
All activities are launched through startActivity, including the apps.
I want the standard Android Launcher behavior, that is: when entering an app through DashboardActivity, if I click home button, go to the main Launcher activity (LauncherActivity), and when clicking back, go to the dashboard (DashboardActivity).
The problem I have is that when clicking home, it goes back to DashboardActivity, not to LauncherActivity. If I finish DashboardActivity, then when clicking back on an app, it goes back to LauncherActivity.
Any ideas on how to solve this?
This is definitely back/task stack related. See this link for more information about the task stack.
When you go from LauncherActivity to DashboardActivity, the dashboard is placed on to the task stack. When the LauncherActivity is requested again via the HOME button, the task stack is restored back to the last Activity which was in use after launching the LauncherActivity, which was DashboardActivity.
You have several different options to resolve this:
Don't use a separate Activity for the "dashboard". Consider a drawer or even a Fragment which shows the content and can be popped back to the main LauncherActivity when it is done calling startActivity to launch another app.
After your DashboardActivity calls startActivity, it should call finish() so it will get popped off the current task stack.
Usually launchers are setup to be launched in singleInstance mode, preventing multiple instances of the launcher Activity to run at the same time. Note that you'll need to support onNewIntent in your LauncherActivity.
To prevent odd interactions with the task manager, consider setting FLAG_ACTIVITY_NO_HISTORY when launcher your DashboardActivity.
I have an activity A, and when I press an toolbar item, it starts activity B using startActivity(intent). Whenever I press back button or the up navigation icon, it closes my app. I believe it's because I'm using launchMode="singleTop" in my parent activity (I'm using this because I have a Search View and a searchable configuration, because I don't want to start another instance of my activity on for search). So the question is: How can I get back from child activity(B) to parent activity(A) using both up navigation and back button without closing my app? I've searched about it, and I found something about onNewIntent(). If this is my solution, how should I use it properly?
Here is my manifest file:
<activity
android:name="com.example.fernando.inspectionrover.MainActivity"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
<activity
android:name="com.example.fernando.inspectionrover.BluetoothSettingsActivity"
android:parentActivityName="com.example.fernando.inspectionrover.MainActivity"
android:screenOrientation="landscape">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.fernando.inspectionrover.MainActivity" />
Here is how start my new activity:
switch (id) {
case R.id.bluetoothActivity:
Intent switchActivity = new Intent(this, BluetoothSettingsActivity.class);
startActivity(switchActivity);
Log.i(LIFE_CYCLE, "Switching from " + getLocalClassName() + " to Bluetooth Setting Activity");
finish();
break;
}
Single Top means that if you launch an activity that is already on top, it wont be created again just resumed.
The reason your back navigation close the app is because you are calling finish() just after you start a new activity. Which means you don't need that activity anymore so it is removed from the stack. If you go back on activityB, the app will close because there is nothing to go back (you called finish() remember?
I may be just poking at the easiest answer but I think the main problem is that you are calling finish after you start the new activity. This calls on destroy for the calling activity and removes it from the activity stack.
I have this <intent-filter> that every time certain link is pressed it opens my app but the problem is it opens a new instance of my app. Is there anyway to trigger onResume() and just resume my app without losing its state or the activities stack?
This is the intent filter:
<intent-filter>
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="example.com" />
<data android:pathPattern="/.*" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
Update
Thanks to user David Wasser answer below I found answer:
So I created EntryActivity which is launched on top of gmail/inbox app:
public class EntryActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_activity);
Uri uriParams = getIntent().getData();
Log.e("EntryActivity", uriParams.getHost() );
Log.e("EntryActivity", uriParams.getQueryParameter("uid") + " " + uriParams.getQueryParameter("type") + " " + uriParams.getQueryParameter("token") );
Intent startCategory = new Intent(this, GotEmailActivity.class);
startCategory.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startCategory);
this.finish();
}
}
Then when my app is opened at GotEmailActivity I send email to user with link to open app and GotEmailActivity has attribute android:launchMode="singleTop" in AndroidManifest so only 1 instance of it is opened:
<!--
Important: notice android:launchMode="singleTop"
which seeks if an instance of this activity is already opened and
resumes already opened instance, if not it opens new instance.
-->
<activity
android:name=".presenters.register.email.GotEmailActivity"
android:label="#string/title_activity_got_email"
android:launchMode="singleTop"
android:theme="#android:style/Theme.Translucent.NoTitleBar" >
Now what is happening is that EntryActivity is opened ontop of Gmail app but it closes inmediatle but first launches GotEmailActivity which is already opened so attribute launchMode Singletop prevents a new instance of such activity.
You should create another Activity that you use as an entry point to your application when responding to that <intent-filter>. Something like this:
What you need is just a simple Activity that does nothing. Here is an example:
public class EntryActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check to see if this Activity is the root activity
if (isTaskRoot()) {
// This Activity is the only Activity, so
// the app wasn't running. So start the app from the
// beginning (redirect to MainActivity)
Intent mainIntent = getIntent(); // Copy the Intent used to launch me
// Launch the real root Activity (launch Intent)
mainIntent.setClass(this, MainActivity.class);
// I'm done now, so finish()
startActivity(mainIntent);
finish();
} else {
// App was already running, so just finish, which will drop the user
// in to the activity that was at the top of the task stack
finish();
}
}
}
Put your <intent-filter> on this activity, instead of your "launcher" Activity. Make sure that in the manifest the task affinity of this activity is the same as the task affinity of the other activities in your application (by default it is, if you haven't explicitly set android:taskAffinity).
When the <intent-filter> gets triggered, if your application is running, then the EntryActivity will be started on top of the topmost activity in your application's task and that task will be brought to the foreground. When the EntryActivity finishes, it will simply return the user to the topmost activity in your application (ie: wherever the user left it when it went into the background).
If your app was not running, the EntryActivity recognizes this and starts your app from the beginning, passing it the Intent containing the ACTION and DATA that triggered the <intent-filter>.
Should work.
I have tried everything I have been able to find online to stop this happening before someone suggests 'Just go google it'....
I will be explicit in case it is not clear enough, I do not want to have to click back twice when I am on the registration or login screen. Its like I have an Activity A the user never sees, A starts an intent to either B or C.
On B or C I do not want to click twice to exit the application.
I have an Activity that I want to be invisible to the user, its purpose is to check if the application has been registered, if it has it starts an intent to login Activity, if the app is not registered it starts an intent to registration activity. The issue that when on the login or registration screen I have to press back twice to exit the application.
If I do not call finish() in this Activity the back button takes me to the transparent Activity and I have to press back again, calling finish() means I don't go back to the transparent Activity but I do have to press back twice - which I don't want.
I already tried calling the startActivityForResult() example, but this doesn't have any effect.
The Activity is using the transparent theme as using the NoDisplay theme caused an exception, googling this seemed to imply an issue with the emulator and suggested fix was to use transparent.
<activity
android:name=".activity.AppEntryPoint"
android:label="#string/app_name"
android:theme="#android:style/Theme.Translucent.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The Activity doesn't do a lot at the moment, currently I am trying the code below but this also has no effect and I still have to press the back button twice.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!"".equals(((GlobalData) this.getApplication()).password)) {
navigateToLoginScreen();
} else {
registerApplication();
}
}
private void registerApplication() {
Intent registerScreen = new Intent(this, RegistrationActivity.class);
registerScreen.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(registerScreen);
finish();
}
private void navigateToLoginScreen() {
Intent loginScreen = new Intent(this, LoginActivity.class);
loginScreen.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(loginScreen);
finish();
}
What can I do to make sure that the user only has to press back once when they get to the second screen, whether it is the login or the registration screen?
i think this solution will solve your problem.
just add android:noHistory="true" in the manifest file to your first activity, like this:
<activity
android:name=".activity.AppEntryPoint"
android:label="#string/app_name"
android:noHistory="true"
android:theme="#android:style/Theme.Translucent.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I have the following problem:
When I press the Android HOME key, I can see the "Desktop" and my app icon. Then I press my app icon and my application launches twice. I don't want open my app twice.
How my program works:
I have 4 Activities (A, B, C, D).
A - The Main Activity: It is the first to open. It opens the other activity that has a lot of buttons. It's like a Java's main() method. I show a SplashScreen and I call another Activity. Then I finish my activity "A".
B - The Menu Screen: In this activity, I have some buttons, like a menu. I have a configuration button, update button, and Login Button. When I click the login button, I finish this activity and open the Login Screen (Activity "C").
C - The Login Screen: The user writes the Login and Password. If the login is successful, I finish this activity and open the Activity "D".
D - The application main screen: It stays opened all the time and launches another Activities. I finish this when I want close my application.
P.S.: I tried change the launchMode flag (androidManifest.xml), but didn't work.
My AndroidManifest.xml bellow:
<application android:label="#string/app_name" android:icon="#drawable/icon" android:name="MyApplication">
<activity android:name="A"
android:label="#string/app_name"
android:configChanges="orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="br.com.site.B" android:label="#string/app_name" />
<activity android:name="br.com.site.C" android:label="#string/app_name" />
<activity android:name="br.com.site.D" android:label="#string/app_name" />
</application>
And this is my Activity "A.java" source:
public class A extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finish();
startActivity(new Intent(this, AtualizaDadosFrame.class));
}
}
I don't want open my app twice.
Thanks in advance!
I'm going to assume that you started the app initially (the first time) from an IDE (like Eclipse or IntelliJ). If so, this is a known bug in Android (see http://code.google.com/p/android/issues/detail?id=26658 ). Many people have struggled for days chasing this problem :-(
Please don't change the launchMode. This is not the correct way to solve this problem. The default (standard) launchMode is the one that works in most cases.
EDIT (Added link to workaround):
A simple workaround for this problem can be found at http://code.google.com/p/android/issues/detail?id=2373#c21
You should set the desired launch mode in your AndroidManifest.xml.
You can restrict this.....
Please go through below link.
Home key press behaviour