From fa3d403840dffe0a6ba000b1691cfd40f426916e Mon Sep 17 00:00:00 2001
From: nift4 <nift4@protonmail.com>
Date: Wed, 5 Apr 2023 12:38:05 +0200
Subject: [PATCH] Power menu styles: Initial checkin for U [1/3]

2024/05/07 - ikeramat & dhina17: port to u-qpr2

Squashed:
- SystemUI: power menu styles refresh

Change-Id: I8e4a29ab0f65e3051b898e49e96ed0b2ef43acca
---
 .../drawable/global_actions_background.xml    |  22 +
 .../global_actions_column_seascape.xml        |  68 ++
 .../layout-land/global_actions_grid_item.xml  |  61 ++
 .../global_actions_grid_seascape.xml          |  79 ++
 .../global_actions_grid_v2.xml                |  68 ++
 .../layout-sw600dp/global_actions_grid_v2.xml |  76 ++
 .../res/layout/global_actions_grid.xml        |   3 +-
 .../res/layout/global_actions_grid_item.xml   |  60 ++
 .../res/layout/global_actions_grid_v2.xml     |  41 +
 .../res/layout/global_actions_lock_view.xml   |  35 +
 .../global_actions_power_dialog_flow.xml      |   2 +-
 .../SystemUI/res/values-sw392dp/dimens.xml    |   8 +
 .../SystemUI/res/values-sw410dp/dimens.xml    |   8 +
 .../SystemUI/res/values-sw600dp/config.xml    |   6 +
 .../SystemUI/res/values-sw600dp/dimens.xml    |   3 +
 packages/SystemUI/res/values/colors.xml       |  12 +
 packages/SystemUI/res/values/config.xml       |   6 +
 packages/SystemUI/res/values/dimens.xml       |  11 +
 .../GlobalActionsColumnLayout.java            |   3 +-
 .../globalactions/GlobalActionsDialog.java    | 807 ++++++++++++++++++
 .../GlobalActionsDialogLite.java              | 160 +++-
 .../globalactions/GlobalActionsImpl.java      |  33 +-
 .../GlobalActionsPowerDialog.java             |   5 +-
 .../globalactions/MinHeightScrollView.java    |  43 +
 .../interactor/FooterActionsInteractor.kt     |  15 +-
 .../GlobalActionsDialogTest.java              | 601 +++++++++++++
 .../android/server/policy/GlobalActions.java  |   6 +-
 .../server/policy/PhoneWindowManager.java     |   9 +
 28 files changed, 2206 insertions(+), 45 deletions(-)
 create mode 100644 packages/SystemUI/res/drawable/global_actions_background.xml
 create mode 100644 packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
 create mode 100644 packages/SystemUI/res/layout-land/global_actions_grid_item.xml
 create mode 100644 packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
 create mode 100644 packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml
 create mode 100644 packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml
 create mode 100644 packages/SystemUI/res/layout/global_actions_grid_item.xml
 create mode 100644 packages/SystemUI/res/layout/global_actions_grid_v2.xml
 create mode 100644 packages/SystemUI/res/layout/global_actions_lock_view.xml
 create mode 100644 packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
 create mode 100644 packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
 create mode 100644 packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java

diff --git a/packages/SystemUI/res/drawable/global_actions_background.xml b/packages/SystemUI/res/drawable/global_actions_background.xml
new file mode 100644
index 000000000000..ebabcebf4240
--- /dev/null
+++ b/packages/SystemUI/res/drawable/global_actions_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2021, 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.
+*/
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <solid android:color="@color/global_actions_extra_background"/>
+  <corners android:radius="@dimen/global_actions_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
new file mode 100644
index 000000000000..412beb789deb
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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
+  -->
+
+<com.android.systemui.globalactions.GlobalActionsColumnLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/global_actions_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:clipToPadding="false"
+    android:theme="@style/Theme.SystemUI.QuickSettings"
+    android:gravity="center_horizontal | bottom"
+    android:clipChildren="false"
+>
+    <LinearLayout
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:padding="0dp"
+        android:orientation="horizontal"
+    >
+        <!-- Grid of action items -->
+        <com.android.systemui.globalactions.ListGridLayout
+            android:id="@android:id/list"
+            android:layout_gravity="bottom|left"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+            android:translationZ="@dimen/global_actions_translate"
+            android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
+            android:paddingRight="@dimen/global_actions_grid_vertical_padding"
+            android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
+            android:background="?android:attr/colorBackgroundFloating"
+        />
+        <!-- For separated items-->
+        <LinearLayout
+            android:id="@+id/separated_button"
+            android:layout_gravity="top|left"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+            android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
+            android:paddingRight="@dimen/global_actions_grid_vertical_padding"
+            android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
+            android:orientation="horizontal"
+            android:background="?android:attr/colorBackgroundFloating"
+            android:translationZ="@dimen/global_actions_translate"
+        />
+    </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsColumnLayout>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml
new file mode 100644
index 000000000000..0f9deaa3c569
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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
+  -->
+
+<!-- RelativeLayouts have an issue enforcing minimum heights, so just
+     work around this for now with LinearLayouts. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:layout_marginTop="@dimen/global_actions_grid_item_side_margin"
+    android:layout_marginBottom="@dimen/global_actions_grid_item_side_margin"
+    android:layout_marginLeft="@dimen/global_actions_grid_item_vertical_margin"
+    android:layout_marginRight="@dimen/global_actions_grid_item_vertical_margin"
+>
+    <LinearLayout
+        android:layout_width="@dimen/global_actions_grid_item_height"
+        android:layout_height="@dimen/global_actions_grid_item_width"
+        android:gravity="top|center_horizontal"
+        android:orientation="vertical"
+    >
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="@dimen/global_actions_grid_item_icon_width"
+            android:layout_height="@dimen/global_actions_grid_item_icon_height"
+            android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
+            android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
+            android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+            android:scaleType="centerInside"
+            android:tint="@color/global_actions_text"
+        />
+
+        <TextView
+            android:id="@*android:id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:singleLine="true"
+            android:gravity="center"
+            android:textSize="12dp"
+            android:textColor="@color/global_actions_text"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+        />
+    </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
new file mode 100644
index 000000000000..e52ad2acadc0
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.systemui.globalactions.GlobalActionsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/global_actions_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:theme="@style/Theme.SystemUI.QuickSettings"
+    android:gravity="left | center_vertical"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:paddingLeft="@dimen/global_actions_grid_container_shadow_offset"
+    android:layout_marginLeft="@dimen/global_actions_grid_container_negative_shadow_offset"
+>
+    <LinearLayout
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:padding="0dp"
+        android:orientation="vertical"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layout_marginLeft="@dimen/global_actions_grid_container_bottom_margin"
+    >
+        <!-- For separated items-->
+        <LinearLayout
+            android:id="@+id/separated_button"
+            android:layout_gravity="top|left"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+            android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
+            android:paddingRight="@dimen/global_actions_grid_vertical_padding"
+            android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
+            android:orientation="horizontal"
+            android:layoutDirection="rtl"
+            android:background="?android:attr/colorBackgroundFloating"
+            android:gravity="center"
+            android:translationZ="@dimen/global_actions_translate"
+        />
+        <!-- Grid of action items -->
+        <com.android.systemui.globalactions.ListGridLayout
+            android:id="@android:id/list"
+            android:layout_gravity="bottom|left"
+            android:gravity="right"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+            android:translationZ="@dimen/global_actions_translate"
+            android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
+            android:paddingRight="@dimen/global_actions_grid_vertical_padding"
+            android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
+            android:background="?android:attr/colorBackgroundFloating"
+        >
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layoutDirection="locale"
+            />
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layoutDirection="locale"
+            />
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layoutDirection="locale"
+            />
+        </com.android.systemui.globalactions.ListGridLayout>
+    </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsGridLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml b/packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml
new file mode 100644
index 000000000000..953a29e3a07e
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/global_actions_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+  <LinearLayout
+      android:layout_weight="1"
+      android:layout_height="match_parent"
+      android:layout_width="0dp"
+      android:clipChildren="false"
+      android:orientation="vertical"
+      android:clipToPadding="false"
+      android:id="@+id/controls_pane"
+      >
+        <LinearLayout
+            android:id="@+id/global_actions_controls"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"/>
+  </LinearLayout>
+
+  <LinearLayout
+      android:layout_weight="1"
+      android:layout_height="match_parent"
+      android:layout_width="0dp"
+      android:orientation="vertical"
+      android:id="@+id/nfc_pane"
+      >
+    <include layout="@layout/global_actions_view" />
+
+    <include layout="@layout/global_actions_lock_view" />
+
+      <LinearLayout
+          android:id="@+id/global_actions_grid_root"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:clipChildren="false"
+          android:orientation="vertical"
+          android:clipToPadding="false">
+
+        <FrameLayout
+            android:id="@+id/global_actions_wallet"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
+      </LinearLayout>
+
+  </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml b/packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml
new file mode 100644
index 000000000000..6ffcef7b24e6
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/global_actions_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+  <LinearLayout
+      android:layout_weight="1"
+      android:layout_height="0dp"
+      android:layout_width="match_parent"
+      android:orientation="vertical"
+      android:id="@+id/nfc_pane"
+      >
+
+    <include layout="@layout/global_actions_view" />
+
+    <include layout="@layout/global_actions_lock_view" />
+
+
+    <com.android.systemui.globalactions.MinHeightScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:scrollbars="none">
+
+      <LinearLayout
+          android:id="@+id/global_actions_grid_root"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:clipChildren="false"
+          android:orientation="vertical"
+          android:clipToPadding="false">
+
+        <FrameLayout
+            android:id="@+id/global_actions_wallet"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
+      </LinearLayout>
+    </com.android.systemui.globalactions.MinHeightScrollView>
+
+  </LinearLayout>
+
+  <LinearLayout
+      android:layout_weight="1"
+      android:layout_height="0dp"
+      android:layout_width="match_parent"
+      android:orientation="vertical"
+      android:id="@+id/controls_pane"
+      android:clipToPadding="false"
+      android:clipChildren="false">
+        <LinearLayout
+            android:id="@+id/global_actions_controls"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"/>
+  </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index 8c621b92a513..33d573d58a8d 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -7,7 +7,6 @@
     android:layout_height="match_parent"
     android:clipChildren="false"
     android:clipToPadding="false"
