diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-01-24 13:15:09 -0800 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-01-24 21:23:03 -0800 |
commit | 5d9d03a0234faa3cffd11502f973057045cafe82 (patch) | |
tree | 7dbde1fb5e09b2d77ac5249f14591e8f958f046a | |
parent | 169fafe6797dc4c7ae17eba29b72034be6c9c8ec (diff) | |
download | frameworks_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.xml | 11 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 15 | ||||
-rw-r--r-- | core/java/android/app/Fragment.java | 27 | ||||
-rw-r--r-- | core/java/android/app/FragmentManager.java | 12 | ||||
-rw-r--r-- | core/java/android/content/AsyncTaskLoader.java | 2 | ||||
-rw-r--r-- | core/java/android/content/ContentProvider.java | 2 | ||||
-rw-r--r-- | core/java/android/util/LogWriter.java | 82 | ||||
-rw-r--r-- | core/java/android/widget/ListView.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 2 |
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>(); } } |