Merge "Treat apps that use channels as O apps" into oc-dev
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index aaaff0c..4e11233 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -26,6 +26,7 @@
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.PackageManager.InstallReason;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.FileBridge;
@@ -948,7 +949,7 @@
         /** {@hide} */
         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
         /** {@hide} */
-        public int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
+        public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
         /** {@hide} */
         public long sizeBytes = -1;
         /** {@hide} */
@@ -1146,7 +1147,10 @@
             }
         }
 
-        public void setInstallReason(int installReason) {
+        /**
+         * Set the reason for installing this package.
+         */
+        public void setInstallReason(@InstallReason int installReason) {
             this.installReason = installReason;
         }
 
@@ -1236,7 +1240,7 @@
         /** {@hide} */
         public int mode;
         /** {@hide} */
-        public int installReason;
+        public @InstallReason int installReason;
         /** {@hide} */
         public long sizeBytes;
         /** {@hide} */
@@ -1324,9 +1328,9 @@
         /**
          * Return the reason for installing this package.
          *
-         * @see PackageManager#INSTALL_REASON_UNKNOWN
+         * @return The install reason.
          */
-        public int getInstallReason() {
+        public @InstallReason int getInstallReason() {
             return installReason;
         }
 
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 5a570a1..6914e21 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -361,6 +361,8 @@
         // ZERO WIDTH JOINER + regional indicator symbol
         state.setByString("| U+1F469 U+200D U+1F1FA");
         forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
         state.assertEquals("|");
 
         // Regional indicator symbol + end with ZERO WIDTH JOINER
@@ -371,6 +373,8 @@
         // Regional indicator symbol + ZERO WIDTH JOINER
         state.setByString("| U+1F1FA U+200D U+1F469");
         forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
         state.assertEquals("|");
 
         // Start with ZERO WIDTH JOINER + emoji modifier
@@ -391,6 +395,8 @@
         // Emoji modifier + ZERO WIDTH JOINER
         state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
         forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
         state.assertEquals("|");
 
         // Regional indicator symbol + emoji modifier
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 2ef1cf5..c309133 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -34,6 +34,7 @@
             <intent-filter>
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
+                <action android:name="android.intent.action.LOCALE_CHANGED" />
             </intent-filter>
         </receiver>
         <service android:name="com.android.carrierdefaultapp.ProvisionObserver"
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index 7fd1601..0213306 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -112,8 +112,6 @@
 
     private static void onShowCaptivePortalNotification(Intent intent, Context context) {
         logd("onShowCaptivePortalNotification");
-        final NotificationManager notificationMgr = context.getSystemService(
-                NotificationManager.class);
         Intent portalIntent = new Intent(context, CaptivePortalLoginActivity.class);
         portalIntent.putExtras(intent);
         portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
@@ -123,7 +121,8 @@
         Notification notification = getNotification(context, R.string.portal_notification_id,
                 R.string.portal_notification_detail, pendingIntent);
         try {
-            notificationMgr.notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
+            context.getSystemService(NotificationManager.class)
+                    .notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
         } catch (NullPointerException npe) {
             loge("setNotificationVisible: " + npe);
         }
@@ -131,12 +130,11 @@
 
     private static void onShowNoDataServiceNotification(Context context) {
         logd("onShowNoDataServiceNotification");
-        final NotificationManager notificationMgr = context.getSystemService(
-                NotificationManager.class);
         Notification notification = getNotification(context, R.string.no_data_notification_id,
                 R.string.no_data_notification_detail, null);
         try {
-            notificationMgr.notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
+            context.getSystemService(NotificationManager.class)
+                    .notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
         } catch (NullPointerException npe) {
             loge("setNotificationVisible: " + npe);
         }
@@ -144,26 +142,16 @@
 
     private static void onCancelAllNotifications(Context context) {
         logd("onCancelAllNotifications");
-        final NotificationManager notificationMgr = context.getSystemService(
-                NotificationManager.class);
-        notificationMgr.cancelAll();
+        context.getSystemService(NotificationManager.class).cancelAll();
     }
 
     private static Notification getNotification(Context context, int titleId, int textId,
                                          PendingIntent pendingIntent) {
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        final NotificationManager notificationManager = context.getSystemService(
-                NotificationManager.class);
         final Resources resources = context.getResources();
         final Bundle extras = Bundle.forPair(Notification.EXTRA_SUBSTITUTE_APP_NAME,
                 resources.getString(R.string.android_system_label));
-        /* Creates the notification channel and registers it with NotificationManager. If a channel
-         * with the same ID is already registered, NotificationManager will ignore this call.
-         */
-        notificationManager.createNotificationChannel(new NotificationChannel(
-                NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
-                resources.getString(R.string.mobile_data_status_notification_channel_name),
-                NotificationManager.IMPORTANCE_DEFAULT));
+        createNotificationChannels(context);
         Notification.Builder builder = new Notification.Builder(context)
                 .setContentTitle(resources.getString(titleId))
                 .setContentText(String.format(resources.getString(textId),
@@ -187,6 +175,19 @@
         return builder.build();
     }
 
+    /**
+     * Creates the notification channel and registers it with NotificationManager. Also used to
+     * update an existing channel's name.
+     */
+    static void createNotificationChannels(Context context) {
+        context.getSystemService(NotificationManager.class)
+                .createNotificationChannel(new NotificationChannel(
+                NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
+                context.getResources().getString(
+                        R.string.mobile_data_status_notification_channel_name),
+                NotificationManager.IMPORTANCE_DEFAULT));
+    }
+
     private static void logd(String s) {
         Log.d(TAG, s);
     }
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
index 3fd89d9..3f55ff5 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
@@ -32,6 +32,10 @@
             Log.d(TAG, "skip carrier actions during provisioning");
             return;
         }
+        if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+            CarrierActionUtils.createNotificationChannels(context);
+            return;
+        }
         List<Integer> actionList = CustomConfigLoader.loadCarrierActionList(context, intent);
         for (int actionIdx : actionList) {
             Log.d(TAG, "apply carrier action idx: " + actionIdx);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
deleted file mode 100644
index 0688481..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.plugins.doze;
-
-import android.app.PendingIntent;
-import android.content.Context;
-
-import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-/**
- * Provides a {@link DozeUi}.
- */
-@ProvidesInterface(action = DozeProvider.ACTION, version = DozeProvider.VERSION)
-public interface DozeProvider extends Plugin {
-
-    String ACTION = "com.android.systemui.action.PLUGIN_DOZE";
-    int VERSION = 1;
-
-    /**
-     * Caution: Even if this is called, the DozeUi provided may still be in use until it transitions
-     * to DozeState.FINISH
-     */
-    @Override
-    default void onDestroy() {
-    }
-
-    /**
-     * @return the plugin's implementation of DozeUi.
-     */
-    DozeUi provideDozeUi(Context context, DozeMachine machine, WakeLock wakeLock);
-
-    /**
-     * If true, the plugin allows the default pulse triggers to fire, otherwise they are disabled.
-     */
-    default boolean allowDefaultPulseTriggers() {
-        return false;
-    }
-
-    /**
-     * Ui for use in DozeMachine.
-     */
-    interface DozeUi {
-        /** Called whenever the DozeMachine state transitions */
-        void transitionTo(DozeState oldState, DozeState newState);
-    }
-
-    /** WakeLock wrapper for testability */
-    interface WakeLock {
-        /** @see android.os.PowerManager.WakeLock#acquire() */
-        void acquire();
-        /** @see android.os.PowerManager.WakeLock#release() */
-        void release();
-        /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
-        Runnable wrap(Runnable r);
-    }
-
-    /** Plugin version of the DozeMachine's state */
-    enum DozeState {
-        /** Default state. Transition to INITIALIZED to get Doze going. */
-        UNINITIALIZED,
-        /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
-        INITIALIZED,
-        /** Regular doze. Device is asleep and listening for pulse triggers. */
-        DOZE,
-        /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
-        DOZE_AOD,
-        /** Pulse has been requested. Device is awake and preparing UI */
-        DOZE_REQUEST_PULSE,
-        /** Pulse is showing. Device is awake and showing UI. */
-        DOZE_PULSING,
-        /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
-        DOZE_PULSE_DONE,
-        /** Doze is done. DozeService is finished. */
-        FINISH,
-        /** WakeUp. */
-        WAKE_UP,
-    }
-
-    /** Plugin interface for the doze machine. */
-    interface DozeMachine {
-        /** Request that the DozeMachine transitions to {@code state} */
-        void requestState(DozeState state);
-
-        /** Request that the PendingIntent is sent. */
-        void requestSendIntent(PendingIntent intent);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index ba8e54a..eea09df 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -18,23 +18,18 @@
 
 import android.app.AlarmManager;
 import android.app.Application;
-import android.app.PendingIntent;
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.os.Handler;
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.systemui.SystemUIApplication;
-import com.android.systemui.plugins.doze.DozeProvider;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.wakelock.WakeLock;
 
 public class DozeFactory {
 
-    private final DozeProvider mDozePlugin;
-
-    public DozeFactory(DozeProvider plugin) {
-        mDozePlugin = plugin;
+    public DozeFactory() {
     }
 
     /** Creates a DozeMachine with its parts for {@code dozeService}. */
@@ -65,89 +60,14 @@
     private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
             DozeHost host, AmbientDisplayConfiguration config, DozeParameters params,
             Handler handler, WakeLock wakeLock, DozeMachine machine) {
-        boolean allowPulseTriggers = mDozePlugin == null || mDozePlugin.allowDefaultPulseTriggers();
+        boolean allowPulseTriggers = true;
         return new DozeTriggers(context, machine, host, config, params,
                 sensorManager, handler, wakeLock, allowPulseTriggers);
     }
 
     private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
             DozeMachine machine, Handler handler, AlarmManager alarmManager) {
-        if (mDozePlugin != null) {
-            DozeProvider.DozeUi dozeUi = mDozePlugin.provideDozeUi(context,
-                    pluginMachine(context, machine, host),
-                    wakeLock);
-            return (oldState, newState) -> {
-                dozeUi.transitionTo(pluginState(oldState),
-                        pluginState(newState));
-            };
-        } else {
-            return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
-        }
-    }
-
-    private DozeProvider.DozeMachine pluginMachine(Context context, DozeMachine machine,
-            DozeHost host) {
-        return new DozeProvider.DozeMachine() {
-            @Override
-            public void requestState(DozeProvider.DozeState state) {
-                if (state == DozeProvider.DozeState.WAKE_UP) {
-                    machine.wakeUp();
-                    return;
-                }
-                machine.requestState(implState(state));
-            }
-
-            @Override
-            public void requestSendIntent(PendingIntent intent) {
-                host.startPendingIntentDismissingKeyguard(intent);
-            }
-        };
-    }
-
-    private DozeMachine.State implState(DozeProvider.DozeState s) {
-        switch (s) {
-            case UNINITIALIZED:
-                return DozeMachine.State.UNINITIALIZED;
-            case INITIALIZED:
-                return DozeMachine.State.INITIALIZED;
-            case DOZE:
-                return DozeMachine.State.DOZE;
-            case DOZE_AOD:
-                return DozeMachine.State.DOZE_AOD;
-            case DOZE_REQUEST_PULSE:
-                return DozeMachine.State.DOZE_REQUEST_PULSE;
-            case DOZE_PULSING:
-                return DozeMachine.State.DOZE_PULSING;
-            case DOZE_PULSE_DONE:
-                return DozeMachine.State.DOZE_PULSE_DONE;
-            case FINISH:
-                return DozeMachine.State.FINISH;
-            default:
-                throw new IllegalArgumentException("Unknown state: " + s);
-        }
-    }
-
-    private DozeProvider.DozeState pluginState(DozeMachine.State s) {
-        switch (s) {
-            case UNINITIALIZED:
-                return DozeProvider.DozeState.UNINITIALIZED;
-            case INITIALIZED:
-                return DozeProvider.DozeState.INITIALIZED;
-            case DOZE:
-                return DozeProvider.DozeState.DOZE;
-            case DOZE_AOD:
-                return DozeProvider.DozeState.DOZE_AOD;
-            case DOZE_REQUEST_PULSE:
-                return DozeProvider.DozeState.DOZE_REQUEST_PULSE;
-            case DOZE_PULSING:
-                return DozeProvider.DozeState.DOZE_PULSING;
-            case DOZE_PULSE_DONE:
-                return DozeProvider.DozeState.DOZE_PULSE_DONE;
-            case FINISH:
-                return DozeProvider.DozeState.FINISH;
-            default:
-                throw new IllegalArgumentException("Unknown state: " + s);
-        }
+        return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
     }
 
     public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index e55a597..5241266 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -24,7 +24,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.doze.DozeProvider;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -50,9 +49,7 @@
             return;
         }
 
-        DozeProvider provider = Dependency.get(PluginManager.class)
-                .getOneShotPlugin(DozeProvider.class);
-        mDozeMachine = new DozeFactory(provider).assembleMachine(this);
+        mDozeMachine = new DozeFactory().assembleMachine(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index eea3de3..215604b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -20,10 +20,17 @@
 import android.os.PowerManager;
 import android.support.annotation.VisibleForTesting;
 
-import com.android.systemui.plugins.doze.DozeProvider;
-
 /** WakeLock wrapper for testability */
-public interface WakeLock extends DozeProvider.WakeLock {
+public interface WakeLock {
+
+    /** @see android.os.PowerManager.WakeLock#acquire() */
+    void acquire();
+
+    /** @see android.os.PowerManager.WakeLock#release() */
+    void release();
+
+    /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
+    Runnable wrap(Runnable r);
 
     static WakeLock createPartial(Context context, String tag) {
         return wrap(createPartialInner(context, tag));
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1b970e5..dc2dfa8 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3868,9 +3868,14 @@
                         writeApkToBackup(mPackage, output);
                     }
 
+                    final boolean isSharedStorage =
+                            mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
+                    final long timeout = isSharedStorage ?
+                            TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_FULL_BACKUP_INTERVAL;
+
                     if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
-                    prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL,
-                            mTimeoutMonitor /* in parent class */, OP_TYPE_BACKUP_WAIT);
+                    prepareOperationTimeout(mToken, timeout, mTimeoutMonitor /* in parent class */,
+                            OP_TYPE_BACKUP_WAIT);
                     mAgent.doFullBackup(mPipe, mQuota, mToken, mBackupManagerBinder);
                 } catch (IOException e) {
                     Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
@@ -7578,9 +7583,12 @@
                         if (okay) {
                             boolean agentSuccess = true;
                             long toCopy = info.size;
+                            final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
+                            final long timeout = isSharedStorage ?
+                                    TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_RESTORE_INTERVAL;
                             final int token = generateToken();
                             try {
-                                prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, null,
+                                prepareOperationTimeout(token, timeout, null,
                                         OP_TYPE_RESTORE_WAIT);
                                 if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) {
                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 67704e7..be242b6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1503,8 +1503,16 @@
         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
     }
 
-    @Override
-    int getOrientation() {
+    /**
+     * Returns the orientation that this display should be in factoring in its children containers.
+     *
+     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+     *                             factored in when determining the orientation. If false only
+     *                             non-app/system containers will be used to determine the returned
+     *                             orientation.
+     * @return The orientation the display should be in.
+     */
+    int getOrientation(boolean includeAppContainers) {
         final WindowManagerPolicy policy = mService.mPolicy;
 
         if (mService.mDisplayFrozen) {
@@ -1533,8 +1541,14 @@
             }
         }
 
-        // Top system windows are not requesting an orientation. Start searching from apps.
-        return mTaskStackContainers.getOrientation();
+        // Top system windows are not requesting an orientation. Get orientation from app containers
+        // if allowed. Otherwise, return the last orientation.
+        return includeAppContainers ? mTaskStackContainers.getOrientation() : mLastOrientation;
+    }
+
+    @Override
+    int getOrientation() {
+        return getOrientation(true /* includeAppContainers */);
     }
 
     void updateDisplayInfo() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a7f6600..a48397b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2373,7 +2373,7 @@
         try {
             synchronized(mWindowMap) {
                 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
-                        displayId);
+                        displayId, true /* includeAppContainers */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2383,13 +2383,13 @@
     }
 
     private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded, int displayId) {
+            IBinder freezeThisOneIfNeeded, int displayId, boolean includeAppContainers) {
         if (!mDisplayReady) {
             return null;
         }
         Configuration config = null;
 
-        if (updateOrientationFromAppTokensLocked(false, displayId)) {
+        if (updateOrientationFromAppTokensLocked(false, displayId, includeAppContainers)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
             if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2427,6 +2427,11 @@
         return config;
     }
 
+    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+        return updateOrientationFromAppTokensLocked(inTransaction, displayId,
+                false /* includeAppContainers */);
+    }
+
     /**
      * 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
@@ -2437,13 +2442,25 @@
      * 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.
+     *
+     * @param inTransaction True if we are currently in a surface transaction.
+     * @param displayId Id of the display to update orientation for.
+     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+     *                             factored in when determining the orientation. If false only
+     *                             non-app/system containers will be used to determine the returned
+     *                             orientation.
+     *                             NOTE: Only call originating from activity manager are expected to
+     *                             set this to true as it needs to synchronize several app states
+     *                             like visibility with the update of display orientation.
+     * @return True if the display orientation was updated.
      * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
      */
-    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
-        long ident = Binder.clearCallingIdentity();
+    private boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId,
+            boolean includeAppContainers) {
+        final long ident = Binder.clearCallingIdentity();
         try {
             final DisplayContent dc = mRoot.getDisplayContent(displayId);
-            final int req = dc.getOrientation();
+            final int req = dc.getOrientation(includeAppContainers);
             if (req != dc.getLastOrientation()) {
                 dc.setLastOrientation(req);
                 //send a message to Policy indicating orientation change to take