Improve switching to car mode, retain night mode option.

Fiddle with how we go into car mode to try to ensure we get a clean
transition.  Also have the system take care of remembering the night
mode setting so it will stay at what you want.

Change-Id: Icb94fdd961c7a192f7707ec71544485a1ea12455
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 5bd23f4..4e506e7 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -45,6 +45,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.Slog;
@@ -127,20 +128,39 @@
                     category = null;
                 }
                 if (category != null) {
+                    // This is the new activity that will serve as home while
+                    // we are in care mode.
                     intent = new Intent(Intent.ACTION_MAIN);
                     intent.addCategory(category);
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                             | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                    
+                    // Now we are going to be careful about switching the
+                    // configuration and starting the activity -- we need to
+                    // do this in a specific order under control of the
+                    // activity manager, to do it cleanly.  So compute the
+                    // new config, but don't set it yet, and let the
+                    // activity manager take care of both the start and config
+                    // change.
+                    Configuration newConfig = null;
+                    if (mHoldingConfiguration) {
+                        updateConfigurationLocked(false);
+                        newConfig = mConfiguration;
+                    }
                     try {
+                        ActivityManagerNative.getDefault().startActivityWithConfig(
+                                null, intent, null, null, 0, null, null, 0, false, false,
+                                newConfig);
                         mContext.startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
+                        mHoldingConfiguration = false;
+                    } catch (RemoteException e) {
                         Slog.w(TAG, e.getCause());
                     }
                 }
 
                 if (mHoldingConfiguration) {
                     mHoldingConfiguration = false;
-                    updateConfigurationLocked();
+                    updateConfigurationLocked(true);
                 }
             }
         }
@@ -275,6 +295,9 @@
                 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
         mDeskModeKeepsScreenOn = (context.getResources().getInteger(
                 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
+        
+        mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
     }
 
     public void disableCarMode() {
@@ -319,6 +342,10 @@
             }
 
             if (mNightMode != mode) {
+                long ident = Binder.clearCallingIdentity();
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.UI_NIGHT_MODE, mode);
+                Binder.restoreCallingIdentity(ident);
                 mNightMode = mode;
                 updateLocked();
             }
@@ -360,7 +387,7 @@
         }
     }
 
-    final void updateConfigurationLocked() {
+    final void updateConfigurationLocked(boolean sendIt) {
         int uiMode = 0;
         if (mCarModeEnabled) {
             uiMode = Configuration.UI_MODE_TYPE_CAR;
@@ -385,13 +412,14 @@
 
         if (!mHoldingConfiguration && uiMode != mSetUiMode) {
             mSetUiMode = uiMode;
+            mConfiguration.uiMode = uiMode;
 
-            try {
-                final IActivityManager am = ActivityManagerNative.getDefault();
-                mConfiguration.uiMode = uiMode;
-                am.updateConfiguration(mConfiguration);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failure communicating with activity manager", e);
+            if (sendIt) {
+                try {
+                    ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failure communicating with activity manager", e);
+                }
             }
         }
     }
@@ -447,7 +475,7 @@
                 mHoldingConfiguration = true;
             }
 
-            updateConfigurationLocked();
+            updateConfigurationLocked(true);
 
             // keep screen on when charging and in car mode
             boolean keepScreenOn = mCharging &&
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7034c88..f734053 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3612,7 +3612,7 @@
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
-            boolean debug, WaitResult outResult) {
+            boolean debug, WaitResult outResult, Configuration config) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -3666,6 +3666,15 @@
                     grantedUriPermissions, grantedMode, aInfo,
                     resultTo, resultWho, requestCode, callingPid, callingUid,
                     onlyIfNeeded, componentSpecified);
+            if (config != null) {
+                // If the caller also wants to switch to a new configuration,
+                // do so now.  This allows a clean switch, as we are waiting
+                // for the current activity to pause (so we will not destroy
+                // it), and have not yet started the next activity.
+                enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                        "updateConfiguration()");
+                updateConfigurationLocked(config, null);
+            }
             Binder.restoreCallingIdentity(origId);
             
             if (outResult != null) {
@@ -3707,8 +3716,9 @@
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
             boolean debug) {
-        return startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
-                grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, null);
+        return startActivityMayWait(caller, intent, resolvedType,
+                grantedUriPermissions, grantedMode, resultTo, resultWho,
+                requestCode, onlyIfNeeded, debug, null, null);
     }
 
     public final WaitResult startActivityAndWait(IApplicationThread caller,
@@ -3717,11 +3727,22 @@
             String resultWho, int requestCode, boolean onlyIfNeeded,
             boolean debug) {
         WaitResult res = new WaitResult();
-        startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
-                grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, res);
+        startActivityMayWait(caller, intent, resolvedType,
+                grantedUriPermissions, grantedMode, resultTo, resultWho,
+                requestCode, onlyIfNeeded, debug, res, null);
         return res;
     }
     
+    public final int startActivityWithConfig(IApplicationThread caller,
+            Intent intent, String resolvedType, Uri[] grantedUriPermissions,
+            int grantedMode, IBinder resultTo,
+            String resultWho, int requestCode, boolean onlyIfNeeded,
+            boolean debug, Configuration config) {
+        return startActivityMayWait(caller, intent, resolvedType,
+                grantedUriPermissions, grantedMode, resultTo, resultWho,
+                requestCode, onlyIfNeeded, debug, null, config);
+    }
+
      public int startActivityIntentSender(IApplicationThread caller,
             IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,