Merge "Enable kvm-clock on guest kernels equal to or above 5.4" into emu-master-dev
diff --git a/android/android-emu/android/hw-sensors.cpp b/android/android-emu/android/hw-sensors.cpp
index 4eb51b7..7229d75 100644
--- a/android/android-emu/android/hw-sensors.cpp
+++ b/android/android-emu/android/hw-sensors.cpp
@@ -906,9 +906,13 @@
 }
 
 static HwSensors _sensorsState[1] = {};
+static const QAndroidEmulatorWindowAgent* _windowAgent = NULL;
 
-void android_hw_sensors_init(void) {
+void android_hw_sensors_init(const QAndroidEmulatorWindowAgent* windowAgent) {
     HwSensors* hw = _sensorsState;
+    if (windowAgent != NULL) {
+        _windowAgent = windowAgent;
+    }
 
     if (hw->service == NULL) {
         _hwSensors_init(hw);
@@ -916,6 +920,10 @@
     }
 }
 
+const QAndroidEmulatorWindowAgent* android_hw_sensors_get_window_agent() {
+    return _windowAgent;
+}
+
 void android_hw_sensors_init_remote_controller(void) {
     HwSensors* hw = _sensorsState;
 
@@ -935,7 +943,7 @@
 extern int android_sensors_set_coarse_orientation(
         AndroidCoarseOrientation orient,
         float tilt_degrees) {
-    android_hw_sensors_init();
+    android_hw_sensors_init(NULL);
     _hwSensors_setCoarseOrientation(_sensorsState, orient, tilt_degrees);
     return 0;
 }
diff --git a/android/android-emu/android/hw-sensors.h b/android/android-emu/android/hw-sensors.h
index 3615c15..db1bf0d 100644
--- a/android/android-emu/android/hw-sensors.h
+++ b/android/android-emu/android/hw-sensors.h
@@ -14,6 +14,7 @@
 
 #include "android/physics/Physics.h"
 #include "android/utils/compiler.h"
+#include "android/emulation/control/window_agent.h"
 
 #include <stdint.h>
 #include <math.h>
@@ -25,7 +26,9 @@
 ANDROID_BEGIN_HEADER
 
 /* initialize sensor emulation */
-extern void  android_hw_sensors_init( void );
+extern void  android_hw_sensors_init(const QAndroidEmulatorWindowAgent* windowAgent);
+
+const QAndroidEmulatorWindowAgent* android_hw_sensors_get_window_agent();
 
 /* initialize remote controller for HW sensors. This must be called after
  * init_clocks(), i.e. later than android_hw_sensors_init(). */
@@ -208,6 +211,8 @@
 // Stop recording ground truth.
 extern int android_physical_model_stop_recording();
 
+extern void android_hw_sensor_set_window_agent(void* agent);
+
 /* Foldable state */
 
 #define ANDROID_FOLDABLE_MAX_HINGES 3
diff --git a/android/android-emu/android/physics/FoldableModel.cpp b/android/android-emu/android/physics/FoldableModel.cpp
index f71be2d..119e01a 100644
--- a/android/android-emu/android/physics/FoldableModel.cpp
+++ b/android/android-emu/android/physics/FoldableModel.cpp
@@ -194,13 +194,16 @@
     mState.currentHingeDegrees[hingeIndex] = degrees;
     enum FoldablePostures p = calculatePosture();
     if (mState.currentPosture != p) {
+        enum FoldablePostures oldP = mState.currentPosture;
         mState.currentPosture = p;
         sendPostureToSystem();
+        setToolBarFold(oldP);
     }
 }
 
 void FoldableModel::setPosture(float posture, PhysicalInterpolation mode) {
     enum FoldablePostures p = (enum FoldablePostures)posture;
+    enum FoldablePostures oldP = mState.currentPosture;
     if (mState.currentPosture == p) {
         return;
     }
@@ -215,6 +218,7 @@
             }
         }
     }