-    android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"
 >
 
     <FrameLayout
@@ -92,4 +91,4 @@
         </LinearLayout>
 
     </com.android.systemui.globalactions.GlobalActionsGridLayout>
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml
new file mode 100644
index 000000000000..31c7cbf6ff1b
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_grid_item.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<!-- RelativeLayouts have an issue enforcing minimum heights, so just
+     work around this for now with LinearLayouts. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:layout_marginTop="@dimen/global_actions_grid_item_vertical_margin"
+    android:layout_marginBottom="@dimen/global_actions_grid_item_vertical_margin"
+    android:layout_marginLeft="@dimen/global_actions_grid_item_side_margin"
+    android:layout_marginRight="@dimen/global_actions_grid_item_side_margin"
+>
+    <LinearLayout
+        android:layout_width="@dimen/global_actions_grid_item_width"
+        android:layout_height="@dimen/global_actions_grid_item_height"
+        android:gravity="top|center_horizontal"
+        android:orientation="vertical"
+    >
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="@dimen/global_actions_grid_item_icon_width"
+            android:layout_height="@dimen/global_actions_grid_item_icon_height"
+            android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
+            android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
+            android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+            android:scaleType="centerInside"
+            android:tint="@color/global_actions_text"
+        />
+
+        <TextView
+            android:id="@*android:id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:singleLine="true"
+            android:gravity="center"
+            android:textSize="12dp"
+            android:textColor="@color/global_actions_text"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+        />
+    </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
new file mode 100644
index 000000000000..30ffc32ce1f8
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/global_actions_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+>
+
+  <include layout="@layout/global_actions_view" />
+
+  <include layout="@layout/global_actions_lock_view" />
+
+  <com.android.systemui.globalactions.MinHeightScrollView
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:orientation="vertical"
+      android:scrollbars="none">
+
+    <LinearLayout
+        android:id="@+id/global_actions_grid_root"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:clipChildren="false"
+        android:orientation="vertical"
+        android:clipToPadding="false">
+
+      <FrameLayout
+          android:id="@+id/global_actions_wallet"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"/>
+
+      <LinearLayout
+          android:id="@+id/global_actions_controls"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:orientation="vertical"/>
+
+    </LinearLayout>
+  </com.android.systemui.globalactions.MinHeightScrollView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_lock_view.xml b/packages/SystemUI/res/layout/global_actions_lock_view.xml
new file mode 100644
index 000000000000..eccc63688065
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_lock_view.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/global_actions_lock_message_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone">
+  <TextView
+      android:id="@+id/global_actions_lock_message"
+      style="@style/TextAppearance.Control.Title"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginHorizontal="@dimen/global_actions_side_margin"
+      android:drawablePadding="12dp"
+      android:gravity="center"
+      android:text="@string/global_action_lock_message"
+      app:layout_constraintBottom_toBottomOf="parent"
+      app:layout_constraintTop_toTopOf="parent"
+      app:layout_constraintVertical_bias="0.35"/>
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_power_dialog_flow.xml b/packages/SystemUI/res/layout/global_actions_power_dialog_flow.xml
index 478aa5b894a0..1d27e56a06cd 100644
--- a/packages/SystemUI/res/layout/global_actions_power_dialog_flow.xml
+++ b/packages/SystemUI/res/layout/global_actions_power_dialog_flow.xml
@@ -20,7 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center"
-    android:background="@drawable/global_actions_lite_background"
+    android:background="@android:color/transparent"
     android:padding="@dimen/global_actions_lite_padding"
     android:clipChildren="false"
     android:clipToPadding="false">
diff --git a/packages/SystemUI/res/values-sw392dp/dimens.xml b/packages/SystemUI/res/values-sw392dp/dimens.xml
index 96af3c13f32e..2d77cf6b6975 100644
--- a/packages/SystemUI/res/values-sw392dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw392dp/dimens.xml
@@ -20,8 +20,16 @@
     <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
 
     <dimen name="global_actions_grid_item_side_margin">10dp</dimen>
+    <dimen name="global_actions_grid_item_vertical_margin">6dp</dimen>
+    <dimen name="global_actions_grid_item_width">72dp</dimen>
     <dimen name="global_actions_grid_item_height">72dp</dimen>
 
+    <dimen name="global_actions_grid_item_icon_width">22dp</dimen>
+    <dimen name="global_actions_grid_item_icon_height">22dp</dimen>
+    <dimen name="global_actions_grid_item_icon_top_margin">14dp</dimen>
+    <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
+    <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
     <!-- Home Controls -->
     <dimen name="global_actions_side_margin">16dp</dimen>
 
diff --git a/packages/SystemUI/res/values-sw410dp/dimens.xml b/packages/SystemUI/res/values-sw410dp/dimens.xml
index ff6e005a94c7..f08e985a3077 100644
--- a/packages/SystemUI/res/values-sw410dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp/dimens.xml
@@ -25,8 +25,16 @@
     <dimen name="global_actions_grid_horizontal_padding">4dp</dimen>
 
     <dimen name="global_actions_grid_item_side_margin">12dp</dimen>
+    <dimen name="global_actions_grid_item_vertical_margin">8dp</dimen>
+    <dimen name="global_actions_grid_item_width">72dp</dimen>
     <dimen name="global_actions_grid_item_height">72dp</dimen>
 
+    <dimen name="global_actions_grid_item_icon_width">24dp</dimen>
+    <dimen name="global_actions_grid_item_icon_height">24dp</dimen>
+    <dimen name="global_actions_grid_item_icon_top_margin">18dp</dimen>
+    <dimen name="global_actions_grid_item_icon_side_margin">24dp</dimen>
+    <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
     <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
     <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 1f671ac4c875..9c804f451f98 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -32,6 +32,12 @@
     <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
     <integer name="navigation_bar_deadzone_orientation">0</integer>
 
+    <!-- Whether wallet view is shown in landscape / seascape orientations -->
+    <bool name="global_actions_show_landscape_wallet_view">true</bool>
+
+    <!-- Max number of columns for quick controls area -->
+    <integer name="controls_max_columns">4</integer>
+
     <!-- How many lines to show in the security footer -->
     <integer name="qs_security_footer_maxLines">1</integer>
 
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 1e54fc9e1445..9204278a851f 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -64,6 +64,9 @@
     <!-- Text size for user name in user switcher -->
     <dimen name="kg_user_switcher_text_size">18sp</dimen>
 
+    <!-- TODO(himanshujaju) - add comments -->
+    <dimen name="global_actions_wallet_top_margin">5dp</dimen>
+
     <dimen name="global_actions_grid_item_layout_height">80dp</dimen>
 
     <dimen name="qs_brightness_margin_bottom">16dp</dimen>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 774a3662fca6..436cc4e66c23 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -34,6 +34,17 @@
 
     <!-- The color of the background in the grid of the Global Actions menu -->
     <color name="global_actions_grid_background">#F1F3F4</color>
+    <color name="global_actions_extra_background">@*android:color/primary_device_default_dark</color>
+
+    <!-- The color of the text in the Global Actions menu -->
+    <color name="global_actions_text">@color/GM2_grey_700</color>
+
+    <!-- The color of the text in the Global Actions menu -->
+    <color name="global_actions_alert_text">@color/GM2_red_700</color>
+
+    <!-- The color of the background of the emergency button when home controls are visible -->
+    <color name="global_actions_emergency_background">@color/GM2_red_400</color>
+    <color name="global_actions_emergency_text">@color/GM2_grey_100</color>
 
     <!-- Colors for Power Menu Lite -->
     <color name="global_actions_lite_background">@*android:color/primary_device_default_light</color>
@@ -155,6 +166,7 @@
     <color name="GM2_grey_900">#202124</color>
 
     <color name="GM2_red_300">#F28B82</color>
+    <color name="GM2_red_400">#EE675C</color>
     <color name="GM2_red_500">#EA4335</color>
     <color name="GM2_red_600">#B3261E</color>
     <color name="GM2_red_700">#C5221F</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 550a4a2573c3..e4f4c2973d9e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -565,6 +565,9 @@
     <!-- Max number of columns for quick controls area -->
     <integer name="controls_max_columns">2</integer>
 
+    <!-- Max number of columns for power menu -->
+    <integer name="power_menu_max_columns">3</integer>
+
     <!-- Max number of columns for power menu lite -->
     <integer name="power_menu_lite_max_columns">2</integer>
     <!-- Max number of rows for power menu lite -->
@@ -593,6 +596,9 @@
     <!-- content URL in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false -->
     <string translatable="false" name="config_batteryStateUnknownUrl"></string>
 
+    <!-- Whether wallet view is shown in landscape / seascape orientations -->
+    <bool name="global_actions_show_landscape_wallet_view">false</bool>
+
     <!-- Package name of the preferred system app to perform eSOS action -->
     <string name="config_preferredEmergencySosPackage" translatable="false"></string>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a0f236c72143..1fc8b0c03117 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -992,14 +992,25 @@
 
     <dimen name="global_actions_grid_item_layout_height">98dp</dimen>
     <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
+    <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
+    <dimen name="global_actions_grid_item_width">64dp</dimen>
     <dimen name="global_actions_grid_item_height">64dp</dimen>
 
+    <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
+    <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
+    <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
+    <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
+    <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
     <!-- Margins at the left and right of the power menu and home controls widgets. -->
     <dimen name="global_actions_side_margin">10dp</dimen>
 
     <!-- Amount to shift the layout when exiting/entering for controls activities -->
     <dimen name="global_actions_controls_y_translation">20dp</dimen>
 
