diff options
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/ActivityManager.java | 48 | ||||
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 61 | ||||
| -rw-r--r-- | core/java/android/app/LoadedApk.java | 4 | ||||
| -rw-r--r-- | core/java/android/app/WallpaperManager.java | 8 | ||||
| -rw-r--r-- | core/java/android/content/ComponentCallbacks2.java | 6 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 16 | ||||
| -rw-r--r-- | core/java/android/os/Trace.java | 2 | ||||
| -rw-r--r-- | core/java/android/widget/RemoteViews.java | 516 | ||||
| -rw-r--r-- | core/java/android/widget/RemoteViewsAdapter.java | 6 | ||||
| -rw-r--r-- | core/java/android/widget/SearchView.java | 50 |
10 files changed, 606 insertions, 111 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 11b4c3a..7dce2d3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -502,7 +502,16 @@ public class ActivityManager { /** * Return a list of the tasks that the user has recently launched, with * the most recent being first and older ones after in order. - * + * + * <p><b>Note: this method is only intended for debugging and presenting + * task management user interfaces</b>. This should never be used for + * core logic in an application, such as deciding between different + * behaviors based on the information found here. Such uses are + * <em>not</em> supported, and will likely break in the future. For + * example, if multiple applications can be actively running at the + * same time, assumptions made about the meaning of the data here for + * purposes of control flow will be incorrect.</p> + * * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many tasks the * user has started and the maximum number the system can remember. @@ -669,6 +678,15 @@ public class ActivityManager { * can be restarted in its previous state when next brought to the * foreground. * + * <p><b>Note: this method is only intended for debugging and presenting + * task management user interfaces</b>. This should never be used for + * core logic in an application, such as deciding between different + * behaviors based on the information found here. Such uses are + * <em>not</em> supported, and will likely break in the future. For + * example, if multiple applications can be actively running at the + * same time, assumptions made about the meaning of the data here for + * purposes of control flow will be incorrect.</p> + * * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many tasks the * user has started. @@ -1016,7 +1034,10 @@ public class ActivityManager { /** * Return a list of the services that are currently running. - * + * + * <p><b>Note: this method is only intended for debugging or implementing + * service management type user interfaces.</b></p> + * * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many services * are running. @@ -1128,6 +1149,16 @@ public class ActivityManager { } } + /** + * Return general information about the memory state of the system. This + * can be used to help decide how to manage your own memory, though note + * that polling is not recommended and + * {@link android.content.ComponentCallbacks2#onTrimMemory(int) + * ComponentCallbacks2.onTrimMemory(int)} is the preferred way to do this. + * Also see {@link #getMyMemoryState} for how to retrieve the current trim + * level of your process as needed, which gives a better hint for how to + * manage its memory. + */ public void getMemoryInfo(MemoryInfo outInfo) { try { ActivityManagerNative.getDefault().getMemoryInfo(outInfo); @@ -1497,6 +1528,9 @@ public class ActivityManager { * Returns a list of application processes installed on external media * that are running on the device. * + * <p><b>Note: this method is only intended for debugging or building + * a user-facing process management UI.</b></p> + * * @return Returns a list of ApplicationInfo records, or null if none * This list ordering is not specified. * @hide @@ -1511,7 +1545,10 @@ public class ActivityManager { /** * Returns a list of application processes that are running on the device. - * + * + * <p><b>Note: this method is only intended for debugging or building + * a user-facing process management UI.</b></p> + * * @return Returns a list of RunningAppProcessInfo records, or null if there are no * running processes (it will not return an empty list). This list ordering is not * specified. @@ -1544,7 +1581,10 @@ public class ActivityManager { /** * Return information about the memory usage of one or more processes. - * + * + * <p><b>Note: this method is only intended for debugging or building + * a user-facing process management UI.</b></p> + * * @param pids The pids of the processes whose memory usage is to be * retrieved. * @return Returns an array of memory information, one for each diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e2e791b..1a46430 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -61,6 +61,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; +import android.os.Trace; import android.os.UserId; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; @@ -1177,49 +1178,73 @@ public final class ActivityThread { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what); switch (msg.what) { case LAUNCH_ACTIVITY: { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; case RELAUNCH_ACTIVITY: { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart"); ActivityClientRecord r = (ActivityClientRecord)msg.obj; handleRelaunchActivity(r); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; case PAUSE_ACTIVITY: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2); maybeSnapshot(); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case PAUSE_ACTIVITY_FINISHING: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case STOP_ACTIVITY_SHOW: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); handleStopActivity((IBinder)msg.obj, true, msg.arg2); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case STOP_ACTIVITY_HIDE: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); handleStopActivity((IBinder)msg.obj, false, msg.arg2); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SHOW_WINDOW: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow"); handleWindowVisibility((IBinder)msg.obj, true); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case HIDE_WINDOW: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow"); handleWindowVisibility((IBinder)msg.obj, false); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case RESUME_ACTIVITY: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); handleResumeActivity((IBinder)msg.obj, true, msg.arg1 != 0); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SEND_RESULT: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult"); handleSendResult((ResultData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case DESTROY_ACTIVITY: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0, msg.arg2, false); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case BIND_APPLICATION: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); AppBindData data = (AppBindData)msg.obj; handleBindApplication(data); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case EXIT_APPLICATION: if (mInitialApplication != null) { @@ -1228,33 +1253,51 @@ public final class ActivityThread { Looper.myLooper().quit(); break; case NEW_INTENT: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); handleNewIntent((NewIntentData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case RECEIVER: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp"); handleReceiver((ReceiverData)msg.obj); maybeSnapshot(); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CREATE_SERVICE: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate"); handleCreateService((CreateServiceData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case BIND_SERVICE: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind"); handleBindService((BindServiceData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case UNBIND_SERVICE: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind"); handleUnbindService((BindServiceData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SERVICE_ARGS: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart"); handleServiceArgs((ServiceArgsData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case STOP_SERVICE: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop"); handleStopService((IBinder)msg.obj); maybeSnapshot(); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case REQUEST_THUMBNAIL: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestThumbnail"); handleRequestThumbnail((IBinder)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CONFIGURATION_CHANGED: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged"); handleConfigurationChanged((Configuration)msg.obj, null); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CLEAN_UP_CONTEXT: ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj; @@ -1267,31 +1310,43 @@ public final class ActivityThread { handleDumpService((DumpComponentInfo)msg.obj); break; case LOW_MEMORY: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "lowMemory"); handleLowMemory(); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case ACTIVITY_CONFIGURATION_CHANGED: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged"); handleActivityConfigurationChanged((IBinder)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case PROFILER_CONTROL: handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj, msg.arg2); break; case CREATE_BACKUP_AGENT: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupCreateAgent"); handleCreateBackupAgent((CreateBackupAgentData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case DESTROY_BACKUP_AGENT: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupDestroyAgent"); handleDestroyBackupAgent((CreateBackupAgentData)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SUICIDE: Process.killProcess(Process.myPid()); break; case REMOVE_PROVIDER: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "providerRemove"); completeRemoveProvider((IContentProvider)msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case ENABLE_JIT: ensureJitEnabled(); break; case DISPATCH_PACKAGE_BROADCAST: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastPackage"); handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SCHEDULE_CRASH: throw new RemoteServiceException((String)msg.obj); @@ -1305,16 +1360,22 @@ public final class ActivityThread { handleDumpProvider((DumpComponentInfo)msg.obj); break; case SLEEPING: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "sleeping"); handleSleeping((IBinder)msg.obj, msg.arg1 != 0); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SET_CORE_SETTINGS: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setCoreSettings"); handleSetCoreSettings((Bundle) msg.obj); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case UPDATE_PACKAGE_COMPATIBILITY_INFO: handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj); break; case TRIM_MEMORY: + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory"); handleTrimMemory(msg.arg1); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 8ab1ed6..be4b284 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -36,6 +36,7 @@ import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.StrictMode; +import android.os.Trace; import android.os.UserId; import android.util.AndroidRuntimeException; import android.util.Slog; @@ -745,6 +746,7 @@ public final class LoadedApk { return; } + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); try { ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); @@ -759,6 +761,7 @@ public final class LoadedApk { } if (mInstrumentation == null || !mInstrumentation.onException(mReceiver, e)) { + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); throw new RuntimeException( "Error receiving broadcast " + intent + " in " + mReceiver, e); @@ -768,6 +771,7 @@ public final class LoadedApk { if (receiver.getPendingResult() != null) { finish(); } + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 6f19934..3824f44 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -637,6 +637,14 @@ public class WallpaperManager { * wallpaper it would like to use. This allows such applications to have * a virtual wallpaper that is larger than the physical screen, matching * the size of their workspace. + * + * <p>Note developers, who don't seem to be reading this. This is + * for <em>home screens</em> to tell what size wallpaper they would like. + * Nobody else should be calling this! Certainly not other non-home-screen + * apps that change the wallpaper. Those apps are supposed to + * <b>retrieve</b> the suggested size so they can construct a wallpaper + * that matches it. + * * @param minimumWidth Desired minimum width * @param minimumHeight Desired minimum height */ diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java index 85294dd..a3b4e5e 100644 --- a/core/java/android/content/ComponentCallbacks2.java +++ b/core/java/android/content/ComponentCallbacks2.java @@ -88,7 +88,11 @@ public interface ComponentCallbacks2 extends ComponentCallbacks { * should never compare to exact values of the level, since new intermediate * values may be added -- you will typically want to compare if the value * is greater or equal to a level you are interested in. - * + * + * <p>To retrieve the processes current trim level at any point, you can + * use {@link android.app.ActivityManager#getMyMemoryState + * ActivityManager.getMyMemoryState(RunningAppProcessInfo)}. + * * @param level The context of the trim, giving a hint of the amount of * trimming the application may like to perform. May be * {@link #TRIM_MEMORY_COMPLETE}, {@link #TRIM_MEMORY_MODERATE}, diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 6653336..d0d9bd6 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1624,8 +1624,20 @@ public class Intent implements Parcelable, Cloneable { /** * Broadcast Action: The current system wallpaper has changed. See * {@link android.app.WallpaperManager} for retrieving the new wallpaper. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + * This should <em>only</em> be used to determine when the wallpaper + * has changed to show the new wallpaper to the user. You should certainly + * never, in response to this, change the wallpaper or other attributes of + * it such as the suggested size. That would be crazy, right? You'd cause + * all kinds of loops, especially if other apps are doing similar things, + * right? Of course. So please don't do this. + * + * @deprecated Modern applications should use + * {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WALLPAPER + * WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER} to have the wallpaper + * shown behind their UI, rather than watching for this broadcast and + * rendering the wallpaper on their own. + */ + @Deprecated @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED"; /** * Broadcast Action: The current device {@link android.content.res.Configuration} diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 4645fab..2a45506 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -34,6 +34,8 @@ public final class Trace { public static final long TRACE_TAG_INPUT = 1L << 2; public static final long TRACE_TAG_VIEW = 1L << 3; public static final long TRACE_TAG_WEBVIEW = 1L << 4; + public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5; + public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6; private static final long sEnabledTags = nativeGetEnabledTags(); diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 214775a..57a3012 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,29 @@ public class RemoteViews implements Parcelable, Filter { public ViewGroupAction(int viewId, RemoteViews nestedViews) { this.viewId = viewId; this.nestedViews = nestedViews; + 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 +1100,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 +1175,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 +1220,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 +1345,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 +1366,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 +1394,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 +1443,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 +1919,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 +1954,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 +1978,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 +1990,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 +2006,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 +2058,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 8067435..f266d50 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 99cd0b8..561326e 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. |