+    setToolBarFold(oldP);
 }
 
 float FoldableModel::getHingeAngle(uint32_t hingeIndex,
@@ -244,5 +248,20 @@
 
 }
 
+void FoldableModel::setToolBarFold(enum FoldablePostures oldPosture) {
+    const QAndroidEmulatorWindowAgent* windowAgent =
+        android_hw_sensors_get_window_agent();
+    if (!windowAgent) {
+        return;
+    }
+    if (mState.currentPosture == POSTURE_CLOSED) {
+        windowAgent->fold(true);
+    } else {
+        if (oldPosture == POSTURE_CLOSED) {
+            windowAgent->fold(false);
+        }
+    }
+}
+
 }  // namespace physics
 }  // namespace android
\ No newline at end of file
diff --git a/android/android-emu/android/physics/FoldableModel.h b/android/android-emu/android/physics/FoldableModel.h
index 60d808a..ed0d17a 100644
--- a/android/android-emu/android/physics/FoldableModel.h
+++ b/android/android-emu/android/physics/FoldableModel.h
@@ -46,6 +46,7 @@
 private:
     enum FoldablePostures calculatePosture();
     void sendPostureToSystem();
+    void setToolBarFold(enum FoldablePostures oldPosture);
 
     FoldableState mState;
     std::vector<struct AnglesToPosture> mAnglesToPostures;
diff --git a/android/android-emu/android/qemu-setup.cpp b/android/android-emu/android/qemu-setup.cpp
index b6d46ce..44903c6 100644
--- a/android/android-emu/android/qemu-setup.cpp
+++ b/android/android-emu/android/qemu-setup.cpp
@@ -496,7 +496,7 @@
     android_http_proxy_setup(op_http_proxy, VERBOSE_CHECK(proxy));
 
     /* initialize sensors, this must be done here due to timer issues */
-    android_hw_sensors_init();
+    android_hw_sensors_init(agents->emu);
     android::automation::AutomationController::initialize();
     android::videoinjection::VideoInjectionController::initialize();
     android::offworld::registerOffworldPipeService();
diff --git a/android/android-emu/android/skin/qt/device-3d-widget.cpp b/android/android-emu/android/skin/qt/device-3d-widget.cpp
index 9f124d5..f796b74 100644
--- a/android/android-emu/android/skin/qt/device-3d-widget.cpp
+++ b/android/android-emu/android/skin/qt/device-3d-widget.cpp
@@ -373,7 +373,7 @@
         float ur = (hSplit) ? 1.0f : float(centerY - i.b) / float(displayH);
         float ub = (hSplit) ? float(i.b + centerY) / float(displayH) : 0.0f;
         float ut = (hSplit) ? float(i.t + centerY) / float(displayH) : 1.0f;
