diff --git a/res/raw/gesture_global_actions_panel.mp4 b/res/raw/gesture_global_actions_panel.mp4
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a31de98fb42..af94db3a358 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7264,6 +7264,8 @@
work challenge, work, profile
work profile, managed profile, unify, unification, work, profile
gestures
+
+ global actions
pay, tap, payments
backup, back up
gesture
@@ -10148,6 +10150,15 @@
To check time, notifications, and other info, tap your screen.
+
+ To show the global actions panel, press & hold Power button
+
+ Show global actions
+
+ Global actions
+
+ The global actions panel can be accessed even when the device is locked.
+
Swipe fingerprint for notifications
diff --git a/res/xml/gestures.xml b/res/xml/gestures.xml
index 8515bd71892..5dcb1b02d01 100644
--- a/res/xml/gestures.xml
+++ b/res/xml/gestures.xml
@@ -75,4 +75,10 @@
android:fragment="com.android.settings.gestures.PreventRingingGestureSettings"
settings:controller="com.android.settings.gestures.PreventRingingParentPreferenceController" />
+
+
diff --git a/res/xml/global_actions_panel_settings.xml b/res/xml/global_actions_panel_settings.xml
new file mode 100644
index 00000000000..af155bc74fc
--- /dev/null
+++ b/res/xml/global_actions_panel_settings.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java b/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java
new file mode 100644
index 00000000000..07d303ba0ad
--- /dev/null
+++ b/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * 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
+ */
+
+package com.android.settings.gestures;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+public class GlobalActionsPanelPreferenceController extends GesturePreferenceController {
+ private static final String PREF_KEY_VIDEO = "global_actions_panel_video";
+
+ // TODO (b/132182180) -- Use Secure Settings constants instead of hard-coded strings
+ @VisibleForTesting
+ protected static final String ENABLED_SETTING = "global_actions_panel_enabled";
+ // TODO (b/132182180) -- Use Secure Settings constants instead of hard-coded strings
+ @VisibleForTesting
+ protected static final String AVAILABLE_SETTING = "global_actions_panel_available";
+
+ @VisibleForTesting
+ protected static final String TOGGLE_KEY = "gesture_global_actions_panel_switch";
+
+ public GlobalActionsPanelPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ int enabled = Settings.Secure.getInt(mContext.getContentResolver(), AVAILABLE_SETTING, 0);
+ return enabled == 1 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ return Settings.Secure.putInt(mContext.getContentResolver(), ENABLED_SETTING,
+ isChecked ? 1 : 0);
+ }
+
+ @Override
+ protected String getVideoPrefKey() {
+ return PREF_KEY_VIDEO;
+ }
+
+ @Override
+ public boolean isSliceable() {
+ return TextUtils.equals(getPreferenceKey(), TOGGLE_KEY);
+ }
+
+ @Override
+ public boolean isChecked() {
+ int enabled = Settings.Secure.getInt(mContext.getContentResolver(), ENABLED_SETTING, 0);
+ return enabled == 1;
+ }
+}
diff --git a/src/com/android/settings/gestures/GlobalActionsPanelSettings.java b/src/com/android/settings/gestures/GlobalActionsPanelSettings.java
new file mode 100644
index 00000000000..0ace61f0c05
--- /dev/null
+++ b/src/com/android/settings/gestures/GlobalActionsPanelSettings.java
@@ -0,0 +1,62 @@
+/*
+ * 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
+ */
+
+package com.android.settings.gestures;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SearchIndexable
+public class GlobalActionsPanelSettings extends DashboardFragment {
+
+ private static final String TAG = "GlobalActionsPanelSettings";
+
+ // TODO (132184167): Use correct settings constant
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.SETTINGS_GESTURES;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.global_actions_panel_settings;
+ }
+
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.global_actions_panel_settings;
+ return Arrays.asList(sir);
+ }
+ };
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java
new file mode 100644
index 00000000000..1fed7df6059
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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
+ */
+
+package com.android.settings.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class GlobalActionsPanelPreferenceControllerTest {
+
+ private Context mContext;
+ private GlobalActionsPanelPreferenceController mController;
+
+ private static final String KEY_GESTURE_PANEL = "gesture_global_actions_panel";
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new GlobalActionsPanelPreferenceController(mContext, KEY_GESTURE_PANEL);
+ }
+
+ @Test
+ public void testIsChecked_panelEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), mController.ENABLED_SETTING, 1);
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void testIsChecked_panelDisabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), mController.ENABLED_SETTING, 0);
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void getAvailabilityStatus_panelAvailable() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), mController.AVAILABLE_SETTING, 1);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_panelUnavailable() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), mController.AVAILABLE_SETTING, 0);
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(mController.CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void isSliceable_correctKey() {
+ final GlobalActionsPanelPreferenceController controller =
+ new GlobalActionsPanelPreferenceController(mContext, mController.TOGGLE_KEY);
+ assertThat(controller.isSliceable()).isTrue();
+ }
+
+ @Test
+ public void isSliceable_incorrectKey() {
+ final GlobalActionsPanelPreferenceController controller =
+ new GlobalActionsPanelPreferenceController(mContext, "bad_key");
+ assertThat(controller.isSliceable()).isFalse();
+ }
+}