diff options
-rw-r--r-- | api/current.xml | 26 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 153 | ||||
-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/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/com/android/internal/view/BaseIWindow.java | 3 | ||||
-rw-r--r-- | services/java/com/android/server/WindowManagerService.java | 395 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 31 | ||||
-rw-r--r-- | tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java | 3 |
15 files changed, 516 insertions, 257 deletions
diff --git a/api/current.xml b/api/current.xml index 6b277f3..c0a76f8 100644 --- a/api/current.xml +++ b/api/current.xml @@ -173008,6 +173008,19 @@ visibility="public" > </method> +<method name="dispatchConfigurationChanged" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="newConfig" type="android.content.res.Configuration"> +</parameter> +</method> <method name="dispatchDisplayHint" return="void" abstract="false" @@ -174699,6 +174712,19 @@ visibility="public" > </method> +<method name="onConfigurationChanged" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +<parameter name="newConfig" type="android.content.res.Configuration"> +</parameter> +</method> <method name="onCreateContextMenu" return="void" abstract="false" 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/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/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/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); diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 7fcf900..a481036 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -373,10 +373,15 @@ public class WindowManagerService extends IWindowManager.Stub boolean mLayoutNeeded = true; boolean mAnimationPending = false; boolean mDisplayFrozen = false; + boolean mWaitingForConfig = false; boolean mWindowsFreezingScreen = false; long mFreezeGcPending = 0; int mAppsFreezingScreen = 0; + int mLayoutSeq = 0; + + Configuration mCurConfiguration = new Configuration(); + // This is held as long as we have the screen frozen, to give us time to // perform a rotation animation when turning off shows the lock screen which // changes the orientation. @@ -1828,7 +1833,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) { - attachedWindow = windowForClientLocked(null, attrs.token); + attachedWindow = windowForClientLocked(null, attrs.token, false); if (attachedWindow == null) { Log.w(TAG, "Attempted to add window with token that is not a window: " + attrs.token + ". Aborting."); @@ -1988,6 +1993,10 @@ public class WindowManagerService extends IWindowManager.Stub if (localLOGV) Log.v( TAG, "New client " + client.asBinder() + ": window=" + win); + + if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) { + reportNewConfig = true; + } } // sendNewConfiguration() checks caller permissions so we must call it with @@ -1997,14 +2006,6 @@ public class WindowManagerService extends IWindowManager.Stub final long origId = Binder.clearCallingIdentity(); if (reportNewConfig) { sendNewConfiguration(); - } else { - // Update Orientation after adding a window, only if the window needs to be - // displayed right away - if (win.isVisibleOrAdding()) { - if (updateOrientationFromAppTokensUnchecked(null, null) != null) { - sendNewConfiguration(); - } - } } Binder.restoreCallingIdentity(origId); @@ -2013,7 +2014,7 @@ public class WindowManagerService extends IWindowManager.Stub public void removeWindow(Session session, IWindow client) { synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win == null) { return; } @@ -2081,8 +2082,9 @@ public class WindowManagerService extends IWindowManager.Stub // Removing a visible window will effect the computed orientation // So just update orientation if needed. if (wasVisible && computeForcedAppOrientationLocked() - != mForcedAppOrientation) { - mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION)); + != mForcedAppOrientation + && updateOrientationFromAppTokensLocked()) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); Binder.restoreCallingIdentity(origId); @@ -2177,7 +2179,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { - WindowState w = windowForClientLocked(session, client); + WindowState w = windowForClientLocked(session, client, false); if ((w != null) && (w.mSurface != null)) { if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION"); Surface.openTransaction(); @@ -2203,7 +2205,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { - WindowState w = windowForClientLocked(session, client); + WindowState w = windowForClientLocked(session, client, false); if (w != null) { w.mGivenInsetsPending = false; w.mGivenContentInsets.set(contentInsets); @@ -2221,7 +2223,7 @@ public class WindowManagerService extends IWindowManager.Stub public void getWindowDisplayFrame(Session session, IWindow client, Rect outDisplayFrame) { synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win == null) { outDisplayFrame.setEmpty(); return; @@ -2291,11 +2293,11 @@ public class WindowManagerService extends IWindowManager.Stub Surface outSurface) { boolean displayed = false; boolean inTouchMode; - Configuration newConfig = null; + boolean configChanged; long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; } @@ -2507,7 +2509,7 @@ public class WindowManagerService extends IWindowManager.Stub if (assignLayers) { assignLayersLocked(); } - newConfig = updateOrientationFromAppTokensLocked(null, null); + configChanged = updateOrientationFromAppTokensLocked(); performLayoutAndPlaceSurfacesLocked(); if (displayed && win.mIsWallpaper) { updateWallpaperOffsetLocked(win, mDisplay.getWidth(), @@ -2533,7 +2535,7 @@ public class WindowManagerService extends IWindowManager.Stub inTouchMode = mInTouchMode; } - if (newConfig != null) { + if (configChanged) { sendNewConfiguration(); } @@ -2546,7 +2548,7 @@ public class WindowManagerService extends IWindowManager.Stub public void finishDrawingWindow(Session session, IWindow client) { final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win != null && win.finishDrawingLocked()) { if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) { adjustWallpaperWindowsLocked(); @@ -2988,62 +2990,62 @@ public class WindowManagerService extends IWindowManager.Stub } public int getOrientationFromAppTokensLocked() { - int pos = mAppTokens.size() - 1; - int curGroup = 0; - int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - boolean findingBehind = false; - boolean haveGroup = false; - boolean lastFullscreen = false; - while (pos >= 0) { - AppWindowToken wtoken = mAppTokens.get(pos); - pos--; - // if we're about to tear down this window and not seek for - // the behind activity, don't use it for orientation - if (!findingBehind - && (!wtoken.hidden && wtoken.hiddenRequested)) { + int pos = mAppTokens.size() - 1; + int curGroup = 0; + int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + boolean findingBehind = false; + boolean haveGroup = false; + boolean lastFullscreen = false; + while (pos >= 0) { + AppWindowToken wtoken = mAppTokens.get(pos); + pos--; + // if we're about to tear down this window and not seek for + // the behind activity, don't use it for orientation + if (!findingBehind + && (!wtoken.hidden && wtoken.hiddenRequested)) { + continue; + } + + if (!haveGroup) { + // We ignore any hidden applications on the top. + if (wtoken.hiddenRequested || wtoken.willBeHidden) { continue; } - - if (!haveGroup) { - // We ignore any hidden applications on the top. - if (wtoken.hiddenRequested || wtoken.willBeHidden) { - continue; - } - haveGroup = true; - curGroup = wtoken.groupId; - lastOrientation = wtoken.requestedOrientation; - } else if (curGroup != wtoken.groupId) { - // If we have hit a new application group, and the bottom - // of the previous group didn't explicitly say to use - // the orientation behind it, and the last app was - // full screen, then we'll stick with the - // user's orientation. - if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND - && lastFullscreen) { - return lastOrientation; - } - } - int or = wtoken.requestedOrientation; - // If this application is fullscreen, and didn't explicitly say - // to use the orientation behind it, then just take whatever - // orientation it has and ignores whatever is under it. - lastFullscreen = wtoken.appFullscreen; - if (lastFullscreen - && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { - return or; - } - // If this application has requested an explicit orientation, - // then use it. - if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || - or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || - or == ActivityInfo.SCREEN_ORIENTATION_SENSOR || - or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR || - or == ActivityInfo.SCREEN_ORIENTATION_USER) { - return or; - } - findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); - } - return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + haveGroup = true; + curGroup = wtoken.groupId; + lastOrientation = wtoken.requestedOrientation; + } else if (curGroup != wtoken.groupId) { + // If we have hit a new application group, and the bottom + // of the previous group didn't explicitly say to use + // the orientation behind it, and the last app was + // full screen, then we'll stick with the + // user's orientation. + if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND + && lastFullscreen) { + return lastOrientation; + } + } + int or = wtoken.requestedOrientation; + // If this application is fullscreen, and didn't explicitly say + // to use the orientation behind it, then just take whatever + // orientation it has and ignores whatever is under it. + lastFullscreen = wtoken.appFullscreen; + if (lastFullscreen + && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { + return or; + } + // If this application has requested an explicit orientation, + // then use it. + if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || + or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || + or == ActivityInfo.SCREEN_ORIENTATION_SENSOR || + or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR || + or == ActivityInfo.SCREEN_ORIENTATION_USER) { + return or; + } + findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); + } + return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } public Configuration updateOrientationFromAppTokens( @@ -3053,81 +3055,75 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } - Configuration config; + Configuration config = null; long ident = Binder.clearCallingIdentity(); - config = updateOrientationFromAppTokensUnchecked(currentConfig, - freezeThisOneIfNeeded); - Binder.restoreCallingIdentity(ident); - return config; - } - - Configuration updateOrientationFromAppTokensUnchecked( - Configuration currentConfig, IBinder freezeThisOneIfNeeded) { - Configuration config; + synchronized(mWindowMap) { - config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded); - if (config != null) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); + if (updateOrientationFromAppTokensLocked()) { + if (freezeThisOneIfNeeded != null) { + AppWindowToken wtoken = findAppWindowToken( + freezeThisOneIfNeeded); + if (wtoken != null) { + startAppFreezingScreenLocked(wtoken, + ActivityInfo.CONFIG_ORIENTATION); + } + } + config = computeNewConfigurationLocked(); + + } else if (currentConfig != null) { + // No obvious action we need to take, but if our current + // state mismatches the activity maanager's, update it + mTempConfiguration.setToDefaults(); + if (computeNewConfigurationLocked(mTempConfiguration)) { + if (currentConfig.diff(mTempConfiguration) != 0) { + mWaitingForConfig = true; + mLayoutNeeded = true; + startFreezingDisplayLocked(); + config = new Configuration(mTempConfiguration); + } + } } } + + Binder.restoreCallingIdentity(ident); return config; } /* + * Determine the new desired orientation of the display, returning + * a non-null new Configuration if it has changed from the current + * orientation. IF TRUE IS RETURNED SOMEONE MUST CALL + * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE + * SCREEN. This will typically be done for you if you call + * sendNewConfiguration(). + * * The orientation is computed from non-application windows first. If none of * the non-application windows specify orientation, the orientation is computed from * application tokens. * @see android.view.IWindowManager#updateOrientationFromAppTokens( * android.os.IBinder) */ - Configuration updateOrientationFromAppTokensLocked( - Configuration appConfig, IBinder freezeThisOneIfNeeded) { + boolean updateOrientationFromAppTokensLocked() { boolean changed = false; long ident = Binder.clearCallingIdentity(); try { int req = computeForcedAppOrientationLocked(); if (req != mForcedAppOrientation) { - changed = true; mForcedAppOrientation = req; //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); - } - - if (changed) { - changed = setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, - mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)); - if (changed) { - if (freezeThisOneIfNeeded != null) { - AppWindowToken wtoken = findAppWindowToken( - freezeThisOneIfNeeded); - if (wtoken != null) { - startAppFreezingScreenLocked(wtoken, - ActivityInfo.CONFIG_ORIENTATION); - } - } - return computeNewConfigurationLocked(); + if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION, + mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)) { + changed = true; } } - // No obvious action we need to take, but if our current - // state mismatches the activity maanager's, update it - if (appConfig != null) { - mTempConfiguration.setToDefaults(); - if (computeNewConfigurationLocked(mTempConfiguration)) { - if (appConfig.diff(mTempConfiguration) != 0) { - return new Configuration(mTempConfiguration); - } - } - } + return changed; } finally { Binder.restoreCallingIdentity(ident); } - - return null; } int computeForcedAppOrientationLocked() { @@ -3138,6 +3134,19 @@ public class WindowManagerService extends IWindowManager.Stub return req; } + public void setNewConfiguration(Configuration config) { + if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, + "setNewConfiguration()")) { + throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); + } + + synchronized(mWindowMap) { + mCurConfiguration = new Configuration(config); + mWaitingForConfig = false; + performLayoutAndPlaceSurfacesLocked(); + } + } + public void setAppOrientation(IApplicationToken token, int requestedOrientation) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "setAppOrientation()")) { @@ -3648,9 +3657,7 @@ public class WindowManagerService extends IWindowManager.Stub mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); } - if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) { - stopFreezingDisplayLocked(); - } + stopFreezingDisplayLocked(); } } } @@ -4403,20 +4410,21 @@ public class WindowManagerService extends IWindowManager.Stub changed = setRotationUncheckedLocked(rotation, animFlags); } - if (changed) { - sendNewConfiguration(); - synchronized(mWindowMap) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - } else if (alwaysSendConfiguration) { - //update configuration ignoring orientation change + if (changed || alwaysSendConfiguration) { sendNewConfiguration(); } Binder.restoreCallingIdentity(origId); } + /** + * Apply a new rotation to the screen, respecting the requests of + * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply + * re-evaluate the desired rotation. + * + * Returns null if the rotation has been changed. In this case YOU + * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN. + */ public boolean setRotationUncheckedLocked(int rotation, int animFlags) { boolean changed; if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { @@ -4442,6 +4450,8 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000); + mWaitingForConfig = true; + mLayoutNeeded = true; startFreezingDisplayLocked(); Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); mQueue.setOrientation(rotation); @@ -6707,7 +6717,8 @@ public class WindowManagerService extends IWindowManager.Stub long ident = Binder.clearCallingIdentity(); try { return mPolicy.performHapticFeedbackLw( - windowForClientLocked(this, window), effectId, always); + windowForClientLocked(this, window, true), + effectId, always); } finally { Binder.restoreCallingIdentity(ident); } @@ -6718,7 +6729,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { long ident = Binder.clearCallingIdentity(); try { - setWindowWallpaperPositionLocked(windowForClientLocked(this, window), + setWindowWallpaperPositionLocked( + windowForClientLocked(this, window, true), x, y, xStep, yStep); } finally { Binder.restoreCallingIdentity(ident); @@ -6736,7 +6748,7 @@ public class WindowManagerService extends IWindowManager.Stub long ident = Binder.clearCallingIdentity(); try { return sendWindowWallpaperCommandLocked( - windowForClientLocked(this, window), + windowForClientLocked(this, window, true), action, x, y, z, extras, sync); } finally { Binder.restoreCallingIdentity(ident); @@ -6852,6 +6864,10 @@ public class WindowManagerService extends IWindowManager.Stub WindowState mNextOutsideTouch; + int mLayoutSeq = -1; + + Configuration mConfiguration = null; + // Actual frame shown on-screen (may be modified by animation) final Rect mShownFrame = new Rect(); final Rect mLastShownFrame = new Rect(); @@ -7980,7 +7996,7 @@ public class WindowManagerService extends IWindowManager.Stub public void binderDied() { try { synchronized(mWindowMap) { - WindowState win = windowForClientLocked(mSession, mClient); + WindowState win = windowForClientLocked(mSession, mClient, false); Log.i(TAG, "WIN DEATH: " + win); if (win != null) { removeWindowLocked(mSession, win); @@ -8056,8 +8072,6 @@ public class WindowManagerService extends IWindowManager.Stub } void dump(PrintWriter pw, String prefix) { - StringBuilder sb = new StringBuilder(64); - pw.print(prefix); pw.print("mSession="); pw.print(mSession); pw.print(" mClient="); pw.println(mClient.asBinder()); pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs); @@ -8105,7 +8119,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled); } pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth); - pw.print(" h="); pw.println(mRequestedHeight); + pw.print(" h="); pw.print(mRequestedHeight); + pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); if (mXOffset != 0 || mYOffset != 0) { pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); pw.print(" y="); pw.println(mYOffset); @@ -8119,6 +8134,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets); pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending); } + pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration); pw.print(prefix); pw.print("mShownFrame="); mShownFrame.printShortString(pw); pw.print(" last="); mLastShownFrame.printShortString(pw); @@ -8693,7 +8709,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int FORCE_GC = 15; public static final int ENABLE_SCREEN = 16; public static final int APP_FREEZE_TIMEOUT = 17; - public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18; + public static final int SEND_NEW_CONFIGURATION = 18; private Session mLastReportedHold; @@ -9019,10 +9035,9 @@ public class WindowManagerService extends IWindowManager.Stub break; } - case COMPUTE_AND_SEND_NEW_CONFIGURATION: { - if (updateOrientationFromAppTokensUnchecked(null, null) != null) { - sendNewConfiguration(); - } + case SEND_NEW_CONFIGURATION: { + removeMessages(SEND_NEW_CONFIGURATION); + sendNewConfiguration(); break; } @@ -9064,23 +9079,33 @@ public class WindowManagerService extends IWindowManager.Stub // Internals // ------------------------------------------------------------- - final WindowState windowForClientLocked(Session session, IWindow client) { - return windowForClientLocked(session, client.asBinder()); + final WindowState windowForClientLocked(Session session, IWindow client, + boolean throwOnError) { + return windowForClientLocked(session, client.asBinder(), throwOnError); } - final WindowState windowForClientLocked(Session session, IBinder client) { + final WindowState windowForClientLocked(Session session, IBinder client, + boolean throwOnError) { WindowState win = mWindowMap.get(client); if (localLOGV) Log.v( TAG, "Looking up client " + client + ": " + win); if (win == null) { - RuntimeException ex = new RuntimeException(); - Log.w(TAG, "Requested window " + client + " does not exist", ex); + RuntimeException ex = new IllegalArgumentException( + "Requested window " + client + " does not exist"); + if (throwOnError) { + throw ex; + } + Log.w(TAG, "Failed looking up window", ex); return null; } if (session != null && win.mSession != session) { - RuntimeException ex = new RuntimeException(); - Log.w(TAG, "Requested window " + client + " is in session " + - win.mSession + ", not " + session, ex); + RuntimeException ex = new IllegalArgumentException( + "Requested window " + client + " is in session " + + win.mSession + ", not " + session); + if (throwOnError) { + throw ex; + } + Log.w(TAG, "Failed looking up window", ex); return null; } @@ -9183,6 +9208,13 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mWaitingForConfig) { + // Our configuration has changed (most likely rotation), but we + // don't yet have the complete configuration to report to + // applications. Don't do any window layout until we have it. + return; + } + boolean recoveringMemory = false; if (mForceRemoves != null) { recoveringMemory = true; @@ -9249,6 +9281,10 @@ public class WindowManagerService extends IWindowManager.Stub while (mLayoutNeeded) { mPolicy.beginLayoutLw(dw, dh); + int seq = mLayoutSeq+1; + if (seq < 0) seq = 0; + mLayoutSeq = seq; + // First perform layout of any root windows (not attached // to another window). int topAttached = -1; @@ -9266,7 +9302,7 @@ public class WindowManagerService extends IWindowManager.Stub || win.mAttachedHidden || win.mExiting || win.mDestroying; - if (win.mLayoutAttached) { + if (!win.mLayoutAttached) { if (DEBUG_LAYOUT) Log.v(TAG, "First pass " + win + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame + " mLayoutAttached=" + win.mLayoutAttached); @@ -9286,6 +9322,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!gone || !win.mHaveFrame) { if (!win.mLayoutAttached) { mPolicy.layoutWindowLw(win, win.mAttrs, null); + win.mLayoutSeq = seq; if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame=" + win.mFrame + " mContainingFrame=" + win.mContainingFrame + " mDisplayFrame=" @@ -9316,6 +9353,7 @@ public class WindowManagerService extends IWindowManager.Stub if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled) || !win.mHaveFrame) { mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow); + win.mLayoutSeq = seq; if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame=" + win.mFrame + " mContainingFrame=" + win.mContainingFrame + " mDisplayFrame=" @@ -9336,11 +9374,8 @@ public class WindowManagerService extends IWindowManager.Stub Log.w(TAG, "Layout repeat aborted after too many iterations"); mLayoutNeeded = false; if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { - Configuration newConfig = updateOrientationFromAppTokensLocked( - null, null); - if (newConfig != null) { - mLayoutNeeded = true; - mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION); + if (updateOrientationFromAppTokensLocked()) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } } else { @@ -9349,10 +9384,8 @@ public class WindowManagerService extends IWindowManager.Stub repeats++; if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Log.v(TAG, "Computing new config from layout"); - Configuration newConfig = updateOrientationFromAppTokensLocked( - null, null); - if (newConfig != null) { - mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION); + if (updateOrientationFromAppTokensLocked()) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } } @@ -9996,14 +10029,22 @@ public class WindowManagerService extends IWindowManager.Stub } } } - if (!w.mAppFreezing) { + if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) { w.mContentInsetsChanged = !w.mLastContentInsets.equals(w.mContentInsets); w.mVisibleInsetsChanged = !w.mLastVisibleInsets.equals(w.mVisibleInsets); + boolean configChanged = + w.mConfiguration != mCurConfiguration + && (w.mConfiguration == null + || mCurConfiguration.diff(w.mConfiguration) != 0); + if (localLOGV) Log.v(TAG, "Resizing " + w + + ": configChanged=" + configChanged + + " last=" + w.mLastFrame + " frame=" + w.mFrame); if (!w.mLastFrame.equals(w.mFrame) || w.mContentInsetsChanged - || w.mVisibleInsetsChanged) { + || w.mVisibleInsetsChanged + || configChanged) { w.mLastFrame.set(w.mFrame); w.mLastContentInsets.set(w.mContentInsets); w.mLastVisibleInsets.set(w.mVisibleInsets); @@ -10014,7 +10055,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Log.v(TAG, "Resizing while display frozen: " + w); w.mOrientationChanging = true; - if (mWindowsFreezingScreen) { + if (!mWindowsFreezingScreen) { mWindowsFreezingScreen = true; // XXX should probably keep timeout from // when we first froze the display. @@ -10327,9 +10368,7 @@ public class WindowManagerService extends IWindowManager.Stub mWindowsFreezingScreen = false; mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); } - if (mAppsFreezingScreen == 0) { - stopFreezingDisplayLocked(); - } + stopFreezingDisplayLocked(); } i = mResizingWindows.size(); @@ -10340,9 +10379,20 @@ public class WindowManagerService extends IWindowManager.Stub try { if (DEBUG_ORIENTATION) Log.v(TAG, "Reporting new frame to " + win + ": " + win.mFrame); + boolean configChanged = + win.mConfiguration != mCurConfiguration + && (win.mConfiguration == null + || mCurConfiguration.diff(win.mConfiguration) != 0); + win.mConfiguration = mCurConfiguration; + if (DEBUG_ORIENTATION && configChanged) { + Log.i(TAG, "Sending new config to window " + win + ": " + + win.mFrame.width() + "x" + win.mFrame.height() + + " / " + win.mConfiguration); + } win.mClient.resized(win.mFrame.width(), win.mFrame.height(), win.mLastContentInsets, - win.mLastVisibleInsets, win.mDrawPending); + win.mLastVisibleInsets, win.mDrawPending, + configChanged ? win.mConfiguration : null); win.mContentInsetsChanged = false; win.mVisibleInsetsChanged = false; } catch (RemoteException e) { @@ -10732,6 +10782,10 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) { + return; + } + mDisplayFrozen = false; mH.removeMessages(H.APP_FREEZE_TIMEOUT); if (PROFILE_ORIENTATION) { @@ -10921,7 +10975,9 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); } - pw.print(" mInTouchMode="); pw.println(mInTouchMode); + pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration); + pw.print(" mInTouchMode="); pw.print(mInTouchMode); + pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); pw.print(" mSystemBooted="); pw.print(mSystemBooted); pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); @@ -10939,7 +10995,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen); pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen); - pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen); + pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); + pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); pw.print(" mRotation="); pw.print(mRotation); pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation); pw.print(", mRequestedRotation="); pw.println(mRequestedRotation); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 47a58cf..45c3f00 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -766,6 +766,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Configuration mConfiguration = new Configuration(); /** + * Current sequencing integer of the configuration, for skipping old + * configurations. + */ + int mConfigurationSeq = 0; + + /** * Hardware-reported OpenGLES version. */ final int GL_ES_VERSION; @@ -2662,20 +2668,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mConfiguration, next.mayFreezeScreenLocked(next.app) ? next : null); if (config != null) { - /* - * Explicitly restore the locale to the one from the - * old configuration, since the one that comes back from - * the window manager has the default (boot) locale. - * - * It looks like previously the locale picker only worked - * by coincidence: usually it would do its setting of - * the locale after the activity transition, so it didn't - * matter that this lost it. With the synchronized - * block now keeping them from happening at the same time, - * this one always would happen second and undo what the - * locale picker had just done. - */ - config.locale = mConfiguration.locale; next.frozenBeforeDestroy = true; } updated = updateConfigurationLocked(config, next); @@ -8347,7 +8339,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mAlwaysFinishActivities = alwaysFinishActivities; // This happens before any activities are started, so we can // change mConfiguration in-place. + mConfiguration.locale = Locale.getDefault(); mConfiguration.updateFrom(configuration); + mConfigurationSeq = mConfiguration.seq = 1; if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration); } } @@ -13090,6 +13084,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen values.userSetLocale); } + mConfigurationSeq++; + if (mConfigurationSeq <= 0) { + mConfigurationSeq = 1; + } + newConfig.seq = mConfigurationSeq; mConfiguration = newConfig; Log.i(TAG, "Config changed: " + newConfig); @@ -13146,6 +13145,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + if (values != null && mWindowManager != null) { + mWindowManager.setNewConfiguration(mConfiguration); + } + return kept; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 990498f..41d9f9d 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -30,6 +30,7 @@ import com.android.ninepatch.NinePatch; import com.android.tools.layoutlib.create.MethodAdapter; import com.android.tools.layoutlib.create.OverrideMethod; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; @@ -1133,7 +1134,7 @@ public final class Bridge implements ILayoutBridge { } @SuppressWarnings("unused") - public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4) + public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5) throws RemoteException { // pass for now. } |