+    <!-- Shift quick access wallet down in Global Actions when Controls are unavailable -->
+    <dimen name="global_actions_wallet_top_margin">40dp</dimen>
+
     <!-- Shutdown and restart actions are larger in power options dialog -->
     <dimen name="global_actions_power_dialog_item_height">128dp</dimen>
     <dimen name="global_actions_power_dialog_item_width">128dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java
index a3065d3cca59..78b9054b813e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java
@@ -42,7 +42,8 @@ public class GlobalActionsColumnLayout extends GlobalActionsLayout {
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
 
-        post(() -> updateSnap());
+        // TODO re-add this when adding animation for it
+        // post(() -> updateSnap());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
new file mode 100644
index 000000000000..197e94be5cd9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 droid-ng
+ *
+ * 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.globalactions;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
+import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
+import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.app.IActivityManager;
+import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.dreams.IDreamManager;
+import android.telecom.TelecomManager;
+import android.transition.AutoTransition;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.app.animation.Interpolators;
+import com.android.internal.R;
+import com.android.systemui.animation.Expandable;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.view.RotationPolicy;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.ControlsServiceInfo;
+import com.android.systemui.controls.controller.ControlsController;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.management.ControlsAnimations;
+import com.android.systemui.controls.ui.ControlsUiController;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
+import com.android.systemui.plugins.GlobalActionsPanelPlugin;
+import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.ShadeController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.leak.RotationUtils;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+/**
+ * Helper to show the global actions dialog.  Each item is an {@link Action} that may show depending
+ * on whether the keyguard is showing, and whether the device is provisioned.
+ * This version includes wallet and controls.
+ */
+public class GlobalActionsDialog extends GlobalActionsDialogLite
+        implements DialogInterface.OnDismissListener,
+        DialogInterface.OnShowListener,
+        ConfigurationController.ConfigurationListener,
+        GlobalActionsPanelPlugin.Callbacks,
+        LifecycleOwner {
+
+    private static final String TAG = "GlobalActionsDialog";
+
+    public static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
+    public static final String PREFS_CONTROLS_FILE = "controls_prefs";
+    private static final int SEEDING_MAX = 2;
+
+    private final LockPatternUtils mLockPatternUtils;
+    private final KeyguardStateController mKeyguardStateController;
+    private final ActivityStarter mActivityStarter;
+    private final SysuiColorExtractor mSysuiColorExtractor;
+    private final IStatusBarService mCentralSurfacesService;
+    private final NotificationShadeWindowController mNotificationShadeWindowController;
+    private GlobalActionsPanelPlugin mWalletPlugin;
+    private Optional<ControlsUiController> mControlsUiControllerOptional;
+    private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>();
+    private ControlsComponent mControlsComponent;
+    private Optional<ControlsController> mControlsControllerOptional;
+    private UserContextProvider mUserContextProvider;
+    @VisibleForTesting
+    boolean mShowLockScreenCardsAndControls = false;
+
+    private final KeyguardStateController.Callback mKeyguardStateControllerListener =
+            new KeyguardStateController.Callback() {
+        @Override
+        public void onUnlockedChanged() {
+            if (mDialog != null) {
+                ActionsDialog dialog = (ActionsDialog) mDialog;
+                boolean unlocked = mKeyguardStateController.isUnlocked();
+                if (dialog.mWalletViewController != null) {
+                    dialog.mWalletViewController.onDeviceLockStateChanged(!unlocked);
+                }
+                if (!dialog.isShowingControls() && mControlsComponent.getVisibility() == AVAILABLE) {
+                    dialog.showControls(mControlsUiControllerOptional.get());
+                }
+                if (unlocked) {
+                    dialog.hideLockMessage();
+                }
+            }
+        }
+    };
+
+    private final ContentObserver mSettingsObserver = new ContentObserver(mMainHandler) {
+        @Override
+        public void onChange(boolean selfChange) {
+            onPowerMenuLockScreenSettingsChanged();
+        }
+    };
+
+    /**
+     * @param context everything needs a context :(
+     */
+    @Inject
+    public GlobalActionsDialog(
+            Context context,
+            GlobalActionsManager windowManagerFuncs,
+            AudioManager audioManager,
+            IDreamManager iDreamManager,
+            DevicePolicyManager devicePolicyManager,
+            LockPatternUtils lockPatternUtils,
+            BroadcastDispatcher broadcastDispatcher,
+            GlobalSettings globalSettings,
+            SecureSettings secureSettings,
+            @NonNull VibratorHelper vibrator,
+            @Main Resources resources,
+            ConfigurationController configurationController,
+            UserTracker userTracker,
+            ActivityStarter activityStarter,
+            KeyguardStateController keyguardStateController,
+            UserManager userManager,
+            TrustManager trustManager,
+            IActivityManager iActivityManager,
+            @Nullable TelecomManager telecomManager,
+            MetricsLogger metricsLogger,
+            SysuiColorExtractor colorExtractor,
+            IStatusBarService statusBarService,
+            NotificationShadeWindowController notificationShadeWindowController,
+            StatusBarWindowController statusBarOptional,
+            IWindowManager iWindowManager,
+            LightBarController lightBarController,
+            @Background Executor backgroundExecutor,
+            UiEventLogger uiEventLogger,
+            RingerModeTracker ringerModeTracker,
+            @Main Handler handler,
+            UserContextProvider userContextProvider,
+            PackageManager packageManager,
+            ShadeController shadeController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DialogLaunchAnimator dialogLaunchAnimator,
+            SelectedUserInteractor selectedUserInteractor,
+            ControlsComponent controlsComponent) {
+        super(context,
+                windowManagerFuncs,
+                audioManager,
+                iDreamManager,
+                devicePolicyManager,
+                lockPatternUtils,
+                broadcastDispatcher,
+                globalSettings,
+                secureSettings,
+                vibrator,
+                resources,
+                configurationController,
+                userTracker,
+                keyguardStateController,
+                userManager,
+                trustManager,
+                iActivityManager,
+                telecomManager,
+                metricsLogger,
+                colorExtractor,
+                statusBarService,
+                lightBarController,
+                notificationShadeWindowController,
+                statusBarOptional,
+                iWindowManager,
+                backgroundExecutor,
+                uiEventLogger,
+                ringerModeTracker,
+                handler,
+                packageManager,
+                shadeController,
+                keyguardUpdateMonitor,
+                dialogLaunchAnimator,
+                selectedUserInteractor,
+                controlsComponent);
+
+        mLockPatternUtils = lockPatternUtils;
+        mKeyguardStateController = keyguardStateController;
+        mSysuiColorExtractor = colorExtractor;
+        mCentralSurfacesService = statusBarService;
+        mNotificationShadeWindowController = notificationShadeWindowController;
+        mControlsComponent = controlsComponent;
+        mControlsUiControllerOptional = controlsComponent.getControlsUiController();
+        mControlsControllerOptional = controlsComponent.getControlsController();
+        mUserContextProvider = userContextProvider;
+        mActivityStarter = activityStarter;
+
+        mKeyguardStateController.addCallback(mKeyguardStateControllerListener);
+
+        if (mControlsComponent.getControlsListingController().isPresent()) {
+            mControlsComponent.getControlsListingController().get()
+                    .addCallback(list -> {
+                        mControlsServiceInfos = new ArrayList(list);
+                        // This callback may occur after the dialog has been shown. If so, add
+                        // controls into the already visible space or show the lock msg if needed.
+                        if (mDialog != null) {
+                            ActionsDialog dialog = (ActionsDialog) mDialog;
+                            if (!dialog.isShowingControls()
+                                    && mControlsComponent.getVisibility() == AVAILABLE) {
+                                dialog.showControls(mControlsUiControllerOptional.get());
+                            } else if (shouldShowLockMessage(dialog)) {
+                                dialog.showLockMessage();
+                            }
+                        }
+                    });
+        }
+
+        // Listen for changes to show controls on the power menu while locked
+        onPowerMenuLockScreenSettingsChanged();
+        mGlobalSettings.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT),
+                false /* notifyForDescendants */,
+                mSettingsObserver);
+    }
+
+    @Override
+    protected void onRefresh() {
+        super.onRefresh();
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        mKeyguardStateController.removeCallback(mKeyguardStateControllerListener);
+        mGlobalSettings.unregisterContentObserver(mSettingsObserver);
+    }
+
+    /**
+     * See if any available control service providers match one of the preferred components. If
+     * they do, and there are no current favorites for that component, query the preferred
+     * component for a limited number of suggested controls.
+     */
+    private void seedFavorites() {
+        if (!mControlsControllerOptional.isPresent()
+                || mControlsServiceInfos.isEmpty()) {
+            return;
+        }
+
+        String[] preferredControlsPackages = getContext().getResources()
+                .getStringArray(com.android.systemui.res.R.array.config_controlsPreferredPackages);
+
+        SharedPreferences prefs = mUserContextProvider.getUserContext()
+                .getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE);
+        Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
+                Collections.emptySet());
+
+        List<ComponentName> componentsToSeed = new ArrayList<>();
+        for (int i = 0; i < Math.min(SEEDING_MAX, preferredControlsPackages.length); i++) {
+            String pkg = preferredControlsPackages[i];
+            for (ControlsServiceInfo info : mControlsServiceInfos) {
+                if (!pkg.equals(info.componentName.getPackageName())) continue;
+                if (seededPackages.contains(pkg)) {
+                    break;
+                } else if (mControlsControllerOptional.get()
+                        .countFavoritesForComponent(info.componentName) > 0) {
+                    // When there are existing controls but no saved preference, assume it
+                    // is out of sync, perhaps through a device restore, and update the
+                    // preference
+                    addPackageToSeededSet(prefs, pkg);
+                    break;
+                }
+                componentsToSeed.add(info.componentName);
+                break;
+            }
+        }
+
+        if (componentsToSeed.isEmpty()) return;
+
+        mControlsControllerOptional.get().seedFavoritesForComponents(
+                componentsToSeed,
+                (response) -> {
+                    Log.d(TAG, "Controls seeded: " + response);
+                    if (response.getAccepted()) {
+                        addPackageToSeededSet(prefs, response.getPackageName());
+                    }
+                });
+    }
+
+    private void addPackageToSeededSet(SharedPreferences prefs, String pkg) {
+        Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
+                Collections.emptySet());
+        Set<String> updatedPkgs = new HashSet<>(seededPackages);
+        updatedPkgs.add(pkg);
+        prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, updatedPkgs).apply();
+    }
+
+    /**
+     * Show the global actions dialog (creating if necessary)
+     *
+     * @param keyguardShowing True if keyguard is showing
+     */
+    @Override
+    public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
+            @Nullable Expandable v, GlobalActionsPanelPlugin walletPlugin) {
+        mWalletPlugin = walletPlugin;
+        super.showOrHideDialog(keyguardShowing, isDeviceProvisioned, null);
+    }
+
+    @Override
+    protected void handleShow(@Nullable Expandable expandable) {
+        seedFavorites();
+        super.handleShow(null);
+    }
+
+    /**
+     * Returns the maximum number of power menu items to show based on which GlobalActions
+     * layout is being used.
+     */
+    @VisibleForTesting
+    @Override
+    protected int getMaxShownPowerItems() {
+        return getContext().getResources().getInteger(
+                com.android.systemui.res.R.integer.power_menu_max_columns);
+    }
+
+    /**
+     * Create the global actions dialog.
+     *
+     * @return A new dialog.
+     */
+    @Override
+    protected ActionsDialogLite createDialog() {
+        initDialogItems();
+
+        ControlsUiController uiController = null;
+        if (mControlsComponent.getVisibility() == AVAILABLE) {
+            uiController = mControlsUiControllerOptional.get();
+        }
+        ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
+        this::getWalletViewController, mSysuiColorExtractor,
+                mCentralSurfacesService, mLightBarController, mKeyguardStateController,
+                mNotificationShadeWindowController, mStatusBarWindowController,
+                controlsAvailable(), uiController, this::onRefresh, mKeyguardShowing,
+                mPowerAdapter, mRestartAdapter, mUsersAdapter, mUiEventLogger,
+                mShadeController, mKeyguardUpdateMonitor,
+                mLockPatternUtils, mSelectedUserInteractor);
+
+        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
+        dialog.setOnDismissListener(this);
+        dialog.setOnShowListener(this);
+
+        return dialog;
+    }
+
+    @Nullable
+    private GlobalActionsPanelPlugin.PanelViewController getWalletViewController() {
+        if (mWalletPlugin == null) {
+            return null;
+        }
+        return mWalletPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());
+    }
+
+    /**
+     * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
+     * called when the quick access wallet requests that an intent be started (with lock screen
+     * shown first if needed).
+     */
+    @Override
+    public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
+        mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
+    }
+
+    @Override
+    protected int getEmergencyTextColor(Context context, boolean dummy) {
+        return context.getResources().getColor(
+                com.android.systemui.res.R.color.global_actions_emergency_text);
+    }
+
+    @Override
+    protected int getEmergencyIconColor(Context context, boolean dummy) {
+        return getContext().getResources().getColor(
+                com.android.systemui.res.R.color.global_actions_emergency_text);
+    }
+
+    @Override
+    protected int getEmergencyBackgroundColor(Context context, boolean dummy) {
+        return getContext().getResources().getColor(
+                com.android.systemui.res.R.color.global_actions_emergency_background);
+    }
+
+    @Override
+    protected int getGridItemLayoutResource() {
+        return com.android.systemui.res.R.layout.global_actions_grid_item_v2;
+    }
+
+    @VisibleForTesting
+    class ActionsDialog extends ActionsDialogLite {
+
+        private final Provider<GlobalActionsPanelPlugin.PanelViewController> mWalletFactory;
+        @Nullable private GlobalActionsPanelPlugin.PanelViewController mWalletViewController;
+        private ResetOrientationData mResetOrientationData;
+        private final boolean mControlsAvailable;
+
+        private ControlsUiController mControlsUiController;
+        private ViewGroup mControlsView;
+        @VisibleForTesting ViewGroup mLockMessageContainer;
+        private TextView mLockMessage;
+
+        ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter,
+                Provider<GlobalActionsPanelPlugin.PanelViewController> walletFactory,
+                SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
+                LightBarController lightBarController,
+                KeyguardStateController keyguardStateController,
+                NotificationShadeWindowController notificationShadeWindowController,
+                StatusBarWindowController statusBarOptional, boolean controlsAvailable,
+                @Nullable ControlsUiController controlsUiController, Runnable onRotateCallback,
+                boolean keyguardShowing, MyPowerOptionsAdapter powerAdapter,
+                MyRestartOptionsAdapter restartAdapter, MyUsersAdapter usersAdapter,
+                UiEventLogger uiEventLogger, ShadeController shadeController,
+                KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
+                SelectedUserInteractor selectedUserInteractor) {
+            super(context, com.android.systemui.res.R.style.Theme_SystemUI_Dialog_GlobalActions,
+                    adapter, overflowAdapter, sysuiColorExtractor, statusBarService,
+                    lightBarController, keyguardStateController, notificationShadeWindowController,
+                    statusBarOptional, onRotateCallback, keyguardShowing, powerAdapter,
+                    restartAdapter, usersAdapter, uiEventLogger, shadeController,
+                    keyguardUpdateMonitor, lockPatternUtils, selectedUserInteractor);
+            mControlsAvailable = controlsAvailable;
+            mControlsUiController = controlsUiController;
+            mWalletFactory = walletFactory;
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            initializeLayout();
+            if (shouldShowLockMessage()) {
+                showLockMessage();
+            }
+        }
+
+        private boolean shouldShowLockMessage() {
+            return GlobalActionsDialog.this.shouldShowLockMessage(this);
+        }
+
+        private boolean isShowingControls() {
+            return mControlsUiController != null;
+        }
+
+        private void showControls(ControlsUiController controller) {
+            mControlsUiController = controller;
+            mControlsUiController.show(mControlsView, this::dismissForControlsActivity,
+                    null /* activityContext */);
+        }
+
+        private boolean isWalletViewAvailable() {
+            return mWalletViewController != null && mWalletViewController.getPanelContent() != null;
+        }
+
+        private void initializeWalletView() {
+            if (mWalletFactory == null) {
+                return;
+            }
+            mWalletViewController = mWalletFactory.get();
+            if (!isWalletViewAvailable()) {
+                return;
+            }
+
+            boolean isLandscapeWalletViewShown = mContext.getResources().getBoolean(
+                    com.android.systemui.res.R.bool.global_actions_show_landscape_wallet_view);
+
+            int rotation = RotationUtils.getRotation(mContext);
+            boolean rotationLocked = RotationPolicy.isRotationLocked(mContext);
+            if (rotation != RotationUtils.ROTATION_NONE) {
+                if (rotationLocked) {
+                    if (mResetOrientationData == null) {
+                        mResetOrientationData = new ResetOrientationData();
+                        mResetOrientationData.locked = true;
+                        mResetOrientationData.rotation = rotation;
+                    }
+
+                    // Unlock rotation, so user can choose to rotate to portrait to see the panel.
+                    // This call is posted so that the rotation does not change until post-layout,
+                    // otherwise onConfigurationChanged() may not get invoked.
+                    mGlobalActionsLayout.post(() ->
+                            RotationPolicy.setRotationLockAtAngle(
+                                    mContext, false, RotationUtils.ROTATION_NONE, TAG));
+
+                    if (!isLandscapeWalletViewShown) {
+                        return;
+                    }
+                }
+            } else {
+                if (!rotationLocked) {
+                    if (mResetOrientationData == null) {
+                        mResetOrientationData = new ResetOrientationData();
+                        mResetOrientationData.locked = false;
+                    }
+                }
+
+                boolean shouldLockRotation = !isLandscapeWalletViewShown;
+                if (rotationLocked != shouldLockRotation) {
+                    // Locks the screen to portrait if the landscape / seascape orientation does not
+                    // show the wallet view, so the user doesn't accidentally hide the panel.
+                    // This call is posted so that the rotation does not change until post-layout,
+                    // otherwise onConfigurationChanged() may not get invoked.
+                    mGlobalActionsLayout.post(() ->
+                            RotationPolicy.setRotationLockAtAngle(
+                            mContext, shouldLockRotation, RotationUtils.ROTATION_NONE, TAG));
+                }
+            }
+
+            // Disable rotation suggestions, if enabled
+            setRotationSuggestionsEnabled(false);
+
+            FrameLayout panelContainer =
+                    findViewById(com.android.systemui.res.R.id.global_actions_wallet);
+            FrameLayout.LayoutParams panelParams =
+                    new FrameLayout.LayoutParams(
+                            FrameLayout.LayoutParams.MATCH_PARENT,
+                            FrameLayout.LayoutParams.MATCH_PARENT);
+            if (!mControlsAvailable) {
+                panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
+                        com.android.systemui.res.R.dimen.global_actions_wallet_top_margin);
+            }
+            View walletView = mWalletViewController.getPanelContent();
+            panelContainer.addView(walletView, panelParams);
+            // Smooth transitions when wallet is resized, which can happen when a card is added
+            ViewGroup root = findViewById(com.android.systemui.res.R.id.global_actions_grid_root);
+            if (root != null) {
+                walletView.addOnLayoutChangeListener((v, l, t, r, b, ol, ot, or, ob) -> {
+                    int oldHeight = ob - ot;
+                    int newHeight = b - t;
+                    if (oldHeight > 0 && oldHeight != newHeight) {
+                        TransitionSet transition = new AutoTransition()
+                                .setDuration(250)
+                                .setOrdering(TransitionSet.ORDERING_TOGETHER);
+                        TransitionManager.beginDelayedTransition(root, transition);
+                    }
+                });
+            }
+        }
+
+        @Override
+        protected int getLayoutResource() {
+            return com.android.systemui.res.R.layout.global_actions_grid_v2;
+        }
+
+        @Override
+        protected void initializeLayout() {
+            super.initializeLayout();
+            mControlsView = findViewById(com.android.systemui.res.R.id.global_actions_controls);
+            mLockMessageContainer = requireViewById(
+                    com.android.systemui.res.R.id.global_actions_lock_message_container);
+            mLockMessage =
+                    requireViewById(com.android.systemui.res.R.id.global_actions_lock_message);
+            initializeWalletView();
+            getWindow().setBackgroundDrawable(mBackgroundDrawable);
+        }
+
+        @Override
+        public void show() {
+            super.show();
+            if (mControlsUiController != null) {
+                mControlsUiController.show(mControlsView, this::dismissForControlsActivity,
+                        null /* activityContext */);
+            }
+
+            mBackgroundDrawable.setAlpha(0);
+            float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
+            ObjectAnimator alphaAnimator =
+                    ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f);
+            alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+            alphaAnimator.setDuration(183);
+            alphaAnimator.addUpdateListener((animation) -> {
+                float animatedValue = animation.getAnimatedFraction();
+                int alpha = (int) (animatedValue * mScrimAlpha * 255);
+                mBackgroundDrawable.setAlpha(alpha);
+            });
+
+            ObjectAnimator xAnimator =
+                    ObjectAnimator.ofFloat(mContainer, "translationX", xOffset, 0f);
+            xAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+            xAnimator.setDuration(350);
+
+            AnimatorSet animatorSet = new AnimatorSet();
+            animatorSet.playTogether(alphaAnimator, xAnimator);
+            animatorSet.start();
+        }
+
+        @Override
+        public void dismiss() {
+            dismissWallet();
+            if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
+            if (mControlsUiController != null) mControlsUiController.hide(mControlsView);
+            mContainer.setTranslationX(0);
+            ObjectAnimator alphaAnimator =
+                    ObjectAnimator.ofFloat(mContainer, "alpha", 1f, 0f);
+            alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+            alphaAnimator.setDuration(233);
+            alphaAnimator.addUpdateListener((animation) -> {
+                float animatedValue = 1f - animation.getAnimatedFraction();
+                int alpha = (int) (animatedValue * mScrimAlpha * 255);
+                mBackgroundDrawable.setAlpha(alpha);
+            });
+
+            float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
+            ObjectAnimator xAnimator =
+                    ObjectAnimator.ofFloat(mContainer, "translationX", 0f, xOffset);
+            xAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+            xAnimator.setDuration(350);
+
+            AnimatorSet animatorSet = new AnimatorSet();
+            animatorSet.playTogether(alphaAnimator, xAnimator);
+            animatorSet.addListener(new AnimatorListenerAdapter() {
+                public void onAnimationEnd(Animator animation) {
+                    completeDismiss();
+                }
+            });
+
+            animatorSet.start();
+        }
+
+        void completeDismiss() {
+            resetOrientation();
+            super.dismiss();
+        }
+
+        private void dismissForControlsActivity() {
+            dismissWallet();
+            if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
+            if (mControlsUiController != null) mControlsUiController.hide(mControlsView);
+            ViewGroup root = (ViewGroup) mGlobalActionsLayout.getParent();
+            ControlsAnimations.exitAnimation(root, this::completeDismiss).start();
+        }
+
+        private void dismissWallet() {
+            if (mWalletViewController != null) {
+                mWalletViewController.onDismissed();
+                // The wallet controller should not be re-used after being dismissed.
+                mWalletViewController = null;
+            }
+        }
+
+        private void resetOrientation() {
+            if (mResetOrientationData != null) {
+                RotationPolicy.setRotationLockAtAngle(mContext, mResetOrientationData.locked,
+                        mResetOrientationData.rotation, TAG);
+            }
+            setRotationSuggestionsEnabled(true);
+        }
+
+        @Override
+        public void refreshDialog() {
+            // ensure dropdown menus are dismissed before re-initializing the dialog
+            dismissWallet();
+            if (mControlsUiController != null) {
+                mControlsUiController.hide(mControlsView);
+            }
+
+            super.refreshDialog();
+            if (mControlsUiController != null) {
+                mControlsUiController.show(mControlsView, this::dismissForControlsActivity,
+                        null /* activityContext */);
+            }
+        }
+
+        void hideLockMessage() {
+            if (mLockMessageContainer.getVisibility() == View.VISIBLE) {
+                mLockMessageContainer.animate().alpha(0).setDuration(150).setListener(
+                        new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                mLockMessageContainer.setVisibility(View.GONE);
+                            }
+                        }).start();
+            }
+        }
+
+        void showLockMessage() {
+            Drawable lockIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_lock);
+            lockIcon.setTint(mContext.getColor(com.android.systemui.R.color.control_primary_text));
+            mLockMessage.setCompoundDrawablesWithIntrinsicBounds(null, lockIcon, null, null);
+            mLockMessageContainer.setVisibility(View.VISIBLE);
+        }
+
+        private class ResetOrientationData {
+            public boolean locked;
+            public int rotation;
+        }
+    }
+
+    /**
+     * Determines whether or not debug mode has been activated for the Global Actions Panel.
+     */
+    private static boolean isPanelDebugModeEnabled(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED, 0) == 1;
+    }
+
+    /**
+     * Determines whether or not the Global Actions menu should be forced to use the newer
+     * grid-style layout.
+     */
+    private static boolean isForceGridEnabled(Context context) {
+        return isPanelDebugModeEnabled(context);
+    }
+
+    private boolean controlsAvailable() {
+        return isDeviceProvisioned()
+                && mControlsComponent.isEnabled()
+                && !mControlsServiceInfos.isEmpty();
+    }
+
+    private boolean shouldShowLockMessage(ActionsDialog dialog) {
+        return mControlsComponent.getVisibility() == AVAILABLE_AFTER_UNLOCK
+                || isWalletAvailableAfterUnlock(dialog);
+    }
+
+    // Temporary while we move items out of the power menu
+    private boolean isWalletAvailableAfterUnlock(ActionsDialog dialog) {
+        boolean isLockedAfterBoot = mLockPatternUtils.getStrongAuthForUser(getCurrentUser().id)
+                == STRONG_AUTH_REQUIRED_AFTER_BOOT;
+        return !mKeyguardStateController.isUnlocked()
+                && (!mShowLockScreenCardsAndControls || isLockedAfterBoot)
+                && dialog.isWalletViewAvailable();
+    }
+
+    private void onPowerMenuLockScreenSettingsChanged() {
+        mShowLockScreenCardsAndControls = mSecureSettings.getInt(
+                Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0) != 0;
+    }
+
+    @Override
+    protected boolean shouldForceDark() {
+        return true;
+    }
+
+    @Override
+    protected boolean shouldUseControlsLayout() {
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index d70815f0b88b..dc083d97ec47 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -61,6 +61,7 @@ import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.RectF;
@@ -96,6 +97,8 @@ import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -158,6 +161,7 @@ import com.android.systemui.statusbar.window.StatusBarWindowController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 import com.android.systemui.util.EmergencyDialerConstants;
 import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.leak.RotationUtils;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -213,7 +217,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     private final IDreamManager mDreamManager;
     private final DevicePolicyManager mDevicePolicyManager;
     private final LockPatternUtils mLockPatternUtils;
-    private final SelectedUserInteractor mSelectedUserInteractor;
+    protected final SelectedUserInteractor mSelectedUserInteractor;
     private final KeyguardStateController mKeyguardStateController;
     private final BroadcastDispatcher mBroadcastDispatcher;
     protected final GlobalSettings mGlobalSettings;
@@ -226,7 +230,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     private final IActivityManager mIActivityManager;
     private final TelecomManager mTelecomManager;
     private final MetricsLogger mMetricsLogger;
-    private final UiEventLogger mUiEventLogger;
+    protected final UiEventLogger mUiEventLogger;
     private final LineageGlobalActions mLineageGlobalActions;
 
     // Used for RingerModeTracker
@@ -258,7 +262,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     // Power menu customizations
     private String[] mActions;
 
-    private boolean mKeyguardShowing = false;
+    protected boolean mKeyguardShowing = false;
     private boolean mDeviceProvisioned = false;
     private ToggleState mAirplaneState = ToggleState.Off;
     private boolean mIsWaitingForEcmExit = false;
@@ -271,7 +275,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     private final IStatusBarService mStatusBarService;
     protected final LightBarController mLightBarController;
     protected final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final StatusBarWindowController mStatusBarWindowController;
+    protected final StatusBarWindowController mStatusBarWindowController;
     private final IWindowManager mIWindowManager;
     private final Executor mBackgroundExecutor;
     private final RingerModeTracker mRingerModeTracker;
@@ -279,8 +283,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     protected Handler mMainHandler;
     private int mSmallestScreenWidthDp;
     private int mOrientation;
-    private final ShadeController mShadeController;
-    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    protected final ShadeController mShadeController;
+    protected final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
     private final ControlsComponent mControlsComponent;
 
@@ -481,7 +485,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
         mConfigurationController.removeCallback(this);
     }
 
