summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-01-24 13:15:09 -0800
committerDianne Hackborn <hackbod@google.com>2011-01-24 21:23:03 -0800
commit5d9d03a0234faa3cffd11502f973057045cafe82 (patch)
tree7dbde1fb5e09b2d77ac5249f14591e8f958f046a
parent169fafe6797dc4c7ae17eba29b72034be6c9c8ec (diff)
downloadframeworks_base-5d9d03a0234faa3cffd11502f973057045cafe82.zip
frameworks_base-5d9d03a0234faa3cffd11502f973057045cafe82.tar.gz
frameworks_base-5d9d03a0234faa3cffd11502f973057045cafe82.tar.bz2
Maybe fix issue #3093599: java.lang.IndexOutOfBoundsException...
...Invalid index 0, size is 0 at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2326) It looks like if an arrow key is dispatched between the time the list view is told its data set has changed and it does the resulting layout pass, we could try to move the position to a now invalid index. This may prevent that from happening. Also put in a better error message if saving state of a fragment whose target is no longer in the fragment manager. And fix a bug in PackageManager where we could return a null from queryIntentActivities(). And add a new API to find out whether a fragment is being removed, to help fix issue #3306021: NPE at android.app.AlertDialog.getDefaultDialogTheme(AlertDialog.java) Next, for new HC apps we can delay committing data to storage until the activity is stopped. Finally, use the new multi-threaded AyncTask executor in a few places, so we don't have worked blocked by long-running tasks from the application. Change-Id: I27b2aafedf2e1bf3a2316309889613fa539760f3
-rw-r--r--api/current.xml11
-rw-r--r--core/java/android/app/ActivityThread.java15
-rw-r--r--core/java/android/app/Fragment.java27
-rw-r--r--core/java/android/app/FragmentManager.java12
-rw-r--r--core/java/android/content/AsyncTaskLoader.java2
-rw-r--r--core/java/android/content/ContentProvider.java2
-rw-r--r--core/java/android/util/LogWriter.java82
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--services/java/com/android/server/PackageManagerService.java2
9 files changed, 149 insertions, 6 deletions
diff --git a/api/current.xml b/api/current.xml
index d17325f..b7d7b3a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -29889,6 +29889,17 @@
visibility="public"
>
</method>
+<method name="isRemoving"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isResumed"
return="boolean"
abstract="false"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 511ddc1..960b943 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2385,7 +2385,9 @@ public final class ActivityThread {
performPauseActivity(token, finished, r.isPreHoneycomb());
// Make sure any pending writes are now committed.
- QueuedWork.waitToFinish();
+ if (r.isPreHoneycomb()) {
+ QueuedWork.waitToFinish();
+ }
// Tell the activity manager we have paused.
try {
@@ -2583,6 +2585,11 @@ public final class ActivityThread {
updateVisibility(r, show);
+ // Make sure any pending writes are now committed.
+ if (!r.isPreHoneycomb()) {
+ QueuedWork.waitToFinish();
+ }
+
// Tell activity manager we have been stopped.
try {
ActivityManagerNative.getDefault().activityStopped(
@@ -2647,6 +2654,12 @@ public final class ActivityThread {
}
r.stopped = true;
}
+
+ // Make sure any pending writes are now committed.
+ if (!r.isPreHoneycomb()) {
+ QueuedWork.waitToFinish();
+ }
+
// Tell activity manager we slept.
try {
ActivityManagerNative.getDefault().activitySlept(r.token);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 3280b22..b3d111a 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -357,6 +357,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
// True if the fragment is in the list of added fragments.
boolean mAdded;
+ // If set this fragment is being removed from its activity.
+ boolean mRemoving;
+
// True if the fragment is in the resumed state.
boolean mResumed;
@@ -638,6 +641,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
* Return <code>getActivity().getResources()</code>.
*/
final public Resources getResources() {
+ if (mActivity == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
return mActivity.getResources();
}
@@ -689,7 +695,16 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
* Return true if the fragment is currently added to its activity.
*/
final public boolean isAdded() {
- return mActivity != null && mActivity.mFragments.mAdded.contains(this);
+ return mActivity != null && mAdded;
+ }
+
+ /**
+ * Return true if this fragment is currently being removed from its
+ * activity. This is <em>not</em> whether its activity is finishing, but
+ * rather whether it is in the process of being removed from its activity.
+ */
+ final public boolean isRemoving() {
+ return mRemoving;
}
/**
@@ -787,6 +802,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
if (mLoaderManager != null) {
return mLoaderManager;
}
+ if (mActivity == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
mCheckedForLoaderManager = true;
mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, true);
return mLoaderManager;
@@ -797,6 +815,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
* containing Activity.
*/
public void startActivity(Intent intent) {
+ if (mActivity == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
mActivity.startActivityFromFragment(this, intent, -1);
}
@@ -805,6 +826,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
* containing Activity.
*/
public void startActivityForResult(Intent intent, int requestCode) {
+ if (mActivity == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
mActivity.startActivityFromFragment(this, intent, requestCode);
}
@@ -1217,6 +1241,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
writer.print(" mWho="); writer.print(mWho);
writer.print(" mBackStackNesting="); writer.println(mBackStackNesting);
writer.print(prefix); writer.print("mAdded="); writer.print(mAdded);
+ writer.print(" mRemoving="); writer.print(mRemoving);
writer.print(" mResumed="); writer.print(mResumed);
writer.print(" mFromLayout="); writer.print(mFromLayout);
writer.print(" mInLayout="); writer.println(mInLayout);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index e729805..2c9c85b 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -28,6 +28,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.LogWriter;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuInflater;
@@ -968,6 +970,7 @@ final class FragmentManagerImpl extends FragmentManager {
makeActive(fragment);
if (DEBUG) Log.v(TAG, "add: " + fragment);
fragment.mAdded = true;
+ fragment.mRemoving = false;
if (fragment.mHasMenu) {
mNeedMenuInvalidate = true;
}
@@ -984,6 +987,7 @@ final class FragmentManagerImpl extends FragmentManager {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
+ fragment.mRemoving = true;
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
transition, transitionStyle);
if (inactive) {
@@ -1376,6 +1380,14 @@ final class FragmentManagerImpl extends FragmentManager {
}
if (f.mTarget != null) {
+ if (f.mTarget.mIndex < 0) {
+ String msg = "Failure saving state: " + f
+ + " has target not in fragment manager: " + f.mTarget;
+ Slog.e(TAG, msg);
+ dump(" ", null, new PrintWriter(new LogWriter(
+ Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
+ throw new IllegalStateException(msg);
+ }
if (fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = new Bundle();
}
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 3d6182b..a7dd5fb 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -195,7 +195,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
}
}
if (DEBUG) Slog.v(TAG, "Executing: " + mTask);
- mTask.execute((Void[]) null);
+ mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5467a30..1764e11 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -899,7 +899,7 @@ public abstract class ContentProvider implements ComponentCallbacks {
return null;
}
};
- task.execute((Object[])null);
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null);
return fds[0];
} catch (IOException e) {
diff --git a/core/java/android/util/LogWriter.java b/core/java/android/util/LogWriter.java
new file mode 100644
index 0000000..ce30631
--- /dev/null
+++ b/core/java/android/util/LogWriter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import java.io.Writer;
+
+/** @hide */
+public class LogWriter extends Writer {
+ private final int mPriority;
+ private final String mTag;
+ private final int mBuffer;
+ private StringBuilder mBuilder = new StringBuilder(128);
+
+ /**
+ * Create a new Writer that sends to the log with the given priority
+ * and tag.
+ *
+ * @param priority The desired log priority:
+ * {@link android.util.Log#VERBOSE Log.VERBOSE},
+ * {@link android.util.Log#DEBUG Log.DEBUG},
+ * {@link android.util.Log#INFO Log.INFO},
+ * {@link android.util.Log#WARN Log.WARN}, or
+ * {@link android.util.Log#ERROR Log.ERROR}.
+ * @param tag A string tag to associate with each printed log statement.
+ */
+ public LogWriter(int priority, String tag) {
+ mPriority = priority;
+ mTag = tag;
+ mBuffer = Log.LOG_ID_MAIN;
+ }
+
+ /**
+ * @hide
+ * Same as above, but buffer is one of the LOG_ID_ constants from android.util.Log.
+ */
+ public LogWriter(int priority, String tag, int buffer) {
+ mPriority = priority;
+ mTag = tag;
+ mBuffer = buffer;
+ }
+
+ @Override public void close() {
+ flushBuilder();
+ }
+
+ @Override public void flush() {
+ flushBuilder();
+ }
+
+ @Override public void write(char[] buf, int offset, int count) {
+ for(int i = 0; i < count; i++) {
+ char c = buf[offset + i];
+ if ( c == '\n') {
+ flushBuilder();
+ }
+ else {
+ mBuilder.append(c);
+ }
+ }
+ }
+
+ private void flushBuilder() {
+ if (mBuilder.length() > 0) {
+ Log.println_native(mBuffer, mPriority, mTag, mBuilder.toString());
+ mBuilder.delete(0, mBuilder.length());
+ }
+ }
+}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 796af55..a107c60 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2706,7 +2706,7 @@ public class ListView extends AbsListView {
int startPos = (mSelectedPosition != INVALID_POSITION) ?
mSelectedPosition - 1 :
firstPosition + getChildCount() - 1;
- if (startPos < 0) {
+ if (startPos < 0 || startPos >= mAdapter.getCount()) {
return INVALID_POSITION;
}
if (startPos > last) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 059c0b8..5806de2 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2087,7 +2087,7 @@ class PackageManagerService extends IPackageManager.Stub {
return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
resolvedType, flags, pkg.activities);
}
- return null;
+ return new ArrayList<ResolveInfo>();
}
}