Skip to content

Commit 9828830

Browse files
adampAndroid (Google) Code Review
authored andcommitted
Merge "TaskStackBuilder and Activity navigation features for framework"
2 parents 5459c43 + dd8fab2 commit 9828830

File tree

12 files changed

+683
-14
lines changed

12 files changed

+683
-14
lines changed

api/current.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ package android {
727727
field public static final int panelColorForeground = 16842848; // 0x1010060
728728
field public static final int panelFullBackground = 16842847; // 0x101005f
729729
field public static final int panelTextAppearance = 16842850; // 0x1010062
730+
field public static final int parentActivityName = 16843696; // 0x10103b0
730731
field public static final deprecated int password = 16843100; // 0x101015c
731732
field public static final int path = 16842794; // 0x101002a
732733
field public static final int pathPattern = 16842796; // 0x101002c
@@ -2578,6 +2579,7 @@ package android.app {
25782579
method public java.lang.String getLocalClassName();
25792580
method public android.view.MenuInflater getMenuInflater();
25802581
method public final android.app.Activity getParent();
2582+
method public android.content.Intent getParentActivityIntent();
25812583
method public android.content.SharedPreferences getPreferences(int);
25822584
method public int getRequestedOrientation();
25832585
method public int getTaskId();
@@ -2594,6 +2596,8 @@ package android.app {
25942596
method public boolean isTaskRoot();
25952597
method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
25962598
method public boolean moveTaskToBack(boolean);
2599+
method public boolean navigateUpTo(android.content.Intent);
2600+
method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent);
25972601
method public void onActionModeFinished(android.view.ActionMode);
25982602
method public void onActionModeStarted(android.view.ActionMode);
25992603
method protected void onActivityResult(int, int, android.content.Intent);
@@ -2610,6 +2614,7 @@ package android.app {
26102614
method public java.lang.CharSequence onCreateDescription();
26112615
method protected deprecated android.app.Dialog onCreateDialog(int);
26122616
method protected deprecated android.app.Dialog onCreateDialog(int, android.os.Bundle);
2617+
method public void onCreateNavigateUpTaskStack(android.app.TaskStackBuilder);
26132618
method public boolean onCreateOptionsMenu(android.view.Menu);
26142619
method public boolean onCreatePanelMenu(int, android.view.Menu);
26152620
method public android.view.View onCreatePanelView(int);
@@ -2627,6 +2632,8 @@ package android.app {
26272632
method public void onLowMemory();
26282633
method public boolean onMenuItemSelected(int, android.view.MenuItem);
26292634
method public boolean onMenuOpened(int, android.view.Menu);
2635+
method public boolean onNavigateUp();
2636+
method public boolean onNavigateUpFromChild(android.app.Activity);
26302637
method protected void onNewIntent(android.content.Intent);
26312638
method public boolean onOptionsItemSelected(android.view.MenuItem);
26322639
method public void onOptionsMenuClosed(android.view.Menu);
@@ -2636,6 +2643,7 @@ package android.app {
26362643
method protected void onPostResume();
26372644
method protected deprecated void onPrepareDialog(int, android.app.Dialog);
26382645
method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
2646+
method public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder);
26392647
method public boolean onPrepareOptionsMenu(android.view.Menu);
26402648
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
26412649
method protected void onRestart();
@@ -2686,6 +2694,7 @@ package android.app {
26862694
method public void setTitleColor(int);
26872695
method public void setVisible(boolean);
26882696
method public final void setVolumeControlStream(int);
2697+
method public boolean shouldUpRecreateTask(android.content.Intent);
26892698
method public final deprecated void showDialog(int);
26902699
method public final deprecated boolean showDialog(int, android.os.Bundle);
26912700
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
@@ -3932,6 +3941,18 @@ package android.app {
39323941
method public void setDefaultTab(int);
39333942
}
39343943

3944+
public class TaskStackBuilder implements java.lang.Iterable {
3945+
method public android.app.TaskStackBuilder addNextIntent(android.content.Intent);
3946+
method public android.app.TaskStackBuilder addParentStack(android.app.Activity);
3947+
method public android.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
3948+
method public static android.app.TaskStackBuilder from(android.content.Context);
3949+
method public android.content.Intent getIntent(int);
3950+
method public int getIntentCount();
3951+
method public android.app.PendingIntent getPendingIntent(int, int);
3952+
method public java.util.Iterator<android.content.Intent> iterator();
3953+
method public void startActivities();
3954+
}
3955+
39353956
public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
39363957
ctor public TimePickerDialog(android.content.Context, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
39373958
ctor public TimePickerDialog(android.content.Context, int, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
@@ -6102,6 +6123,7 @@ package android.content.pm {
61026123
field public int configChanges;
61036124
field public int flags;
61046125
field public int launchMode;
6126+
field public java.lang.String parentActivityName;
61056127
field public java.lang.String permission;
61066128
field public int screenOrientation;
61076129
field public int softInputMode;

core/java/android/app/Activity.java

Lines changed: 216 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import android.content.IntentSender;
3030
import android.content.SharedPreferences;
3131
import android.content.pm.ActivityInfo;
32+
import android.content.pm.PackageManager;
33+
import android.content.pm.PackageManager.NameNotFoundException;
3234
import android.content.res.Configuration;
3335
import android.content.res.Resources;
3436
import android.content.res.TypedArray;
@@ -65,13 +67,13 @@
6567
import android.view.MenuItem;
6668
import android.view.MotionEvent;
6769
import android.view.View;
68-
import android.view.WindowManagerImpl;
6970
import android.view.View.OnCreateContextMenuListener;
7071
import android.view.ViewGroup;
7172
import android.view.ViewGroup.LayoutParams;
7273
import android.view.ViewManager;
7374
import android.view.Window;
7475
import android.view.WindowManager;
76+
import android.view.WindowManagerImpl;
7577
import android.view.accessibility.AccessibilityEvent;
7678
import android.widget.AdapterView;
7779

@@ -704,6 +706,7 @@ static final class NonConfigurationInstances {
704706
/*package*/ boolean mVisibleFromServer = false;
705707
/*package*/ boolean mVisibleFromClient = true;
706708
/*package*/ ActionBarImpl mActionBar = null;
709+
private boolean mEnableDefaultActionBarUp;
707710

708711
private CharSequence mTitle;
709712
private int mTitleColor = 0;
@@ -865,6 +868,13 @@ protected void onCreate(Bundle savedInstanceState) {
865868
if (mLastNonConfigurationInstances != null) {
866869
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
867870
}
871+
if (mActivityInfo.parentActivityName != null) {
872+
if (mActionBar == null) {
873+
mEnableDefaultActionBarUp = true;
874+
} else {
875+
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
876+
}
877+
}
868878
if (savedInstanceState != null) {
869879
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
870880
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
@@ -1829,6 +1839,7 @@ private void initActionBar() {
18291839
}
18301840

18311841
mActionBar = new ActionBarImpl(this);
1842+
mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
18321843
}
18331844

18341845
/**
@@ -2630,7 +2641,7 @@ public boolean onPrepareOptionsMenu(Menu menu) {
26302641
* facilities.
26312642
*
26322643
* <p>Derived classes should call through to the base class for it to
2633-
* perform the default menu handling.
2644+
* perform the default menu handling.</p>
26342645
*
26352646
* @param item The menu item that was selected.
26362647
*
@@ -2643,9 +2654,104 @@ public boolean onOptionsItemSelected(MenuItem item) {
26432654
if (mParent != null) {
26442655
return mParent.onOptionsItemSelected(item);
26452656
}
2657+
if (item.getItemId() == android.R.id.home && mActionBar != null &&
2658+
(mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
2659+
if (mParent == null) {
2660+
onNavigateUp();
2661+
} else {
2662+
mParent.onNavigateUpFromChild(this);
2663+
}
2664+
return true;
2665+
}
26462666
return false;
26472667
}
26482668

2669+
/**
2670+
* This method is called whenever the user chooses to navigate Up within your application's
2671+
* activity hierarchy from the action bar.
2672+
*
2673+
* <p>If the attribute {@link android.R.attr#parentActivityName parentActivityName}
2674+
* was specified in the manifest for this activity or an activity-alias to it,
2675+
* default Up navigation will be handled automatically. If any activity
2676+
* along the parent chain requires extra Intent arguments, the Activity subclass
2677+
* should override the method {@link #onPrepareNavigateUpTaskStack(TaskStackBuilder)}
2678+
* to supply those arguments.</p>
2679+
*
2680+
* <p>See <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
2681+
* from the developer guide and <a href="{@docRoot}design/patterns/navigation.html">Navigation</a>
2682+
* from the design guide for more information about navigating within your app.</p>
2683+
*
2684+
* <p>See the {@link TaskStackBuilder} class and the Activity methods
2685+
* {@link #getParentActivityIntent()}, {@link #shouldUpRecreateTask(Intent)}, and
2686+
* {@link #navigateUpTo(Intent)} for help implementing custom Up navigation.
2687+
* The AppNavigation sample application in the Android SDK is also available for reference.</p>
2688+
*
2689+
* @return true if Up navigation completed successfully and this Activity was finished,
2690+
* false otherwise.
2691+
*/
2692+
public boolean onNavigateUp() {
2693+
// Automatically handle hierarchical Up navigation if the proper
2694+
// metadata is available.
2695+
Intent upIntent = getParentActivityIntent();
2696+
if (upIntent != null) {
2697+
if (shouldUpRecreateTask(upIntent)) {
2698+
TaskStackBuilder b = TaskStackBuilder.from(this);
2699+
onCreateNavigateUpTaskStack(b);
2700+
onPrepareNavigateUpTaskStack(b);
2701+
b.startActivities();
2702+
finish();
2703+
} else {
2704+
navigateUpTo(upIntent);
2705+
}
2706+
return true;
2707+
}
2708+
return false;
2709+
}
2710+
2711+
/**
2712+
* This is called when a child activity of this one attempts to navigate up.
2713+
* The default implementation simply calls onNavigateUp() on this activity (the parent).
2714+
*
2715+
* @param child The activity making the call.
2716+
*/
2717+
public boolean onNavigateUpFromChild(Activity child) {
2718+
return onNavigateUp();
2719+
}
2720+
2721+
/**
2722+
* Define the synthetic task stack that will be generated during Up navigation from
2723+
* a different task.
2724+
*
2725+
* <p>The default implementation of this method adds the parent chain of this activity
2726+
* as specified in the manifest to the supplied {@link TaskStackBuilder}. Applications
2727+
* may choose to override this method to construct the desired task stack in a different
2728+
* way.</p>
2729+
*
2730+
* <p>Applications that wish to supply extra Intent parameters to the parent stack defined
2731+
* by the manifest should override {@link #onPrepareNavigateUpTaskStack(TaskStackBuilder)}.</p>
2732+
*
2733+
* @param builder An empty TaskStackBuilder - the application should add intents representing
2734+
* the desired task stack
2735+
*/
2736+
public void onCreateNavigateUpTaskStack(TaskStackBuilder builder) {
2737+
builder.addParentStack(this);
2738+
}
2739+
2740+
/**
2741+
* Prepare the synthetic task stack that will be generated during Up navigation
2742+
* from a different task.
2743+
*
2744+
* <p>This method receives the {@link TaskStackBuilder} with the constructed series of
2745+
* Intents as generated by {@link #onCreateNavigateUpTaskStack(TaskStackBuilder)}.
2746+
* If any extra data should be added to these intents before launching the new task,
2747+
* the application should override this method and add that data here.</p>
2748+
*
2749+
* @param builder A TaskStackBuilder that has been populated with Intents by
2750+
* onCreateNavigateUpTaskStack.
2751+
*/
2752+
public void onPrepareNavigateUpTaskStack(TaskStackBuilder builder) {
2753+
}
2754+
26492755
/**
26502756
* This hook is called whenever the options menu is being closed (either by the user canceling
26512757
* the menu with the back/menu button, or when an item is selected).
@@ -4658,6 +4764,114 @@ public void onActionModeStarted(ActionMode mode) {
46584764
public void onActionModeFinished(ActionMode mode) {
46594765
}
46604766

4767+
/**
4768+
* Returns true if the app should recreate the task when navigating 'up' from this activity
4769+
* by using targetIntent.
4770+
*
4771+
* <p>If this method returns false the app can trivially call
4772+
* {@link #navigateUpTo(Intent)} using the same parameters to correctly perform
4773+
* up navigation. If this method returns false, the app should synthesize a new task stack
4774+
* by using {@link TaskStackBuilder} or another similar mechanism to perform up navigation.</p>
4775+
*
4776+
* @param targetIntent An intent representing the target destination for up navigation
4777+
* @return true if navigating up should recreate a new task stack, false if the same task
4778+
* should be used for the destination
4779+
*/
4780+
public boolean shouldUpRecreateTask(Intent targetIntent) {
4781+
try {
4782+
PackageManager pm = getPackageManager();
4783+
ComponentName cn = targetIntent.getComponent();
4784+
if (cn == null) {
4785+
cn = targetIntent.resolveActivity(pm);
4786+
}
4787+
ActivityInfo info = pm.getActivityInfo(cn, 0);
4788+
if (info.taskAffinity == null) {
4789+
return false;
4790+
}
4791+
return !ActivityManagerNative.getDefault()
4792+
.targetTaskAffinityMatchesActivity(mToken, info.taskAffinity);
4793+
} catch (RemoteException e) {
4794+
return false;
4795+
} catch (NameNotFoundException e) {
4796+
return false;
4797+
}
4798+
}
4799+
4800+
/**
4801+
* Navigate from this activity to the activity specified by upIntent, finishing this activity
4802+
* in the process. If the activity indicated by upIntent already exists in the task's history,
4803+
* this activity and all others before the indicated activity in the history stack will be
4804+
* finished. If the indicated activity does not appear in the history stack, this is equivalent
4805+
* to simply calling finish() on this activity.
4806+
*
4807+
* <p>This method should be used when performing up navigation from within the same task
4808+
* as the destination. If up navigation should cross tasks in some cases, see
4809+
* {@link #shouldUpRecreateTask(Intent)}.</p>
4810+
*
4811+
* @param upIntent An intent representing the target destination for up navigation
4812+
*
4813+
* @return true if up navigation successfully reached the activity indicated by upIntent and
4814+
* upIntent was delivered to it. false if an instance of the indicated activity could
4815+
* not be found and this activity was simply finished normally.
4816+
*/
4817+
public boolean navigateUpTo(Intent upIntent) {
4818+
if (mParent == null) {
4819+
ComponentName destInfo = upIntent.getComponent();
4820+
if (destInfo == null) {
4821+
destInfo = upIntent.resolveActivity(getPackageManager());
4822+
if (destInfo == null) {
4823+
return false;
4824+
}
4825+
upIntent = new Intent(upIntent);
4826+
upIntent.setComponent(destInfo);
4827+
}
4828+
int resultCode;
4829+
Intent resultData;
4830+
synchronized (this) {
4831+
resultCode = mResultCode;
4832+
resultData = mResultData;
4833+
}
4834+
if (resultData != null) {
4835+
resultData.setAllowFds(false);
4836+
}
4837+
try {
4838+
return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
4839+
resultCode, resultData);
4840+
} catch (RemoteException e) {
4841+
return false;
4842+
}
4843+
} else {
4844+
return mParent.navigateUpToFromChild(this, upIntent);
4845+
}
4846+
}
4847+
4848+
/**
4849+
* This is called when a child activity of this one calls its
4850+
* {@link #navigateUpTo} method. The default implementation simply calls
4851+
* navigateUpTo(upIntent) on this activity (the parent).
4852+
*
4853+
* @param child The activity making the call.
4854+
* @param upIntent An intent representing the target destination for up navigation
4855+
*
4856+
* @return true if up navigation successfully reached the activity indicated by upIntent and
4857+
* upIntent was delivered to it. false if an instance of the indicated activity could
4858+
* not be found and this activity was simply finished normally.
4859+
*/
4860+
public boolean navigateUpToFromChild(Activity child, Intent upIntent) {
4861+
return navigateUpTo(upIntent);
4862+
}
4863+
4864+
/**
4865+
* Obtain an {@link Intent} that will launch an explicit target activity specified by
4866+
* this activity's logical parent. The logical parent is named in the application's manifest
4867+
* by the {@link android.R.attr#parentActivityName parentActivityName} attribute.
4868+
*
4869+
* @return a new Intent targeting the defined parent of this activity
4870+
*/
4871+
public Intent getParentActivityIntent() {
4872+
return new Intent().setClassName(this, mActivityInfo.parentActivityName);
4873+
}
4874+
46614875
// ------------------ Internal API ------------------
46624876

46634877
final void setParent(Activity parent) {

core/java/android/app/ActivityManager.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1774,5 +1774,4 @@ public boolean switchUser(int userid) {
17741774
return false;
17751775
}
17761776
}
1777-
17781777
}

0 commit comments

Comments
 (0)