diff --git a/api/current.xml b/api/current.xml
index 50546d3629a0f..dc4ba2c9bc5da 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -28030,6 +28030,19 @@
+
+
+
+
+
+
+
+
+
+
@@ -223896,7 +223924,7 @@
deprecated="not deprecated"
visibility="public"
>
-
+
@@ -247337,7 +247365,7 @@
0) {
+ op.removed = new ArrayList(N);
+ for (int i=0; i mPendingActions;
+ Runnable[] mTmpActions;
+ boolean mExecutingActions;
+
ArrayList mActive;
ArrayList mAdded;
ArrayList mAvailIndices;
@@ -91,6 +95,13 @@ public class FragmentManager {
Bundle mStateBundle = null;
SparseArray mStateArray = null;
+ Runnable mExecCommit = new Runnable() {
+ @Override
+ public void run() {
+ execPendingActions();
+ }
+ };
+
Animation loadAnimation(Fragment fragment, int transit, boolean enter,
int transitionStyle) {
Animation animObj = fragment.onCreateAnimation(transitionStyle, enter,
@@ -486,6 +497,52 @@ public class FragmentManager {
return null;
}
+ public void enqueueAction(Runnable action) {
+ synchronized (this) {
+ if (mPendingActions == null) {
+ mPendingActions = new ArrayList();
+ }
+ mPendingActions.add(action);
+ if (mPendingActions.size() == 1) {
+ mActivity.mHandler.removeCallbacks(mExecCommit);
+ mActivity.mHandler.post(mExecCommit);
+ }
+ }
+ }
+
+ /**
+ * Only call from main thread!
+ */
+ public void execPendingActions() {
+ if (mExecutingActions) {
+ throw new IllegalStateException("Recursive entry to execPendingActions");
+ }
+
+ while (true) {
+ int numActions;
+
+ synchronized (this) {
+ if (mPendingActions == null || mPendingActions.size() == 0) {
+ return;
+ }
+
+ numActions = mPendingActions.size();
+ if (mTmpActions == null || mTmpActions.length < numActions) {
+ mTmpActions = new Runnable[numActions];
+ }
+ mPendingActions.toArray(mTmpActions);
+ mPendingActions.clear();
+ mActivity.mHandler.removeCallbacks(mExecCommit);
+ }
+
+ mExecutingActions = true;
+ for (int i=0; i();
@@ -503,8 +560,9 @@ public class FragmentManager {
return false;
}
final BackStackEntry bss = mBackStack.remove(last);
- handler.post(new Runnable() {
+ enqueueAction(new Runnable() {
public void run() {
+ if (DEBUG) Log.v(TAG, "Popping back stack state: " + bss);
bss.popFromBackStack();
moveToState(mCurState, reverseTransit(bss.getTransition()),
bss.getTransitionStyle(), true);
@@ -526,9 +584,10 @@ public class FragmentManager {
for (int i=mBackStack.size()-1; i>index; i--) {
states.add(mBackStack.remove(i));
}
- handler.post(new Runnable() {
+ enqueueAction(new Runnable() {
public void run() {
for (int i=0; imust have a ListView whose id
+ * is {@link android.R.id.list android.R.id.list} and can optionally
+ * have a sibling view id {@link android.R.id.empty android.R.id.empty}
+ * that is to be shown when the list is empty.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- return inflater.inflate(com.android.internal.R.layout.list_content,
+ return inflater.inflate(com.android.internal.R.layout.list_content_rich,
container, false);
}
@@ -246,6 +259,62 @@ public class ListFragment extends Fragment {
return mList;
}
+ /**
+ * The default content for a ListFragment has a TextView that can
+ * be shown when the list is empty. If you would like to have it
+ * shown, call this method to supply the text it should use.
+ */
+ public void setEmptyText(CharSequence text) {
+ ensureList();
+ if (mStandardEmptyView == null) {
+ throw new IllegalStateException("Can't be used with a custom content view");
+ }
+ if (!mSetEmptyView) {
+ mSetEmptyView = true;
+ mList.setEmptyView(mStandardEmptyView);
+ }
+ }
+
+ /**
+ * Control whether the list is being displayed. You can make it not
+ * displayed if you are waiting for the initial data to show in it. During
+ * this time an indeterminant progress indicator will be shown instead.
+ *
+ * @param shown If true, the list view is shown; if false, the progress
+ * indicator. The initial value is true.
+ * @param animate If true, an animation will be used to transition to the
+ * new state.
+ */
+ public void setListShown(boolean shown, boolean animate) {
+ ensureList();
+ if (mProgressContainer == null) {
+ throw new IllegalStateException("Can't be used with a custom content view");
+ }
+ if (mListShown == shown) {
+ return;
+ }
+ mListShown = shown;
+ if (shown) {
+ if (animate) {
+ mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_out));
+ mListContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_in));
+ }
+ mProgressContainer.setVisibility(View.GONE);
+ mListContainer.setVisibility(View.VISIBLE);
+ } else {
+ if (animate) {
+ mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_in));
+ mListContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_out));
+ }
+ mProgressContainer.setVisibility(View.VISIBLE);
+ mListContainer.setVisibility(View.GONE);
+ }
+ }
+
/**
* Get the ListAdapter associated with this activity's ListView.
*/
@@ -261,16 +330,33 @@ public class ListFragment extends Fragment {
if (root == null) {
throw new IllegalStateException("Content view not yet created");
}
- View emptyView = root.findViewById(com.android.internal.R.id.empty);
- mList = (ListView)root.findViewById(com.android.internal.R.id.list);
- if (mList == null) {
- throw new RuntimeException(
- "Your content must have a ListView whose id attribute is " +
- "'android.R.id.list'");
- }
- if (emptyView != null) {
- mList.setEmptyView(emptyView);
+ if (root instanceof ListView) {
+ mList = (ListView)root;
+ } else {
+ mStandardEmptyView = (TextView)root.findViewById(
+ com.android.internal.R.id.internalEmpty);
+ if (mStandardEmptyView == null) {
+ mEmptyView = root.findViewById(android.R.id.empty);
+ }
+ mProgressContainer = root.findViewById(com.android.internal.R.id.progressContainer);
+ mListContainer = root.findViewById(com.android.internal.R.id.listContainer);
+ View rawListView = root.findViewById(android.R.id.list);
+ if (!(rawListView instanceof ListView)) {
+ throw new RuntimeException(
+ "Content has view with id attribute 'android.R.id.list' "
+ + "that is not a ListView class");
+ }
+ mList = (ListView)rawListView;
+ if (mList == null) {
+ throw new RuntimeException(
+ "Your content must have a ListView whose id attribute is " +
+ "'android.R.id.list'");
+ }
+ if (mEmptyView != null) {
+ mList.setEmptyView(mEmptyView);
+ }
}
+ mListShown = true;
mList.setOnItemClickListener(mOnClickListener);
if (mAdapter != null) {
setListAdapter(mAdapter);
diff --git a/core/java/android/app/LoaderManagingFragment.java b/core/java/android/app/LoaderManagingFragment.java
index a8a5ca4674106..5d417a0ece944 100644
--- a/core/java/android/app/LoaderManagingFragment.java
+++ b/core/java/android/app/LoaderManagingFragment.java
@@ -44,7 +44,7 @@ public abstract class LoaderManagingFragment extends Fragment
* when the new loader completes it's work. The callback will be delivered before the old loader
* is destroyed.
*/
- protected Loader startLoading(int id, Bundle args) {
+ public Loader startLoading(int id, Bundle args) {
LoaderInfo info = mLoaders.get(id);
if (info != null) {
// Keep track of the previous instance of this loader so we can destroy
diff --git a/core/res/res/layout/list_content_rich.xml b/core/res/res/layout/list_content_rich.xml
new file mode 100644
index 0000000000000..14140322b7cd4
--- /dev/null
+++ b/core/res/res/layout/list_content_rich.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6b371df717a64..de1ea68a71e59 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1919,6 +1919,9 @@
combined with setIcon(android.R.drawable.ic_dialog_alert) -->
Attention
+
+ Loading...
+
ON