-    protected Context getContext() {
+    public Context getContext() {
         return mContext;
     }
 
@@ -493,6 +497,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
         return mKeyguardUpdateMonitor;
     }
 
+    public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
+            @Nullable Expandable v, GlobalActionsPanelPlugin walletPlugin) {
+        showOrHideDialog(keyguardShowing, isDeviceProvisioned, v);
+    }
+
     /**
      * Show the global actions dialog (creating if necessary) or hide it if it's already showing.
      *
@@ -514,7 +523,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
             mDialog.dismiss();
             mDialog = null;
         } else {
-            handleShow(expandable);
+            handleShow(shouldUseControlsLayout() ? expandable : null);
         }
     }
 
@@ -949,6 +958,34 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
         }
     }
 
+    protected int getEmergencyTextColor(Context context, boolean alternate) {
+        if (alternate) {
+            return context.getResources().getColor(
+                        com.android.systemui.res.R.color.global_actions_alert_text);
+        }
+        return context.getResources().getColor(
+                com.android.systemui.res.R.color.global_actions_lite_text);
+    }
+
+    protected int getEmergencyIconColor(Context context, boolean alternate) {
+        if (alternate) {
+            return context.getResources().getColor(
+                        com.android.systemui.res.R.color.global_actions_alert_text);
+        }
+        return context.getResources().getColor(
+                 com.android.systemui.res.R.color.global_actions_lite_emergency_icon);
+    }
+
+    protected int getEmergencyBackgroundColor(Context context, boolean alternate) {
+        if (alternate) {
+            return context.getResources().getColor(
+                        com.android.systemui.res.R.color.global_actions_emergency_background);
+        }
+        return context.getResources().getColor(
+                com.android.systemui.res.R.color.global_actions_lite_emergency_background);
+    }
+
+
     @VisibleForTesting
     protected abstract class EmergencyAction extends SinglePressAction {
         EmergencyAction(int iconResId, int messageResId) {
@@ -957,7 +994,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
 
         @Override
         public boolean shouldBeSeparated() {
-            return false;
+            return !useGridLayout() && !shouldUseControlsLayout();
         }
 
         @Override
@@ -994,18 +1031,18 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     }
 
     protected int getEmergencyTextColor(Context context) {
-        return context.getResources().getColor(
-                com.android.systemui.res.R.color.global_actions_lite_text);
+        return GlobalActionsDialogLite.this.getEmergencyTextColor(
+                context, !shouldUseControlsLayout());
     }
 
     protected int getEmergencyIconColor(Context context) {
-        return context.getResources().getColor(
-                com.android.systemui.res.R.color.global_actions_lite_emergency_icon);
+        return GlobalActionsDialogLite.this.getEmergencyIconColor(
+                context, !shouldUseControlsLayout());
     }
 
     protected int getEmergencyBackgroundColor(Context context) {
-        return context.getResources().getColor(
-                com.android.systemui.res.R.color.global_actions_lite_emergency_background);
+        return GlobalActionsDialogLite.this.getEmergencyBackgroundColor(
+                context, !shouldUseControlsLayout());
     }
 
     private class EmergencyAffordanceAction extends EmergencyAction {
@@ -1805,8 +1842,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
                 Log.w(TAG, "No power options action found at position: " + position);
                 return null;
             }
-            int viewLayoutResource =
-                    com.android.systemui.res.R.layout.global_actions_grid_item_lite;
+            int viewLayoutResource = getGridItemLayoutResource();
             View view = convertView != null ? convertView
                     : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false);
             view.setOnClickListener(v -> onClickItem(position));
@@ -2178,6 +2214,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     }
 
     protected int getGridItemLayoutResource() {
+        if (!shouldUseControlsLayout()) {
+            return com.android.systemui.res.R.layout.global_actions_grid_item;
+        }
         return com.android.systemui.res.R.layout.global_actions_grid_item_lite;
     }
 
@@ -2635,7 +2674,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
     }
 
     @VisibleForTesting
-    static class ActionsDialogLite extends SystemUIDialog implements DialogInterface,
+    class ActionsDialogLite extends SystemUIDialog implements DialogInterface,
             ColorExtractor.OnColorsChangedListener {
 
         protected final Context mContext;
@@ -2696,7 +2735,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
                     @Override
                     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                             float distanceY) {
-                        if (distanceY < 0 && distanceY > distanceX
+                        if (e1 != null && distanceY < 0 && distanceY > distanceX
                                 && e1.getY() <= mStatusBarWindowController.getStatusBarHeight()) {
                             // Downwards scroll from top
                             openShadeAndDismiss();
@@ -2775,8 +2814,22 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
             mBlurUtils = new BlurUtils(mContext.getResources(),
                     CrossWindowBlurListeners.getInstance(), new DumpManager());
 
+            // Window initialization
+            Window window = getWindow();
+            window.requestFeature(Window.FEATURE_NO_TITLE);
+            // Inflate the decor view, so the attributes below are not overwritten by the theme.
+            window.getDecorView();
+            window.setLayout(MATCH_PARENT, MATCH_PARENT);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            window.addFlags(
+                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                            | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+            window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+            window.getAttributes().setFitInsetsTypes(0 /* types */);
             if (mBlurUtils.supportsBlursOnWindows()) {
-                Window window = getWindow();
                 // Enable blur behind
                 // Enable dim behind since we are setting some amount dim for the blur.
                 window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND
@@ -2858,13 +2911,14 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
         }
 
         public void showPowerOptionsMenu() {
-            mPowerOptionsDialog = GlobalActionsPowerDialog.create(mContext, mPowerOptionsAdapter);
+            mPowerOptionsDialog = GlobalActionsPowerDialog.create(
+                    mContext, mPowerOptionsAdapter, shouldForceDark());
             mPowerOptionsDialog.show();
         }
 
         public void showRestartOptionsMenu() {
             mRestartOptionsDialog = GlobalActionsPowerDialog.create(mContext,
-                    mRestartOptionsAdapter);
+                    mRestartOptionsAdapter, shouldForceDark());
             mRestartOptionsDialog.show();
         }
 
