diff options
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() { |