diff options
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 153 | ||||
-rw-r--r-- | core/java/android/app/Service.java | 60 | ||||
-rw-r--r-- | core/java/android/content/res/Configuration.java | 48 | ||||
-rw-r--r-- | core/java/android/content/res/Resources.java | 4 | ||||
-rw-r--r-- | core/java/android/hardware/Camera.java | 62 | ||||
-rw-r--r-- | core/java/android/os/Message.java | 76 | ||||
-rw-r--r-- | core/java/android/service/wallpaper/WallpaperService.java | 3 | ||||
-rw-r--r-- | core/java/android/view/IWindow.aidl | 3 | ||||
-rw-r--r-- | core/java/android/view/IWindowManager.aidl | 9 | ||||
-rw-r--r-- | core/java/android/view/SurfaceView.java | 3 | ||||
-rw-r--r-- | core/java/android/view/View.java | 27 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 14 | ||||
-rw-r--r-- | core/java/android/view/ViewRoot.java | 51 | ||||
-rw-r--r-- | core/java/android/widget/ListView.java | 7 | ||||
-rw-r--r-- | core/java/com/android/internal/view/BaseIWindow.java | 3 |
15 files changed, 401 insertions, 122 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 56e44c8..13cc3ba 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1392,7 +1392,7 @@ public final class ActivityThread { r.startsNotResumed = notResumed; r.createdConfig = config; - synchronized (mRelaunchingActivities) { + synchronized (mPackages) { mRelaunchingActivities.add(r); } @@ -1523,8 +1523,11 @@ public final class ActivityThread { } public void scheduleConfigurationChanged(Configuration config) { - synchronized (mRelaunchingActivities) { - mPendingConfiguration = config; + synchronized (mPackages) { + if (mPendingConfiguration == null || + mPendingConfiguration.isOtherSeqNewer(config)) { + mPendingConfiguration = config; + } } queueOrSendMessage(H.CONFIGURATION_CHANGED, config); } @@ -2060,6 +2063,7 @@ public final class ActivityThread { = new HashMap<IBinder, Service>(); AppBindData mBoundApplication; Configuration mConfiguration; + Configuration mResConfiguration; Application mInitialApplication; final ArrayList<Application> mAllApplications = new ArrayList<Application>(); @@ -2073,14 +2077,6 @@ public final class ActivityThread { boolean mSystemThread = false; boolean mJitEnabled = false; - /** - * Activities that are enqueued to be relaunched. This list is accessed - * by multiple threads, so you must synchronize on it when accessing it. - */ - final ArrayList<ActivityRecord> mRelaunchingActivities - = new ArrayList<ActivityRecord>(); - Configuration mPendingConfiguration = null; - // These can be accessed by multiple threads; mPackages is the lock. // XXX For now we keep around information about all packages we have // seen, not removing entries from this map. @@ -2092,6 +2088,9 @@ public final class ActivityThread { DisplayMetrics mDisplayMetrics = null; HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources = new HashMap<ResourcesKey, WeakReference<Resources> >(); + final ArrayList<ActivityRecord> mRelaunchingActivities + = new ArrayList<ActivityRecord>(); + Configuration mPendingConfiguration = null; // The lock of mProviderMap protects the following variables. final HashMap<String, ProviderRecord> mProviderMap @@ -3555,7 +3554,7 @@ public final class ActivityThread { // First: make sure we have the most recent configuration and most // recent version of the activity, or skip it if some previous call // had taken a more recent version. - synchronized (mRelaunchingActivities) { + synchronized (mPackages) { int N = mRelaunchingActivities.size(); IBinder token = tmp.token; tmp = null; @@ -3585,8 +3584,12 @@ public final class ActivityThread { // assume that is really what we want regardless of what we // may have pending. if (mConfiguration == null - || mConfiguration.diff(tmp.createdConfig) != 0) { - changedConfig = tmp.createdConfig; + || (tmp.createdConfig.isOtherSeqNewer(mConfiguration) + && mConfiguration.diff(tmp.createdConfig) != 0)) { + if (changedConfig == null + || tmp.createdConfig.isOtherSeqNewer(changedConfig)) { + changedConfig = tmp.createdConfig; + } } } @@ -3761,62 +3764,81 @@ public final class ActivityThread { } } + final void applyConfigurationToResourcesLocked(Configuration config) { + if (mResConfiguration == null) { + mResConfiguration = new Configuration(); + } + if (!mResConfiguration.isOtherSeqNewer(config)) { + return; + } + mResConfiguration.updateFrom(config); + DisplayMetrics dm = getDisplayMetricsLocked(true); + + // set it for java, this also affects newly created Resources + if (config.locale != null) { + Locale.setDefault(config.locale); + } + + Resources.updateSystemConfiguration(config, dm); + + ContextImpl.ApplicationPackageManager.configurationChanged(); + //Log.i(TAG, "Configuration changed in " + currentPackageName()); + + Iterator<WeakReference<Resources>> it = + mActiveResources.values().iterator(); + //Iterator<Map.Entry<String, WeakReference<Resources>>> it = + // mActiveResources.entrySet().iterator(); + while (it.hasNext()) { + WeakReference<Resources> v = it.next(); + Resources r = v.get(); + if (r != null) { + r.updateConfiguration(config, dm); + //Log.i(TAG, "Updated app resources " + v.getKey() + // + " " + r + ": " + r.getConfiguration()); + } else { + //Log.i(TAG, "Removing old resources " + v.getKey()); + it.remove(); + } + } + } + final void handleConfigurationChanged(Configuration config) { - synchronized (mRelaunchingActivities) { + ArrayList<ComponentCallbacks> callbacks = null; + + synchronized (mPackages) { if (mPendingConfiguration != null) { - config = mPendingConfiguration; + if (!mPendingConfiguration.isOtherSeqNewer(config)) { + config = mPendingConfiguration; + } mPendingConfiguration = null; } - } - - ArrayList<ComponentCallbacks> callbacks - = new ArrayList<ComponentCallbacks>(); - if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: " - + config); + if (config == null) { + return; + } + + if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: " + + config); - synchronized(mPackages) { + applyConfigurationToResourcesLocked(config); + if (mConfiguration == null) { mConfiguration = new Configuration(); } - mConfiguration.updateFrom(config); - DisplayMetrics dm = getDisplayMetricsLocked(true); - - // set it for java, this also affects newly created Resources - if (config.locale != null) { - Locale.setDefault(config.locale); - } - - Resources.updateSystemConfiguration(config, dm); - - ContextImpl.ApplicationPackageManager.configurationChanged(); - //Log.i(TAG, "Configuration changed in " + currentPackageName()); - { - Iterator<WeakReference<Resources>> it = - mActiveResources.values().iterator(); - //Iterator<Map.Entry<String, WeakReference<Resources>>> it = - // mActiveResources.entrySet().iterator(); - while (it.hasNext()) { - WeakReference<Resources> v = it.next(); - Resources r = v.get(); - if (r != null) { - r.updateConfiguration(config, dm); - //Log.i(TAG, "Updated app resources " + v.getKey() - // + " " + r + ": " + r.getConfiguration()); - } else { - //Log.i(TAG, "Removing old resources " + v.getKey()); - it.remove(); - } - } + if (!mConfiguration.isOtherSeqNewer(config)) { + return; } + mConfiguration.updateFrom(config); callbacks = collectComponentCallbacksLocked(false, config); } - final int N = callbacks.size(); - for (int i=0; i<N; i++) { - performConfigurationChanged(callbacks.get(i), config); + if (callbacks != null) { + final int N = callbacks.size(); + for (int i=0; i<N; i++) { + performConfigurationChanged(callbacks.get(i), config); + } } } @@ -3856,7 +3878,7 @@ public final class ActivityThread { ArrayList<ComponentCallbacks> callbacks = new ArrayList<ComponentCallbacks>(); - synchronized(mPackages) { + synchronized (mPackages) { callbacks = collectComponentCallbacksLocked(true, null); } @@ -4348,6 +4370,25 @@ public final class ActivityThread { "Unable to instantiate Application():" + e.toString(), e); } } + + ViewRoot.addConfigCallback(new ComponentCallbacks() { + public void onConfigurationChanged(Configuration newConfig) { + synchronized (mPackages) { + if (mPendingConfiguration == null || + mPendingConfiguration.isOtherSeqNewer(newConfig)) { + mPendingConfiguration = newConfig; + + // We need to apply this change to the resources + // immediately, because upon returning the view + // hierarchy will be informed about it. + applyConfigurationToResourcesLocked(newConfig); + } + } + queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig); + } + public void onLowMemory() { + } + }); } private final void detach() diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 8ec5bd4..6767332 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -56,6 +56,8 @@ import java.io.PrintWriter; * <li><a href="#ServiceLifecycle">Service Lifecycle</a> * <li><a href="#Permissions">Permissions</a> * <li><a href="#ProcessLifecycle">Process Lifecycle</a> + * <li><a href="#LocalServiceSample">Local Service Sample</a> + * <li><a href="#RemoteMessengerServiceSample">Remote Messenger Service Sample</a> * </ol> * * <a name="ServiceLifecycle"></a> @@ -166,6 +168,64 @@ import java.io.PrintWriter; * (such as an {@link android.app.Activity}) can, of course, increase the * importance of the overall * process beyond just the importance of the service itself. + * + * <a name="LocalServiceSample"></a> + * <h3>Local Service Sample</h3> + * + * <p>One of the most common uses of a Service is as a secondary component + * running alongside other parts of an application, in the same process as + * the rest of the components. All components of an .apk run in the same + * process unless explicitly stated otherwise, so this is a typical situation. + * + * <p>When used in this way, by assuming the + * components are in the same process, you can greatly simplify the interaction + * between them: clients of the service can simply cast the IBinder they + * receive from it to a concrete class published by the service. + * + * <p>An example of this use of a Service is shown here. First is the Service + * itself, publishing a custom class when bound: + * + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java + * service} + * + * <p>With that done, one can now write client code that directly accesses the + * running service, such as: + * + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.java + * bind} + * + * <a name="RemoteMessengerServiceSample"></a> + * <h3>Remote Messenger Service Sample</h3> + * + * <p>If you need to be able to write a Service that can perform complicated + * communication with clients in remote processes (beyond simply the use of + * {@link Context#startService(Intent) Context.startService} to send + * commands to it), then you can use the {@link android.os.Messenger} class + * instead of writing full AIDL files. + * + * <p>An example of a Service that uses Messenger as its client interface + * is shown here. First is the Service itself, publishing a Messenger to + * an internal Handler when bound: + * + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.java + * service} + * + * <p>If we want to make this service run in a remote process (instead of the + * standard one for its .apk), we can use <code>android:process</code> in its + * manifest tag to specify one: + * + * {@sample development/samples/ApiDemos/AndroidManifest.xml remote_service_declaration} + * + * <p>Note that the name "remote" chosen here is arbitrary, and you can use + * other names if you want additional processes. The ':' prefix appends the + * name to your package's standard process name. + * + * <p>With that done, clients can now bind to the service and send messages + * to it. Note that this allows clients to register with it to receive + * messages back as well: + * + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.java + * bind} */ public abstract class Service extends ContextWrapper implements ComponentCallbacks { private static final String TAG = "Service"; diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index aa5f128..6490b65 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -193,6 +193,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration public int uiMode; /** + * @hide Internal book-keeping. + */ + public int seq; + + /** * Construct an invalid Configuration. You must call {@link #setToDefaults} * for this object to be valid. {@more} */ @@ -220,6 +225,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration orientation = o.orientation; screenLayout = o.screenLayout; uiMode = o.uiMode; + seq = o.seq; } public String toString() { @@ -250,6 +256,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration sb.append(screenLayout); sb.append(" uiMode="); sb.append(uiMode); + if (seq != 0) { + sb.append(" seq="); + sb.append(seq); + } sb.append('}'); return sb.toString(); } @@ -260,7 +270,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration public void setToDefaults() { fontScale = 1; mcc = mnc = 0; - locale = Locale.getDefault(); + locale = null; userSetLocale = false; touchscreen = TOUCHSCREEN_UNDEFINED; keyboard = KEYBOARD_UNDEFINED; @@ -271,6 +281,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration orientation = ORIENTATION_UNDEFINED; screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; uiMode = UI_MODE_TYPE_NORMAL; + seq = 0; } /** {@hide} */ @@ -357,6 +368,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration uiMode = delta.uiMode; } + if (delta.seq != 0) { + seq = delta.seq; + } + return changed; } @@ -456,6 +471,35 @@ public final class Configuration implements Parcelable, Comparable<Configuration } /** + * @hide Return true if the sequence of 'other' is better than this. Assumes + * that 'this' is your current sequence and 'other' is a new one you have + * received some how and want to compare with what you have. + */ + public boolean isOtherSeqNewer(Configuration other) { + if (other == null) { + // Sanity check. + return false; + } + if (other.seq == 0) { + // If the other sequence is not specified, then we must assume + // it is newer since we don't know any better. + return true; + } + if (seq == 0) { + // If this sequence is not specified, then we also consider the + // other is better. Yes we have a preference for other. Sue us. + return true; + } + int diff = other.seq - seq; + if (diff > 0x10000) { + // If there has been a sufficiently large jump, assume the + // sequence has wrapped around. + return false; + } + return diff > 0; + } + + /** * Parcelable methods */ public int describeContents() { @@ -488,6 +532,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration dest.writeInt(orientation); dest.writeInt(screenLayout); dest.writeInt(uiMode); + dest.writeInt(seq); } public static final Parcelable.Creator<Configuration> CREATOR @@ -522,6 +567,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration orientation = source.readInt(); screenLayout = source.readInt(); uiMode = source.readInt(); + seq = source.readInt(); } public int compareTo(Configuration that) { diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index ae8e297..a5e39d4 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -39,6 +39,7 @@ import android.view.Display; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; +import java.util.Locale; /** * Class for accessing an application's resources. This sits on top of the @@ -1259,6 +1260,9 @@ public class Resources { if (config != null) { configChanges = mConfiguration.updateFrom(config); } + if (mConfiguration.locale == null) { + mConfiguration.locale = Locale.getDefault(); + } if (metrics != null) { mMetrics.setTo(metrics); mMetrics.updateMetrics(mCompatibilityInfo, diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index c0bff66..6dba94d 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -26,7 +26,7 @@ import java.io.IOException; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; -import android.graphics.PixelFormat; +import android.graphics.ImageFormat; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -192,7 +192,7 @@ public class Camera { * The callback that delivers the preview frames. * * @param data The contents of the preview frame in the format defined - * by {@link android.graphics.PixelFormat}, which can be queried + * by {@link android.graphics.ImageFormat}, which can be queried * with {@link android.hardware.Camera.Parameters#getPreviewFormat()}. * If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)} * is never called, the default will be the YCbCr_420_SP @@ -276,7 +276,7 @@ public class Camera { * Adds a pre-allocated buffer to the callback buffer queue. * Preview width and height can be determined from getPreviewSize, and bitsPerPixel can be * found from from {@link android.hardware.Camera.Parameters#getPreviewFormat()} and - * {@link android.graphics.PixelFormat#getPixelFormatInfo(int, PixelFormat)} + * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} * * Alternatively, a buffer from a previous callback may be passed in or used * to determine the size of new preview frame buffers. @@ -1086,15 +1086,15 @@ public class Camera { /** * Sets the image format for preview pictures. * <p>If this is never called, the default format will be - * {@link android.graphics.PixelFormat#YCbCr_420_SP}, which + * {@link android.graphics.ImageFormat#NV21}, which * uses the NV21 encoding format.</p> * * @param pixel_format the desired preview picture format, defined - * by one of the {@link android.graphics.PixelFormat} constants. - * (E.g., <var>PixelFormat.YCbCr_420_SP</var> (default), - * <var>PixelFormat.RGB_565</var>, or - * <var>PixelFormat.JPEG</var>) - * @see android.graphics.PixelFormat + * by one of the {@link android.graphics.ImageFormat} constants. + * (E.g., <var>ImageFormat.NV21</var> (default), + * <var>ImageFormat.RGB_565</var>, or + * <var>ImageFormat.JPEG</var>) + * @see android.graphics.ImageFormat */ public void setPreviewFormat(int pixel_format) { String s = cameraFormatForPixelFormat(pixel_format); @@ -1110,7 +1110,7 @@ public class Camera { * Returns the image format for preview pictures got from * {@link PreviewCallback}. * - * @return the {@link android.graphics.PixelFormat} int representing + * @return the {@link android.graphics.ImageFormat} int representing * the preview picture format. */ public int getPreviewFormat() { @@ -1128,7 +1128,7 @@ public class Camera { ArrayList<Integer> formats = new ArrayList<Integer>(); for (String s : split(str)) { int f = pixelFormatForCameraFormat(s); - if (f == PixelFormat.UNKNOWN) continue; + if (f == ImageFormat.UNKNOWN) continue; formats.add(f); } return formats; @@ -1171,10 +1171,10 @@ public class Camera { * Sets the image format for pictures. * * @param pixel_format the desired picture format - * (<var>PixelFormat.YCbCr_420_SP (NV21)</var>, - * <var>PixelFormat.RGB_565</var>, or - * <var>PixelFormat.JPEG</var>) - * @see android.graphics.PixelFormat + * (<var>ImageFormat.NV21</var>, + * <var>ImageFormat.RGB_565</var>, or + * <var>ImageFormat.JPEG</var>) + * @see android.graphics.ImageFormat */ public void setPictureFormat(int pixel_format) { String s = cameraFormatForPixelFormat(pixel_format); @@ -1189,7 +1189,7 @@ public class Camera { /** * Returns the image format for pictures. * - * @return the PixelFormat int representing the picture format + * @return the ImageFormat int representing the picture format */ public int getPictureFormat() { return pixelFormatForCameraFormat(get(KEY_PICTURE_FORMAT)); @@ -1198,7 +1198,7 @@ public class Camera { /** * Gets the supported picture formats. * - * @return a List of Integer objects (values are PixelFormat.XXX). This + * @return a List of Integer objects (values are ImageFormat.XXX). This * method will always return a list with at least one element. */ public List<Integer> getSupportedPictureFormats() { @@ -1206,7 +1206,7 @@ public class Camera { ArrayList<Integer> formats = new ArrayList<Integer>(); for (String s : split(str)) { int f = pixelFormatForCameraFormat(s); - if (f == PixelFormat.UNKNOWN) continue; + if (f == ImageFormat.UNKNOWN) continue; formats.add(f); } return formats; @@ -1214,35 +1214,35 @@ public class Camera { private String cameraFormatForPixelFormat(int pixel_format) { switch(pixel_format) { - case PixelFormat.YCbCr_422_SP: return PIXEL_FORMAT_YUV422SP; - case PixelFormat.YCbCr_420_SP: return PIXEL_FORMAT_YUV420SP; - case PixelFormat.YCbCr_422_I: return PIXEL_FORMAT_YUV422I; - case PixelFormat.RGB_565: return PIXEL_FORMAT_RGB565; - case PixelFormat.JPEG: return PIXEL_FORMAT_JPEG; - default: return null; + case ImageFormat.NV16: return PIXEL_FORMAT_YUV422SP; + case ImageFormat.NV21: return PIXEL_FORMAT_YUV420SP; + case ImageFormat.YUY2: return PIXEL_FORMAT_YUV422I; + case ImageFormat.RGB_565: return PIXEL_FORMAT_RGB565; + case ImageFormat.JPEG: return PIXEL_FORMAT_JPEG; + default: return null; } } private int pixelFormatForCameraFormat(String format) { if (format == null) - return PixelFormat.UNKNOWN; + return ImageFormat.UNKNOWN; if (format.equals(PIXEL_FORMAT_YUV422SP)) - return PixelFormat.YCbCr_422_SP; + return ImageFormat.NV16; if (format.equals(PIXEL_FORMAT_YUV420SP)) - return PixelFormat.YCbCr_420_SP; + return ImageFormat.NV21; if (format.equals(PIXEL_FORMAT_YUV422I)) - return PixelFormat.YCbCr_422_I; + return ImageFormat.YUY2; if (format.equals(PIXEL_FORMAT_RGB565)) - return PixelFormat.RGB_565; + return ImageFormat.RGB_565; if (format.equals(PIXEL_FORMAT_JPEG)) - return PixelFormat.JPEG; + return ImageFormat.JPEG; - return PixelFormat.UNKNOWN; + return ImageFormat.UNKNOWN; } /** diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java index 4130109..476da1d 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -40,20 +40,36 @@ public final class Message implements Parcelable { */ public int what; - // Use these fields instead of using the class's Bundle if you can. - /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()} - if you only need to store a few integer values. */ + /** + * arg1 and arg2 are lower-cost alternatives to using + * {@link #setData(Bundle) setData()} if you only need to store a + * few integer values. + */ public int arg1; - /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()} - if you only need to store a few integer values.*/ + /** + * arg1 and arg2 are lower-cost alternatives to using + * {@link #setData(Bundle) setData()} if you only need to store a + * few integer values. + */ public int arg2; - /** An arbitrary object to send to the recipient. This must be null when - * sending messages across processes. */ + /** + * An arbitrary object to send to the recipient. When using + * {@link Messenger} to send the message across processes this can only + * be non-null if it contains a Parcelable of a framework class (not one + * implemented by the application). For other data transfer use + * {@link #setData}. + * + * <p>Note that Parcelable objects here are not supported prior to + * the {@link android.os.Build.VERSION_CODES#FROYO} release. + */ public Object obj; - /** Optional Messenger where replies to this message can be sent. + /** + * Optional Messenger where replies to this message can be sent. The + * semantics of exactly how this is used are up to the sender and + * receiver. */ public Messenger replyTo; @@ -278,14 +294,22 @@ public final class Message implements Parcelable { * the <em>target</em> {@link Handler} that is receiving this Message to * dispatch it. If * not set, the message will be dispatched to the receiving Handler's - * {@link Handler#handleMessage(Message Handler.handleMessage())}. */ + * {@link Handler#handleMessage(Message Handler.handleMessage())}. + */ public Runnable getCallback() { return callback; } /** * Obtains a Bundle of arbitrary data associated with this - * event, lazily creating it if necessary. Set this value by calling {@link #setData(Bundle)}. + * event, lazily creating it if necessary. Set this value by calling + * {@link #setData(Bundle)}. Note that when transferring data across + * processes via {@link Messenger}, you will need to set your ClassLoader + * on the Bundle via {@link Bundle#setClassLoader(ClassLoader) + * Bundle.setClassLoader()} so that it can instantiate your objects when + * you retrieve them. + * @see #peekData() + * @see #setData(Bundle) */ public Bundle getData() { if (data == null) { @@ -297,14 +321,21 @@ public final class Message implements Parcelable { /** * Like getData(), but does not lazily create the Bundle. A null - * is returned if the Bundle does not already exist. + * is returned if the Bundle does not already exist. See + * {@link #getData} for further information on this. + * @see #getData() + * @see #setData(Bundle) */ public Bundle peekData() { return data; } - /** Sets a Bundle of arbitrary data values. Use arg1 and arg1 members - * as a lower cost way to send a few simple integer values, if you can. */ + /** + * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members + * as a lower cost way to send a few simple integer values, if you can. + * @see #getData() + * @see #peekData() + */ public void setData(Bundle data) { this.data = data; } @@ -381,13 +412,25 @@ public final class Message implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { - if (obj != null || callback != null) { + if (callback != null) { throw new RuntimeException( - "Can't marshal objects across processes."); + "Can't marshal callbacks across processes."); } dest.writeInt(what); dest.writeInt(arg1); dest.writeInt(arg2); + if (obj != null) { + try { + Parcelable p = (Parcelable)obj; + dest.writeInt(1); + dest.writeParcelable(p, flags); + } catch (ClassCastException e) { + throw new RuntimeException( + "Can't marshal non-Parcelable objects across processes."); + } + } else { + dest.writeInt(0); + } dest.writeLong(when); dest.writeBundle(data); Messenger.writeMessengerOrNullToParcel(replyTo, dest); @@ -397,6 +440,9 @@ public final class Message implements Parcelable { what = source.readInt(); arg1 = source.readInt(); arg2 = source.readInt(); + if (source.readInt() != 0) { + obj = source.readParcelable(getClass().getClassLoader()); + } when = source.readLong(); data = source.readBundle(); replyTo = Messenger.readMessengerOrNullFromParcel(source); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index eb48a0c..52de64c 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -28,6 +28,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; @@ -226,7 +227,7 @@ public abstract class WallpaperService extends Service { @Override public void resized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw) { + Rect visibleInsets, boolean reportDraw, Configuration newConfig) { Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED, reportDraw ? 1 : 0); mCaller.sendMessage(msg); diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 71302cb..3b09808 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -17,6 +17,7 @@ package android.view; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -44,7 +45,7 @@ oneway interface IWindow { void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor); void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets, - boolean reportDraw); + boolean reportDraw, in Configuration newConfig); void dispatchKey(in KeyEvent event); void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone); void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0ebe360..9b7b2f4 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -64,8 +64,6 @@ interface IWindowManager void addAppToken(int addPos, IApplicationToken token, int groupId, int requestedOrientation, boolean fullscreen); void setAppGroupId(IBinder token, int groupId); - Configuration updateOrientationFromAppTokens(in Configuration currentConfig, - IBinder freezeThisOneIfNeeded); void setAppOrientation(IApplicationToken token, int requestedOrientation); int getAppOrientation(IApplicationToken token); void setFocusedApp(IBinder token, boolean moveFocusNow); @@ -85,6 +83,13 @@ interface IWindowManager void moveAppTokensToTop(in List<IBinder> tokens); void moveAppTokensToBottom(in List<IBinder> tokens); + // Re-evaluate the current orientation from the caller's state. + // If there is a change, the new Configuration is returned and the + // caller must call setNewConfiguration() sometime later. + Configuration updateOrientationFromAppTokens(in Configuration currentConfig, + IBinder freezeThisOneIfNeeded); + void setNewConfiguration(in Configuration config); + // these require DISABLE_KEYGUARD permission void disableKeyguard(IBinder token, String tag); void reenableKeyguard(IBinder token); diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index ca5e1de..d7f2539 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -19,6 +19,7 @@ package android.view; import com.android.internal.view.BaseIWindow; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.CompatibilityInfo.Translator; import android.graphics.Canvas; @@ -504,7 +505,7 @@ public class SurfaceView extends View { } public void resized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw) { + Rect visibleInsets, boolean reportDraw, Configuration newConfig) { SurfaceView surfaceView = mSurfaceView.get(); if (surfaceView != null) { if (localLOGV) Log.v( diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bc49439..2eb633f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20,6 +20,7 @@ import com.android.internal.R; import com.android.internal.view.menu.MenuBuilder; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -3933,6 +3934,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Dispatch a notification about a resource configuration change down + * the view hierarchy. + * ViewGroups should override to route to their children. + * + * @param newConfig The new resource configuration. + * + * @see #onConfigurationChanged + */ + public void dispatchConfigurationChanged(Configuration newConfig) { + onConfigurationChanged(newConfig); + } + + /** + * Called when the current configuration of the resources being used + * by the application have changed. You can use this to decide when + * to reload resources that can changed based on orientation and other + * configuration characterstics. You only need to use this if you are + * not relying on the normal {@link android.app.Activity} mechanism of + * recreating the activity instance upon a configuration change. + * + * @param newConfig The new resource configuration. + */ + protected void onConfigurationChanged(Configuration newConfig) { + } + + /** * Private function to aggregate all per-view attributes in to the view * root. */ diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 2ed623d..0663215 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -19,6 +19,7 @@ package android.view; import com.android.internal.R; import android.content.Context; +import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -722,6 +723,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * {@inheritDoc} */ + @Override + public void dispatchConfigurationChanged(Configuration newConfig) { + super.dispatchConfigurationChanged(newConfig); + final int count = mChildrenCount; + final View[] children = mChildren; + for (int i = 0; i < count; i++) { + children[i].dispatchConfigurationChanged(newConfig); + } + } + + /** + * {@inheritDoc} + */ public void recomputeViewAttributes(View child) { ViewParent parent = mParent; if (parent != null) parent.recomputeViewAttributes(this); diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 07b2d1c..264b8c9 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -41,7 +41,9 @@ import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; import android.content.res.Resources; +import android.content.ComponentCallbacks; import android.content.Context; import android.app.ActivityManagerNative; import android.Manifest; @@ -101,6 +103,9 @@ public final class ViewRoot extends Handler implements ViewParent, static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>(); static boolean sFirstDrawComplete = false; + static final ArrayList<ComponentCallbacks> sConfigCallbacks + = new ArrayList<ComponentCallbacks>(); + private static int sDrawTime; long mLastTrackballTime = 0; @@ -171,6 +176,12 @@ public final class ViewRoot extends Handler implements ViewParent, final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets = new ViewTreeObserver.InternalInsetsInfo(); + class ResizedInfo { + Rect coveredInsets; + Rect visibleInsets; + Configuration newConfig; + } + boolean mScrollMayChange; int mSoftInputMode; View mLastScrolledFocus; @@ -265,6 +276,12 @@ public final class ViewRoot extends Handler implements ViewParent, } } + public static void addConfigCallback(ComponentCallbacks callback) { + synchronized (sConfigCallbacks) { + sConfigCallbacks.add(callback); + } + } + // FIXME for perf testing only private boolean mProfile = false; @@ -1782,23 +1799,33 @@ public final class ViewRoot extends Handler implements ViewParent, handleGetNewSurface(); break; case RESIZED: - Rect coveredInsets = ((Rect[])msg.obj)[0]; - Rect visibleInsets = ((Rect[])msg.obj)[1]; + ResizedInfo ri = (ResizedInfo)msg.obj; if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2 - && mPendingContentInsets.equals(coveredInsets) - && mPendingVisibleInsets.equals(visibleInsets)) { + && mPendingContentInsets.equals(ri.coveredInsets) + && mPendingVisibleInsets.equals(ri.visibleInsets)) { break; } // fall through... case RESIZED_REPORT: if (mAdded) { + Configuration config = ((ResizedInfo)msg.obj).newConfig; + if (config != null) { + synchronized (sConfigCallbacks) { + for (int i=sConfigCallbacks.size()-1; i>=0; i--) { + sConfigCallbacks.get(i).onConfigurationChanged(config); + } + } + if (mView != null) { + mView.dispatchConfigurationChanged(config); + } + } mWinFrame.left = 0; mWinFrame.right = msg.arg1; mWinFrame.top = 0; mWinFrame.bottom = msg.arg2; - mPendingContentInsets.set(((Rect[])msg.obj)[0]); - mPendingVisibleInsets.set(((Rect[])msg.obj)[1]); + mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets); + mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets); if (msg.what == RESIZED_REPORT) { mReportNextDraw = true; } @@ -2587,7 +2614,7 @@ public final class ViewRoot extends Handler implements ViewParent, } public void dispatchResized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw) { + Rect visibleInsets, boolean reportDraw, Configuration newConfig) { if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w + " h=" + h + " coveredInsets=" + coveredInsets.toShortString() + " visibleInsets=" + visibleInsets.toShortString() @@ -2601,7 +2628,11 @@ public final class ViewRoot extends Handler implements ViewParent, } msg.arg1 = w; msg.arg2 = h; - msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) }; + ResizedInfo ri = new ResizedInfo(); + ri.coveredInsets = new Rect(coveredInsets); + ri.visibleInsets = new Rect(visibleInsets); + ri.newConfig = newConfig; + msg.obj = ri; sendMessage(msg); } @@ -2802,11 +2833,11 @@ public final class ViewRoot extends Handler implements ViewParent, } public void resized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw) { + Rect visibleInsets, boolean reportDraw, Configuration newConfig) { final ViewRoot viewRoot = mViewRoot.get(); if (viewRoot != null) { viewRoot.dispatchResized(w, h, coveredInsets, - visibleInsets, reportDraw); + visibleInsets, reportDraw, newConfig); } } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 5308725..2feed03 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -3092,9 +3092,9 @@ public class ListView extends AbsListView { previouslyFocusedRect.offset(mScrollX, mScrollY); final ListAdapter adapter = mAdapter; - final int firstPosition = mFirstPosition; - // Don't cache the result of getChildCount here, it could change in layoutChildren. - if (adapter.getCount() < getChildCount() + firstPosition) { + // Don't cache the result of getChildCount or mFirstPosition here, + // it could change in layoutChildren. + if (adapter.getCount() < getChildCount() + mFirstPosition) { mLayoutMode = LAYOUT_NORMAL; layoutChildren(); } @@ -3104,6 +3104,7 @@ public class ListView extends AbsListView { Rect otherRect = mTempRect; int minDistance = Integer.MAX_VALUE; final int childCount = getChildCount(); + final int firstPosition = mFirstPosition; for (int i = 0; i < childCount; i++) { // only consider selectable views diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index 15dcbd6..22c6e79 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -1,5 +1,6 @@ package com.android.internal.view; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -17,7 +18,7 @@ public class BaseIWindow extends IWindow.Stub { } public void resized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw) { + Rect visibleInsets, boolean reportDraw, Configuration newConfig) { if (reportDraw) { try { mSession.finishDrawing(this); |