@@ -2874,11 +2928,28 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
         }
 
         public void showUsersMenu() {
-            mUsersDialog = GlobalActionsPowerDialog.create(mContext, mUsersAdapter);
+            mUsersDialog = GlobalActionsPowerDialog.create(
+                    mContext, mUsersAdapter, shouldForceDark());
             mUsersDialog.show();
         }
 
         protected int getLayoutResource() {
+            if (!shouldUseControlsLayout()) {
+                int rotation = RotationUtils.getRotation(mContext);
+                if (rotation == RotationUtils.ROTATION_SEASCAPE) {
+                    if (useGridLayout()) {
+                        return com.android.systemui.res.R.layout.global_actions_grid_seascape;
+                    } else {
+                        return com.android.systemui.res.R.layout.global_actions_column_seascape;
+                    }
+                } else {
+                    if (useGridLayout()) {
+                        return com.android.systemui.res.R.layout.global_actions_grid;
+                    } else {
+                        return com.android.systemui.res.R.layout.global_actions_column;
+                    }
+                }
+            }
             return com.android.systemui.res.R.layout.global_actions_grid_lite;
         }
 
@@ -2898,7 +2969,19 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
             });
             mGlobalActionsLayout.setRotationListener(this::onRotate);
             mGlobalActionsLayout.setAdapter(mAdapter);
