summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Steve Elliott <steell@google.com> 2019-03-05 10:24:16 -0500
committer Steve Elliott <steell@google.com> 2019-03-06 11:30:58 -0500
commit9b87a44b79918b4608d02fac04eed5442cd18dda (patch)
treebeffa255f2dd5017b453a5161c02bc232bb31f7e
parentb21765f2f330537ad86c3c4b40517e4afe6c0140 (diff)
"Global Actions Panel" plugin
This change adds a new plugin API surface inside of Global Actions, where a plugin can provide a View to be rendered alongside the Global Actions menu. When the GlobalActionsDialog.ActionDialog is created, the plugin can produce a GlobalActionsPanelPlugin.PanelViewController instance, which is used to provide the View to be rendered, and respond to Global Actions events (right now, only dismissal). At this time, the plugin is given an instance of GlobalActionsPanelPlugin.Callbacks, allowing the plugin to interact with the GlobalActionsDialog (right now, only to request dismissal). When there is a Panel present, a darker scrim is used that is *not* based on the colors underneath. In order to provide maximum flexibility, the View comprising the Panel is rendered above (z-ordering) the existing Global Actions menu, and can take up the entire screen if desired. In practice, plugins should take care to not block access to the GlobalActions menu. Change-Id: I9d6eea80f7eb49e9adbc1a634f7d9c1ab720cddb Test: manual
-rw-r--r--core/java/android/util/FeatureFlagUtils.java5
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java86
-rw-r--r--packages/SystemUI/res/drawable/global_action_panel_scrim.xml26
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java112
5 files changed, 210 insertions, 22 deletions
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index fac699ece642..b99336bb0dbf 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -39,6 +39,8 @@ public class FeatureFlagUtils {
public static final String SAFETY_HUB = "settings_safety_hub";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String GLOBAL_ACTIONS_GRID_ENABLED = "settings_global_actions_grid_enabled";
+ public static final String GLOBAL_ACTIONS_PANEL_ENABLED =
+ "settings_global_actions_panel_enabled";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -56,7 +58,8 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
DEFAULT_FLAGS.put(SAFETY_HUB, "false");
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
- DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "false");
+ DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true");
+ DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
}
/**
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
new file mode 100644
index 000000000000..7c7268865235
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
@@ -0,0 +1,86 @@
+/*
+ * 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.systemui.plugins;
+
+import android.view.View;
+
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Plugin which provides a "Panel" {@link View} to be rendered inside of the GlobalActions menu.
+ *
+ * Implementations should construct a new {@link PanelViewController} with the given
+ * {@link Callbacks} instance inside of {@link #onPanelShown(Callbacks)}, and should not hold onto
+ * a reference, instead allowing Global Actions to manage the lifetime of the object.
+ *
+ * Under this assumption, {@link PanelViewController} represents the lifetime of a single invocation
+ * of the Global Actions menu. The {@link View} for the Panel is generated when the
+ * {@link PanelViewController} is constructed, and {@link PanelViewController#getPanelContent()}
+ * serves as a simple getter. When Global Actions is dismissed,
+ * {@link PanelViewController#onDismissed()} can be used to cleanup any resources allocated when
+ * constructed. Global Actions will then release the reference, and the {@link PanelViewController}
+ * will be garbage-collected.
+ */
+@ProvidesInterface(
+ action = GlobalActionsPanelPlugin.ACTION, version = GlobalActionsPanelPlugin.VERSION)
+@DependsOn(target = GlobalActionsPanelPlugin.Callbacks.class)
+@DependsOn(target = GlobalActionsPanelPlugin.PanelViewController.class)
+public interface GlobalActionsPanelPlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_GLOBAL_ACTIONS_PANEL";
+ int VERSION = 0;
+
+ /**
+ * Invoked when the GlobalActions menu is shown.
+ *
+ * @param callbacks {@link Callbacks} instance that can be used by the Panel to interact with
+ * the Global Actions menu.
+ * @return A {@link PanelViewController} instance used to receive Global Actions events.
+ */
+ PanelViewController onPanelShown(Callbacks callbacks);
+
+ /**
+ * Provides methods to interact with the Global Actions menu.
+ */
+ @ProvidesInterface(version = Callbacks.VERSION)
+ interface Callbacks {
+ int VERSION = 0;
+
+ /** Dismisses the Global Actions menu. */
+ void dismissGlobalActionsMenu();
+ }
+
+ /**
+ * Receives Global Actions events, and provides the Panel {@link View}.
+ */
+ @ProvidesInterface(version = PanelViewController.VERSION)
+ interface PanelViewController {
+ int VERSION = 0;
+
+ /**
+ * Returns the {@link View} for the Panel to be rendered in Global Actions. This View can be
+ * any size, and will be rendered above the Global Actions menu when z-ordered.
+ */
+ View getPanelContent();
+
+ /**
+ * Invoked when the Global Actions menu (containing the View returned from
+ * {@link #getPanelContent()}) is dismissed.
+ */
+ void onDismissed();
+ }
+}
diff --git a/packages/SystemUI/res/drawable/global_action_panel_scrim.xml b/packages/SystemUI/res/drawable/global_action_panel_scrim.xml
new file mode 100644
index 000000000000..177b8d204ac8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/global_action_panel_scrim.xml
@@ -0,0 +1,26 @@
+<?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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:centerY="0.45"
+ android:startColor="#be3c4043"
+ android:centerColor="#be3c4043"
+ android:endColor="#4d3c4043"
+ android:angle="270" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 50cf37beb878..a40a14a47744 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -856,6 +856,9 @@
<!-- Global actions grid layout -->
<dimen name="global_actions_grid_side_margin">4dp</dimen>
+ <!-- Global actions panel -->
+ <dimen name="global_actions_panel_top_margin">85dp</dimen>
+
<!-- The maximum offset in either direction that elements are moved horizontally to prevent
burn-in on AOD. -->
<dimen name="burn_in_prevention_offset_x">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index c16c91bd4625..8a95cc4910ad 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -67,6 +67,7 @@ import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;
@@ -88,8 +89,10 @@ import com.android.systemui.Interpolators;
import com.android.systemui.MultiListLayout;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
-import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
import com.android.systemui.util.EmergencyDialerConstants;
import com.android.systemui.util.leak.RotationUtils;
import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
@@ -161,6 +164,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final ScreenshotHelper mScreenshotHelper;
private final ScreenRecordHelper mScreenRecordHelper;
+ private final Extension<GlobalActionsPanelPlugin> mPanelExtension;
+
/**
* @param context everything needs a context :(
*/
@@ -204,6 +209,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mScreenRecordHelper = new ScreenRecordHelper(context);
Dependency.get(ConfigurationController.class).addCallback(this);
+
+ mPanelExtension = Dependency.get(ExtensionController.class)
+ .newExtension(GlobalActionsPanelPlugin.class)
+ .withPlugin(GlobalActionsPanelPlugin.class)
+ .build();
}
/**
@@ -399,8 +409,16 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
return false;
};
+ GlobalActionsPanelPlugin.PanelViewController panelViewController =
+ mPanelExtension.get() != null
+ ? mPanelExtension.get().onPanelShown(() -> {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
+ })
+ : null;
ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener,
- mSeparatedEmergencyButtonEnabled);
+ mSeparatedEmergencyButtonEnabled, panelViewController);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.setKeyguardShowing(mKeyguardShowing);
@@ -1470,20 +1488,22 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private MultiListLayout mGlobalActionsLayout;
private final OnClickListener mClickListener;
private final OnItemLongClickListener mLongClickListener;
- private final GradientDrawable mGradientDrawable;
+ private final Drawable mBackgroundDrawable;
private final ColorExtractor mColorExtractor;
+ private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
private boolean mKeyguardShowing;
private boolean mShouldDisplaySeparatedButton;
private boolean mShowing;
+ private final float mScrimAlpha;
public ActionsDialog(Context context, OnClickListener clickListener, MyAdapter adapter,
- OnItemLongClickListener longClickListener, boolean shouldDisplaySeparatedButton) {
+ OnItemLongClickListener longClickListener, boolean shouldDisplaySeparatedButton,
+ GlobalActionsPanelPlugin.PanelViewController plugin) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
mClickListener = clickListener;
mLongClickListener = longClickListener;
- mGradientDrawable = new GradientDrawable(mContext);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mShouldDisplaySeparatedButton = shouldDisplaySeparatedButton;
@@ -1504,12 +1524,46 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- window.setBackgroundDrawable(mGradientDrawable);
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
initializeLayout();
setTitle(R.string.global_actions);
+
+ mPanelController = plugin;
+ View panelView = initializePanel();
+ if (panelView == null) {
+ mBackgroundDrawable = new GradientDrawable(context);
+ mScrimAlpha = 0.7f;
+ } else {
+ mBackgroundDrawable = context.getDrawable(
+ com.android.systemui.R.drawable.global_action_panel_scrim);
+ mScrimAlpha = 1f;
+ addContentView(
+ panelView,
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ }
+ window.setBackgroundDrawable(mBackgroundDrawable);
+ }
+
+ private View initializePanel() {
+ if (isPanelEnabled(mContext) && mPanelController != null) {
+ View panelView = mPanelController.getPanelContent();
+ if (panelView != null) {
+ FrameLayout panelContainer = new FrameLayout(mContext);
+ FrameLayout.LayoutParams panelParams =
+ new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT);
+ panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen.global_actions_panel_top_margin);
+ panelContainer.addView(panelView, panelParams);
+ return panelContainer;
+ }
+ }
+ return null;
}
private void initializeLayout() {
@@ -1530,6 +1584,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mGlobalActionsLayout.setRotationListener(this::onRotate);
}
+ private boolean isPanelEnabled(Context context) {
+ return FeatureFlagUtils.isEnabled(
+ context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+ }
+
private int getGlobalActionsLayoutId(Context context) {
if (isGridEnabled(context)) {
if (RotationUtils.getRotation(context) == RotationUtils.ROTATION_SEASCAPE) {
@@ -1590,13 +1649,18 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
super.onStart();
updateList();
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- mColorExtractor.addOnColorsChangedListener(this);
- mGradientDrawable.setScreenSize(displaySize.x, displaySize.y);
- GradientColors colors = mColorExtractor.getColors(mKeyguardShowing ?
- WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM);
- updateColors(colors, false /* animate */);
+ if (mBackgroundDrawable instanceof GradientDrawable) {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ mColorExtractor.addOnColorsChangedListener(this);
+ ((GradientDrawable) mBackgroundDrawable)
+ .setScreenSize(displaySize.x, displaySize.y);
+ GradientColors colors = mColorExtractor.getColors(
+ mKeyguardShowing
+ ? WallpaperManager.FLAG_LOCK
+ : WallpaperManager.FLAG_SYSTEM);
+ updateColors(colors, false /* animate */);
+ }
}
/**
@@ -1605,11 +1669,14 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
* @param animate Interpolates gradient if true, just sets otherwise.
*/
private void updateColors(GradientColors colors, boolean animate) {
- mGradientDrawable.setColors(colors, animate);
+ if (!(mBackgroundDrawable instanceof GradientDrawable)) {
+ return;
+ }
+ ((GradientDrawable) mBackgroundDrawable).setColors(colors, animate);
View decorView = getWindow().getDecorView();
if (colors.supportsDarkText()) {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
- View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
decorView.setSystemUiVisibility(0);
}
@@ -1625,7 +1692,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
public void show() {
super.show();
mShowing = true;
- mGradientDrawable.setAlpha(0);
+ mBackgroundDrawable.setAlpha(0);
mGlobalActionsLayout.setTranslationX(getAnimTranslation());
mGlobalActionsLayout.setAlpha(0);
mGlobalActionsLayout.animate()
@@ -1635,8 +1702,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setUpdateListener(animation -> {
int alpha = (int) ((Float) animation.getAnimatedValue()
- * ScrimController.GRADIENT_SCRIM_ALPHA * 255);
- mGradientDrawable.setAlpha(alpha);
+ * mScrimAlpha * 255);
+ mBackgroundDrawable.setAlpha(alpha);
})
.start();
}
@@ -1653,14 +1720,17 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
.alpha(0)
.translationX(getAnimTranslation())
.setDuration(300)
- .withEndAction(() -> super.dismiss())
+ .withEndAction(super::dismiss)
.setInterpolator(new LogAccelerateInterpolator())
.setUpdateListener(animation -> {
int alpha = (int) ((1f - (Float) animation.getAnimatedValue())
- * ScrimController.GRADIENT_SCRIM_ALPHA * 255);
- mGradientDrawable.setAlpha(alpha);
+ * mScrimAlpha * 255);
+ mBackgroundDrawable.setAlpha(alpha);
})
.start();
+ if (mPanelController != null) {
+ mPanelController.onDismissed();
+ }
}
void dismissImmediately() {