Fix issue #5405788: Device continuously opening and closing...

...the "Complete action using" dialog

When an application goes idle, it sends back to the activity manager
the configuration it last used, to make sure the two don't get out
of sync.  Fix a bunch of edge cases here in dealing with that, and
be sure to also send the current configuration when launching an
activity so the client is always up-to-date when launching.

Also a small fix to not show the upgrading dialog during first boot.

Change-Id: I14ed366a87cd689d1c78787369e052422290ac6f
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d2facdc..8afe9bf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -490,6 +490,15 @@
         // Formatting for checkin service - update version if row format changes
         private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
 
+        private void updatePendingConfiguration(Configuration config) {
+            synchronized (mPackages) {
+                if (mPendingConfiguration == null ||
+                        mPendingConfiguration.isOtherSeqNewer(config)) {
+                    mPendingConfiguration = config;
+                }
+            }
+        }
+
         public final void schedulePauseActivity(IBinder token, boolean finished,
                 boolean userLeaving, int configChanges) {
             queueOrSendMessage(
@@ -530,8 +539,8 @@
         // we use token to identify this activity without having to send the
         // activity itself back to the activity manager. (matters more with ipc)
         public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-                ActivityInfo info, CompatibilityInfo compatInfo, Bundle state,
-                List<ResultInfo> pendingResults,
+                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+                Bundle state, List<ResultInfo> pendingResults,
                 List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                 String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
             ActivityClientRecord r = new ActivityClientRecord();
@@ -553,6 +562,8 @@
             r.profileFd = profileFd;
             r.autoStopProfiler = autoStopProfiler;
 
+            updatePendingConfiguration(curConfig);
+
             queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
         }
 
@@ -697,12 +708,7 @@
         }
 
         public void scheduleConfigurationChanged(Configuration config) {
-            synchronized (mPackages) {
-                if (mPendingConfiguration == null ||
-                        mPendingConfiguration.isOtherSeqNewer(config)) {
-                    mPendingConfiguration = config;
-                }
-            }
+            updatePendingConfiguration(config);
             queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
         }
 
@@ -1966,6 +1972,9 @@
             mProfiler.autoStopProfiler = r.autoStopProfiler;
         }
 
+        // Make sure we are running with the most recent config.
+        handleConfigurationChanged(null, null);
+
         if (localLOGV) Slog.v(
             TAG, "Handling launch of " + r);
         Activity a = performLaunchActivity(r, customIntent);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index cde06cd..c4a4fea 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -132,6 +132,7 @@
             IBinder b = data.readStrongBinder();
             int ident = data.readInt();
             ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
+            Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
             Bundle state = data.readBundle();
             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
@@ -142,7 +143,7 @@
             ParcelFileDescriptor profileFd = data.readInt() != 0
                     ? data.readFileDescriptor() : null;
             boolean autoStopProfiler = data.readInt() != 0;
-            scheduleLaunchActivity(intent, b, ident, info, compatInfo, state, ri, pi,
+            scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, state, ri, pi,
                     notResumed, isForward, profileName, profileFd, autoStopProfiler);
             return true;
         }
@@ -630,10 +631,10 @@
     }
 
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-            ActivityInfo info, CompatibilityInfo compatInfo, Bundle state,
-            List<ResultInfo> pendingResults,
-		List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
-		String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
+            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+            Bundle state, List<ResultInfo> pendingResults,
+    		List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+    		String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
     		throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -641,6 +642,7 @@
         data.writeStrongBinder(token);
         data.writeInt(ident);
         info.writeToParcel(data, 0);
+        curConfig.writeToParcel(data, 0);
         compatInfo.writeToParcel(data, 0);
         data.writeBundle(state);
         data.writeTypedList(pendingResults);
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 5d200b4..1253fe7 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -53,10 +53,10 @@
     void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException;
     void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
     void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-            ActivityInfo info, CompatibilityInfo compatInfo, Bundle state,
-            List<ResultInfo> pendingResults,
-		List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
-		String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
+            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+            Bundle state, List<ResultInfo> pendingResults,
+    		List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+    		String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
     		throws RemoteException;
     void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
             List<Intent> pendingNewIntents, int configChanges,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a3bcc28..decb974 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -362,4 +362,6 @@
     void verifyPendingInstall(int id, int verificationCode);
 
     VerifierDeviceIdentity getVerifierDeviceIdentity();
+
+    boolean isFirstBoot();
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5006de7..3ae62ad 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -163,6 +163,11 @@
             pm = PackageManagerService.main(context,
                     factoryTest != SystemServer.FACTORY_TEST_OFF,
                     onlyCore);
+            boolean firstBoot = false;
+            try {
+                firstBoot = pm.isFirstBoot();
+            } catch (RemoteException e) {
+            }
 
             ActivityManagerService.setSystemProcess();
 
@@ -208,7 +213,8 @@
 
             Slog.i(TAG, "Window Manager");
             wm = WindowManagerService.main(context, power,
-                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
+                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
+                    !firstBoot);
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
 
             ActivityManagerService.self().setWindowManager(wm);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 7bc19ab4..b9d3d76 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -589,8 +589,8 @@
                 }
             }
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
-                    System.identityHashCode(r),
-                    r.info, r.compat, r.icicle, results, newIntents, !andResume,
+                    System.identityHashCode(r), r.info, mService.mConfiguration,
+                    r.compat, r.icicle, results, newIntents, !andResume,
                     mService.isNextTransitionForward(), profileFile, profileFd,
                     profileAutoStop);
             
