Work on issue #2263557: PMF3000 showing hybrid of portrait and landscape modes
This is a bunch of reworking of how configuration changes are handled:
- When orientation is changing (for whatever reason), the window manager no
longer tries to pre-emptively compute a new configuration. Instead, it
just determines change is happening and tells the window manager.
- The activity manager is now responsible for giving the window manager the
final configuration it is using. This is both so it knows whem the
activity manager is done with its configuration updates, and so the window
manager can use the "real" configuration.
- When an orientation or other configuration change is happening, freeze the
screen and keep it frozen until the activity manager has given us the
final configuration.
- The window manager can now send new configurations to its clients during
its layout pass, as part of a resize, if it has determined that it has
changed. This allows for a new View.onConfigurationChanged() API for any
view to easily find out when the configuration has changed.
- ViewRoot now also works with the activity thread to make sure the process's
current resources are updated to the new configuration when it receives one
from a window. This ensures that at the time onConfigurationChanged() and
other view callbacks are happening, the correct configuration is in force.
- There is now a sequence number associated with Configuration, which
ActivityThread uses to avoid using stale configurations. This is needed now
that it can receive configurations asynchronously from both the window
manager and activity manager.
- The hack for keeping the locale has been removed, and underlying problem
fixed by having Configuration initialize its locale to "unknown" instead of
a valid default value.
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 @@
r.startsNotResumed = notResumed;
r.createdConfig = config;
- synchronized (mRelaunchingActivities) {
+ synchronized (mPackages) {
mRelaunchingActivities.add(r);
}
@@ -1523,8 +1523,11 @@
}
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 @@
= new HashMap<IBinder, Service>();
AppBindData mBoundApplication;
Configuration mConfiguration;
+ Configuration mResConfiguration;
Application mInitialApplication;
final ArrayList<Application> mAllApplications
= new ArrayList<Application>();
@@ -2073,14 +2077,6 @@
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 @@
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 @@
// 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 @@
// 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 @@
}
}
- final void handleConfigurationChanged(Configuration config) {
+ final void applyConfigurationToResourcesLocked(Configuration config) {
+ if (mResConfiguration == null) {
+ mResConfiguration = new Configuration();
+ }
+ if (!mResConfiguration.isOtherSeqNewer(config)) {
+ return;
+ }
+ mResConfiguration.updateFrom(config);
+ DisplayMetrics dm = getDisplayMetricsLocked(true);
- synchronized (mRelaunchingActivities) {
- if (mPendingConfiguration != null) {
- config = mPendingConfiguration;
- mPendingConfiguration = null;
- }
+ // set it for java, this also affects newly created Resources
+ if (config.locale != null) {
+ Locale.setDefault(config.locale);
}
- ArrayList<ComponentCallbacks> callbacks
- = new ArrayList<ComponentCallbacks>();
+ Resources.updateSystemConfiguration(config, dm);
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
- + config);
+ ContextImpl.ApplicationPackageManager.configurationChanged();
+ //Log.i(TAG, "Configuration changed in " + currentPackageName());
- synchronized(mPackages) {
+ 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) {
+
+ ArrayList<ComponentCallbacks> callbacks = null;
+
+ synchronized (mPackages) {
+ if (mPendingConfiguration != null) {
+ if (!mPendingConfiguration.isOtherSeqNewer(config)) {
+ config = mPendingConfiguration;
+ }
+ mPendingConfiguration = null;
+ }
+
+ if (config == null) {
+ return;
+ }
+
+ if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
+ + config);
+
+ applyConfigurationToResourcesLocked(config);
+
if (mConfiguration == null) {
mConfiguration = new Configuration();
}
+ if (!mConfiguration.isOtherSeqNewer(config)) {
+ return;
+ }
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();
- }
- }
- }
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 @@
ArrayList<ComponentCallbacks> callbacks
= new ArrayList<ComponentCallbacks>();
- synchronized(mPackages) {
+ synchronized (mPackages) {
callbacks = collectComponentCallbacksLocked(true, null);
}
@@ -4348,6 +4370,25 @@
"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()