+            ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView();
+            root.setOnApplyWindowInsetsListener((v, windowInsets) -> {
+                Insets i = windowInsets.getInsetsIgnoringVisibility(
+                        WindowInsets.Type.navigationBars() | WindowInsets.Type.systemGestures()
+                        | WindowInsets.Type.displayCutout());
+                root.setPadding(i.left, i.top, i.right, i.bottom);
+                return WindowInsets.CONSUMED;
+            });
             mContainer = findViewById(com.android.systemui.res.R.id.global_actions_container);
+            // Some legacy dialog layouts don't have the outer container
+            if (mContainer == null) {
+                mContainer = mGlobalActionsLayout;
+            }
             mContainer.setOnTouchListener((v, event) -> {
                 mGestureDetector.onTouchEvent(event);
                 return v.onTouchEvent(event);
@@ -2925,12 +3008,14 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
 
             if (mBackgroundDrawable == null) {
                 mBackgroundDrawable = new ScrimDrawable();
-                mScrimAlpha = 1.0f;
             }
 
             // Set dim only when blur is enabled.
             if (mBlurUtils.supportsBlursOnWindows()) {
                 getWindow().setDimAmount(0.54f);
+                mScrimAlpha = 0.0f;
+            } else {
+                mScrimAlpha = 1.0f;
             }
 
             // If user entered from the lock screen and smart lock was enabled, disable it
@@ -3008,12 +3093,17 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
                 return;
             }
             ((ScrimDrawable) mBackgroundDrawable).setColor(Color.BLACK, animate);
-            View decorView = getWindow().getDecorView();
+            WindowInsetsController insetController = getWindow().getInsetsController();
             if (colors.supportsDarkText()) {
-                decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
-                        | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+                insetController.setSystemBarsAppearance(
+                        WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
+                        | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
+                        WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
+                        | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
             } else {
-                decorView.setSystemUiVisibility(0);
+                insetController.setSystemBarsAppearance(0,
+                        WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
+                        | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
             }
         }
 
@@ -3213,4 +3303,18 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
             refreshDialog();
         }
     }