@@ -4035,7 +4035,18 @@
         // But then we need to figure out how it needs to deal with that.
         Configuration oldConfig = r.configuration;
         r.configuration = newConfig;
-        
+
+        // Determine what has changed.  May be nothing, if this is a config
+        // that has come back from the app after going idle.  In that case
+        // we just want to leave the official config object now in the
+        // activity and do nothing else.
+        final int changes = oldConfig.diff(newConfig);
+        if (changes == 0 && !r.forceNewConfig) {
+            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+                    "Configuration no differences in " + r);
+            return true;
+        }
+
         // If the activity isn't currently running, just leave the new
         // configuration and it will pick that up next time it starts.
         if (r.app == null || r.app.thread == null) {
@@ -4046,8 +4057,7 @@
             return true;
         }
         
-        // Figure out what has changed between the two configurations.
-        int changes = oldConfig.diff(newConfig);
+        // Figure out how to handle the changes between the configurations.
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
             Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
                     + Integer.toHexString(changes) + ", handles=0x"
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 19dd606..0e9f64c 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1157,6 +1157,10 @@
         } // synchronized (mInstallLock)
     }
 
+    public boolean isFirstBoot() {
+        return !mRestoredSettings;
+    }
+
     private String getRequiredVerifierLPr() {
         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
         final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
@@ -2983,12 +2987,14 @@
         }
         if (pkgs != null) {
             for (int i=0; i<pkgs.size(); i++) {
-                try {
-                    ActivityManagerNative.getDefault().showBootMessage(
-                            mContext.getResources().getString(
-                                    com.android.internal.R.string.android_upgrading_apk,
-                                    i+1, pkgs.size()), true);
-                } catch (RemoteException e) {
+                if (!isFirstBoot()) {
+                    try {
+                        ActivityManagerNative.getDefault().showBootMessage(
+                                mContext.getResources().getString(
+                                        com.android.internal.R.string.android_upgrading_apk,
+                                        i+1, pkgs.size()), true);
+                    } catch (RemoteException e) {
+                    }
                 }
                 PackageParser.Package p = pkgs.get(i);
                 synchronized (mInstallLock) {
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 7cdb5b1..bfe6613 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1238,9 +1238,8 @@
                 mReadMessages.append("No start tag found in settings file\n");
                 PackageManagerService.reportSettingsProblem(Log.WARN,
                         "No start tag found in package manager settings");
-                Log
-                        .wtf(PackageManagerService.TAG,
-                                "No start tag found in package manager settings");
+                Log.wtf(PackageManagerService.TAG,
+                        "No start tag found in package manager settings");
                 return false;
             }
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 73a9601..06a6e98 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -297,6 +297,8 @@
 
     final boolean mHaveInputMethods;
 
+    final boolean mAllowBootMessages;
+
     final boolean mLimitedAlphaCompositing;
 
     final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
@@ -633,8 +635,8 @@
     float mCompatibleScreenScale;
 
     public static WindowManagerService main(Context context,
-            PowerManagerService pm, boolean haveInputMethods) {
-        WMThread thr = new WMThread(context, pm, haveInputMethods);
+            PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) {
+        WMThread thr = new WMThread(context, pm, haveInputMethods, allowBootMsgs);
         thr.start();
 
         synchronized (thr) {
@@ -654,19 +656,21 @@
         private final Context mContext;
         private final PowerManagerService mPM;
         private final boolean mHaveInputMethods;
+        private final boolean mAllowBootMessages;
 
         public WMThread(Context context, PowerManagerService pm,
-                boolean haveInputMethods) {
+                boolean haveInputMethods, boolean allowBootMsgs) {
             super("WindowManager");
             mContext = context;
             mPM = pm;
             mHaveInputMethods = haveInputMethods;
+            mAllowBootMessages = allowBootMsgs;
         }
 
         public void run() {
             Looper.prepare();
             WindowManagerService s = new WindowManagerService(mContext, mPM,
-                    mHaveInputMethods);
+                    mHaveInputMethods, mAllowBootMessages);
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_DISPLAY);
             android.os.Process.setCanSelfBackground(false);
@@ -728,9 +732,10 @@
     }
 
     private WindowManagerService(Context context, PowerManagerService pm,
-            boolean haveInputMethods) {
+            boolean haveInputMethods, boolean showBootMsgs) {
         mContext = context;
         mHaveInputMethods = haveInputMethods;
+        mAllowBootMessages = showBootMsgs;
         mLimitedAlphaCompositing = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_limitedAlpha);
 
@@ -4846,6 +4851,9 @@
     public void showBootMessage(final CharSequence msg, final boolean always) {
         boolean first = false;
         synchronized(mWindowMap) {
+            if (!mAllowBootMessages) {
+                return;
+            }
             if (!mShowingBootMessages) {
                 if (!always) {
                     return;