-        std::vector<float> attribFront;
+        std::vector<float> attribFront, attribBack;
         if (hSplit) {
             attribFront = {
                     l, b, 0.0, 0.0, 0.0, +1.0, ul, ub,  // front
@@ -381,6 +381,11 @@
                     l, t, 0.0, 0.0, 0.0, +1.0, ul, ut,
                     r, t, 0.0, 0.0, 0.0, +1.0, ur, ut,
             };
+            attribBack = {
+                    l,   b,    -d, 0.0, 0.0, -1.0, ul, ub,  // front
+                    r,   b,    -d, 0.0, 0.0, -1.0, ur, ub,  l,   t,    -d, 0.0,
+                    0.0, -1.0, ul, ut,  r,   t,    -d, 0.0, 0.0, -1.0, ur, ut,
+            };
         } else {
             // rotate 90 degree for vertical split texture sampling
             attribFront = {
@@ -389,31 +394,41 @@
                     l, t, 0.0, 0.0, 0.0, +1.0, ul, ub,
                     r, t, 0.0, 0.0, 0.0, +1.0, ul, ut,
             };
+            attribBack = {
+                    l,   b,    -d, 0.0, 0.0, -1.0, ur, ub,  // front
+                    r,   b,    -d, 0.0, 0.0, -1.0, ur, ut,  l,   t,    -d, 0.0,
+                    0.0, -1.0, ul, ub,  r,   t,    -d, 0.0, 0.0, -1.0, ul, ut,
+            };
         }
         std::vector<float> attribCommon =
                 {
-                        l, b, -d,  0.0,  0.0,  -1.0, 0.0, 0.0,  // back
-                        r, b, -d,  0.0,  0.0,  -1.0, 1.0, 0.0,
-                        l, t, -d,  0.0,  0.0,  -1.0, 0.0, 1.0,
-                        r, t, -d,  0.0,  0.0,  -1.0, 1.0, 1.0,
-                        l, b, -d,  -1.0, 0.0,  0.0,  0.0, 0.0,  // left
-                        l, b, 0.0, -1.0, 0.0,  0.0,  1.0, 0.0,
-                        l, t, -d,  -1.0, 0.0,  0.0,  0.0, 1.0,
-                        l, t, 0.0, -1.0, 0.0,  0.0,  1.0, 1.0,
-                        r, b, -d,  +1.0, 0.0,  0.0,  0.0, 0.0,  // right
-                        r, b, 0.0, +1.0, 0.0,  0.0,  1.0, 0.0,
-                        r, t, -d,  +1.0, 0.0,  0.0,  0.0, 1.0,
-                        r, t, 0.0, +1.0, 0.0,  0.0,  1.0, 1.0,
-                        l, t, 0.0, 0.0,  +1.0, 0.0,  0.0, 0.0,  // top
-                        r, t, 0.0, 0.0,  +1.0, 0.0,  1.0, 0.0,
-                        l, t, -d,  0.0,  +1.0, 0.0,  0.0, 1.0,
-                        r, t, -d,  0.0,  +1.0, 0.0,  1.0, 1.0,
-                        l, b, 0.0, 0.0,  -1.0, 0.0,  0.0, 0.0,  // bottom
-                        r, b, 0.0, 0.0,  -1.0, 0.0,  1.0, 0.0,
-                        l, b, -d,  0.0,  -1.0, 0.0,  0.0, 1.0,
-                        r, b, -d,  0.0,  -1.0, 0.0,  1.0, 1.0,
+                        //                        l, b, -d,  0.0,  0.0,  -1.0,
+                        //                        0.0, 0.0,  // back
+                        //                        r, b, -d,  0.0,  0.0,
+                        //                        -1.0, 1.0, 0.0,
+                        //                        l, t, -d,  0.0,  0.0,  -1.0,
+                        //                        0.0, 1.0,
+                        //                        r, t, -d,  0.0,  0.0,
+                        //                        -1.0, 1.0, 1.0,
+                        l, b, -d,  -1.0, 0.0,  0.0, 0.0, 0.0,  // left
+                        l, b, 0.0, -1.0, 0.0,  0.0, 1.0, 0.0,
+                        l, t, -d,  -1.0, 0.0,  0.0, 0.0, 1.0,
+                        l, t, 0.0, -1.0, 0.0,  0.0, 1.0, 1.0,
+                        r, b, -d,  +1.0, 0.0,  0.0, 0.0, 0.0,  // right
+                        r, b, 0.0, +1.0, 0.0,  0.0, 1.0, 0.0,
+                        r, t, -d,  +1.0, 0.0,  0.0, 0.0, 1.0,
+                        r, t, 0.0, +1.0, 0.0,  0.0, 1.0, 1.0,
+                        l, t, 0.0, 0.0,  +1.0, 0.0, 0.0, 0.0,  // top
+                        r, t, 0.0, 0.0,  +1.0, 0.0, 1.0, 0.0,
+                        l, t, -d,  0.0,  +1.0, 0.0, 0.0, 1.0,
+                        r, t, -d,  0.0,  +1.0, 0.0, 1.0, 1.0,
+                        l, b, 0.0, 0.0,  -1.0, 0.0, 0.0, 0.0,  // bottom
+                        r, b, 0.0, 0.0,  -1.0, 0.0, 1.0, 0.0,
+                        l, b, -d,  0.0,  -1.0, 0.0, 0.0, 1.0,
+                        r, b, -d,  0.0,  -1.0, 0.0, 1.0, 1.0,
                 };
         attribs.insert(attribs.end(), attribFront.begin(), attribFront.end());
