I am writing an app that can be launched from another app by receiving an intent with ACTION_VIEW or ACTION_EDIT. For example, it can be opened by viewing an email attachment. The trouble is that when you click on the home button and click again on the launch icon of the email app you were using, my activity is killed and any user edits that had been made are lost. What I want to happen is that when the user clicks the home button, my activity is re-parented so that it resumes when the user clicks on the launch icon of my app. I've tried setting android:allowTaskReparenting="true" in manifest.xml but this doesn't work. Sometimes it doesn't have any effect at all, and sometimes the activity is moved to my launch icon, yet still gets killed when you click again on the email app icon. The documentation on allowTaskReparenting is really vague. It says the property means:
“Whether or not the activity can move from the task that started it to the task it has an affinity for.”
What does the word can mean here? What I want is a guarantee that the activity does move (and stays there). Is there any way to achieve this?
Thanks in advance to anyone who can help.
EDIT
In response to comments below, I have put together a baby version demonstrating the problems I am encountering. When you start EditFileActivity by clicking on a file in another app (e.g, an attachment to an email) you can then edit the file. But clicking on the home icon and then clicking again on the email app icon causes the changes you have made to the file to be lost. I want the android system to only forget about an instance of EditFileActivity if the user explicitly clicks back and then says "yes" or "no". Ideally I want all instances of EditFileActivity to stack up on my app's launch icon. I could implement something similar to this by using singleTask or singleInstance and writing some kind of activity showing all open files in tabs, but it would be much easier if I could get the android system itself to help me. Any ideas?
Here is a complete project demonstrating the problem.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.Example"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="11"/>
<application
android:label="Example"
android:icon="@drawable/ic_launcher">
<activity
android:name=".LaunchActivity"
android:label="LaunchActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".EditFileActivity"
android:label="EditFileActivity"
android:screenOrientation="portrait">
<!-- This is just an example. I wouldn't use this intent filter in a real app! -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.EDIT"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:mimeType="*/*"/>
<data android:host="*"/>
</intent-filter>
</activity>
</application>
</manifest>`
LaunchActivity:
public class LaunchActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setText("This is the activity you see when you click on the application's launch icon. It does absolutely nothing.");
textView.setTextSize(18);
setContentView(textView);
}
}
EditFileActivity:
public class EditFileActivity extends Activity {
// This String represents the contents of the file.
// In a "real" app the String would be initialised by reading the data from the Intent that started the activity.
// However, for the purposes of this example, the initial value is "Default".
private String fileContents = "Default";
private boolean editsMade = false;
private TextView textView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
textView.setText(fileContents);
textView.setTextSize(18);
textView.setPadding(10, 10, 10, 10);
setContentView(textView);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
makeEdits();
}
});
}
@Override
public void onBackPressed() {
if (editsMade) {
savePrompt();
} else {
finish();
}
}
private void savePrompt() {
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == Dialog.BUTTON_POSITIVE) {
// Here is where I would save the edited file.
Toast.makeText(EditFileActivity.this, "File saved", Toast.LENGTH_LONG).show();
}
finish();
}
};
new AlertDialog.Builder(this)
.setTitle("Close File")
.setMessage("Do you want to save the changes you made?")
.setPositiveButton("Yes", listener)
.setNegativeButton("No", listener)
.show();
}
private void makeEdits() {
final EditText editText = new EditText(this);
editText.setText(fileContents);
new AlertDialog.Builder(this)
.setTitle("Edit File")
.setView(editText)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
Editable editable = editText.getText();
assert editable != null;
String newContents = editable.toString();
if (!fileContents.equals(newContents)) {
editsMade = true;
fileContents = newContents;
textView.setText(fileContents);
}
}
})
.setNegativeButton("Cancel", null)
.show();
}
}
UPDATE 10/12/2014
The problems encountered were due to the use of the Intent flag FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET. Fortunately, Google have deprecated this flag, as of API Level 21.
Issue:
This happens because the email application had set
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
intent flag while launching your activity. When this flag is set, next time when the task is brought to the foreground, your activity will be finished, so that user returns to the previous activity.From docs:
Solution: Use
singleTask
launchMode for your activity. The email app will not kill your activity, as the activity belongs to different task now.If the activity instance is already in the task and an attempt is made to launch the activity again, then a new instance is not created. Instead
onNewIntent
is called. Here you can prompt the user to save the previous edit if any, before presenting new content.Source