diff options
15 files changed, 656 insertions, 154 deletions
diff --git a/api/current.txt b/api/current.txt index 46e3aa05c96c..9303937834b1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2601,6 +2601,7 @@ package android.app { method public void finish(); method public void finishActivity(int); method public void finishActivityFromChild(android.app.Activity, int); + method public void finishAffinity(); method public void finishFromChild(android.app.Activity); method public android.app.ActionBar getActionBar(); method public final android.app.Application getApplication(); @@ -27842,6 +27843,7 @@ package android.widget { public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable { ctor public RemoteViews(java.lang.String, int); + ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews); ctor public RemoteViews(android.os.Parcel); method public void addView(int, android.widget.RemoteViews); method public android.view.View apply(android.content.Context, android.view.ViewGroup); @@ -27983,7 +27985,11 @@ package android.widget { public class SearchView extends android.widget.LinearLayout implements android.view.CollapsibleActionView { ctor public SearchView(android.content.Context); ctor public SearchView(android.content.Context, android.util.AttributeSet); + method public int getImeOptions(); + method public int getInputType(); + method public int getMaxWidth(); method public java.lang.CharSequence getQuery(); + method public java.lang.CharSequence getQueryHint(); method public android.widget.CursorAdapter getSuggestionsAdapter(); method public boolean isIconfiedByDefault(); method public boolean isIconified(); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 35bc7ff925a5..4add7f40455b 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4093,6 +4093,36 @@ public class Activity extends ContextThemeWrapper } /** + * Finish this activity as well as all activities immediately below it + * in the current task that have the same affinity. This is typically + * used when an application can be launched on to another task (such as + * from an ACTION_VIEW of a content type it understands) and the user + * has used the up navigation to switch out of the current task and in + * to its own task. In this case, if the user has navigated down into + * any other activities of the second application, all of those should + * be removed from the original task as part of the task switch. + * + * <p>Note that this finish does <em>not</em> allow you to deliver results + * to the previous activity, and an exception will be thrown if you are trying + * to do so.</p> + */ + public void finishAffinity() { + if (mParent != null) { + throw new IllegalStateException("Can not be called from an embedded activity"); + } + if (mResultCode != RESULT_CANCELED || mResultData != null) { + throw new IllegalStateException("Can not be called to deliver a result"); + } + try { + if (ActivityManagerNative.getDefault().finishActivityAffinity(mToken)) { + mFinished = true; + } + } catch (RemoteException e) { + // Empty + } + } + + /** * This is called when a child activity of this one calls its * {@link #finish} method. The default implementation simply calls * finish() on this activity (the parent), finishing the entire group. diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 7e1589f6c9f7..2f2918d8ccbd 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -218,7 +218,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(result ? 1 : 0); return true; } - + case FINISH_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -243,6 +243,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case FINISH_ACTIVITY_AFFINITY_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + boolean res = finishActivityAffinity(token); + reply.writeNoException(); + reply.writeInt(res ? 1 : 0); + return true; + } + case WILL_ACTIVITY_BE_VISIBLE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -1866,6 +1875,18 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } + public boolean finishActivityAffinity(IBinder token) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + mRemote.transact(FINISH_ACTIVITY_AFFINITY_TRANSACTION, data, reply, 0); + reply.readException(); + boolean res = reply.readInt() != 0; + data.recycle(); + reply.recycle(); + return res; + } public boolean willActivityBeVisible(IBinder token) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 3fc228076791..a2c7fa4423c7 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -72,6 +72,7 @@ public interface IActivityManager extends IInterface { public boolean finishActivity(IBinder token, int code, Intent data) throws RemoteException; public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException; + public boolean finishActivityAffinity(IBinder token) throws RemoteException; public boolean willActivityBeVisible(IBinder token) throws RemoteException; public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, @@ -590,4 +591,5 @@ public interface IActivityManager extends IInterface { int TARGET_TASK_AFFINITY_MATCHES_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+145; int NAVIGATE_UP_TO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+146; int SET_LOCK_SCREEN_SHOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+147; + int FINISH_ACTIVITY_AFFINITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+148; } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 018785bb8294..2782dcaab11c 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -3049,6 +3049,13 @@ public final class ContactsContract { * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating social * stream items requires android.permission.WRITE_SOCIAL_STREAM permission. * </p> + * <h3>Account check</h3> + * <p> + * The content URIs to the insert, update and delete operations are required to have the account + * information matching that of the owning raw contact as query parameters, namely + * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}. + * {@link RawContacts#DATA_SET} isn't required. + * </p> * <h3>Operations</h3> * <dl> * <dt><b>Insert</b></dt> @@ -3063,9 +3070,12 @@ public final class ContactsContract { * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys"); * values.put(StreamItems.TIMESTAMP, timestamp); * values.put(StreamItems.COMMENTS, "3 people reshared this"); - * Uri streamItemUri = getContentResolver().insert( - * Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), - * RawContacts.StreamItems.CONTENT_DIRECTORY), values); + * Uri.Builder builder = RawContacts.CONTENT_URI.buildUpon(); + * ContentUris.appendId(builder, rawContactId); + * builder.appendEncodedPath(RawContacts.StreamItems.CONTENT_DIRECTORY); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * Uri streamItemUri = getContentResolver().insert(builder.build(), values); * long streamItemId = ContentUris.parseId(streamItemUri); * </pre> * </dd> @@ -3077,7 +3087,10 @@ public final class ContactsContract { * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys"); * values.put(StreamItems.TIMESTAMP, timestamp); * values.put(StreamItems.COMMENTS, "3 people reshared this"); - * Uri streamItemUri = getContentResolver().insert(StreamItems.CONTENT_URI, values); + * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon(); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * Uri streamItemUri = getContentResolver().insert(builder.build(), values); * long streamItemId = ContentUris.parseId(streamItemUri); *</pre> * </dd> @@ -3410,6 +3423,13 @@ public final class ContactsContract { * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission. * </p> + * <h3>Account check</h3> + * <p> + * The content URIs to the insert, update and delete operations are required to have the account + * information matching that of the owning raw contact as query parameters, namely + * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}. + * {@link RawContacts#DATA_SET} isn't required. + * </p> * <h3>Operations</h3> * <dl> * <dt><b>Insert</b></dt> @@ -3426,9 +3446,12 @@ public final class ContactsContract { * ContentValues values = new ContentValues(); * values.put(StreamItemPhotos.SORT_INDEX, 1); * values.put(StreamItemPhotos.PHOTO, photoData); - * Uri photoUri = getContentResolver().insert(Uri.withAppendedPath( - * ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId) - * StreamItems.StreamItemPhotos#CONTENT_DIRECTORY), values); + * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon(); + * ContentUris.appendId(builder, streamItemId); + * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * Uri photoUri = getContentResolver().insert(builder.build(), values); * long photoId = ContentUris.parseId(photoUri); * </pre> * </dd> @@ -3439,7 +3462,10 @@ public final class ContactsContract { * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId); * values.put(StreamItemPhotos.SORT_INDEX, 1); * values.put(StreamItemPhotos.PHOTO, photoData); - * Uri photoUri = getContentResolver().insert(StreamItems.CONTENT_PHOTO_URI, values); + * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon(); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * Uri photoUri = getContentResolver().insert(builder.build(), values); * long photoId = ContentUris.parseId(photoUri); * </pre> * </dd> @@ -3459,12 +3485,13 @@ public final class ContactsContract { * <pre> * ContentValues values = new ContentValues(); * values.put(StreamItemPhotos.PHOTO, newPhotoData); - * getContentResolver().update( - * ContentUris.withAppendedId( - * Uri.withAppendedPath( - * ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId) - * StreamItems.StreamItemPhotos#CONTENT_DIRECTORY), - * streamItemPhotoId), values, null, null); + * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon(); + * ContentUris.appendId(builder, streamItemId); + * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); + * ContentUris.appendId(builder, streamItemPhotoId); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * getContentResolver().update(builder.build(), values, null, null); * </pre> * </dd> * <dt>Via the {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI} URI:</dt> @@ -3473,7 +3500,10 @@ public final class ContactsContract { * ContentValues values = new ContentValues(); * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId); * values.put(StreamItemPhotos.PHOTO, newPhotoData); - * getContentResolver().update(StreamItems.CONTENT_PHOTO_URI, values); + * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon(); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * getContentResolver().update(builder.build(), values); * </pre> * </dd> * </dl> @@ -3489,21 +3519,24 @@ public final class ContactsContract { * </dt> * <dd> * <pre> - * getContentResolver().delete( - * ContentUris.withAppendedId( - * Uri.withAppendedPath( - * ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId) - * StreamItems.StreamItemPhotos#CONTENT_DIRECTORY), - * streamItemPhotoId), null, null); + * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon(); + * ContentUris.appendId(builder, streamItemId); + * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); + * ContentUris.appendId(builder, streamItemPhotoId); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * getContentResolver().delete(builder.build(), null, null); * </pre> * </dd> * <dt>Deleting all photos under a stream item</dt> * <dd> * <pre> - * getContentResolver().delete( - * Uri.withAppendedPath( - * ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId) - * StreamItems.StreamItemPhotos#CONTENT_DIRECTORY), null, null); + * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon(); + * ContentUris.appendId(builder, streamItemId); + * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); + * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); + * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); + * getContentResolver().delete(builder.build(), null, null); * </pre> * </dd> * </dl> diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 214775ac98f9..e628bc1a4029 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -87,7 +88,32 @@ public class RemoteViews implements Parcelable, Filter { */ private MemoryUsageCounter mMemoryUsageCounter; - + /** + * Maps bitmaps to unique indicies to avoid Bitmap duplication. + */ + private BitmapCache mBitmapCache; + + /** + * Indicates whether or not this RemoteViews object is contained as a child of any other + * RemoteViews. + */ + private boolean mIsRoot = true; + + /** + * Constants to whether or not this RemoteViews is composed of a landscape and portrait + * RemoteViews. + */ + private static final int MODE_NORMAL = 0; + private static final int MODE_HAS_LANDSCAPE_AND_PORTRAIT = 1; + + /** + * Used in conjunction with the special constructor + * {@link #RemoteViews(RemoteViews, RemoteViews)} to keep track of the landscape and portrait + * RemoteViews. + */ + private RemoteViews mLandscape = null; + private RemoteViews mPortrait = null; + /** * This flag indicates whether this RemoteViews object is being created from a * RemoteViewsService for use as a child of a widget collection. This flag is used @@ -163,6 +189,10 @@ public class RemoteViews implements Parcelable, Filter { } return true; } + + public void setBitmapCache(BitmapCache bitmapCache) { + // Do nothing + } } private class SetEmptyView extends Action { @@ -643,6 +673,112 @@ public class RemoteViews implements Parcelable, Filter { } } + private static class BitmapCache { + ArrayList<Bitmap> mBitmaps; + + public BitmapCache() { + mBitmaps = new ArrayList<Bitmap>(); + } + + public BitmapCache(Parcel source) { + int count = source.readInt(); + mBitmaps = new ArrayList<Bitmap>(); + for (int i = 0; i < count; i++) { + Bitmap b = Bitmap.CREATOR.createFromParcel(source); + mBitmaps.add(b); + } + } + + public int getBitmapId(Bitmap b) { + if (b == null) { + return -1; + } else { + if (mBitmaps.contains(b)) { + return mBitmaps.indexOf(b); + } else { + mBitmaps.add(b); + return (mBitmaps.size() - 1); + } + } + } + + public Bitmap getBitmapForId(int id) { + if (id == -1 || id >= mBitmaps.size()) { + return null; + } else { + return mBitmaps.get(id); + } + } + + public void writeBitmapsToParcel(Parcel dest, int flags) { + int count = mBitmaps.size(); + dest.writeInt(count); + for (int i = 0; i < count; i++) { + mBitmaps.get(i).writeToParcel(dest, flags); + } + } + + public void assimilate(BitmapCache bitmapCache) { + ArrayList<Bitmap> bitmapsToBeAdded = bitmapCache.mBitmaps; + int count = bitmapsToBeAdded.size(); + for (int i = 0; i < count; i++) { + Bitmap b = bitmapsToBeAdded.get(i); + if (!mBitmaps.contains(b)) { + mBitmaps.add(b); + } + } + } + + public void addBitmapMemory(MemoryUsageCounter memoryCounter) { + for (int i = 0; i < mBitmaps.size(); i++) { + memoryCounter.addBitmapMemory(mBitmaps.get(i)); + } + } + } + + private class BitmapReflectionAction extends Action { + int bitmapId; + int viewId; + Bitmap bitmap; + String methodName; + + BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) { + this.bitmap = bitmap; + this.viewId = viewId; + this.methodName = methodName; + bitmapId = mBitmapCache.getBitmapId(bitmap); + } + + BitmapReflectionAction(Parcel in) { + viewId = in.readInt(); + methodName = in.readString(); + bitmapId = in.readInt(); + bitmap = mBitmapCache.getBitmapForId(bitmapId); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + dest.writeString(methodName); + dest.writeInt(bitmapId); + } + + @Override + public void apply(View root, ViewGroup rootParent) throws ActionException { + ReflectionAction ra = new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, + bitmap); + ra.apply(root, rootParent); + } + + @Override + public void setBitmapCache(BitmapCache bitmapCache) { + bitmapId = bitmapCache.getBitmapId(bitmap); + } + + public final static int TAG = 12; + } + /** * Base class for the reflection actions. */ @@ -894,24 +1030,7 @@ public class RemoteViews implements Parcelable, Filter { case BITMAP: if (this.value != null) { final Bitmap b = (Bitmap) this.value; - final Bitmap.Config c = b.getConfig(); - // If we don't know, be pessimistic and assume 4 - int bpp = 4; - if (c != null) { - switch (c) { - case ALPHA_8: - bpp = 1; - break; - case RGB_565: - case ARGB_4444: - bpp = 2; - break; - case ARGB_8888: - bpp = 4; - break; - } - } - counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp); + counter.addBitmapMemory(b); } break; default: @@ -920,6 +1039,16 @@ public class RemoteViews implements Parcelable, Filter { } } + private void configureRemoteViewsAsChild(RemoteViews rv) { + mBitmapCache.assimilate(rv.mBitmapCache); + rv.setBitmapCache(mBitmapCache); + rv.setNotRoot(); + } + + void setNotRoot() { + mIsRoot = false; + } + /** * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()} @@ -929,17 +1058,31 @@ public class RemoteViews implements Parcelable, Filter { public ViewGroupAction(int viewId, RemoteViews nestedViews) { this.viewId = viewId; this.nestedViews = nestedViews; + if (nestedViews != null) { + configureRemoteViewsAsChild(nestedViews); + } } - public ViewGroupAction(Parcel parcel) { + public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) { viewId = parcel.readInt(); - nestedViews = parcel.readParcelable(null); + boolean nestedViewsNull = parcel.readInt() == 0; + if (!nestedViewsNull) { + nestedViews = new RemoteViews(parcel, bitmapCache); + } else { + nestedViews = null; + } } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(TAG); dest.writeInt(viewId); - dest.writeParcelable(nestedViews, 0 /* no flags */); + if (nestedViews != null) { + dest.writeInt(1); + nestedViews.writeToParcel(dest, flags); + } else { + // signifies null + dest.writeInt(0); + } } @Override @@ -959,7 +1102,14 @@ public class RemoteViews implements Parcelable, Filter { @Override public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { if (nestedViews != null) { - counter.bitmapIncrement(nestedViews.estimateBitmapMemoryUsage()); + counter.increment(nestedViews.estimateMemoryUsage()); + } + } + + @Override + public void setBitmapCache(BitmapCache bitmapCache) { + if (nestedViews != null) { + nestedViews.setBitmapCache(bitmapCache); } } @@ -1027,18 +1177,39 @@ public class RemoteViews implements Parcelable, Filter { */ private class MemoryUsageCounter { public void clear() { - mBitmapHeapMemoryUsage = 0; + mMemoryUsage = 0; } - public void bitmapIncrement(int numBytes) { - mBitmapHeapMemoryUsage += numBytes; + public void increment(int numBytes) { + mMemoryUsage += numBytes; } - public int getBitmapHeapMemoryUsage() { - return mBitmapHeapMemoryUsage; + public int getMemoryUsage() { + return mMemoryUsage; } - int mBitmapHeapMemoryUsage; + public void addBitmapMemory(Bitmap b) { + final Bitmap.Config c = b.getConfig(); + // If we don't know, be pessimistic and assume 4 + int bpp = 4; + if (c != null) { + switch (c) { + case ALPHA_8: + bpp = 1; + break; + case RGB_565: + case ARGB_4444: + bpp = 2; + break; + case ARGB_8888: + bpp = 4; + break; + } + } + increment(b.getWidth() * b.getHeight() * bpp); + } + + int mMemoryUsage; } /** @@ -1051,62 +1222,122 @@ public class RemoteViews implements Parcelable, Filter { public RemoteViews(String packageName, int layoutId) { mPackage = packageName; mLayoutId = layoutId; + mBitmapCache = new BitmapCache(); // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); recalculateMemoryUsage(); } + private boolean hasLandscapeAndPortraitLayouts() { + return (mLandscape != null) && (mPortrait != null); + } + + /** + * Create a new RemoteViews object that will inflate as the specified + * landspace or portrait RemoteViews, depending on the current configuration. + * + * @param landscape The RemoteViews to inflate in landscape configuration + * @param portrait The RemoteViews to inflate in portrait configuration + */ + public RemoteViews(RemoteViews landscape, RemoteViews portrait) { + if (landscape == null || portrait == null) { + throw new RuntimeException("Both RemoteViews must be non-null"); + } + if (landscape.getPackage().compareTo(portrait.getPackage()) != 0) { + throw new RuntimeException("Both RemoteViews must share the same package"); + } + mPackage = portrait.getPackage(); + mLayoutId = portrait.getLayoutId(); + + mLandscape = landscape; + mPortrait = portrait; + + // setup the memory usage statistics + mMemoryUsageCounter = new MemoryUsageCounter(); + + mBitmapCache = new BitmapCache(); + configureRemoteViewsAsChild(landscape); + configureRemoteViewsAsChild(portrait); + + recalculateMemoryUsage(); + } + /** * Reads a RemoteViews object from a parcel. * * @param parcel */ public RemoteViews(Parcel parcel) { - mPackage = parcel.readString(); - mLayoutId = parcel.readInt(); - mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false; + this(parcel, null); + } - int count = parcel.readInt(); - if (count > 0) { - mActions = new ArrayList<Action>(count); - for (int i=0; i<count; i++) { - int tag = parcel.readInt(); - switch (tag) { - case SetOnClickPendingIntent.TAG: - mActions.add(new SetOnClickPendingIntent(parcel)); - break; - case SetDrawableParameters.TAG: - mActions.add(new SetDrawableParameters(parcel)); - break; - case ReflectionAction.TAG: - mActions.add(new ReflectionAction(parcel)); - break; - case ViewGroupAction.TAG: - mActions.add(new ViewGroupAction(parcel)); - break; - case ReflectionActionWithoutParams.TAG: - mActions.add(new ReflectionActionWithoutParams(parcel)); - break; - case SetEmptyView.TAG: - mActions.add(new SetEmptyView(parcel)); - break; - case SetPendingIntentTemplate.TAG: - mActions.add(new SetPendingIntentTemplate(parcel)); - break; - case SetOnClickFillInIntent.TAG: - mActions.add(new SetOnClickFillInIntent(parcel)); - break; - case SetRemoteViewsAdapterIntent.TAG: - mActions.add(new SetRemoteViewsAdapterIntent(parcel)); - break; - case TextViewDrawableAction.TAG: - mActions.add(new TextViewDrawableAction(parcel)); - break; - default: - throw new ActionException("Tag " + tag + " not found"); + private RemoteViews(Parcel parcel, BitmapCache bitmapCache) { + int mode = parcel.readInt(); + + // We only store a bitmap cache in the root of the RemoteViews. + if (bitmapCache == null) { + mBitmapCache = new BitmapCache(parcel); + } else { + setBitmapCache(bitmapCache); + setNotRoot(); + } + + if (mode == MODE_NORMAL) { + mPackage = parcel.readString(); + mLayoutId = parcel.readInt(); + mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false; + + int count = parcel.readInt(); + if (count > 0) { + mActions = new ArrayList<Action>(count); + for (int i=0; i<count; i++) { + int tag = parcel.readInt(); + switch (tag) { + case SetOnClickPendingIntent.TAG: + mActions.add(new SetOnClickPendingIntent(parcel)); + break; + case SetDrawableParameters.TAG: + mActions.add(new SetDrawableParameters(parcel)); + break; + case ReflectionAction.TAG: + mActions.add(new ReflectionAction(parcel)); + break; + case ViewGroupAction.TAG: + mActions.add(new ViewGroupAction(parcel, mBitmapCache)); + break; + case ReflectionActionWithoutParams.TAG: + mActions.add(new ReflectionActionWithoutParams(parcel)); + break; + case SetEmptyView.TAG: + mActions.add(new SetEmptyView(parcel)); + break; + case SetPendingIntentTemplate.TAG: + mActions.add(new SetPendingIntentTemplate(parcel)); + break; + case SetOnClickFillInIntent.TAG: + mActions.add(new SetOnClickFillInIntent(parcel)); + break; + case SetRemoteViewsAdapterIntent.TAG: + mActions.add(new SetRemoteViewsAdapterIntent(parcel)); + break; + case TextViewDrawableAction.TAG: + mActions.add(new TextViewDrawableAction(parcel)); + break; + case BitmapReflectionAction.TAG: + mActions.add(new BitmapReflectionAction(parcel)); + break; + default: + throw new ActionException("Tag " + tag + " not found"); + } } } + } else { + // MODE_HAS_LANDSCAPE_AND_PORTRAIT + mLandscape = new RemoteViews(parcel, mBitmapCache); + mPortrait = new RemoteViews(parcel, mBitmapCache); + mPackage = mPortrait.getPackage(); + mLayoutId = mPortrait.getLayoutId(); } // setup the memory usage statistics @@ -1116,11 +1347,18 @@ public class RemoteViews implements Parcelable, Filter { @Override public RemoteViews clone() { - final RemoteViews that = new RemoteViews(mPackage, mLayoutId); - if (mActions != null) { - that.mActions = (ArrayList<Action>)mActions.clone(); - } + RemoteViews that; + if (!hasLandscapeAndPortraitLayouts()) { + that = new RemoteViews(mPackage, mLayoutId); + if (mActions != null) { + that.mActions = (ArrayList<Action>)mActions.clone(); + } + } else { + RemoteViews land = mLandscape.clone(); + RemoteViews port = mPortrait.clone(); + that = new RemoteViews(land, port); + } // update the memory usage stats of the cloned RemoteViews that.recalculateMemoryUsage(); return that; @@ -1130,6 +1368,13 @@ public class RemoteViews implements Parcelable, Filter { return mPackage; } + /** + * Reutrns the layout id of the root layout associated with this RemoteViews. In the case + * that the RemoteViews has both a landscape and portrait root, this will return the layout + * id associated with the portrait layout. + * + * @return the layout id. + */ public int getLayoutId() { return mLayoutId; } @@ -1151,20 +1396,47 @@ public class RemoteViews implements Parcelable, Filter { private void recalculateMemoryUsage() { mMemoryUsageCounter.clear(); - // Accumulate the memory usage for each action - if (mActions != null) { - final int count = mActions.size(); - for (int i= 0; i < count; ++i) { - mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter); + if (!hasLandscapeAndPortraitLayouts()) { + // Accumulate the memory usage for each action + if (mActions != null) { + final int count = mActions.size(); + for (int i= 0; i < count; ++i) { + mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter); + } + } + if (mIsRoot) { + mBitmapCache.addBitmapMemory(mMemoryUsageCounter); } + } else { + mMemoryUsageCounter.increment(mLandscape.estimateMemoryUsage()); + mMemoryUsageCounter.increment(mPortrait.estimateMemoryUsage()); + mBitmapCache.addBitmapMemory(mMemoryUsageCounter); + } + } + + /** + * Recursively sets BitmapCache in the hierarchy and update the bitmap ids. + */ + private void setBitmapCache(BitmapCache bitmapCache) { + mBitmapCache = bitmapCache; + if (!hasLandscapeAndPortraitLayouts()) { + if (mActions != null) { + final int count = mActions.size(); + for (int i= 0; i < count; ++i) { + mActions.get(i).setBitmapCache(bitmapCache); + } + } + } else { + mLandscape.setBitmapCache(bitmapCache); + mPortrait.setBitmapCache(bitmapCache); } } /** * Returns an estimate of the bitmap heap memory usage for this RemoteViews. */ - int estimateBitmapMemoryUsage() { - return mMemoryUsageCounter.getBitmapHeapMemoryUsage(); + int estimateMemoryUsage() { + return mMemoryUsageCounter.getMemoryUsage(); } /** @@ -1173,6 +1445,11 @@ public class RemoteViews implements Parcelable, Filter { * @param a The action to add */ private void addAction(Action a) { + if (hasLandscapeAndPortraitLayouts()) { + throw new RuntimeException("RemoteViews specifying separate landscape and portrait" + + " layouts cannot be modified. Instead, fully configure the landscape and" + + " portrait layouts individually before constructing the combined layout."); + } if (mActions == null) { mActions = new ArrayList<Action>(); } @@ -1644,7 +1921,7 @@ public class RemoteViews implements Parcelable, Filter { * @param value The value to pass to the method. */ public void setBitmap(int viewId, String methodName, Bitmap value) { - addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value)); + addAction(new BitmapReflectionAction(viewId, methodName, value)); } /** @@ -1679,6 +1956,18 @@ public class RemoteViews implements Parcelable, Filter { setCharSequence(viewId, "setContentDescription", contentDescription); } + private RemoteViews getRemoteViewsToApply(Context context) { + if (hasLandscapeAndPortraitLayouts()) { + int orientation = context.getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + return mLandscape; + } else { + return mPortrait; + } + } + return this; + } + /** * Inflates the view hierarchy represented by this object and applies * all of the actions. @@ -1691,6 +1980,8 @@ public class RemoteViews implements Parcelable, Filter { * @return The inflated view hierarchy */ public View apply(Context context, ViewGroup parent) { + RemoteViews rvToApply = getRemoteViewsToApply(context); + View result; Context c = prepareContext(context); @@ -1701,13 +1992,13 @@ public class RemoteViews implements Parcelable, Filter { inflater = inflater.cloneInContext(c); inflater.setFilter(this); - result = inflater.inflate(mLayoutId, parent, false); + result = inflater.inflate(rvToApply.getLayoutId(), parent, false); - performApply(result, parent); + rvToApply.performApply(result, parent); return result; } - + /** * Applies all of the actions to the provided view. * @@ -1717,8 +2008,20 @@ public class RemoteViews implements Parcelable, Filter { * the {@link #apply(Context,ViewGroup)} call. */ public void reapply(Context context, View v) { + RemoteViews rvToApply = getRemoteViewsToApply(context); + + // In the case that a view has this RemoteViews applied in one orientation, is persisted + // across orientation change, and has the RemoteViews re-applied in the new orientation, + // we throw an exception, since the layouts may be completely unrelated. + if (hasLandscapeAndPortraitLayouts()) { + if (v.getId() != rvToApply.getLayoutId()) { + throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + + " that does not share the same root layout id."); + } + } + prepareContext(context); - performApply(v, (ViewGroup) v.getParent()); + rvToApply.performApply(v, (ViewGroup) v.getParent()); } private void performApply(View v, ViewGroup parent) { @@ -1757,25 +2060,42 @@ public class RemoteViews implements Parcelable, Filter { public boolean onLoadClass(Class clazz) { return clazz.isAnnotationPresent(RemoteView.class); } - + public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mPackage); - dest.writeInt(mLayoutId); - dest.writeInt(mIsWidgetCollectionChild ? 1 : 0); - int count; - if (mActions != null) { - count = mActions.size(); + if (!hasLandscapeAndPortraitLayouts()) { + dest.writeInt(MODE_NORMAL); + // We only write the bitmap cache if we are the root RemoteViews, as this cache + // is shared by all children. + if (mIsRoot) { + mBitmapCache.writeBitmapsToParcel(dest, flags); + } + dest.writeString(mPackage); + dest.writeInt(mLayoutId); + dest.writeInt(mIsWidgetCollectionChild ? 1 : 0); + int count; + if (mActions != null) { + count = mActions.size(); + } else { + count = 0; + } + dest.writeInt(count); + for (int i=0; i<count; i++) { + Action a = mActions.get(i); + a.writeToParcel(dest, 0); + } } else { - count = 0; - } - dest.writeInt(count); - for (int i=0; i<count; i++) { - Action a = mActions.get(i); - a.writeToParcel(dest, 0); + dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT); + // We only write the bitmap cache if we are the root RemoteViews, as this cache + // is shared by all children. + if (mIsRoot) { + mBitmapCache.writeBitmapsToParcel(dest, flags); + } + mLandscape.writeToParcel(dest, flags); + mPortrait.writeToParcel(dest, flags); } } diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index 806743536c96..f266d50f98e9 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -595,7 +595,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback for (Integer i : mIndexRemoteViews.keySet()) { final RemoteViews v = mIndexRemoteViews.get(i); if (v != null) { - mem += v.estimateBitmapMemoryUsage(); + mem += v.estimateMemoryUsage(); } } return mem; @@ -942,10 +942,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * which wouldn't otherwise be possible. */ public void setVisibleRangeHint(int lowerBound, int upperBound) { - if (lowerBound < 0 || upperBound < 0) { - throw new RuntimeException("Attempted to set invalid range: lowerBound="+lowerBound + - "," + "upperBound="+upperBound); - } mVisibleWindowLowerBound = lowerBound; mVisibleWindowUpperBound = upperBound; } diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 99cd0b8d3575..561326e59473 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -381,6 +381,17 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } /** + * Returns the IME options set on the query text field. + * @return the ime options + * @see TextView#setImeOptions(int) + * + * @attr ref android.R.styleable#SearchView_imeOptions + */ + public int getImeOptions() { + return mQueryTextView.getImeOptions(); + } + + /** * Sets the input type on the query text field. * * @see TextView#setInputType(int) @@ -392,6 +403,16 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { mQueryTextView.setInputType(inputType); } + /** + * Returns the input type set on the query text field. + * @return the input type + * + * @attr ref android.R.styleable#SearchView_inputType + */ + public int getInputType() { + return mQueryTextView.getInputType(); + } + /** @hide */ @Override public boolean requestFocus(int direction, Rect previouslyFocusedRect) { @@ -514,6 +535,26 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } /** + * Gets the hint text to display in the query text field. + * @return the query hint text, if specified, null otherwise. + * + * @attr ref android.R.styleable#SearchView_queryHint + */ + public CharSequence getQueryHint() { + if (mQueryHint != null) { + return mQueryHint; + } else if (mSearchable != null) { + CharSequence hint = null; + int hintId = mSearchable.getHintId(); + if (hintId != 0) { + hint = getContext().getString(hintId); + } + return hint; + } + return null; + } + + /** * Sets the default or resting state of the search field. If true, a single search icon is * shown by default and expands to show the text field and other buttons when pressed. Also, * if the default state is iconified, then it collapses to that state when the close button @@ -651,6 +692,15 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { requestLayout(); } + /** + * Gets the specified maximum width in pixels, if set. Returns zero if + * no maximum width was specified. + * @return the maximum width of the view + */ + public int getMaxWidth() { + return mMaxWidth; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Let the standard measurements take effect in iconified state. diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java index bbd6bea6bf24..2f864d7fa906 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java @@ -47,6 +47,7 @@ public class CameraTest extends ActivityInstrumentationTestCase<MediaFrameworkTe private boolean jpegPictureCallbackResult = false; private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. + private static final int CAMERA_ID = 0; private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback(); private TestShutterCallback mShutterCallback = new TestShutterCallback(); @@ -85,7 +86,7 @@ public class CameraTest extends ActivityInstrumentationTestCase<MediaFrameworkTe // Save the looper so that we can terminate this thread // after we are done with it. mLooper = Looper.myLooper(); - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); startDone.open(); Looper.loop(); // Blocks forever until Looper.quit() is called. Log.v(TAG, "initializeMessageLooper: quit."); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java index 0684946617c0..8e6d5cb44577 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java @@ -54,6 +54,8 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFra private int MIN_VIDEO_FPS = 5; + private static final int CAMERA_ID = 0; + Context mContext; Camera mCamera; @@ -247,7 +249,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFra public void testPortraitH263() throws Exception { boolean videoRecordedResult = false; try { - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(352, 288); parameters.set("orientation", "portrait"); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java index db64b94b8ec5..ccb0638de4af 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -72,6 +72,7 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med "/sdcard/mediaMemOutput.txt"; private static final String MEDIA_PROCMEM_OUTPUT = "/sdcard/mediaProcmemOutput.txt"; + private static final int CAMERA_ID = 0; private static int mStartMemory = 0; private static int mEndMemory = 0; @@ -132,7 +133,7 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med Looper.prepare(); Log.v(TAG, "start loopRun"); mLooper = Looper.myLooper(); - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); startDone.open(); Looper.loop(); Log.v(TAG, "initializeMessageLooper: quit."); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java index a9c6119bd116..ab9e36c3a30a 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java @@ -60,6 +60,7 @@ public class CameraStressTest extends ActivityInstrumentationTestCase2<MediaFram private static final long WAIT_ZOOM_ANIMATION = 5 * 1000; // 5 seconds private static final String CAMERA_STRESS_OUTPUT = "/sdcard/cameraStressOutput.txt"; + private static final int CAMERA_ID = 0; private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); private Thread mLooperThread; @@ -213,7 +214,7 @@ public class CameraStressTest extends ActivityInstrumentationTestCase2<MediaFram Log.v(TAG, "Start preview"); output.write("No of loop: "); - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); Camera.Parameters params = mCamera.getParameters(); mCamera.release(); @@ -230,7 +231,7 @@ public class CameraStressTest extends ActivityInstrumentationTestCase2<MediaFram runOnLooper(new Runnable() { @Override public void run() { - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); } }); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java index e9bc6f005e39..62462bdd18d9 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java @@ -60,6 +60,8 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me private static final String OUTPUT_FILE_EXT = ".3gp"; private static final String MEDIA_STRESS_OUTPUT = "/sdcard/mediaStressOutput.txt"; + private static final int CAMERA_ID = 0; + private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback(); @@ -162,7 +164,7 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me runOnLooper(new Runnable() { @Override public void run() { - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); } }); mCamera.setErrorCallback(mCameraErrorCallback); @@ -250,7 +252,7 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me runOnLooper(new Runnable() { @Override public void run() { - mCamera = Camera.open(); + mCamera = Camera.open(CAMERA_ID); } }); mCamera.setErrorCallback(mCameraErrorCallback); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 6c99cdb955e4..429c3c439ab9 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2697,26 +2697,18 @@ public final class ActivityManagerService extends ActivityManagerNative public final void finishSubActivity(IBinder token, String resultWho, int requestCode) { synchronized(this) { - ActivityRecord self = mMainStack.isInStackLocked(token); - if (self == null) { - return; - } - final long origId = Binder.clearCallingIdentity(); + mMainStack.finishSubActivityLocked(token, resultWho, requestCode); + Binder.restoreCallingIdentity(origId); + } + } - int i; - for (i=mMainStack.mHistory.size()-1; i>=0; i--) { - ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); - if (r.resultTo == self && r.requestCode == requestCode) { - if ((r.resultWho == null && resultWho == null) || - (r.resultWho != null && r.resultWho.equals(resultWho))) { - mMainStack.finishActivityLocked(r, i, - Activity.RESULT_CANCELED, null, "request-sub"); - } - } - } - + public boolean finishActivityAffinity(IBinder token) { + synchronized(this) { + final long origId = Binder.clearCallingIdentity(); + boolean res = mMainStack.finishActivityAffinityLocked(token); Binder.restoreCallingIdentity(origId); + return res; } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index c8e015b176bd..25fae830820c 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -3497,6 +3497,51 @@ final class ActivityStack { return true; } + final void finishSubActivityLocked(IBinder token, String resultWho, int requestCode) { + ActivityRecord self = isInStackLocked(token); + if (self == null) { + return; + } + + int i; + for (i=mHistory.size()-1; i>=0; i--) { + ActivityRecord r = (ActivityRecord)mHistory.get(i); + if (r.resultTo == self && r.requestCode == requestCode) { + if ((r.resultWho == null && resultWho == null) || + (r.resultWho != null && r.resultWho.equals(resultWho))) { + finishActivityLocked(r, i, + Activity.RESULT_CANCELED, null, "request-sub"); + } + } + } + } + + final boolean finishActivityAffinityLocked(IBinder token) { + int index = indexOfTokenLocked(token); + if (DEBUG_RESULTS) Slog.v( + TAG, "Finishing activity affinity @" + index + ": token=" + token); + if (index < 0) { + return false; + } + ActivityRecord r = mHistory.get(index); + + while (index > 0) { + ActivityRecord cur = mHistory.get(index); + if (cur.task != r.task) { + break; + } + if (cur.taskAffinity == null && r.taskAffinity != null) { + break; + } + if (cur.taskAffinity != null && !cur.taskAffinity.equals(r.taskAffinity)) { + break; + } + finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null, "request-affinity"); + index--; + } + return true; + } + final void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) { // send the result ActivityRecord resultTo = r.resultTo; |