Animate media dialogs
This CL applies the DialogLaunchAnimator to the media output and media output group dialogs. See b/200781817#comment2 for before/after videos. Bug: 200781817 Test: Open media output dialog Change-Id: I1bff28cc7647db6b97b8933e5b7605d7df15c63f
This commit is contained in:
@@ -15,7 +15,14 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<style name="Animation.LaunchHostDialog" parent="@android:style/Animation">
|
||||
<style name="HostDialogTheme">
|
||||
<item name="android:windowAnimationStyle">@style/Animation.HostDialog</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:backgroundDimEnabled">true</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="Animation.HostDialog" parent="@android:style/Animation">
|
||||
<item name="android:windowEnterAnimation">@anim/launch_host_dialog_enter</item>
|
||||
<item name="android:windowExitAnimation">@anim/launch_host_dialog_exit</item>
|
||||
</style>
|
||||
|
||||
@@ -118,6 +118,20 @@ class DialogLaunchAnimator(
|
||||
fun onDozeAmountChanged(amount: Float) {
|
||||
currentAnimations.forEach { it.onDozeAmountChanged(amount) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that all dialogs currently shown won't animate into their touch surface when
|
||||
* dismissed.
|
||||
*
|
||||
* This is a temporary API meant to be called right before we both dismiss a dialog and start
|
||||
* an activity, which currently does not look good if we animate the dialog into the touch
|
||||
* surface at the same time as the activity starts.
|
||||
*
|
||||
* TODO(b/193634619): Remove this function and animate dialog into opening activity instead.
|
||||
*/
|
||||
fun disableAllCurrentDialogsExitAnimations() {
|
||||
currentAnimations.forEach { it.exitAnimationDisabled = true }
|
||||
}
|
||||
}
|
||||
|
||||
interface HostDialogProvider {
|
||||
@@ -133,6 +147,7 @@ interface HostDialogProvider {
|
||||
*/
|
||||
fun createHostDialog(
|
||||
context: Context,
|
||||
theme: Int,
|
||||
onCreateCallback: () -> Unit,
|
||||
dismissOverride: (() -> Unit) -> Unit
|
||||
): Dialog
|
||||
@@ -180,7 +195,7 @@ private class DialogLaunchAnimation(
|
||||
* [originalDialog].
|
||||
*/
|
||||
val hostDialog = hostDialogProvider.createHostDialog(
|
||||
context, this::onHostDialogCreated, this::onHostDialogDismissed)
|
||||
context, R.style.HostDialogTheme, this::onHostDialogCreated, this::onHostDialogDismissed)
|
||||
|
||||
/** The root content view of [hostDialog]. */
|
||||
private val hostDialogRoot = FrameLayout(context)
|
||||
@@ -208,6 +223,7 @@ private class DialogLaunchAnimation(
|
||||
private var dismissRequested = false
|
||||
private var drawHostDialog = false
|
||||
var ignoreNextCallToHide = false
|
||||
var exitAnimationDisabled = false
|
||||
|
||||
fun start() {
|
||||
// Show the host (fullscreen) dialog, to which we will add the stolen dialog view.
|
||||
@@ -236,10 +252,6 @@ private class DialogLaunchAnimation(
|
||||
WindowManager.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
// The host dialog animation is a translation of 0px so that it is shown directly. The
|
||||
// translation lasts X ms, so that the scrim fades in during that amount of time.
|
||||
window.attributes.windowAnimations = R.style.Animation_LaunchHostDialog
|
||||
|
||||
// Prevent the host dialog from drawing until the animation starts.
|
||||
hostDialogRoot.viewTreeObserver.addOnPreDrawListener(
|
||||
object : ViewTreeObserver.OnPreDrawListener {
|
||||
@@ -318,9 +330,11 @@ private class DialogLaunchAnimation(
|
||||
(dialogView.parent as? ViewGroup)?.removeView(dialogView)
|
||||
hostDialogRoot.addView(
|
||||
dialogView,
|
||||
|
||||
// We give it the size of its original dialog window.
|
||||
FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
originalDialog.window.attributes.width,
|
||||
originalDialog.window.attributes.height,
|
||||
Gravity.CENTER
|
||||
)
|
||||
)
|
||||
@@ -496,6 +510,10 @@ private class DialogLaunchAnimation(
|
||||
}
|
||||
|
||||
private fun shouldAnimateDialogIntoView(): Boolean {
|
||||
if (exitAnimationDisabled) {
|
||||
return false
|
||||
}
|
||||
|
||||
// The touch surface should be invisible by now, if it's not then something else changed its
|
||||
// visibility and we probably don't want to run the animation.
|
||||
if (touchSurface.visibility != View.INVISIBLE) {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="?android:attr/colorBackground" />
|
||||
</shape>
|
||||
</inset>
|
||||
@@ -19,7 +19,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:id="@+id/internet_connectivity_dialog"
|
||||
android:layout_width="@dimen/internet_dialog_list_max_width"
|
||||
android:layout_width="@dimen/large_dialog_width"
|
||||
android:layout_height="@dimen/internet_dialog_list_max_height"
|
||||
android:background="@drawable/internet_dialog_rounded_top_corner_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/media_output_dialog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="@dimen/large_dialog_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
android:background="@drawable/qs_media_light_source"
|
||||
android:forceHasOverlappingRendering="false">
|
||||
<LinearLayout
|
||||
android:id="@+id/media_seamless_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/qs_seamless_height"
|
||||
|
||||
@@ -104,6 +104,6 @@
|
||||
<!-- When split shade is used, this panel should be aligned to the top -->
|
||||
<dimen name="qs_detail_margin_top">0dp</dimen>
|
||||
|
||||
<!-- Internet panel related dimensions -->
|
||||
<dimen name="internet_dialog_list_max_width">624dp</dimen>
|
||||
<!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
|
||||
<dimen name="large_dialog_width">624dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -1600,7 +1600,9 @@
|
||||
<!-- Internet panel related dimensions -->
|
||||
<dimen name="internet_dialog_list_margin">12dp</dimen>
|
||||
<dimen name="internet_dialog_list_max_height">646dp</dimen>
|
||||
<dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen>
|
||||
|
||||
<!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
|
||||
<dimen name="large_dialog_width">@dimen/match_parent</dimen>
|
||||
|
||||
<!-- Signal icon in internet dialog -->
|
||||
<dimen name="signal_strength_icon_size">24dp</dimen>
|
||||
|
||||
@@ -331,9 +331,6 @@
|
||||
<style name="Animation.ShutdownUi" parent="@android:style/Animation.Toast">
|
||||
</style>
|
||||
|
||||
<style name="Animation.MediaOutputDialog" parent="@android:style/Animation.InputMethod">
|
||||
</style>
|
||||
|
||||
<!-- Standard animations for hiding and showing the status bar. -->
|
||||
<style name="Animation.StatusBar">
|
||||
</style>
|
||||
@@ -434,10 +431,6 @@
|
||||
<item name="android:windowCloseOnTouchOutside">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.SystemUI.Dialog.MediaOutput">
|
||||
<item name="android:windowBackground">@drawable/media_output_dialog_background</item>
|
||||
</style>
|
||||
|
||||
<style name="QSBorderlessButton">
|
||||
<item name="android:padding">12dp</item>
|
||||
<item name="android:background">@drawable/qs_btn_borderless_rect</item>
|
||||
|
||||
@@ -361,9 +361,9 @@ public class MediaControlPanel {
|
||||
seamlessView.setVisibility(View.VISIBLE);
|
||||
setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
|
||||
setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
|
||||
seamlessView.setOnClickListener(v -> {
|
||||
mMediaOutputDialogFactory.create(data.getPackageName(), true);
|
||||
});
|
||||
seamlessView.setOnClickListener(
|
||||
v -> mMediaOutputDialogFactory.create(data.getPackageName(), true,
|
||||
mPlayerViewHolder.getSeamlessButton()));
|
||||
|
||||
ImageView iconView = mPlayerViewHolder.getSeamlessIcon();
|
||||
TextView deviceName = mPlayerViewHolder.getSeamlessText();
|
||||
|
||||
@@ -43,6 +43,7 @@ class PlayerViewHolder private constructor(itemView: View) {
|
||||
val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
|
||||
val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
|
||||
val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
|
||||
val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button)
|
||||
|
||||
// Seek bar
|
||||
val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
|
||||
|
||||
@@ -45,11 +45,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
|
||||
private static final String TAG = "MediaOutputAdapter";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private final MediaOutputDialog mMediaOutputDialog;
|
||||
private ViewGroup mConnectedItem;
|
||||
private boolean mIncludeDynamicGroup;
|
||||
|
||||
public MediaOutputAdapter(MediaOutputController controller) {
|
||||
public MediaOutputAdapter(MediaOutputController controller,
|
||||
MediaOutputDialog mediaOutputDialog) {
|
||||
super(controller);
|
||||
mMediaOutputDialog = mediaOutputDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,7 +139,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
|
||||
mDivider.setTransitionAlpha(1);
|
||||
mAddIcon.setVisibility(View.VISIBLE);
|
||||
mAddIcon.setTransitionAlpha(1);
|
||||
mAddIcon.setOnClickListener(v -> onEndItemClick());
|
||||
mAddIcon.setOnClickListener(this::onEndItemClick);
|
||||
} else {
|
||||
// Init non-active device layout
|
||||
mDivider.setVisibility(View.GONE);
|
||||
@@ -197,7 +200,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
|
||||
mDivider.setTransitionAlpha(1);
|
||||
mAddIcon.setVisibility(View.VISIBLE);
|
||||
mAddIcon.setTransitionAlpha(1);
|
||||
mAddIcon.setOnClickListener(v -> onEndItemClick());
|
||||
mAddIcon.setOnClickListener(this::onEndItemClick);
|
||||
} else {
|
||||
mDivider.setVisibility(View.GONE);
|
||||
mAddIcon.setVisibility(View.GONE);
|
||||
@@ -232,8 +235,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void onEndItemClick() {
|
||||
mController.launchMediaOutputGroupDialog();
|
||||
private void onEndItemClick(View view) {
|
||||
mController.launchMediaOutputGroupDialog(mMediaOutputDialog.getDialogView());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
|
||||
};
|
||||
|
||||
public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
|
||||
super(context, R.style.Theme_SystemUI_Dialog_MediaOutput);
|
||||
super(context);
|
||||
mContext = context;
|
||||
mMediaOutputController = mediaOutputController;
|
||||
mLayoutManager = new LinearLayoutManager(mContext);
|
||||
@@ -97,15 +97,15 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
|
||||
mDialogView = LayoutInflater.from(mContext).inflate(R.layout.media_output_dialog, null);
|
||||
final Window window = getWindow();
|
||||
final WindowManager.LayoutParams lp = window.getAttributes();
|
||||
lp.gravity = Gravity.BOTTOM;
|
||||
lp.gravity = Gravity.CENTER;
|
||||
// Config insets to make sure the layout is above the navigation bar
|
||||
lp.setFitInsetsTypes(statusBars() | navigationBars());
|
||||
lp.setFitInsetsSides(WindowInsets.Side.all());
|
||||
lp.setFitInsetsIgnoringVisibility(true);
|
||||
window.setAttributes(lp);
|
||||
window.setContentView(mDialogView);
|
||||
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
window.setWindowAnimations(R.style.Animation_MediaOutputDialog);
|
||||
window.setLayout(mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width),
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
mHeaderTitle = mDialogView.requireViewById(R.id.header_title);
|
||||
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
|
||||
@@ -229,4 +229,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
|
||||
|
||||
void onHeaderIconClick() {
|
||||
}
|
||||
|
||||
View getDialogView() {
|
||||
return mDialogView;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -48,6 +49,7 @@ import com.android.settingslib.media.MediaDevice;
|
||||
import com.android.settingslib.media.MediaOutputConstants;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
@@ -73,6 +75,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
private final MediaSessionManager mMediaSessionManager;
|
||||
private final ShadeController mShadeController;
|
||||
private final ActivityStarter mActivityStarter;
|
||||
private final DialogLaunchAnimator mDialogLaunchAnimator;
|
||||
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
|
||||
private final boolean mAboveStatusbar;
|
||||
private final NotificationEntryManager mNotificationEntryManager;
|
||||
@@ -82,6 +85,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
private MediaController mMediaController;
|
||||
@VisibleForTesting
|
||||
Callback mCallback;
|
||||
Callback mPreviousCallback;
|
||||
@VisibleForTesting
|
||||
LocalMediaManager mLocalMediaManager;
|
||||
|
||||
@@ -92,7 +96,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
public MediaOutputController(@NonNull Context context, String packageName,
|
||||
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
|
||||
lbm, ShadeController shadeController, ActivityStarter starter,
|
||||
NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) {
|
||||
NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger,
|
||||
DialogLaunchAnimator dialogLaunchAnimator) {
|
||||
mContext = context;
|
||||
mPackageName = packageName;
|
||||
mMediaSessionManager = mediaSessionManager;
|
||||
@@ -104,6 +109,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
|
||||
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mDialogLaunchAnimator = dialogLaunchAnimator;
|
||||
}
|
||||
|
||||
void start(@NonNull Callback cb) {
|
||||
@@ -129,7 +135,19 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPreviousCallback != null) {
|
||||
Log.w(TAG,
|
||||
"Callback started when mPreviousCallback is not null, which is unexpected");
|
||||
mPreviousCallback.dismissDialog();
|
||||
}
|
||||
|
||||
// If we start the output group dialog when the output dialog is shown, we need to keep a
|
||||
// reference to the output dialog to set it back as the callback once we dismiss the output
|
||||
// group dialog.
|
||||
mPreviousCallback = mCallback;
|
||||
mCallback = cb;
|
||||
|
||||
mLocalMediaManager.unregisterCallback(this);
|
||||
mLocalMediaManager.stopScan();
|
||||
mLocalMediaManager.registerCallback(this);
|
||||
@@ -145,6 +163,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
mLocalMediaManager.stopScan();
|
||||
}
|
||||
mMediaDevices.clear();
|
||||
|
||||
// If there was a previous callback, i.e. we just dismissed the output group dialog and are
|
||||
// now back on the output dialog, then we reset the callback to its previous value.
|
||||
mCallback = null;
|
||||
Callback previous = mPreviousCallback;
|
||||
mPreviousCallback = null;
|
||||
if (previous != null) {
|
||||
start(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -436,6 +463,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
}
|
||||
|
||||
void launchBluetoothPairing() {
|
||||
// Dismissing a dialog into its touch surface and starting an activity at the same time
|
||||
// looks bad, so let's make sure the dialog just fades out quickly.
|
||||
mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
|
||||
|
||||
mCallback.dismissDialog();
|
||||
final ActivityStarter.OnDismissAction postKeyguardAction = () -> {
|
||||
mContext.sendBroadcast(new Intent()
|
||||
@@ -447,14 +478,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|
||||
mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true);
|
||||
}
|
||||
|
||||
void launchMediaOutputDialog() {
|
||||
mCallback.dismissDialog();
|
||||
new MediaOutputDialog(mContext, mAboveStatusbar, this, mUiEventLogger);
|
||||
}
|
||||
|
||||
void launchMediaOutputGroupDialog() {
|
||||
mCallback.dismissDialog();
|
||||
new MediaOutputGroupDialog(mContext, mAboveStatusbar, this);
|
||||
void launchMediaOutputGroupDialog(View mediaOutputDialog) {
|
||||
// We show the output group dialog from the output dialog.
|
||||
MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar, this);
|
||||
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
|
||||
}
|
||||
|
||||
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
|
||||
|
||||
@@ -40,11 +40,10 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
|
||||
mediaOutputController, UiEventLogger uiEventLogger) {
|
||||
super(context, mediaOutputController);
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mAdapter = new MediaOutputAdapter(mMediaOutputController);
|
||||
mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
|
||||
if (!aboveStatusbar) {
|
||||
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
|
||||
}
|
||||
show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,10 @@ package com.android.systemui.media.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.media.session.MediaSessionManager
|
||||
import android.view.View
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager
|
||||
import com.android.systemui.animation.DialogLaunchAnimator
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||
import com.android.systemui.statusbar.phone.ShadeController
|
||||
@@ -35,19 +37,29 @@ class MediaOutputDialogFactory @Inject constructor(
|
||||
private val shadeController: ShadeController,
|
||||
private val starter: ActivityStarter,
|
||||
private val notificationEntryManager: NotificationEntryManager,
|
||||
private val uiEventLogger: UiEventLogger
|
||||
private val uiEventLogger: UiEventLogger,
|
||||
private val dialogLaunchAnimator: DialogLaunchAnimator
|
||||
) {
|
||||
companion object {
|
||||
var mediaOutputDialog: MediaOutputDialog? = null
|
||||
}
|
||||
|
||||
/** Creates a [MediaOutputDialog] for the given package. */
|
||||
fun create(packageName: String, aboveStatusBar: Boolean) {
|
||||
fun create(packageName: String, aboveStatusBar: Boolean, view: View? = null) {
|
||||
// Dismiss the previous dialog, if any.
|
||||
mediaOutputDialog?.dismiss()
|
||||
mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar,
|
||||
mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
|
||||
uiEventLogger).run {
|
||||
MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger)
|
||||
|
||||
val controller = MediaOutputController(context, packageName, aboveStatusBar,
|
||||
mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
|
||||
uiEventLogger, dialogLaunchAnimator)
|
||||
val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
|
||||
mediaOutputDialog = dialog
|
||||
|
||||
// Show the dialog.
|
||||
if (view != null) {
|
||||
dialogLaunchAnimator.showFromView(dialog, view)
|
||||
} else {
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
|
||||
if (!aboveStatusbar) {
|
||||
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
|
||||
}
|
||||
show();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,6 +82,8 @@ public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
|
||||
|
||||
@Override
|
||||
void onHeaderIconClick() {
|
||||
mMediaOutputController.launchMediaOutputDialog();
|
||||
// Given that we launched the media output group dialog from the media output dialog,
|
||||
// dismissing this dialog will show the media output dialog again.
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,6 @@ public class InternetDialog extends SystemUIDialog implements
|
||||
private Button mDoneButton;
|
||||
private Drawable mBackgroundOn;
|
||||
private int mListMaxHeight;
|
||||
private int mLayoutWidth;
|
||||
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
private boolean mCanConfigMobileData;
|
||||
|
||||
@@ -181,8 +180,6 @@ public class InternetDialog extends SystemUIDialog implements
|
||||
};
|
||||
mListMaxHeight = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.internet_dialog_list_max_height);
|
||||
mLayoutWidth = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.internet_dialog_list_max_width);
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mAdapter = new InternetAdapter(mInternetDialogController);
|
||||
if (!aboveStatusBar) {
|
||||
@@ -211,7 +208,7 @@ public class InternetDialog extends SystemUIDialog implements
|
||||
window.setContentView(mDialogView);
|
||||
//Only fix the width for large screen or tablet.
|
||||
window.setLayout(mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
R.dimen.large_dialog_width), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
window.setWindowAnimations(R.style.Animation_InternetDialog);
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
window.addFlags(FLAG_LAYOUT_NO_LIMITS);
|
||||
|
||||
@@ -2521,7 +2521,8 @@ public class StatusBar extends SystemUI implements
|
||||
animationController != null && !willLaunchResolverActivity && shouldAnimateLaunch(
|
||||
true /* isActivityIntent */);
|
||||
ActivityLaunchAnimator.Controller animController =
|
||||
animate ? wrapAnimationController(animationController, dismissShade) : null;
|
||||
animationController != null ? wrapAnimationController(animationController,
|
||||
dismissShade) : null;
|
||||
|
||||
// If we animate, we will dismiss the shade only once the animation is done. This is taken
|
||||
// care of by the StatusBarLaunchAnimationController.
|
||||
|
||||
@@ -9,17 +9,19 @@ import com.android.systemui.animation.HostDialogProvider
|
||||
class SystemUIHostDialogProvider : HostDialogProvider {
|
||||
override fun createHostDialog(
|
||||
context: Context,
|
||||
theme: Int,
|
||||
onCreateCallback: () -> Unit,
|
||||
dismissOverride: (() -> Unit) -> Unit
|
||||
): Dialog {
|
||||
return SystemUIHostDialog(context, onCreateCallback, dismissOverride)
|
||||
return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride)
|
||||
}
|
||||
|
||||
private class SystemUIHostDialog(
|
||||
context: Context,
|
||||
theme: Int,
|
||||
private val onCreateCallback: () -> Unit,
|
||||
private val dismissOverride: (() -> Unit) -> Unit
|
||||
) : SystemUIDialog(context) {
|
||||
) : SystemUIDialog(context, theme) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
onCreateCallback()
|
||||
|
||||
@@ -97,6 +97,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
|
||||
private class TestHostDialogProvider : HostDialogProvider {
|
||||
override fun createHostDialog(
|
||||
context: Context,
|
||||
theme: Int,
|
||||
onCreateCallback: () -> Unit,
|
||||
dismissOverride: (() -> Unit) -> Unit
|
||||
): Dialog = TestHostDialog(context, onCreateCallback, dismissOverride)
|
||||
|
||||
@@ -54,6 +54,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
|
||||
|
||||
// Mock
|
||||
private MediaOutputController mMediaOutputController = mock(MediaOutputController.class);
|
||||
private MediaOutputDialog mMediaOutputDialog = mock(MediaOutputDialog.class);
|
||||
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
|
||||
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
|
||||
private Icon mIcon = mock(Icon.class);
|
||||
@@ -65,7 +66,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
|
||||
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController, mMediaOutputDialog);
|
||||
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
|
||||
.onCreateViewHolder(new LinearLayout(mContext), 0);
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
@@ -63,6 +64,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
|
||||
private NotificationEntryManager mNotificationEntryManager =
|
||||
mock(NotificationEntryManager.class);
|
||||
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
|
||||
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
|
||||
|
||||
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
|
||||
private MediaOutputController mMediaOutputController;
|
||||
@@ -75,7 +77,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
|
||||
public void setUp() {
|
||||
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
|
||||
mMediaOutputController);
|
||||
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
|
||||
|
||||
@@ -49,6 +49,7 @@ import com.android.settingslib.media.LocalMediaManager;
|
||||
import com.android.settingslib.media.MediaDevice;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
@@ -91,6 +92,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
||||
private NotificationEntryManager mNotificationEntryManager =
|
||||
mock(NotificationEntryManager.class);
|
||||
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
|
||||
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
|
||||
|
||||
private Context mSpyContext;
|
||||
private MediaOutputController mMediaOutputController;
|
||||
@@ -113,7 +115,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
||||
|
||||
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
|
||||
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
|
||||
MediaDescription.Builder builder = new MediaDescription.Builder();
|
||||
@@ -157,7 +159,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
||||
public void start_withoutPackageName_verifyMediaControllerInit() {
|
||||
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
|
||||
mMediaOutputController.start(mCb);
|
||||
|
||||
@@ -178,7 +180,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
||||
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
|
||||
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
|
||||
mMediaOutputController.start(mCb);
|
||||
|
||||
@@ -449,7 +451,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
||||
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
|
||||
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
|
||||
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.media.LocalMediaManager;
|
||||
import com.android.settingslib.media.MediaDevice;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
@@ -65,6 +66,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
|
||||
private final NotificationEntryManager mNotificationEntryManager =
|
||||
mock(NotificationEntryManager.class);
|
||||
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
|
||||
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
|
||||
|
||||
private MediaOutputDialog mMediaOutputDialog;
|
||||
private MediaOutputController mMediaOutputController;
|
||||
@@ -74,10 +76,11 @@ public class MediaOutputDialogTest extends SysuiTestCase {
|
||||
public void setUp() {
|
||||
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
|
||||
mMediaOutputDialog = new MediaOutputDialog(mContext, false,
|
||||
mMediaOutputController, mUiEventLogger);
|
||||
mMediaOutputDialog.show();
|
||||
|
||||
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
|
||||
when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
|
||||
@@ -123,6 +126,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
|
||||
public void onCreate_ShouldLogVisibility() {
|
||||
MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
|
||||
mMediaOutputController, mUiEventLogger);
|
||||
testDialog.show();
|
||||
|
||||
testDialog.dismissDialog();
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.android.settingslib.media.LocalMediaManager;
|
||||
import com.android.settingslib.media.MediaDevice;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
@@ -64,6 +65,7 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
|
||||
private NotificationEntryManager mNotificationEntryManager =
|
||||
mock(NotificationEntryManager.class);
|
||||
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
|
||||
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
|
||||
|
||||
private MediaOutputGroupDialog mMediaOutputGroupDialog;
|
||||
private MediaOutputController mMediaOutputController;
|
||||
@@ -73,10 +75,11 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
|
||||
public void setUp() {
|
||||
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
|
||||
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
|
||||
mNotificationEntryManager, mUiEventLogger);
|
||||
mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
|
||||
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
|
||||
mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
|
||||
mMediaOutputController);
|
||||
mMediaOutputGroupDialog.show();
|
||||
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user