+
+    protected boolean shouldForceDark() {
+        return false;
+    }
+
+    protected boolean shouldUseControlsLayout() {
+        return Settings.Secure.getInt(
+                mContext.getContentResolver(), LMOSettings.Secure.POWER_MENU_TYPE, 0) == 0;
+    }
+
+    protected boolean useGridLayout() {
+        return Settings.Secure.getInt(
+                mContext.getContentResolver(), LMOSettings.Secure.POWER_MENU_TYPE, 0) == 3;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index e565ee115b25..81052cbd85a7 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -17,13 +17,18 @@ package com.android.systemui.globalactions;
 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
 
 import android.content.Context;
+import android.provider.Settings;
 
 import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import com.libremobileos.providers.LMOSettings;
+
 import javax.inject.Inject;
 
 public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
@@ -31,39 +36,56 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
     private final Context mContext;
     private final KeyguardStateController mKeyguardStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
+    private final ExtensionController.Extension<GlobalActionsPanelPlugin> mWalletPluginProvider;
     private final BlurUtils mBlurUtils;
     private final CommandQueue mCommandQueue;
-    private final GlobalActionsDialogLite mGlobalActionsDialog;
+    private final GlobalActionsDialog mGlobalActionsDialog;
+    private final GlobalActionsDialogLite mGlobalActionsDialogLite;
     private boolean mDisabled;
     private ShutdownUi mShutdownUi;
+    private boolean fullDialog = true;
 
     @Inject
     public GlobalActionsImpl(Context context, CommandQueue commandQueue,
-            GlobalActionsDialogLite globalActionsDialog, BlurUtils blurUtils,
+            GlobalActionsDialogLite globalActionsDialogLite,
+            GlobalActionsDialog globalActionsDialog,
+            BlurUtils blurUtils,
             KeyguardStateController keyguardStateController,
             DeviceProvisionedController deviceProvisionedController,
-            ShutdownUi shutdownUi) {
+            ShutdownUi shutdownUi,
+            ExtensionController extensionController) {
         mContext = context;
         mGlobalActionsDialog = globalActionsDialog;
+        mGlobalActionsDialogLite = globalActionsDialogLite;
         mKeyguardStateController = keyguardStateController;
         mDeviceProvisionedController = deviceProvisionedController;
         mCommandQueue = commandQueue;
         mBlurUtils = blurUtils;
         mCommandQueue.addCallback(this);
         mShutdownUi = shutdownUi;
+        mWalletPluginProvider = extensionController
+                .newExtension(GlobalActionsPanelPlugin.class)
+                .withPlugin(GlobalActionsPanelPlugin.class)
+                .build();
     }
 
     @Override
     public void destroy() {
         mCommandQueue.removeCallback(this);
         mGlobalActionsDialog.destroy();
+        mGlobalActionsDialogLite.destroy();
     }
 
     @Override
     public void showGlobalActions(GlobalActionsManager manager) {
         if (mDisabled) return;
-        mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(),
-                mDeviceProvisionedController.isDeviceProvisioned(), null /* view */);
+        fullDialog = Settings.Secure.getInt(
+                mContext.getContentResolver(), LMOSettings.Secure.POWER_MENU_TYPE, 0) == 1;
+        GlobalActionsDialogLite globalActionsDialog =
+                fullDialog ? mGlobalActionsDialog : mGlobalActionsDialogLite;
+        globalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(),
+                mDeviceProvisionedController.isDeviceProvisioned(),
+                null /* view */, mWalletPluginProvider.get());
     }
 
     @Override