+        attribs.insert(attribs.end(), attribBack.begin(), attribBack.end());
         attribs.insert(attribs.end(), attribCommon.begin(), attribCommon.end());
         for (auto iter : indice) {
             indices.push_back(iter + j * 24);
@@ -780,14 +795,23 @@
                                       (void*)(sizeof(float) * 6));
         mGLES2->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVertexIndexBuffer);
         mGLES2->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-        // Draw 5 non-front sides of each display segment cuboid
-        mGLES2->glActiveTexture(GL_TEXTURE0);
-        mGLES2->glBindTexture(GL_TEXTURE_2D, mSpecularMap);
         GLuint diffuse_map_uniform =
                 mGLES2->glGetUniformLocation(mProgram, "diffuse_map");
         mGLES2->glUniform1i(diffuse_map_uniform, 0);
+        FoldablePostures posture = POSTURE_UNKNOWN;
+        if (mSensorsAgent) {
+            glm::vec3 result;
+            mSensorsAgent->getPhysicalParameter(PHYSICAL_PARAMETER_POSTURE,
+                                                &result.x, &result.y, &result.z,
+                                                PARAMETER_VALUE_TYPE_CURRENT);
+            posture = (FoldablePostures)result.x;
+        }
+
         uint32_t i = 0;
+        // Draw 5 non-front sides of each display segment cuboid
+        mGLES2->glActiveTexture(GL_TEXTURE0);
+        mGLES2->glBindTexture(GL_TEXTURE_2D, mSpecularMap);
+        i = 0;
         for (auto iter : mDisplaySegments) {
             if (iter.t == iter.b) {
                 continue;
@@ -811,8 +835,26 @@
                 mGLES2->glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT,
                                        (void*)(i * 36 * sizeof(GLuint)));
             } else {
-                mGLES2->glDrawElements(GL_TRIANGLES, 30, GL_UNSIGNED_INT,
-                                       (void*)((i * 36 + 6) * sizeof(GLuint)));
+                if (ToolWindow::isFoldableConfigured()) {
+                    if (posture == POSTURE_CLOSED) {
+                        // legacy foldable configured, display moves to
+                        // secondary smaller screen on the back of device
+                        mGLES2->glDrawElements(
+                                GL_TRIANGLES, 6, GL_UNSIGNED_INT,
+                                (void*)((i * 36) * sizeof(GLuint)));
+                        mGLES2->glDrawElements(
+                                GL_TRIANGLES, 24, GL_UNSIGNED_INT,
+                                (void*)((i * 36 + 12) * sizeof(GLuint)));
+                    } else {
+                        mGLES2->glDrawElements(
+                                GL_TRIANGLES, 30, GL_UNSIGNED_INT,
+                                (void*)((i * 36 + 6) * sizeof(GLuint)));
+                    }
+                } else {
+                    mGLES2->glDrawElements(
+                            GL_TRIANGLES, 30, GL_UNSIGNED_INT,
+                            (void*)((i * 36 + 6) * sizeof(GLuint)));
+                }
             }
             i++;
         }
@@ -846,8 +888,13 @@
                                        &normal_transform[0][0]);
             mGLES2->glUniformMatrix4fv(mvp_matrix_uniform, 1, GL_FALSE,
                                        &model_view_projection[0][0]);
