diff options
author | 2019-03-05 10:24:16 -0500 | |
---|---|---|
committer | 2019-03-06 11:30:58 -0500 | |
commit | 9b87a44b79918b4608d02fac04eed5442cd18dda (patch) | |
tree | beffa255f2dd5017b453a5161c02bc232bb31f7e | |
parent | b21765f2f330537ad86c3c4b40517e4afe6c0140 (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
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() { |