@@ -78,6 +100,7 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
         mDisabled = disabled;
         if (disabled) {
             mGlobalActionsDialog.dismissDialog();
+            mGlobalActionsDialogLite.dismissDialog();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPowerDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPowerDialog.java
index 3fc3476aa428..c9a662941573 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPowerDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPowerDialog.java
@@ -40,7 +40,7 @@ public class GlobalActionsPowerDialog {
     /**
      * Create a dialog for displaying Shut Down and Restart actions.
      */
-    public static Dialog create(@NonNull Context context, ListAdapter adapter) {
+    public static Dialog create(@NonNull Context context, ListAdapter adapter, boolean forceDark) {
         ViewGroup listView = (ViewGroup) LayoutInflater.from(context).inflate(
                 com.android.systemui.res.R.layout.global_actions_power_dialog_flow, null);
 
@@ -78,7 +78,8 @@ public class GlobalActionsPowerDialog {
         window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
         window.setTitle(""); // prevent Talkback from speaking first item name twice
         window.setBackgroundDrawable(res.getDrawable(
-                com.android.systemui.res.R.drawable.global_actions_lite_background,
+                forceDark ? com.android.systemui.res.R.drawable.global_actions_background
+                        : com.android.systemui.res.R.drawable.global_actions_lite_background,
                 context.getTheme()));
         window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         if (blurUtils.supportsBlursOnWindows()) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
new file mode 100644
index 000000000000..622fa658f1b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.globalactions;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * When measured, this view sets the minimum height of its first child to be equal to its own
+ * target height.
+ *
+ * This ensures fall-through click handlers can be placed on this view's child component.
+ */
+public class MinHeightScrollView extends ScrollView {
+    public MinHeightScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        View firstChild = getChildAt(0);
+        if (firstChild != null) {
+            firstChild.setMinimumHeight(MeasureSpec.getSize(heightMeasureSpec));
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
index 8e307408ba86..6e2470c3b4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
@@ -43,6 +43,7 @@ import com.android.systemui.security.data.repository.SecurityRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.user.data.repository.UserSwitcherRepository
 import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
+import com.libremobileos.providers.LMOSettings
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
@@ -153,11 +154,15 @@ constructor(
         expandable: Expandable,
     ) {
         uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
-        globalActionsDialogLite.showOrHideDialog(
-            /* keyguardShowing= */ false,
-            /* isDeviceProvisioned= */ true,
-            expandable,
-        )
+        if (Settings.Secure.getInt(globalActionsDialogLite.context.getContentResolver(),
+                LMOSettings.Secure.POWER_MENU_TYPE, 0) == 0)
+            globalActionsDialogLite.showOrHideDialog(
+                /* keyguardShowing= */ false,
+                /* isDeviceProvisioned= */ true,
+                expandable,
+            )
+        else
+            globalActionsDialogLite.context.sendBroadcast(Intent("android.intent.action.POWER_MENU"))
     }
 
     override fun showSettings(expandable: Expandable) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
new file mode 100644
index 000000000000..d3bb2e56db1a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2020 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.globalactions;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.service.dreams.IDreamManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.IWindowManager;
+import android.view.View;
+import android.view.WindowManagerPolicyConstants;
+import android.widget.FrameLayout;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.controls.controller.ControlsController;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.management.ControlsListingController;
+import com.android.systemui.controls.ui.ControlsUiController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.GlobalActionsPanelPlugin;
+import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.telephony.TelephonyListenerManager;
+import com.android.systemui.util.RingerModeLiveData;
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.Executor;
+import java.util.regex.Pattern;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class GlobalActionsDialogTest extends SysuiTestCase {
+    private static final long UI_TIMEOUT_MILLIS = 5000; // 5 sec
+    private static final Pattern CANCEL_BUTTON =
+            Pattern.compile("cancel", Pattern.CASE_INSENSITIVE);
+
+    private GlobalActionsDialog mGlobalActionsDialog;
+
+    @Mock private GlobalActions.GlobalActionsManager mWindowManagerFuncs;
+    @Mock private AudioManager mAudioManager;
+    @Mock private IDreamManager mDreamManager;
+    @Mock private DevicePolicyManager mDevicePolicyManager;
+    @Mock private LockPatternUtils mLockPatternUtils;
+    @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private TelephonyListenerManager mTelephonyListenerManager;
+    @Mock private GlobalSettings mGlobalSettings;
+    @Mock private Resources mResources;
+    @Mock private ConfigurationController mConfigurationController;
+    @Mock private ActivityStarter mActivityStarter;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private UserManager mUserManager;
+    @Mock private TrustManager mTrustManager;
+    @Mock private IActivityManager mActivityManager;
+    @Mock private MetricsLogger mMetricsLogger;
+    @Mock private SysuiColorExtractor mColorExtractor;
+    @Mock private IStatusBarService mStatusBarService;
+    @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+    @Mock private ControlsUiController mControlsUiController;
+    @Mock private IWindowManager mWindowManager;
+    @Mock private Executor mBackgroundExecutor;
+    @Mock private ControlsListingController mControlsListingController;
+    @Mock private ControlsController mControlsController;
+    @Mock private UiEventLogger mUiEventLogger;
+    @Mock private RingerModeTracker mRingerModeTracker;
+    @Mock private RingerModeLiveData mRingerModeLiveData;
+    @Mock private SysUiState mSysUiState;
+    @Mock GlobalActionsPanelPlugin mWalletPlugin;
+    @Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
+    @Mock private Handler mHandler;
+    @Mock private UserContextProvider mUserContextProvider;
+    @Mock private UserTracker mUserTracker;
+    @Mock private PackageManager mPackageManager;
+    @Mock private SecureSettings mSecureSettings;
+    @Mock private StatusBar mStatusBar;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private ControlsComponent mControlsComponent;
+
+    private TestableLooper mTestableLooper;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mTestableLooper = TestableLooper.get(this);
+        allowTestableLooperAsMainThread();
+
+        when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
+        when(mResources.getConfiguration()).thenReturn(
+                getContext().getResources().getConfiguration());
+        when(mUserContextProvider.getUserContext()).thenReturn(mContext);
+        mControlsComponent = new ControlsComponent(
+                true,
+                mContext,
+                () -> mControlsController,
+                () -> mControlsUiController,
+                () -> mControlsListingController,
+                mLockPatternUtils,
+                mKeyguardStateController,
+                mUserTracker,
+                mSecureSettings
+        );
+
+        mGlobalActionsDialog = new GlobalActionsDialog(mContext,
+                mWindowManagerFuncs,
+                mAudioManager,
+                mDreamManager,
+                mDevicePolicyManager,
+                mLockPatternUtils,
+                mBroadcastDispatcher,
+                mTelephonyListenerManager,
+                mGlobalSettings,
+                mSecureSettings,
+                null,
+                mResources,
+                mConfigurationController,
+                mActivityStarter,
+                mKeyguardStateController,
+                mUserManager,
+                mTrustManager,
+                mActivityManager,
+                null,
+                mMetricsLogger,
+                mColorExtractor,
+                mStatusBarService,
+                mNotificationShadeWindowController,
+                mWindowManager,
+                mBackgroundExecutor,
+                mUiEventLogger,
+                mRingerModeTracker,
+                mSysUiState,
+                mHandler,
+                mControlsComponent,
+                mUserContextProvider
+                mPackageManager,
+                Optional.of(mStatusBar),
+                mKeyguardUpdateMonitor
+        );
+        mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
+
+        ColorExtractor.GradientColors backdropColors = new ColorExtractor.GradientColors();
+        backdropColors.setMainColor(Color.BLACK);
+        when(mColorExtractor.getNeutralColors()).thenReturn(backdropColors);
+        when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
+    }
+
+    @Test
+    public void testShouldLogShow() {
+        mGlobalActionsDialog.onShow(null);
+        mTestableLooper.processAllMessages();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN);
+    }
+
+    @Test
+    public void testShouldLogDismiss() {
+        mGlobalActionsDialog.onDismiss(mGlobalActionsDialog.mDialog);
+        mTestableLooper.processAllMessages();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_CLOSE);
+    }
+
+    @Test
+    public void testShouldLogBugreportPress() throws InterruptedException {
+        GlobalActionsDialog.BugReportAction bugReportAction =
+                mGlobalActionsDialog.makeBugReportActionForTesting();
+        bugReportAction.onPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS);
+    }
+
+    @Test
+    public void testShouldLogBugreportLongPress() {
+        GlobalActionsDialog.BugReportAction bugReportAction =
+                mGlobalActionsDialog.makeBugReportActionForTesting();
+        bugReportAction.onLongPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
+    }
+
+    @Test
+    public void testShouldLogEmergencyDialerPress() {
+        GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction =
+                mGlobalActionsDialog.makeEmergencyDialerActionForTesting();
+        emergencyDialerAction.onPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
+    }
+
+    @Test
+    public void testShouldLogScreenshotPress() {
+        GlobalActionsDialog.ScreenshotAction screenshotAction =
+                mGlobalActionsDialog.makeScreenshotActionForTesting();
+        screenshotAction.onPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS);
+    }
+
+    @Test
+    public void testShouldShowScreenshot() {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.integer.config_navBarInteractionMode,
+                WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON);
+
+        GlobalActionsDialog.ScreenshotAction screenshotAction =
+                mGlobalActionsDialog.makeScreenshotActionForTesting();
+        assertThat(screenshotAction.shouldShow()).isTrue();
+    }
+
+    @Test
+    public void testShouldNotShowScreenshot() {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.integer.config_navBarInteractionMode,
+                WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON);
+
+        GlobalActionsDialog.ScreenshotAction screenshotAction =
+                mGlobalActionsDialog.makeScreenshotActionForTesting();
+        assertThat(screenshotAction.shouldShow()).isFalse();
+    }
+
+    private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) {
+        mTestableLooper.processAllMessages();
+        verify(mUiEventLogger, times(1))
+                .log(event);
+    }
+
+    @SafeVarargs
+    private static <T> void assertItemsOfType(List<T> stuff, Class<? extends T>... classes) {
+        assertThat(stuff).hasSize(classes.length);
+        for (int i = 0; i < stuff.size(); i++) {
+            assertThat(stuff.get(i)).isInstanceOf(classes[i]);
+        }
+    }
+
+    @Test
+    public void testCreateActionItems_maxThree_noOverflow() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow 3 items to be shown
+        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // ensure items are not blocked by keyguard or device provisioning
+        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class);
+        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
+        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
+    }
+
+    @Test
+    public void testCreateActionItems_maxThree_condensePower() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow 3 items to be shown
+        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // ensure items are not blocked by keyguard or device provisioning
+        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+        // make sure lockdown action will be shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.LockDownAction.class,
+                GlobalActionsDialog.PowerOptionsAction.class);
+        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
+        assertItemsOfType(mGlobalActionsDialog.mPowerItems,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class);
+    }
+
+    @Test
+    public void testCreateActionItems_maxThree_condensePower_splitPower() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow 3 items to be shown
+        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // make sure lockdown action will be shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+        // make sure bugreport also shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any());
+        // ensure items are not blocked by keyguard or device provisioning
+        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.LockDownAction.class,
+                GlobalActionsDialog.PowerOptionsAction.class);
+        assertItemsOfType(mGlobalActionsDialog.mOverflowItems,
+                GlobalActionsDialog.BugReportAction.class);
+        assertItemsOfType(mGlobalActionsDialog.mPowerItems,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class);
+    }
+
+    @Test
+    public void testCreateActionItems_maxFour_condensePower() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow 3 items to be shown
+        doReturn(4).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // make sure lockdown action will be shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+        // ensure items are not blocked by keyguard or device provisioning
+        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.LockDownAction.class,
+                GlobalActionsDialog.PowerOptionsAction.class,
+                GlobalActionsDialog.ScreenshotAction.class);
+        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
+        assertItemsOfType(mGlobalActionsDialog.mPowerItems,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class);
+    }
+
+    @Test
+    public void testCreateActionItems_maxThree_doNotCondensePower() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow 3 items to be shown
+        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // make sure lockdown action will be shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+        // make sure bugreport is also shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any());
+        // ensure items are not blocked by keyguard or device provisioning
+        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.BugReportAction.class);
+        assertItemsOfType(mGlobalActionsDialog.mOverflowItems,
+                GlobalActionsDialog.LockDownAction.class);
+        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
+    }
+
+    @Test
+    public void testCreateActionItems_maxAny() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow any number of power menu items to be shown
+        doReturn(Integer.MAX_VALUE).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // ensure items are not blocked by keyguard or device provisioning
+        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+        // make sure lockdown action will be shown
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class,
+                GlobalActionsDialog.LockDownAction.class);
+        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
+        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
+    }
+
+    @Test
+    public void testCreateActionItems_maxThree_lockdownDisabled_doesNotShowLockdown() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow only 3 items to be shown
+        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        // make sure lockdown action will NOT be shown
+        doReturn(false).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                // lockdown action not allowed
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class);
+        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
+        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
+    }
+
+    @Test
+    public void testCreateActionItems_shouldShowAction_excludeBugReport() {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        // allow only 3 items to be shown
+        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+        doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any());
+        // exclude bugreport in shouldShowAction to demonstrate how any button can be removed
+        doAnswer(
+                invocation -> !(invocation.getArgument(0)
+                        instanceof GlobalActionsDialog.BugReportAction))
+                .when(mGlobalActionsDialog).shouldShowAction(any());
+
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                // bugreport action not allowed
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+        mGlobalActionsDialog.createActionItems();
+
+        assertItemsOfType(mGlobalActionsDialog.mItems,
+                GlobalActionsDialog.EmergencyAction.class,
+                GlobalActionsDialog.ShutDownAction.class,
+                GlobalActionsDialog.RestartAction.class);
+        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
+        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
+    }
+
+    @Test
+    public void testShouldShowLockScreenMessage() throws RemoteException {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        mGlobalActionsDialog.mDialog = null;
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+        when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
+        when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
+        mGlobalActionsDialog.mShowLockScreenCardsAndControls = false;
+        setupDefaultActions();
+        when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
+        when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
+
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
+
+        GlobalActionsDialog.ActionsDialog dialog =
+                (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog;
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.VISIBLE);
+
+        // Dismiss the dialog so that it does not pollute other tests
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
+    }
+
+    @Test
+    public void testShouldNotShowLockScreenMessage_whenWalletOrControlsShownOnLockScreen()
+            throws RemoteException {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        mGlobalActionsDialog.mDialog = null;
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+        when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
+        when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
+        mGlobalActionsDialog.mShowLockScreenCardsAndControls = true;
+        setupDefaultActions();
+        when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
+        when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
+
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
+
+        GlobalActionsDialog.ActionsDialog dialog =
+                (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog;
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
+
+        // Dismiss the dialog so that it does not pollute other tests
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
+    }
+
+    @Test
+    public void testShouldNotShowLockScreenMessage_whenControlsAndWalletBothDisabled()
+            throws RemoteException {
+        mGlobalActionsDialog = spy(mGlobalActionsDialog);
+        mGlobalActionsDialog.mDialog = null;
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+        when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
+        when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
+        mGlobalActionsDialog.mShowLockScreenCardsAndControls = true;
+        setupDefaultActions();
+        when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
+        when(mWalletController.getPanelContent()).thenReturn(null);
+        when(mControlsUiController.getAvailable()).thenReturn(false);
+
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
+
+        GlobalActionsDialog.ActionsDialog dialog =
+                (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog;
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
+
+        // Dismiss the dialog so that it does not pollute other tests
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
+    }
+
+    private UserInfo newUserInfo() {
+        return new UserInfo(0, null, null, UserInfo.FLAG_PRIMARY, null);
+    }
+
+    private void setupDefaultActions() {
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+    }
+}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 76a714c47f2e..07d2f0336217 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -16,12 +16,15 @@ package com.android.server.policy;
 
 import android.content.Context;
 import android.os.Handler;
+import android.provider.Settings;
 import android.util.Slog;
 
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
 import com.android.server.policy.GlobalActionsProvider;
 
+import com.libremobileos.providers.LMOSettings;
+
 class GlobalActions implements GlobalActionsProvider.GlobalActionsListener {
 
     private static final String TAG = "GlobalActions";
@@ -64,7 +67,8 @@ class GlobalActions implements GlobalActionsProvider.GlobalActionsListener {
         mKeyguardShowing = keyguardShowing;
         mDeviceProvisioned = deviceProvisioned;
         mShowing = true;
-        if (mGlobalActionsAvailable) {
+        if (mGlobalActionsAvailable && Settings.Secure.getInt(mContext.getContentResolver(),
+                LMOSettings.Secure.POWER_MENU_TYPE, 0) != 4) {
             mHandler.postDelayed(mShowTimeout, 5000);
             mGlobalActionsProvider.showGlobalActions();
         } else {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2c96300f9f7b..69a1f7a1f0ad 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2676,6 +2676,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mMultiuserReceiver, filter);
 
+        // register power menu broadcast
+        filter = new IntentFilter("android.intent.action.POWER_MENU");
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                showGlobalActionsInternal();
+            }
+        }, filter);
+
         mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHapticFeedbackVibrationProvider =
                 new HapticFeedbackVibrationProvider(mContext.getResources(), mVibrator);
-- 
GitLab