-            mGLES2->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT,
-                                   (void*)(i * 36 * sizeof(GLuint)));
+            if (posture == POSTURE_CLOSED) {
+                mGLES2->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT,
+                                       (void*)((i * 36 + 6) * sizeof(GLuint)));
+            } else {
+                mGLES2->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT,
+                                       (void*)(i * 36 * sizeof(GLuint)));
+            }
             i++;
         }
     } else {
diff --git a/android/android-emu/android/skin/qt/tool-window.cpp b/android/android-emu/android/skin/qt/tool-window.cpp
index 4b1e4e9..a8532cd 100644
--- a/android/android-emu/android/skin/qt/tool-window.cpp
+++ b/android/android-emu/android/skin/qt/tool-window.cpp
@@ -71,6 +71,7 @@
 #include "android/featurecontrol/Features.h"              // for QuickbootFi...
 #include "android/globals.h"                              // for android_hw
 #include "android/hw-events.h"                            // for EV_SW, EV_SYN
+#include "android/hw-sensors.h"
 #include "android/metrics/MetricsReporter.h"              // for MetricsRepo...
 #include "android/metrics/MetricsWriter.h"                // for android_studio
 #include "studio_stats.pb.h"        // for EmulatorSna...
@@ -178,7 +179,6 @@
         mToolsUi->zoom_button->hide();
         mToolsUi->zoom_button->setEnabled(false);
     }
-
     // Get the latest user selections from the user-config code.
     SettingsTheme theme = getSelectedTheme();
     adjustAllButtonsForTheme(theme);
@@ -634,6 +634,9 @@
             break;
         case QtUICommand::FOLD:
             if (down && isFoldableConfigured()) {
+                if (mFolded) {
+                    break;
+                }
                 mFolded = true;
                 ChangeIcon(mToolsUi->fold_switch, "expand_horiz", "Unfold");
                 updateButtonUiCommand(mToolsUi->fold_switch, "UNFOLD");
@@ -641,16 +644,46 @@
                 sendFoldedArea();
                 forwardGenericEventToEmulator(EV_SW, SW_LID, true);
                 forwardGenericEventToEmulator(EV_SYN, 0, 0);
+                float posture, unused1, unused2;
+                sUiEmuAgent->sensors->getPhysicalParameter(PHYSICAL_PARAMETER_POSTURE,
+                                                           &posture,
+                                                           &unused1,
+                                                           &unused2,
+                                                           PARAMETER_VALUE_TYPE_CURRENT);
+                if ((enum FoldablePostures)posture != POSTURE_CLOSED) {
+                    sUiEmuAgent->sensors->setPhysicalParameterTarget(PHYSICAL_PARAMETER_POSTURE,
+                                                                     (float)POSTURE_CLOSED,
+                                                                     0.0f,
+                                                                     0.0f,
+                                                                     PHYSICAL_INTERPOLATION_SMOOTH);
+                }
             }
             break;
         case QtUICommand::UNFOLD:
             if (down && isFoldableConfigured()) {
+                if (!mFolded) {
+                    break;
+                }
                 mFolded = false;
                 ChangeIcon(mToolsUi->fold_switch, "compress_horiz", "Fold");
                 updateButtonUiCommand(mToolsUi->fold_switch, "FOLD");
                 mEmulatorWindow->resizeAndChangeAspectRatio(false);
                 forwardGenericEventToEmulator(EV_SW, SW_LID, false);
                 forwardGenericEventToEmulator(EV_SYN, 0, 0);
+                // unfold = { POSTURE_HALF_OPENED, POSTURE_OPENED, POSTURE_FLIPPED }
+                float posture, unused1, unused2;
+                sUiEmuAgent->sensors->getPhysicalParameter(PHYSICAL_PARAMETER_POSTURE,
+                                                           &posture,
+                                                           &unused1,
+                                                           &unused2,
+                                                           PARAMETER_VALUE_TYPE_CURRENT);
+                if ((enum FoldablePostures)posture == POSTURE_CLOSED) {
+                    sUiEmuAgent->sensors->setPhysicalParameterTarget(PHYSICAL_PARAMETER_POSTURE,
+                                                                     (float)POSTURE_OPENED,
+                                                                     0.0f,
+                                                                     0.0f,
+                                                                     PHYSICAL_INTERPOLATION_SMOOTH);
+                }
             }
             break;
         case QtUICommand::SHOW_MULTITOUCH: